Permalink
Browse files

closes #52: Customization of generated files

  • Loading branch information...
1 parent 2b0d2e7 commit 004329eb6149f067f43d9bbff03d5c754a53d8d7 Heiko Seeberger committed Apr 11, 2012
@@ -20,7 +20,9 @@ package com.typesafe.sbteclipse.core
import EclipsePlugin.{
EclipseClasspathEntry,
+ EclipseTransformerFactory,
EclipseClasspathEntryTransformerFactory,
+ EclipseRewriteRuleTransformerFactory,
EclipseCreateSrc,
EclipseExecutionEnvironment,
EclipseKeys
@@ -51,7 +53,8 @@ import sbt.{
richFile
}
import sbt.complete.Parser
-import scala.xml.{ Elem, PrettyPrinter }
+import scala.xml.{ Node, PrettyPrinter }
+import scala.xml.transform.{ RewriteRule, RuleTransformer }
import scalaz.{ Failure, NonEmptyList, Success }
import scalaz.Scalaz._
import scalaz.effects._
@@ -107,6 +110,8 @@ private object Eclipse {
} yield {
val configs = configurations(ref, state)
val applic = classpathEntryTransformerFactory(ref, state).createTransformer(ref, state) |@|
+ (classpathTransformerFactories(ref, state) map (_.createTransformer(ref, state))).sequence[Validation, RewriteRule] |@|
+ (projectTransformerFactories(ref, state) map (_.createTransformer(ref, state))).sequence[Validation, RewriteRule] |@|
name(ref, state) |@|
buildDirectory(state) |@|
baseDirectory(ref, state) |@|
@@ -151,6 +156,8 @@ private object Eclipse {
relativizeLibs: Boolean,
state: State)(
classpathEntryTransformer: Seq[EclipseClasspathEntry] => Seq[EclipseClasspathEntry],
+ classpathTransformers: Seq[RewriteRule],
+ projectTransformers: Seq[RewriteRule],
name: String,
buildDirectory: File,
baseDirectory: File,
@@ -161,7 +168,7 @@ private object Eclipse {
for {
_ <- executePreTasks(preTasks, state)
n <- io(name)
- _ <- saveXml(baseDirectory / ".project", projectXml(name))
+ _ <- saveXml(baseDirectory / ".project", new RuleTransformer(projectTransformers: _*)(projectXml(name)))
cp <- classpath(
classpathEntryTransformer,
buildDirectory,
@@ -173,15 +180,15 @@ private object Eclipse {
jreContainer,
state
)
- _ <- saveXml(baseDirectory / ".classpath", cp)
+ _ <- saveXml(baseDirectory / ".classpath", new RuleTransformer(classpathTransformers: _*)(cp))
_ <- saveProperties(baseDirectory / ".settings" / "org.scala-ide.sdt.core.prefs", scalacOptions)
} yield n
}
def executePreTasks(preTasks: Seq[(TaskKey[_], ProjectRef)], state: State): IO[Unit] =
io(for ((preTask, ref) <- preTasks) evaluateTask(preTask, ref, state))
- def projectXml(name: String): Elem =
+ def projectXml(name: String): Node =
<projectDescription>
<name>{ name }</name>
<buildSpec>
@@ -204,7 +211,7 @@ private object Eclipse {
externalDependencies: Seq[Lib],
projectDependencies: Seq[String],
jreContainer: String,
- state: State): IO[Elem] = {
+ state: State): IO[Node] = {
val srcEntriesIoSeq =
for ((dir, output) <- srcDirectories) yield srcEntry(baseDirectory, dir, output, state)
for (srcEntries <- srcEntriesIoSeq.sequence) yield {
@@ -398,9 +405,22 @@ private object Eclipse {
def withSource(ref: Reference, state: State): Boolean =
setting(EclipseKeys.withSource in ref, state).fold(_ => false, id)
- def classpathEntryTransformerFactory(ref: Reference, state: State): EclipseClasspathEntryTransformerFactory =
- setting(EclipseKeys.classpathEntryTransformerFactory in ref, state).fold(_ =>
- EclipseClasspathEntryTransformerFactory.Default, id
+ def classpathEntryTransformerFactory(ref: Reference, state: State): EclipseTransformerFactory[Seq[EclipseClasspathEntry] => Seq[EclipseClasspathEntry]] =
+ setting(EclipseKeys.classpathEntryTransformerFactory in ref, state).fold(
+ _ => EclipseClasspathEntryTransformerFactory.Identity,
+ id
+ )
+
+ def classpathTransformerFactories(ref: Reference, state: State): Seq[EclipseTransformerFactory[RewriteRule]] =
+ setting(EclipseKeys.classpathTransformerFactories in ref, state).fold(
+ _ => Seq(EclipseRewriteRuleTransformerFactory.ClasspathDefault),
+ EclipseRewriteRuleTransformerFactory.ClasspathDefault +: _
+ )
+
+ def projectTransformerFactories(ref: Reference, state: State): Seq[EclipseTransformerFactory[RewriteRule]] =
+ setting(EclipseKeys.projectTransformerFactories in ref, state).fold(
+ _ => Seq(EclipseRewriteRuleTransformerFactory.Identity),
+ id
)
def configurations(ref: Reference, state: State): Seq[Configuration] =
@@ -423,7 +443,7 @@ private object Eclipse {
// IO
- def saveXml(file: File, xml: Elem): IO[Unit] =
+ def saveXml(file: File, xml: Node): IO[Unit] =
fileWriter(file).bracket(closeWriter)(writer => io(writer.write(new PrettyPrinter(999, 2) format xml)))
def saveProperties(file: File, settings: Seq[(String, String)]): IO[Unit] =
@@ -457,8 +477,8 @@ private object Eclipse {
private case class Content(
name: String,
dir: File,
- project: Elem,
- classpath: Elem,
+ project: Node,
+ classpath: Node,
scalacOptions: Seq[(String, String)])
private case class Lib(binary: File)(val source: Option[File])
@@ -32,7 +32,8 @@ import sbt.{
}
import sbt.Keys.{ baseDirectory, commands }
import scala.util.control.Exception
-import scala.xml.{ Attribute, Elem, Null, Text }
+import scala.xml.{ Attribute, Elem, MetaData, Node, Null, Text }
+import scala.xml.transform.RewriteRule
object EclipsePlugin extends EclipsePlugin
@@ -49,57 +50,66 @@ trait EclipsePlugin {
object EclipseKeys {
import EclipseOpts._
- val executionEnvironment: SettingKey[Option[EclipseExecutionEnvironment.Value]] =
- SettingKey[Option[EclipseExecutionEnvironment.Value]](
- prefix(ExecutionEnvironment),
- "The optional Eclipse execution environment.")
-
- val skipParents: SettingKey[Boolean] =
- SettingKey[Boolean](
- prefix(SkipParents),
- "Skip creating Eclipse files for parent project?")
-
- val withSource: SettingKey[Boolean] =
- SettingKey[Boolean](
- prefix(WithSource),
- "Download and link sources for library dependencies?")
-
- val classpathEntryTransformerFactory: SettingKey[EclipseClasspathEntryTransformerFactory] =
- SettingKey[EclipseClasspathEntryTransformerFactory](
- prefix("classpathEntryTransformerFactory"),
- "Creates a transformer for classpath entries.")
-
- val commandName: SettingKey[String] =
- SettingKey[String](
- prefix("command-name"),
- "The name of the command.")
-
- val configurations: SettingKey[Set[Configuration]] =
- SettingKey[Set[Configuration]](
- prefix("configurations"),
- "The configurations to take into account.")
-
- val createSrc: SettingKey[EclipseCreateSrc.ValueSet] =
- SettingKey[EclipseCreateSrc.ValueSet](
- prefix("create-src"),
- "The source kinds to be included."
- )
-
- val eclipseOutput: SettingKey[Option[String]] =
- SettingKey[Option[String]](
- prefix("eclipse-output"),
- "The optional output for Eclipse.")
-
- val preTasks: SettingKey[Seq[TaskKey[_]]] =
- SettingKey[Seq[TaskKey[_]]](
- prefix("pre-tasks"),
- "The tasks to be evaluated prior to creating the Eclipse project definition."
- )
-
- val relativizeLibs: SettingKey[Boolean] =
- SettingKey[Boolean](
- prefix("relativize-libs"),
- "Relativize the paths to the libraries?")
+ val executionEnvironment: SettingKey[Option[EclipseExecutionEnvironment.Value]] = SettingKey(
+ prefix(ExecutionEnvironment),
+ "The optional Eclipse execution environment."
+ )
+
+ val skipParents: SettingKey[Boolean] = SettingKey(
+ prefix(SkipParents),
+ "Skip creating Eclipse files for parent project?"
+ )
+
+ val withSource: SettingKey[Boolean] = SettingKey(
+ prefix(WithSource),
+ "Download and link sources for library dependencies?"
+ )
+
+ @deprecated("Use classpathTransformerFactories instead!", "2.1.0")
+ val classpathEntryTransformerFactory: SettingKey[EclipseTransformerFactory[Seq[EclipseClasspathEntry] => Seq[EclipseClasspathEntry]]] = SettingKey(
+ prefix("classpathEntryTransformerFactory"),
+ "Creates a transformer for classpath entries."
+ )
+
+ val classpathTransformerFactories: SettingKey[Seq[EclipseTransformerFactory[RewriteRule]]] = SettingKey(
+ prefix("classpathTransformerFactory"),
+ "Factories for a rewrite rule for the .classpath file."
+ )
+
+ val projectTransformerFactories: SettingKey[Seq[EclipseTransformerFactory[RewriteRule]]] = SettingKey(
+ prefix("projectTransformerFactory"),
+ "Factories for a rewrite rule for the .project file."
+ )
+
+ val commandName: SettingKey[String] = SettingKey(
+ prefix("command-name"),
+ "The name of the command."
+ )
+
+ val configurations: SettingKey[Set[Configuration]] = SettingKey(
+ prefix("configurations"),
+ "The configurations to take into account."
+ )
+
+ val createSrc: SettingKey[EclipseCreateSrc.ValueSet] = SettingKey(
+ prefix("create-src"),
+ "The source kinds to be included."
+ )
+
+ val eclipseOutput: SettingKey[Option[String]] = SettingKey(
+ prefix("eclipse-output"),
+ "The optional output for Eclipse."
+ )
+
+ val preTasks: SettingKey[Seq[TaskKey[_]]] = SettingKey(
+ prefix("pre-tasks"),
+ "The tasks to be evaluated prior to creating the Eclipse project definition."
+ )
+
+ val relativizeLibs: SettingKey[Boolean] = SettingKey(
+ prefix("relativize-libs"),
+ "Relativize the paths to the libraries?"
+ )
private def prefix(key: String) = "eclipse-" + key
}
@@ -124,7 +134,7 @@ trait EclipsePlugin {
}
sealed trait EclipseClasspathEntry {
- def toXml: Elem
+ def toXml: Node
}
object EclipseClasspathEntry {
@@ -169,38 +179,68 @@ trait EclipsePlugin {
val All = ValueSet(Unmanaged, Managed, Source, Resource)
}
- trait EclipseClasspathEntryTransformerFactory {
- def createTransformer(
- ref: ProjectRef,
- state: State): Validation[Seq[EclipseClasspathEntry] => Seq[EclipseClasspathEntry]]
+ trait EclipseTransformerFactory[A] {
+ def createTransformer(ref: ProjectRef, state: State): Validation[A]
}
object EclipseClasspathEntryTransformerFactory {
- object Identity extends EclipseClasspathEntryTransformerFactory {
- import scalaz.Scalaz._
- override def createTransformer(
- ref: ProjectRef,
- state: State): Validation[Seq[EclipseClasspathEntry] => Seq[EclipseClasspathEntry]] =
- ((entries: Seq[EclipseClasspathEntry]) => entries).success
- }
-
- object Default extends EclipseClasspathEntryTransformerFactory {
+ object Identity extends EclipseTransformerFactory[Seq[EclipseClasspathEntry] => Seq[EclipseClasspathEntry]] {
import scalaz.Scalaz._
override def createTransformer(
ref: ProjectRef,
state: State): Validation[Seq[EclipseClasspathEntry] => Seq[EclipseClasspathEntry]] = {
- val transformer =
- (entries: Seq[EclipseClasspathEntry]) => entries collect {
- case EclipseClasspathEntry.Lib(path, _) if path contains "scala-library.jar" =>
- EclipseClasspathEntry.Con("org.scala-ide.sdt.launching.SCALA_CONTAINER")
- case EclipseClasspathEntry.Lib(path, _) if path contains "scala-compiler.jar" =>
- EclipseClasspathEntry.Con("org.scala-ide.sdt.launching.SCALA_COMPILER_CONTAINER")
- case entry =>
- entry
- }
+ val transformer = (entries: Seq[EclipseClasspathEntry]) => entries
transformer.success
}
}
}
+
+ object EclipseRewriteRuleTransformerFactory {
+
+ object IdentityRewriteRule extends RewriteRule {
+ override def transform(node: Node): Node = node
+ }
+
+ object ClasspathDefaultRule extends RewriteRule {
+
+ private val CpEntry = "classpathentry"
+
+ private val ScalaContainer = "org.scala-ide.sdt.launching.SCALA_CONTAINER"
+
+ private val ScalaCompilerContainer = "org.scala-ide.sdt.launching.SCALA_COMPILER_CONTAINER"
+
+ override def transform(node: Node): Seq[Node] = node match {
+ case Elem(pf, CpEntry, attrs, scope, child @ _*) if isScalaLibrary(attrs) =>
+ Elem(pf, CpEntry, container(ScalaContainer), scope, child: _*)
+ case Elem(pf, CpEntry, attrs, scope, child @ _*) if isScalaCompiler(attrs) =>
+ Elem(pf, CpEntry, container(ScalaCompilerContainer), scope, child: _*)
+ case other =>
+ other
+ }
+
+ private def container(name: String) =
+ Attribute("kind", Text("con"), Attribute("path", Text(name), Null))
+
+ private def isScalaLibrary(metaData: MetaData) =
+ metaData("kind") == Text("lib") &&
+ (Option(metaData("path").text) map (_ contains "scala-library.jar") getOrElse false)
+
+ private def isScalaCompiler(metaData: MetaData) =
+ metaData("kind") == Text("lib") &&
+ (Option(metaData("path").text) map (_ contains "scala-compiler.jar") getOrElse false)
+ }
+
+ object Identity extends EclipseTransformerFactory[RewriteRule] {
+ import scalaz.Scalaz._
+ override def createTransformer(ref: ProjectRef, state: State): Validation[RewriteRule] =
+ IdentityRewriteRule.success
+ }
+
+ object ClasspathDefault extends EclipseTransformerFactory[RewriteRule] {
+ import scalaz.Scalaz._
+ override def createTransformer(ref: ProjectRef, state: State): Validation[RewriteRule] =
+ ClasspathDefaultRule.success
+ }
+ }
}
@@ -140,6 +140,7 @@ TaskKey[Unit]("verify-classpath-xml-subb") <<= baseDirectory map { dir =>
TaskKey[Unit]("verify-classpath-xml-subc") <<= baseDirectory map { dir =>
val classpath = XML.loadFile(dir / "sub" / "subc" / ".classpath")
+ val project = XML.loadFile(dir / "sub" / "subc" / ".project")
if ((classpath \ "classpathentry") != (classpath \ "classpathentry").distinct)
error("Expected .classpath of subc project not to contain duplicate entries: %s" format classpath)
// src entries
@@ -148,6 +149,13 @@ TaskKey[Unit]("verify-classpath-xml-subc") <<= baseDirectory map { dir =>
// lib entries with absolute paths
if (!(classpath.child contains <classpathentry kind="lib" path={ "%s/lib_managed/jars/biz.aQute/bndlib/bndlib-1.50.0.jar".format(dir.getCanonicalPath) } />))
error("""Expected .classpath of subc project to contain <classpathentry kind="lib" path="%s/lib_managed/jars/biz.aQute/bndlib/bndlib-1.50.0.jar" />: %s""".format(dir.getCanonicalPath, classpath))
+ // classpath transformer
+ if (!(classpath.child contains <classpathentry kind="con" path="org.scala-ide.sdt.launching.SCALA_CONTAINER"/>))
+ error("""Expected .classpath of root project to contain <classpathentry kind="con" path="org.scala-ide.sdt.launching.SCALA_CONTAINER"/> """)
+ if (!(classpath.child contains <foo bar="baz"/>))
+ error("""Expected .classpath of subc project to contain <foo bar="baz"/>!""")
+ if (!(project.child contains <foo bar="baz"/>))
+ error("""Expected .project of subc project to contain <foo bar="baz"/>!""")
}
TaskKey[Unit]("verify-settings") <<= baseDirectory map { dir =>
Oops, something went wrong.

0 comments on commit 004329e

Please sign in to comment.