Skip to content

Instantly share code, notes, and snippets.

@fxthomas
Last active August 3, 2016 09:17
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fxthomas/5006558 to your computer and use it in GitHub Desktop.
Save fxthomas/5006558 to your computer and use it in GitHub Desktop.
SBTEclipse wiki entry about changing project description files

Changing project files

Eclipse .project and .classpath files are XML files, and you can hook into sbteclipse's generation process by using the classpathTransformerFactories and projectTransformerFactories setting keys.

(The following Scala samples should be inside your project's Build.scala file, or a plugin)

Let's say we want to add the com.example.nature nature to our project. The Eclipse project file has an element called <natures>, under which each nature is listed. For example, here is what sbteclipse will generate out of the box :

<natures>
  <nature>org.scala-ide.sdt.core.scalanature</nature>
  <nature>org.eclipse.jdt.core.javanature</nature>
</natures>

Now, you want to insert this Node inside the <natures> tag :

val to_insert = <nature>com.example.nature</nature>

Let's create an XML rewrite rule for that :

import scala.xml.{Node, Elem}
import scala.xml.transform.RewriteRule

object MyExampleRule extends RewriteRule {
  override def transform(parent: Node): Seq[Node] = {
    parent match {
      // Match the <natures> tag, store the children inside `children`, and
      // return a new tag with the new nature.
      case <natures>{children @ _*}</natures> =>
        <natures>{children ++ Seq(to_insert): _*}</natures>

      // For all other parent tags, do nothing
      case other => other
    }
  }
}

Then, wrap it inside a transformer factory to use it within sbteclipse :

import scalaz.Scalaz._
import com.typesafe.sbteclipse.plugin.EclipsePlugin.EclipseTransformerFactory
import com.typesafe.sbteclipse.core.Validation

object MyExampleTransformer extends EclipseTransformerFactory[RewriteRule] {
  override def createTransformer(
    ref: Project,
    state: State): Validation[RewriteRule] = {

    // `success` is a method of the Validation object
    MyExampleRule.success
  }
}

Finally, you're done, add it inside the projectTransformerFactories key :

EclipseKeys.projectTransformerFactories := Seq(MyExampleTransformer)

Changing classpath files

The .classpath XML files can be modified with the same method. The transformer factories are to be added to the classpathTransformerFactories key.

@hseeberger
Copy link

Looks very good. Your MyExampleRule doesn't compile (under Scala 2.10), though, and it can be simplified:

import scala.xml.Node
import xml.transform.{RuleTransformer, RewriteRule}

class AddNatureRule(nature: String) extends RewriteRule {
  override def transform(parent: Node): Seq[Node] =
    parent match {
      // Match the <natures> tag and add the new nature
      case <natures>{ children }</natures> =>
        <natures>{ children ++ <nature>{ nature }</nature> }</natures>
      // For all other parent tags, do nothing
      case other => other
    }
}

In addition, let's make the MyExampleTransformer code more concise:

object MyExampleTransformer extends EclipseTransformerFactory[RewriteRule] {
  override def createTransformer(ref: Project, state: State): Validation[RewriteRule] =
    MyExampleRule.success  // `success` creates a `Success` (subtype of `Validation`)
}

@kimhanse
Copy link

This is my hack for changing the .classpath file such that a library from a Maven project I have the source for gets configured in Eclipse as a project dependency:

in build.sbt:

EclipseKeys.classpathTransformerFactories := Seq(ClasspathentryTransformer)

in project/Build.scala:

import com.typesafe.sbteclipse.core.Validation
import com.typesafe.sbteclipse.plugin.EclipsePlugin.EclipseTransformerFactory
import sbt.ProjectRef
import sbt.State
import scala.xml.Node
import scalaz.Scalaz.ToValidationV
import xml.transform.RewriteRule

object ClasspathentryRewriteRule extends RewriteRule {
  override def transform(parent: Node): Seq[Node] = {
    parent match {
      // Change classpathentry from Maven repository to Eclipse project dependency
      case c @ <classpathentry/> if (c \ "@path").toString().endsWith("sto-format-0.2.0-SNAPSHOT.jar") =>
        <classpathentry combineaccessrules="false" kind="src" path="/sto-format"/>
      // For all other parent tags, do nothing
      case other => other
    }
  }
}

object ClasspathentryTransformer extends EclipseTransformerFactory[RewriteRule] {
  override def createTransformer(ref: ProjectRef, state: State): Validation[RewriteRule] = {
    ClasspathentryRewriteRule.success // "success" creates a Success (subtype of Validation)
  }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment