Open godenji opened 7 years ago
From an sbt session in a test project:
> reload plugins
> eclipse
Downloads plugin sources and correctly generates .classpath
file, but in project/
, not the project root.
Beyond manually attaching plugin sources in Eclipse is there a way to do this via sbt-eclipse?
Why do you need the plugin or it's sources on the project classpath?
@benmccann so I can browse the plugin sources in Eclipse?
In sbt when I define libraryDependencies += "my-dep" % ... % withSources()
in my build the eclipse
command generates 2 files for the IDE, .classpath
and .project
. In the .classpath
file are <classpathentry sourcepath="...">
entries for the library. I can then click a library class or method within Eclipse and be taken directly to the source.
This does not happen, for some reason, with dependencies defined in project/plugins.sbt
. There are several plugins I'd like to have sources be available for in Eclipse.
Maybe I'm not explaining this properly. Basically, somehow, I'd like the eclipse
command to do the equivalent of "Attach Source" manually in the IDE for project/plugins.sbt
deps.
Worked around with EclipseTransformerFactory
by appending sourcepath
to <classpath ...>
in a custom rewrite handler.
Does the trick but would be nice if sbteclipse did this out of the box when plugins defined in project/plugins.sbt
have withSources
appended to dep line.
@godenji Can you share the workaround? Thanks!
@mkurz sure, here's a stripped down version (have more rewrites to deal with in my implementation). Hacky, but better than manually attaching sources in Eclipse, no thanks ;-)
Add this to your settings once you have the below in place:
EclipseKeys.classpathTransformerFactories := Seq(addSourcesManaged)
import com.typesafe.sbteclipse.core.EclipsePlugin.EclipseTransformerFactory
import com.typesafe.sbteclipse.core._
import scala.xml.transform.RewriteRule
import scala.xml.{Attribute, Text, Null, Node, Elem}
import scalaz.Scalaz._
def findPath(node: Node, search: String) =
node.attributes.asAttrMap.get("path").
filter(_.contains(search))
sealed trait ClasspathAttribs
object ClasspathAttribs {
case object SOURCEPATH extends ClasspathAttribs
case object OUTPUT extends ClasspathAttribs
}
import ClasspathAttribs._
def collectRewrites(node: Node): Set[(ClasspathAttribs, String)] =
Set(
findPath(node, "/com/typesafe/play").map((SOURCEPATH, _)),
findPath(node, "/org/scala-js").map((SOURCEPATH, _))
).flatten
lazy val addSourcesManaged =
new EclipseTransformerFactory[RewriteRule] {
override def createTransformer(ref: ProjectRef, state: State): Validation[RewriteRule] = {
settingValidation(crossTarget in ref, state).map{ ct =>
new RewriteRule {
override def transform(node: Node): Seq[Node] = {
val attribs = collectRewrites(node)
node match {
case el if el.label == "classpathentry" && attribs.exists(_._1 == SOURCEPATH) =>
val elem = Elem(
el.prefix, "classpathentry", el.attributes, el.scope, true
)
attribs.headOption.map(_._2).map { str =>
elem % Attribute(
None, "sourcepath", Text(str.replace(".jar", "-sources.jar")), Null
)
} getOrElse(el)
}
}
}
}
}
}
@mkurz you'll need this as well
def structure(state: State): BuildStructure = Project.extract(state).structure
def settingValidation[A](key: SettingKey[A], state: State): Validation[A] =
key.get(structure(state).data) match {
case Some(a) => a.success
case None => "Undefined setting '%s'!".format(key.key).failureNel
}
@godenji Thanks, but I am getting:
build.sbt:16: error: not found: object ClasspathAttribs
import ClasspathAttribs._
^
build.sbt:18: error: not found: type ClasspathAttribs
def collectRewrites(node: Node): Set[(ClasspathAttribs, String)] =
^
build.sbt:20: error: not found: value SOURCEPATH
findPath(node, "/com/typesafe/play").map((SOURCEPATH, _)),
^
build.sbt:21: error: not found: value SOURCEPATH
findPath(node, "/org/scala-js").map((SOURCEPATH, _))
^
sbt.compiler.EvalException: Type error in expression
[error] sbt.compiler.EvalException: Type error in expression
Create a Transformers.scala file in your project/
trait Transformers {
... all the code
}
object Transformers extends Transformers
then in your build.sbt:
import Transformers._
Would you mind also pasting here a full example of what is added to the .classpath
file by this code for one SBT plugin?
@benmccann
In the case of Play framework the plugin is split up into several different jars. Here's the original classpath entry for one of them, play-server:
<classpathentry kind="lib" path="/path/to/.coursier/cache/v1/https/repo1.maven.org/maven2/com/typesafe/play/play-server_2.12/2.6.0-M4/play-server_2.12-2.6.0-M4.jar"/>
and now with sourcepath appended:
<classpathentry sourcepath="/path/to/.coursier/cache/v1/https/repo1.maven.org/maven2/com/typesafe/play/play-server_2.12/2.6.0-M4/play-server_2.12-2.6.0-M4-sources.jar" kind="lib" path="/path/to/.coursier/cache/v1/https/repo1.maven.org/maven2/com/typesafe/play/play-server_2.12/2.6.0-M4/play-server_2.12-2.6.0-M4.jar"/>
When I
eclipse
generate my projects none of the plugins inproject/plugins.sbt
have corresponding<classpathentry sourcepath="...">
entries in the project's generated.classpath
file. For library dependencies, no problem, sourcepath entries are generated correctly.Running
coursier
the target plugins and their sources are downloaded so the sources are available on the file system.// example /project/plugins.sbt
"com.typesafe.play" % "sbt-plugin" % "2.6.0-M4" withSources
sbt 0.13.15 scala 2.12.2 sbteclipse 5.1.0