Skip to content

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
...
  • 5 commits
  • 32 files changed
  • 0 commit comments
  • 1 contributor
Showing with 514 additions and 149 deletions.
  1. +35 −12 compile/AnalyzingCompiler.scala
  2. +1 −1 compile/ClasspathOptions.scala
  3. +4 −3 compile/CompilerArguments.scala
  4. +15 −0 compile/CompilerInterfaceProvider.scala
  5. +21 −10 compile/JavaCompiler.scala
  6. +1 −1 compile/RawCompiler.scala
  7. +5 −9 compile/inc/CompileSetup.scala
  8. +60 −9 compile/integration/AggressiveCompile.scala
  9. +32 −0 compile/integration/IncrementalCompiler.scala
  10. +14 −30 compile/{ → ivy}/ComponentCompiler.scala
  11. +8 −3 compile/persist/AnalysisFormats.scala
  12. +9 −0 interface/src/main/java/xsbti/ArtifactInfo.java
  13. +29 −0 interface/src/main/java/xsbti/compile/ClasspathOptions.java
  14. +34 −0 interface/src/main/java/xsbti/compile/CompileOrder.java
  15. +8 −0 interface/src/main/java/xsbti/compile/Compilers.java
  16. +14 −0 interface/src/main/java/xsbti/compile/DefinesClass.java
  17. +61 −0 interface/src/main/java/xsbti/compile/IncrementalCompiler.java
  18. +14 −0 interface/src/main/java/xsbti/compile/Inputs.java
  19. +15 −0 interface/src/main/java/xsbti/compile/JavaCompiler.java
  20. +33 −0 interface/src/main/java/xsbti/compile/Options.java
  21. +34 −0 interface/src/main/java/xsbti/compile/ScalaInstance.java
  22. +24 −0 interface/src/main/java/xsbti/compile/Setup.java
  23. +6 −4 ivy/IvyScala.scala
  24. +1 −1 main/Build.scala
  25. +6 −2 main/Defaults.scala
  26. +2 −1 main/Keys.scala
  27. +1 −0 main/Load.scala
  28. +11 −56 {compile/integration → main/actions}/Compiler.scala
  29. +3 −3 main/actions/Doc.scala
  30. +4 −3 project/Sbt.scala
  31. +4 −0 sbt/package.scala
  32. +5 −1 util/classpath/ScalaInstance.scala
View
47 compile/AnalyzingCompiler.scala
@@ -12,9 +12,9 @@ package compiler
* provided by scalaInstance. This class requires a ComponentManager in order to obtain the interface code to scalac and
* the analysis plugin. Because these call Scala code for a different Scala version than the one used for this class, they must
* be compiled for the version of Scala being used.*/
-class AnalyzingCompiler(val scalaInstance: ScalaInstance, val manager: ComponentManager, val cp: ClasspathOptions, log: Logger)
+class AnalyzingCompiler(val scalaInstance: xsbti.compile.ScalaInstance, val provider: CompilerInterfaceProvider, val cp: xsbti.compile.ClasspathOptions, log: Logger)
{
- def this(scalaInstance: ScalaInstance, manager: ComponentManager, log: Logger) = this(scalaInstance, manager, ClasspathOptions.auto, log)
+ def this(scalaInstance: ScalaInstance, provider: CompilerInterfaceProvider, log: Logger) = this(scalaInstance, provider, ClasspathOptions.auto, log)
def apply(sources: Seq[File], classpath: Seq[File], outputDirectory: File, options: Seq[String], callback: AnalysisCallback, maximumErrors: Int, log: Logger)
{
val arguments = (new CompilerArguments(scalaInstance, cp))(sources, classpath, outputDirectory, options)
@@ -48,7 +48,7 @@ class AnalyzingCompiler(val scalaInstance: ScalaInstance, val manager: Component
classOf[Array[String]], classOf[String], classOf[String], classOf[String], classOf[String], classOf[ClassLoader], classOf[Array[String]], classOf[Array[Any]], classOf[xLogger])(
options.toArray[String]: Array[String], bootClasspath, classpathString, initialCommands, cleanupCommands, loader.orNull, names.toArray[String], values.toArray[Any], log)
}
- def force(log: Logger): Unit = getInterfaceJar(log)
+ def force(log: Logger): Unit = provider(scalaInstance, log)
private def call(interfaceClassName: String, log: Logger)(argTypes: Class[_]*)(args: AnyRef*)
{
val interfaceClass = getInterfaceClass(interfaceClassName, log)
@@ -59,20 +59,12 @@ class AnalyzingCompiler(val scalaInstance: ScalaInstance, val manager: Component
}
private[this] def loader =
{
- val interfaceJar = getInterfaceJar(log)
+ val interfaceJar = provider(scalaInstance, log)
// this goes to scalaInstance.loader for scala classes and the loader of this class for xsbti classes
val dual = createDualLoader(scalaInstance.loader, getClass.getClassLoader)
new URLClassLoader(Array(interfaceJar.toURI.toURL), dual)
}
private def getInterfaceClass(name: String, log: Logger) = Class.forName(name, true, loader)
- private def getInterfaceJar(log: Logger) =
- {
- // this is the instance used to compile the interface component
- val componentCompiler = newComponentCompiler(log)
- log.debug("Getting " + ComponentCompiler.compilerInterfaceID + " from component compiler for Scala " + scalaInstance.version)
- componentCompiler(ComponentCompiler.compilerInterfaceID)
- }
- def newComponentCompiler(log: Logger) = new ComponentCompiler(new RawCompiler(scalaInstance, ClasspathOptions.auto, log), manager)
protected def createDualLoader(scalaLoader: ClassLoader, sbtLoader: ClassLoader): ClassLoader =
{
val xsbtiFilter = (name: String) => name.startsWith("xsbti.")
@@ -80,4 +72,35 @@ class AnalyzingCompiler(val scalaInstance: ScalaInstance, val manager: Component
new classpath.DualLoader(scalaLoader, notXsbtiFilter, x => true, sbtLoader, xsbtiFilter, x => false)
}
override def toString = "Analyzing compiler (Scala " + scalaInstance.actualVersion + ")"
+}
+object AnalyzingCompiler
+{
+ import sbt.IO.{copy, createDirectory, zip, jars, unzip, withTemporaryDirectory}
+
+ /** Extract sources from source jars, compile them with the xsbti interfaces on the classpath, and package the compiled classes and
+ * any resources from the source jars into a final jar.*/
+ def compileSources(sourceJars: Iterable[File], targetJar: File, xsbtiJars: Iterable[File], id: String, compiler: RawCompiler, log: Logger)
+ {
+ val isSource = (f: File) => isSourceName(f.getName)
+ def keepIfSource(files: Set[File]): Set[File] = if(files.exists(isSource)) files else Set()
+
+ withTemporaryDirectory { dir =>
+ val extractedSources = (Set[File]() /: sourceJars) { (extracted, sourceJar)=> extracted ++ keepIfSource(unzip(sourceJar, dir)) }
+ val (sourceFiles, resources) = extractedSources.partition(isSource)
+ withTemporaryDirectory { outputDirectory =>
+ log.info("'" + id + "' not yet compiled for Scala " + compiler.scalaInstance.actualVersion + ". Compiling...")
+ val start = System.currentTimeMillis
+ try
+ {
+ compiler(sourceFiles.toSeq, xsbtiJars.toSeq ++ sourceJars, outputDirectory, "-nowarn" :: Nil)
+ log.info(" Compilation completed in " + (System.currentTimeMillis - start) / 1000.0 + " s")
+ }
+ catch { case e: xsbti.CompileFailed => throw new CompileFailed(e.arguments, "Error compiling sbt component '" + id + "'") }
+ import sbt.Path._
+ copy(resources x rebase(dir, outputDirectory))
+ zip((outputDirectory ***) x_! relativeTo(outputDirectory), targetJar)
+ }
+ }
+ }
+ private def isSourceName(name: String): Boolean = name.endsWith(".scala") || name.endsWith(".java")
}
View
2 compile/ClasspathOptions.scala
@@ -3,7 +3,7 @@
*/
package sbt
-final case class ClasspathOptions(bootLibrary: Boolean, compiler: Boolean, extra: Boolean, autoBoot: Boolean, filterLibrary: Boolean)
+final case class ClasspathOptions(bootLibrary: Boolean, compiler: Boolean, extra: Boolean, autoBoot: Boolean, filterLibrary: Boolean) extends xsbti.compile.ClasspathOptions
object ClasspathOptions
{
def manual = ClasspathOptions(false, false, false, true, false)
View
7 compile/CompilerArguments.scala
@@ -4,6 +4,7 @@
package sbt
package compiler
+ import xsbti.ArtifactInfo
import scala.util
import java.io.File
import CompilerArguments.{abs, absString, BootClasspathOption}
@@ -13,7 +14,7 @@ package compiler
* order to add these jars to the boot classpath. The 'scala.home' property must be unset because Scala
* puts jars in that directory on the bootclasspath. Because we use multiple Scala versions,
* this would lead to compiling against the wrong library jar.*/
-final class CompilerArguments(scalaInstance: ScalaInstance, cp: ClasspathOptions)
+final class CompilerArguments(scalaInstance: xsbti.compile.ScalaInstance, cp: xsbti.compile.ClasspathOptions)
{
def apply(sources: Seq[File], classpath: Seq[File], outputDirectory: File, options: Seq[String]): Seq[String] =
{
@@ -27,7 +28,7 @@ final class CompilerArguments(scalaInstance: ScalaInstance, cp: ClasspathOptions
options ++ outputOption ++ bootClasspathOption ++ classpathOption ++ abs(sources)
}
def finishClasspath(classpath: Seq[File]): Seq[File] =
- filterLibrary(classpath) ++ include(cp.compiler, scalaInstance.compilerJar) ++ include(cp.extra, scalaInstance.extraJars : _*)
+ filterLibrary(classpath) ++ include(cp.compiler, scalaInstance.compilerJar) ++ include(cp.extra, scalaInstance.otherJars : _*)
private def include(flag: Boolean, jars: File*) = if(flag) jars else Nil
protected def abs(files: Seq[File]) = files.map(_.getAbsolutePath).sortWith(_ < _)
protected def checkScalaHomeUnset()
@@ -48,7 +49,7 @@ final class CompilerArguments(scalaInstance: ScalaInstance, cp: ClasspathOptions
originalBoot
}
def filterLibrary(classpath: Seq[File]) =
- if(cp.filterLibrary) classpath.filterNot(_.getName contains ScalaArtifacts.LibraryID) else classpath
+ if(cp.filterLibrary) classpath.filterNot(_.getName contains ArtifactInfo.ScalaLibraryID) else classpath
def bootClasspathOption = if(cp.autoBoot) Seq(BootClasspathOption, createBootClasspath) else Nil
def bootClasspath = if(cp.autoBoot) IO.parseClasspath(createBootClasspath) else Nil
}
View
15 compile/CompilerInterfaceProvider.scala
@@ -0,0 +1,15 @@
+package sbt
+package compiler
+
+ import java.io.File
+
+trait CompilerInterfaceProvider
+{
+ def apply(scalaInstance: xsbti.compile.ScalaInstance, log: Logger): File
+}
+object CompilerInterfaceProvider
+{
+ def constant(file: File): CompilerInterfaceProvider = new CompilerInterfaceProvider {
+ def apply(scalaInstance: xsbti.compile.ScalaInstance, log: Logger): File = file
+ }
+}
View
31 compile/JavaCompiler.scala
@@ -9,14 +9,25 @@ import java.io.{File, PrintWriter}
abstract class JavacContract(val name: String, val clazz: String) {
def exec(args: Array[String], writer: PrintWriter): Int
}
-trait JavaCompiler
+trait JavaCompiler extends xsbti.compile.JavaCompiler
{
- def apply(sources: Seq[File], classpath: Seq[File], outputDirectory: File, options: Seq[String])(implicit log: Logger) {
+ def apply(sources: Seq[File], classpath: Seq[File], outputDirectory: File, options: Seq[String])(implicit log: Logger)
+
+ def compile(sources: Array[File], classpath: Array[File], outputDirectory: File, options: Array[String], maxErrors: Int, log: xsbti.Logger): Unit =
+ apply(sources, classpath, outputDirectory, options)(log)
+}
+trait Javadoc
+{
+ def doc(sources: Seq[File], classpath: Seq[File], outputDirectory: File, options: Seq[String], maximumErrors: Int, log: Logger)
+}
+trait JavaTool extends Javadoc with JavaCompiler
+{
+ def apply(sources: Seq[File], classpath: Seq[File], outputDirectory: File, options: Seq[String])(implicit log: Logger) =
compile(JavaCompiler.javac, sources, classpath, outputDirectory, options)(log)
- }
- def doc(sources: Seq[File], classpath: Seq[File], outputDirectory: File, options: Seq[String], maximumErrors: Int, log: Logger) {
+
+ def doc(sources: Seq[File], classpath: Seq[File], outputDirectory: File, options: Seq[String], maximumErrors: Int, log: Logger) =
compile(JavaCompiler.javadoc, sources, classpath, outputDirectory, options)(log)
- }
+
def compile(contract: JavacContract, sources: Seq[File], classpath: Seq[File], outputDirectory: File, options: Seq[String])(implicit log: Logger): Unit
}
object JavaCompiler
@@ -36,8 +47,8 @@ object JavaCompiler
}
}
- def construct(f: Fork, cp: ClasspathOptions, scalaInstance: ScalaInstance): JavaCompiler =
- new JavaCompiler {
+ def construct(f: Fork, cp: ClasspathOptions, scalaInstance: ScalaInstance): JavaTool =
+ new JavaTool {
def compile(contract: JavacContract, sources: Seq[File], classpath: Seq[File], outputDirectory: File, options: Seq[String])(implicit log: Logger) {
val augmentedClasspath = if(cp.autoBoot) classpath ++ Seq(scalaInstance.libraryJar) else classpath
val javaCp = ClasspathOptions.javac(cp.compiler)
@@ -48,13 +59,13 @@ object JavaCompiler
if( code != 0 ) throw new CompileFailed(arguments.toArray, contract.name + " returned nonzero exit code")
}
}
- def directOrFork(cp: ClasspathOptions, scalaInstance: ScalaInstance)(implicit doFork: Fork): JavaCompiler =
+ def directOrFork(cp: ClasspathOptions, scalaInstance: ScalaInstance)(implicit doFork: Fork): JavaTool =
construct(directOrForkJavac, cp, scalaInstance)
- def direct(cp: ClasspathOptions, scalaInstance: ScalaInstance): JavaCompiler =
+ def direct(cp: ClasspathOptions, scalaInstance: ScalaInstance): JavaTool =
construct(directJavac, cp, scalaInstance)
- def fork(cp: ClasspathOptions, scalaInstance: ScalaInstance)(implicit doFork: Fork): JavaCompiler =
+ def fork(cp: ClasspathOptions, scalaInstance: ScalaInstance)(implicit doFork: Fork): JavaTool =
construct(forkJavac, cp, scalaInstance)
def directOrForkJavac(implicit doFork: Fork) = (contract: JavacContract, arguments: Seq[String], log: Logger) =>
View
2 compile/RawCompiler.scala
@@ -10,7 +10,7 @@ package compiler
* is used, for example, to compile the interface/plugin code.
* If `explicitClasspath` is true, the bootclasspath and classpath are not augmented. If it is false,
* the scala-library.jar from `scalaInstance` is put on bootclasspath and the scala-compiler jar goes on the classpath.*/
-class RawCompiler(val scalaInstance: ScalaInstance, cp: ClasspathOptions, log: Logger)
+class RawCompiler(val scalaInstance: xsbti.compile.ScalaInstance, cp: ClasspathOptions, log: Logger)
{
def apply(sources: Seq[File], classpath: Seq[File], outputDirectory: File, options: Seq[String])
{
View
14 compile/inc/CompileSetup.scala
@@ -3,24 +3,20 @@
*/
package sbt
+ import xsbti.compile.CompileOrder
import java.io.File
-object CompileOrder extends Enumeration
-{
- val Mixed, JavaThenScala, ScalaThenJava = Value
-}
-
// this class exists because of Scala's restriction on implicit parameter search.
// We cannot require an implicit parameter Equiv[Seq[String]] to construct Equiv[CompileSetup]
// because complexity(Equiv[Seq[String]]) > complexity(Equiv[CompileSetup])
// (6 > 4)
final class CompileOptions(val options: Seq[String], val javacOptions: Seq[String])
-final class CompileSetup(val outputDirectory: File, val options: CompileOptions, val compilerVersion: String, val order: CompileOrder.Value)
+final class CompileSetup(val outputDirectory: File, val options: CompileOptions, val compilerVersion: String, val order: CompileOrder)
object CompileSetup
{
// Equiv[CompileOrder.Value] dominates Equiv[CompileSetup]
- implicit def equivCompileSetup(implicit equivFile: Equiv[File], equivOpts: Equiv[CompileOptions], equivComp: Equiv[String]/*, equivOrder: Equiv[CompileOrder.Value]*/): Equiv[CompileSetup] = new Equiv[CompileSetup] {
+ implicit def equivCompileSetup(implicit equivFile: Equiv[File], equivOpts: Equiv[CompileOptions], equivComp: Equiv[String]/*, equivOrder: Equiv[CompileOrder]*/): Equiv[CompileSetup] = new Equiv[CompileSetup] {
def equiv(a: CompileSetup, b: CompileSetup) =
equivFile.equiv(a.outputDirectory, b.outputDirectory) &&
equivOpts.equiv(a.options, b.options) &&
@@ -39,7 +35,7 @@ object CompileSetup
def equiv(a: String, b: String) = a == b
}
- implicit val equivOrder: Equiv[CompileOrder.Value] = new Equiv[CompileOrder.Value] {
- def equiv(a: CompileOrder.Value, b: CompileOrder.Value) = a == b
+ implicit val equivOrder: Equiv[CompileOrder] = new Equiv[CompileOrder] {
+ def equiv(a: CompileOrder, b: CompileOrder) = a == b
}
}
View
69 compile/integration/AggressiveCompile.scala
@@ -2,27 +2,29 @@
* Copyright 2010 Mark Harrah
*/
package sbt
+package compiler
import inc._
import java.io.File
- import compiler.{AnalyzingCompiler, CompilerArguments, JavaCompiler}
import classpath.ClasspathUtilities
import classfile.Analyze
import xsbti.api.Source
+ import xsbti.compile.CompileOrder
+ import CompileOrder.{JavaThenScala, Mixed, ScalaThenJava}
import xsbti.AnalysisCallback
import inc.Locate.DefinesClass
import CompileSetup._
- import CompileOrder.{JavaThenScala, Mixed, ScalaThenJava}
import sbinary.DefaultProtocol.{ immutableMapFormat, immutableSetFormat, StringFormat }
+ import Types.const
final class CompileConfiguration(val sources: Seq[File], val classpath: Seq[File],
val previousAnalysis: Analysis, val previousSetup: Option[CompileSetup], val currentSetup: CompileSetup, val getAnalysis: File => Option[Analysis], val definesClass: DefinesClass,
- val maxErrors: Int, val compiler: AnalyzingCompiler, val javac: JavaCompiler)
+ val maxErrors: Int, val compiler: AnalyzingCompiler, val javac: xsbti.compile.JavaCompiler)
class AggressiveCompile(cacheFile: File)
{
- def apply(compiler: AnalyzingCompiler, javac: JavaCompiler, sources: Seq[File], classpath: Seq[File], outputDirectory: File, options: Seq[String] = Nil, javacOptions: Seq[String] = Nil, analysisMap: Map[File, Analysis] = Map.empty, definesClass: DefinesClass = Locate.definesClass _, maxErrors: Int = 100, compileOrder: CompileOrder.Value = Mixed, skip: Boolean = false)(implicit log: Logger): Analysis =
+ def apply(compiler: AnalyzingCompiler, javac: xsbti.compile.JavaCompiler, sources: Seq[File], classpath: Seq[File], outputDirectory: File, options: Seq[String] = Nil, javacOptions: Seq[String] = Nil, analysisMap: File => Option[Analysis] = const(None), definesClass: DefinesClass = Locate.definesClass _, maxErrors: Int = 100, compileOrder: CompileOrder = Mixed, skip: Boolean = false)(implicit log: Logger): Analysis =
{
val setup = new CompileSetup(outputDirectory, new CompileOptions(options, javacOptions), compiler.scalaInstance.actualVersion, compileOrder)
compile1(sources, classpath, setup, store, analysisMap, definesClass, compiler, javac, maxErrors, skip)
@@ -31,13 +33,13 @@ class AggressiveCompile(cacheFile: File)
def withBootclasspath(args: CompilerArguments, classpath: Seq[File]): Seq[File] =
args.bootClasspath ++ args.finishClasspath(classpath)
- def compile1(sources: Seq[File], classpath: Seq[File], setup: CompileSetup, store: AnalysisStore, analysis: Map[File, Analysis], definesClass: DefinesClass, compiler: AnalyzingCompiler, javac: JavaCompiler, maxErrors: Int, skip: Boolean)(implicit log: Logger): Analysis =
+ def compile1(sources: Seq[File], classpath: Seq[File], setup: CompileSetup, store: AnalysisStore, analysis: File => Option[Analysis], definesClass: DefinesClass, compiler: AnalyzingCompiler, javac: xsbti.compile.JavaCompiler, maxErrors: Int, skip: Boolean)(implicit log: Logger): Analysis =
{
val (previousAnalysis, previousSetup) = extract(store.get())
if(skip)
previousAnalysis
else {
- val config = new CompileConfiguration(sources, classpath, previousAnalysis, previousSetup, setup, analysis.get _, definesClass, maxErrors, compiler, javac)
+ val config = new CompileConfiguration(sources, classpath, previousAnalysis, previousSetup, setup, analysis, definesClass, maxErrors, compiler, javac)
val (modified, result) = compile2(config)
if(modified)
store.set(result, setup)
@@ -73,7 +75,7 @@ class AggressiveCompile(cacheFile: File)
val loader = ClasspathUtilities.toLoader(searchClasspath)
def readAPI(source: File, classes: Seq[Class[_]]) { callback.api(source, ClassToAPI(classes)) }
Analyze(outputDirectory, javaSrcs, log)(callback, loader, readAPI) {
- javac(javaSrcs, absClasspath, outputDirectory, options.javacOptions)
+ javac.compile(javaSrcs.toArray, absClasspath.toArray, outputDirectory, options.javacOptions.toArray, maxErrors, log)
}
}
if(order == JavaThenScala) { compileJava(); compileScala() } else { compileScala(); compileJava() }
@@ -108,7 +110,7 @@ class AggressiveCompile(cacheFile: File)
import AnalysisFormats._
val store = AggressiveCompile.staticCache(cacheFile, AnalysisStore.sync(AnalysisStore.cached(FileBasedStore(cacheFile))))
}
-private object AggressiveCompile
+object AggressiveCompile
{
import collection.mutable
import java.lang.ref.{Reference,SoftReference}
@@ -121,4 +123,53 @@ private object AggressiveCompile
b
}
}
-}
+
+ def directOrFork(instance: ScalaInstance, cpOptions: ClasspathOptions, javaHome: Option[File]): JavaTool =
+ if(javaHome.isDefined)
+ JavaCompiler.fork(cpOptions, instance)(forkJavac(javaHome))
+ else
+ JavaCompiler.directOrFork(cpOptions, instance)(forkJavac(None))
+
+ def forkJavac(javaHome: Option[File]): JavaCompiler.Fork =
+ {
+ import Path._
+ def exec(jc: JavacContract) = javaHome match { case None => jc.name; case Some(jh) => (jh / "bin" / jc.name).absolutePath }
+ (contract: JavacContract, args: Seq[String], log: Logger) => {
+ log.debug("Forking " + contract.name + ": " + exec(contract) + " " + args.mkString(" "))
+ val javacLogger = new JavacLogger(log)
+ var exitCode = -1
+ try {
+ exitCode = Process(exec(contract), args) ! javacLogger
+ } finally {
+ javacLogger.flush(exitCode)
+ }
+ exitCode
+ }
+ }
+}
+
+private[sbt] class JavacLogger(log: Logger) extends ProcessLogger {
+ import scala.collection.mutable.ListBuffer
+ import Level.{Info, Warn, Error, Value => LogLevel}
+
+ private val msgs: ListBuffer[(LogLevel, String)] = new ListBuffer()
+
+ def info(s: => String): Unit =
+ synchronized { msgs += ((Info, s)) }
+
+ def error(s: => String): Unit =
+ synchronized { msgs += ((Error, s)) }
+
+ def buffer[T](f: => T): T = f
+
+ private def print(desiredLevel: LogLevel)(t: (LogLevel, String)) = t match {
+ case (Info, msg) => log.info(msg)
+ case (Error, msg) => log.log(desiredLevel, msg)
+ }
+
+ def flush(exitCode: Int): Unit = {
+ val level = if (exitCode == 0) Warn else Error
+ msgs foreach print(level)
+ msgs.clear()
+ }
+}
View
32 compile/integration/IncrementalCompiler.scala
@@ -0,0 +1,32 @@
+package sbt.compiler
+
+ import sbt.inc.Analysis
+ import xsbti.{Logger, Maybe}
+ import xsbti.compile._
+
+ import java.io.File
+
+object IC extends IncrementalCompiler[Analysis, AnalyzingCompiler]
+{
+ def compile(in: Inputs[Analysis, AnalyzingCompiler], log: Logger): Analysis =
+ {
+ val setup = in.setup; import setup._
+ val options = in.options; import options.{options => scalacOptions, _}
+ val compilers = in.compilers; import compilers._
+ val agg = new AggressiveCompile(setup.cacheFile)
+ val aMap = (f: File) => m2o(analysisMap(f))
+ val defClass = (f: File) => { val dc = definesClass(f); (name: String) => dc.apply(name) }
+ agg(scalac, javac, sources, classpath, classesDirectory, scalacOptions, javacOptions, aMap, defClass, maxErrors, order, skip)(log)
+ }
+
+ private[this] def m2o[S](opt: Maybe[S]): Option[S] = if(opt.isEmpty) None else Some(opt.get)
+
+ def newScalaCompiler(instance: ScalaInstance, interfaceJar: File, options: ClasspathOptions, log: Logger): AnalyzingCompiler =
+ new AnalyzingCompiler(instance, CompilerInterfaceProvider.constant(interfaceJar), options, log)
+
+ def compileInterfaceJar(label: String, sourceJar: File, targetJar: File, interfaceJar: File, instance: ScalaInstance, log: Logger)
+ {
+ val raw = new RawCompiler(instance, sbt.ClasspathOptions.auto, log)
+ AnalyzingCompiler.compileSources(sourceJar :: Nil, targetJar, interfaceJar :: Nil, label, raw, log)
+ }
+}
View
44 compile/ComponentCompiler.scala → compile/ivy/ComponentCompiler.scala
@@ -14,6 +14,17 @@ object ComponentCompiler
val compilerInterfaceID = "compiler-interface"
val compilerInterfaceSrcID = compilerInterfaceID + srcExtension
val javaVersion = System.getProperty("java.class.version")
+
+ def interfaceProvider(manager: ComponentManager): CompilerInterfaceProvider = new CompilerInterfaceProvider
+ {
+ def apply(scalaInstance: xsbti.compile.ScalaInstance, log: Logger): File =
+ {
+ // this is the instance used to compile the interface component
+ val componentCompiler = new ComponentCompiler(new RawCompiler(scalaInstance, ClasspathOptions.auto, log), manager)
+ log.debug("Getting " + compilerInterfaceID + " from component compiler for Scala " + scalaInstance.version)
+ componentCompiler(compilerInterfaceID)
+ }
+ }
}
/** This class provides source components compiled with the provided RawCompiler.
* The compiled classes are cached using the provided component manager according
@@ -21,7 +32,6 @@ object ComponentCompiler
class ComponentCompiler(compiler: RawCompiler, manager: ComponentManager)
{
import ComponentCompiler._
- import sbt.IO.{copy, createDirectory, zip, jars, unzip, withTemporaryDirectory}
def apply(id: String): File =
try { getPrecompiled(id) }
catch { case _: InvalidComponent => getLocallyCompiled(id) }
@@ -45,37 +55,11 @@ class ComponentCompiler(compiler: RawCompiler, manager: ComponentManager)
protected def compileAndInstall(id: String, binID: String)
{
val srcID = id + srcExtension
- withTemporaryDirectory { binaryDirectory =>
+ IO.withTemporaryDirectory { binaryDirectory =>
val targetJar = new File(binaryDirectory, id + ".jar")
- compileSources(manager.files(srcID)(IfMissing.Fail), targetJar, id)
+ val xsbtiJars = manager.files(xsbtiID)(IfMissing.Fail)
+ AnalyzingCompiler.compileSources(manager.files(srcID)(IfMissing.Fail), targetJar, xsbtiJars, id, compiler, manager.log)
manager.define(binID, Seq(targetJar))
}
}
- /** Extract sources from source jars, compile them with the xsbti interfaces on the classpath, and package the compiled classes and
- * any resources from the source jars into a final jar.*/
- private def compileSources(sourceJars: Iterable[File], targetJar: File, id: String)
- {
- val isSource = (f: File) => isSourceName(f.getName)
- def keepIfSource(files: Set[File]): Set[File] = if(files.exists(isSource)) files else Set()
-
- withTemporaryDirectory { dir =>
- val extractedSources = (Set[File]() /: sourceJars) { (extracted, sourceJar)=> extracted ++ keepIfSource(unzip(sourceJar, dir)) }
- val (sourceFiles, resources) = extractedSources.partition(isSource)
- withTemporaryDirectory { outputDirectory =>
- val xsbtiJars = manager.files(xsbtiID)(IfMissing.Fail)
- manager.log.info("'" + id + "' not yet compiled for Scala " + compiler.scalaInstance.actualVersion + ". Compiling...")
- val start = System.currentTimeMillis
- try
- {
- compiler(sourceFiles.toSeq, xsbtiJars.toSeq ++ sourceJars, outputDirectory, "-nowarn" :: Nil)
- manager.log.info(" Compilation completed in " + (System.currentTimeMillis - start) / 1000.0 + " s")
- }
- catch { case e: xsbti.CompileFailed => throw new CompileFailed(e.arguments, "Error compiling sbt component '" + id + "'") }
- import sbt.Path._
- copy(resources x rebase(dir, outputDirectory))
- zip((outputDirectory ***) x_! relativeTo(outputDirectory), targetJar)
- }
- }
- }
- private def isSourceName(name: String): Boolean = name.endsWith(".scala") || name.endsWith(".java")
}
View
11 compile/persist/AnalysisFormats.scala
@@ -6,6 +6,7 @@ package inc
import xsbti.api.Source
import xsbti.{Position,Problem,Severity}
+ import xsbti.compile.CompileOrder
import java.io.File
import sbinary._
import DefaultProtocol._
@@ -63,8 +64,8 @@ object AnalysisFormats
wrap[Severity, Byte]( _.ordinal.toByte, b => Severity.values.apply(b.toInt) )
- implicit def setupFormat(implicit outDirF: Format[File], optionF: Format[CompileOptions], compilerVersion: Format[String], orderF: Format[CompileOrder.Value]): Format[CompileSetup] =
- asProduct4[CompileSetup, File, CompileOptions, String, CompileOrder.Value]( (a,b,c,d) => new CompileSetup(a,b,c,d) )(s => (s.outputDirectory, s.options, s.compilerVersion, s.order))(outDirF, optionF, compilerVersion, orderF)
+ implicit def setupFormat(implicit outDirF: Format[File], optionF: Format[CompileOptions], compilerVersion: Format[String], orderF: Format[CompileOrder]): Format[CompileSetup] =
+ asProduct4[CompileSetup, File, CompileOptions, String, CompileOrder]( (a,b,c,d) => new CompileSetup(a,b,c,d) )(s => (s.outputDirectory, s.options, s.compilerVersion, s.order))(outDirF, optionF, compilerVersion, orderF)
implicit def stampsFormat(implicit prodF: Format[Map[File, Stamp]], srcF: Format[Map[File, Stamp]], binF: Format[Map[File, Stamp]], nameF: Format[Map[File, String]]): Format[Stamps] =
asProduct4( Stamps.apply _ )( s => (s.products, s.sources, s.binaries, s.classNames) )(prodF, srcF, binF, nameF)
@@ -88,7 +89,11 @@ object AnalysisFormats
implicit def optsFormat(implicit strF: Format[String]): Format[CompileOptions] =
wrap[CompileOptions, (Seq[String],Seq[String])](co => (co.options, co.javacOptions), os => new CompileOptions(os._1, os._2))
- implicit val orderFormat: Format[CompileOrder.Value] = enumerationFormat(CompileOrder)
+ implicit val orderFormat: Format[CompileOrder] =
+ {
+ val values = CompileOrder.values
+ wrap[CompileOrder, Int](_.ordinal, values)
+ }
implicit def seqFormat[T](implicit optionFormat: Format[T]): Format[Seq[T]] = viaSeq[Seq[T], T](x => x)
implicit def hashStampFormat: Format[Hash] = wrap[Hash, Array[Byte]](_.value, new Hash(_))
View
9 interface/src/main/java/xsbti/ArtifactInfo.java
@@ -0,0 +1,9 @@
+package xsbti;
+
+public final class ArtifactInfo
+{
+ public static final String ScalaOrganization = "org.scala-lang";
+ public static final String ScalaLibraryID = "scala-library";
+ public static final String ScalaCompilerID = "scala-compiler";
+ public static final String SbtOrganization = "org.scala-sbt";
+}
View
29 interface/src/main/java/xsbti/compile/ClasspathOptions.java
@@ -0,0 +1,29 @@
+package xsbti.compile;
+
+/**
+* Configures modifications to the classpath based on the Scala instance used for compilation.
+* This is typically used for the Scala compiler only and all values set to false for the Java compiler.
+*/
+public interface ClasspathOptions
+{
+ /** If true, includes the Scala library on the boot classpath. This should usually be true.*/
+ boolean bootLibrary();
+
+ /** If true, includes the Scala compiler on the standard classpath.
+ * This is typically false and is instead managed by the build tool or environment.
+ */
+ boolean compiler();
+
+ /** If true, includes extra jars from the Scala instance on the standard classpath.
+ * This is typically false and is instead managed by the build tool or environment.
+ */
+ boolean extra();
+
+ /** If true, automatically configures the boot classpath. This should usually be true.*/
+ boolean autoBoot();
+
+ /** If true, the Scala library jar is filtered from the standard classpath.
+ * This should usually be true because the library should be included on the boot classpath of the Scala compiler and not the standard classpath.
+ */
+ boolean filterLibrary();
+}
View
34 interface/src/main/java/xsbti/compile/CompileOrder.java
@@ -0,0 +1,34 @@
+package xsbti.compile;
+
+/**
+* Defines the order in which Scala and Java sources are compiled when compiling a set of sources with both Java and Scala sources.
+* This setting has no effect if only Java sources or only Scala sources are being compiled.
+* It is generally more efficient to use JavaThenScala or ScalaThenJava when mixed compilation is not required.
+*/
+public enum CompileOrder
+{
+ /**
+ * Allows Scala sources to depend on Java sources and allows Java sources to depend on Scala sources.
+ *
+ * In this mode, both Java and Scala sources are passed to the Scala compiler, which generates class files for the Scala sources.
+ * Then, Java sources are passed to the Java compiler, which generates class files for the Java sources.
+ * The Scala classes compiled in the first step are included on the classpath to the Java compiler.
+ */
+ Mixed,
+ /**
+ * Allows Scala sources to depend on the Java sources in the compilation, but does not allow Java sources to depend on Scala sources.
+ *
+ * In this mode, both Java and Scala sources are passed to the Scala compiler, which generates class files for the Scala sources.
+ * Then, Java sources are passed to the Java compiler, which generates class files for the Java sources.
+ * The Scala classes compiled in the first step are included on the classpath to the Java compiler.
+ */
+ JavaThenScala,
+ /**
+ * Allows Java sources to depend on the Scala sources in the compilation, but does not allow Scala sources to depend on Java sources.
+ *
+ * In this mode, both Java and Scala sources are passed to the Scala compiler, which generates class files for the Scala sources.
+ * Then, Java sources are passed to the Java compiler, which generates class files for the Java sources.
+ * The Scala classes compiled in the first step are included on the classpath to the Java compiler.
+ */
+ ScalaThenJava;
+}
View
8 interface/src/main/java/xsbti/compile/Compilers.java
@@ -0,0 +1,8 @@
+package xsbti.compile;
+
+public interface Compilers<ScalaCompiler>
+{
+ JavaCompiler javac();
+ // should be cached by client if desired
+ ScalaCompiler scalac();
+}
View
14 interface/src/main/java/xsbti/compile/DefinesClass.java
@@ -0,0 +1,14 @@
+package xsbti.compile;
+
+import java.io.File;
+
+/**
+* Determines if an entry on a classpath contains a class.
+*/
+public interface DefinesClass
+{
+ /**
+ * Returns true if the classpath entry contains the requested class.
+ */
+ boolean apply(String className);
+}
View
61 interface/src/main/java/xsbti/compile/IncrementalCompiler.java
@@ -0,0 +1,61 @@
+package xsbti.compile;
+
+import xsbti.Logger;
+import java.io.File;
+
+/*
+* This API is subject to change.
+*
+* It is the client's responsibility to:
+* 1. Manage class loaders. Usually the client will want to:
+* i. Keep the class loader used by the ScalaInstance warm.
+* ii. Keep the class loader of the incremental recompilation classes (xsbti.compile) warm.
+* iii. Share the class loader for Scala classes between the incremental compiler implementation and the ScalaInstance where possible (must be binary compatible)
+* 2. Manage the compiler interface jar. The interface must be compiled against the exact Scala version used for compilation and a compatible Java version.
+* 3. Manage compilation order between different compilations.
+* i. Execute a compilation for each dependency, obtaining an Analysis for each.
+* ii. Provide the Analysis from previous compilations to dependent compilations in the analysis map.
+* 4. Provide an implementation of JavaCompiler for compiling Java sources.
+* 5. Define a function that determines if a classpath entry contains a class (Setup.definesClass).
+* i. This is provided by the client so that the client can cache this information across compilations when compiling multiple sets of sources.
+* ii. The cache should be cleared for each new compilation run or else recompilation will not properly account for changes to the classpath.
+* 6. Provide a cache directory.
+* i. This directory is used by IncrementalCompiler to persist data between compilations.
+* ii. It should be a different directory for each set of sources being compiled.
+* 7. Manage parallel execution.
+* i. Each compilation may be performed in a different thread as long as the dependencies have been compiled already.
+* ii. Implementations of all types should be immutable and arrays treated as immutable.
+* 8. Ensure general invariants:
+* i. The implementations of all types are immutable, except for the already discussed Setup.definesClass.
+* ii. Arrays are treated as immutable.
+* iii. No value is ever null.
+*/
+public interface IncrementalCompiler<Analysis, ScalaCompiler>
+{
+ /**
+ * Performs an incremental compilation as configured by `in`.
+ * The returned Analysis should be provided to compilations depending on the classes from this compilation.
+ */
+ Analysis compile(Inputs<Analysis, ScalaCompiler> in, Logger log);
+
+ /**
+ * Creates a compiler instance that can be used by the `compile` method.
+ *
+ * @param instance The Scala version to use
+ * @param interfaceJar The compiler interface jar compiled for the Scala version being used
+ * @param options Configures how arguments to the underlying Scala compiler will be built.
+ */
+ ScalaCompiler newScalaCompiler(ScalaInstance instance, File interfaceJar, ClasspathOptions options, Logger log);
+
+ /**
+ * Compiles the source interface for a Scala version. The resulting jar can then be used by the `newScalaCompiler` method
+ * to create a ScalaCompiler for incremental compilation. It is the client's responsibility to manage compiled jars for
+ * different Scala versions.
+ *
+ * @param label A brief name describing the source component for use in error messages
+ * @param sourceJar The jar file containing the compiler interface sources. These are published as sbt's compiler-interface-src module.
+ * @param targetJar Where to create the output jar file containing the compiled classes.
+ * @param instance The ScalaInstance to compile the compiler interface for.
+ * @param log The logger to use during compilation. */
+ void compileInterfaceJar(String label, File sourceJar, File targetJar, File interfaceJar, ScalaInstance instance, Logger log);
+}
View
14 interface/src/main/java/xsbti/compile/Inputs.java
@@ -0,0 +1,14 @@
+package xsbti.compile;
+
+/** Configures a single compilation of a single set of sources.*/
+public interface Inputs<Analysis,ScalaCompiler>
+{
+ /** The Scala and Java compilers to use for compilation.*/
+ Compilers<ScalaCompiler> compilers();
+
+ /** Standard compilation options, such as the sources and classpath to use. */
+ Options options();
+
+ /** Configures incremental compilation.*/
+ Setup<Analysis> setup();
+}
View
15 interface/src/main/java/xsbti/compile/JavaCompiler.java
@@ -0,0 +1,15 @@
+package xsbti.compile;
+
+import java.io.File;
+import xsbti.Logger;
+
+/**
+* Interface to a Java compiler.
+*/
+public interface JavaCompiler
+{
+ /** Compiles Java sources using the provided classpath, output directory, and additional options.
+ * If supported, the number of reported errors should be limited to `maximumErrors`.
+ * Output should be sent to the provided logger.*/
+ void compile(File[] sources, File[] classpath, File outputDirectory, String[] options, int maximumErrors, Logger log);
+}
View
33 interface/src/main/java/xsbti/compile/Options.java
@@ -0,0 +1,33 @@
+package xsbti.compile;
+
+import java.io.File;
+
+/** Standard compilation options.*/
+public interface Options
+{
+ /** The classpath to use for compilation.
+ * This will be modified according to the ClasspathOptions used to configure the ScalaCompiler.*/
+ File[] classpath();
+
+ /** All sources that should be recompiled.
+ * This should include Scala and Java sources, which are identified by their extension. */
+ File[] sources();
+
+ /** The directory where class files should be generated.
+ * Incremental compilation will manage the class files in this directory.
+ * In particular, outdated class files will be deleted before compilation.
+ * It is important that this directory is exclusively used for one set of sources. */
+ File classesDirectory();
+
+ /** The options to pass to the Scala compiler other than the sources and classpath to use. */
+ String[] options();
+
+ /** The options to pass to the Java compiler other than the sources and classpath to use. */
+ String[] javacOptions();
+
+ /** The maximum number of errors that the Scala compiler should report.*/
+ int maxErrors();
+
+ /** Controls the order in which Java and Scala sources are compiled.*/
+ CompileOrder order();
+}
View
34 interface/src/main/java/xsbti/compile/ScalaInstance.java
@@ -0,0 +1,34 @@
+package xsbti.compile;
+
+import java.io.File;
+
+/**
+* Defines Scala instance, which is a reference version String, a unique version String, a set of jars, and a class loader for a Scala version.
+*
+* Note that in this API a 'jar' can actually be any valid classpath entry.
+*/
+public interface ScalaInstance
+{
+ /** The version used to refer to this Scala version.
+ * It need not be unique and can be a dynamic version like 2.10.0-SNAPSHOT.
+ */
+ String version();
+
+ /** A class loader providing access to the classes and resources in the library and compiler jars. */
+ ClassLoader loader();
+
+ /** The library jar file.*/
+ File libraryJar();
+
+ /** The compiler jar file.*/
+ File compilerJar();
+
+ /** Jars provided by this Scala instance other than the compiler and library jars. */
+ File[] otherJars();
+
+ /** All jar files provided by this Scala instance.*/
+ File[] allJars();
+
+ /** The unique identifier for this Scala instance. An implementation should usually obtain this from the compiler.properties file in the compiler jar. */
+ String actualVersion();
+}
View
24 interface/src/main/java/xsbti/compile/Setup.java
@@ -0,0 +1,24 @@
+package xsbti.compile;
+
+import java.io.File;
+import xsbti.Maybe;
+
+/** Configures incremental recompilation. */
+public interface Setup<Analysis>
+{
+ /** Provides the Analysis for the given classpath entry.*/
+ Maybe<Analysis> analysisMap(File file);
+
+ /** Provides a function to determine if classpath entry `file` contains a given class.
+ * The returned function should generally cache information about `file`, such as the list of entries in a jar.
+ */
+ DefinesClass definesClass(File file);
+
+ /** If true, no sources are actually compiled and the Analysis from the previous compilation is returned.*/
+ boolean skip();
+
+ /** The file used to cache information across compilations.
+ * This file can be removed to force a full recompilation.
+ * The file should be unique and not shared between compilations. */
+ File cacheFile();
+}
View
10 ivy/IvyScala.scala
@@ -14,14 +14,16 @@ import plugins.matcher.ExactPatternMatcher
object ScalaArtifacts
{
- val Organization = "org.scala-lang"
- val LibraryID = "scala-library"
- val CompilerID = "scala-compiler"
+ import xsbti.ArtifactInfo._
+ val Organization = ScalaOrganization
+ val LibraryID = ScalaLibraryID
+ val CompilerID = ScalaCompilerID
def libraryDependency(version: String): ModuleID = ModuleID(Organization, LibraryID, version)
}
object SbtArtifacts
{
- val Organization = "org.scala-sbt"
+ import xsbti.ArtifactInfo._
+ val Organization = SbtOrganization
}
import ScalaArtifacts._
View
2 main/Build.scala
@@ -285,5 +285,5 @@ object BuildPaths
final val GlobalPluginsProperty = "sbt.global.plugins"
final val GlobalSettingsProperty = "sbt.global.settings"
- def crossPath(base: File, instance: ScalaInstance): File = base / ("scala_" + instance.version)
+ def crossPath(base: File, instance: xsbti.compile.ScalaInstance): File = base / ("scala_" + instance.version)
}
View
8 main/Defaults.scala
@@ -6,6 +6,7 @@ package sbt
import Build.data
import Scope.{fillTaskAxis, GlobalScope, ThisScope}
import xsbt.api.Discovery
+ import xsbti.compile.CompileOrder
import Project.{inConfig, Initialize, inScope, inTask, ScopedKey, Setting, SettingsDefinition}
import Load.LoadedBuild
import Artifact.{DocClassifier, SourceClassifier}
@@ -43,8 +44,11 @@ object Defaults extends BuildCommon
def extractAnalysis[T](a: Attributed[T]): (T, inc.Analysis) =
(a.data, a.metadata get Keys.analysis getOrElse inc.Analysis.Empty)
- def analysisMap[T](cp: Seq[Attributed[T]]): Map[T, inc.Analysis] =
- (for(a <- cp; an <- a.metadata get Keys.analysis) yield (a.data, an) ).toMap
+ def analysisMap[T](cp: Seq[Attributed[T]]): T => Option[inc.Analysis] =
+ {
+ val m = (for(a <- cp; an <- a.metadata get Keys.analysis) yield (a.data, an) ).toMap
+ m.get _
+ }
def buildCore: Seq[Setting[_]] = thisBuildCore ++ globalCore
def thisBuildCore: Seq[Setting[_]] = inScope(GlobalScope.copy(project = Select(ThisBuild)))(Seq(
View
3 main/Keys.scala
@@ -10,6 +10,7 @@ package sbt
import inc.Analysis
import inc.Locate.DefinesClass
import std.TaskExtra._
+ import xsbti.compile.CompileOrder
import scala.xml.{Node => XNode, NodeSeq}
import org.apache.ivy.core.module.{descriptor, id}
import descriptor.ModuleDescriptor, id.ModuleRevisionId
@@ -129,7 +130,7 @@ object Keys
val scaladocOptions = TaskKey[Seq[String]]("scaladoc-options", "Options for Scaladoc.", DTask)
val scalacOptions = TaskKey[Seq[String]]("scalac-options", "Options for the Scala compiler.", BPlusTask)
val javacOptions = TaskKey[Seq[String]]("javac-options", "Options for the Java compiler.", BPlusTask)
- val compileOrder = SettingKey[CompileOrder.Value]("compile-order", "Configures the order in which Java and sources within a single compilation are compiled. Valid values are: JavaThenScala, ScalaThenJava, or Mixed.", BPlusSetting)
+ val compileOrder = SettingKey[CompileOrder]("compile-order", "Configures the order in which Java and sources within a single compilation are compiled. Valid values are: JavaThenScala, ScalaThenJava, or Mixed.", BPlusSetting)
val initialCommands = SettingKey[String]("initial-commands", "Initial commands to execute when starting up the Scala interpreter.", AMinusSetting)
val cleanupCommands = SettingKey[String]("cleanup-commands", "Commands to execute before the Scala interpreter exits.", BMinusSetting)
val compileInputs = TaskKey[Compiler.Inputs]("compile-inputs", "Collects all inputs needed for compilation.", DTask)
View
1 main/Load.scala
@@ -7,6 +7,7 @@ package sbt
import java.net.{URI,URL}
import compiler.{Eval,EvalImports}
import xsbt.api.{Discovered,Discovery}
+ import xsbti.compile.CompileOrder
import classpath.ClasspathUtilities
import scala.annotation.tailrec
import collection.mutable
View
67 compile/integration/Compiler.scala → main/actions/Compiler.scala
@@ -4,6 +4,8 @@
package sbt
import xsbti.{Logger => _,_}
+ import xsbti.compile.CompileOrder
+ import CompileOrder.{JavaThenScala, Mixed, ScalaThenJava}
import compiler._
import inc._
import Locate.DefinesClass
@@ -14,12 +16,12 @@ object Compiler
val DefaultMaxErrors = 100
final case class Inputs(compilers: Compilers, config: Options, incSetup: IncSetup)
- final case class Options(classpath: Seq[File], sources: Seq[File], classesDirectory: File, options: Seq[String], javacOptions: Seq[String], maxErrors: Int, order: CompileOrder.Value)
- final case class IncSetup(analysisMap: Map[File, Analysis], definesClass: DefinesClass, skip: Boolean, cacheFile: File)
- final case class Compilers(scalac: AnalyzingCompiler, javac: JavaCompiler)
+ final case class Options(classpath: Seq[File], sources: Seq[File], classesDirectory: File, options: Seq[String], javacOptions: Seq[String], maxErrors: Int, order: CompileOrder)
+ final case class IncSetup(analysisMap: File => Option[Analysis], definesClass: DefinesClass, skip: Boolean, cacheFile: File)
+ final case class Compilers(scalac: AnalyzingCompiler, javac: JavaTool)
@deprecated("Use the other inputs variant.", "0.12.0")
- def inputs(classpath: Seq[File], sources: Seq[File], outputDirectory: File, options: Seq[String], javacOptions: Seq[String], definesClass: DefinesClass, maxErrors: Int, order: CompileOrder.Value)(implicit compilers: Compilers, log: Logger): Inputs =
+ def inputs(classpath: Seq[File], sources: Seq[File], outputDirectory: File, options: Seq[String], javacOptions: Seq[String], definesClass: DefinesClass, maxErrors: Int, order: CompileOrder)(implicit compilers: Compilers, log: Logger): Inputs =
{
import Path._
val classesDirectory = outputDirectory / "classes"
@@ -28,7 +30,7 @@ object Compiler
val incSetup = IncSetup(Map.empty, definesClass, false, cacheFile)
inputs(augClasspath, sources, classesDirectory, options, javacOptions, maxErrors, order)(compilers, incSetup, log)
}
- def inputs(classpath: Seq[File], sources: Seq[File], classesDirectory: File, options: Seq[String], javacOptions: Seq[String], maxErrors: Int, order: CompileOrder.Value)(implicit compilers: Compilers, incSetup: IncSetup, log: Logger): Inputs =
+ def inputs(classpath: Seq[File], sources: Seq[File], classesDirectory: File, options: Seq[String], javacOptions: Seq[String], maxErrors: Int, order: CompileOrder)(implicit compilers: Compilers, incSetup: IncSetup, log: Logger): Inputs =
new Inputs(
compilers,
new Options(classpath, sources, classesDirectory, options, javacOptions, maxErrors, order),
@@ -46,7 +48,7 @@ object Compiler
def compilers(instance: ScalaInstance, cpOptions: ClasspathOptions, javaHome: Option[File])(implicit app: AppConfiguration, log: Logger): Compilers =
{
- val javac = directOrFork(instance, cpOptions, javaHome)
+ val javac = AggressiveCompile.directOrFork(instance, cpOptions, javaHome)
compilers(instance, cpOptions, javac)
}
def compilers(instance: ScalaInstance, cpOptions: ClasspathOptions, javac: JavaCompiler.Fork)(implicit app: AppConfiguration, log: Logger): Compilers =
@@ -54,7 +56,7 @@ object Compiler
val javaCompiler = JavaCompiler.fork(cpOptions, instance)(javac)
compilers(instance, cpOptions, javaCompiler)
}
- def compilers(instance: ScalaInstance, cpOptions: ClasspathOptions, javac: JavaCompiler)(implicit app: AppConfiguration, log: Logger): Compilers =
+ def compilers(instance: ScalaInstance, cpOptions: ClasspathOptions, javac: JavaTool)(implicit app: AppConfiguration, log: Logger): Compilers =
{
val scalac = scalaCompiler(instance, cpOptions)
new Compilers(scalac, javac)
@@ -63,29 +65,8 @@ object Compiler
{
val launcher = app.provider.scalaProvider.launcher
val componentManager = new ComponentManager(launcher.globalLock, app.provider.components, Option(launcher.ivyHome), log)
- new AnalyzingCompiler(instance, componentManager, cpOptions, log)
- }
- def directOrFork(instance: ScalaInstance, cpOptions: ClasspathOptions, javaHome: Option[File]): JavaCompiler =
- if(javaHome.isDefined)
- JavaCompiler.fork(cpOptions, instance)(forkJavac(javaHome))
- else
- JavaCompiler.directOrFork(cpOptions, instance)(forkJavac(None))
-
- def forkJavac(javaHome: Option[File]): JavaCompiler.Fork =
- {
- import Path._
- def exec(jc: JavacContract) = javaHome match { case None => jc.name; case Some(jh) => (jh / "bin" / jc.name).absolutePath }
- (contract: JavacContract, args: Seq[String], log: Logger) => {
- log.debug("Forking " + contract.name + ": " + exec(contract) + " " + args.mkString(" "))
- val javacLogger = new JavacLogger(log)
- var exitCode = -1
- try {
- exitCode = Process(exec(contract), args) ! javacLogger
- } finally {
- javacLogger.flush(exitCode)
- }
- exitCode
- }
+ val provider = ComponentCompiler.interfaceProvider(componentManager)
+ new AnalyzingCompiler(instance, provider, cpOptions, log)
}
def apply(in: Inputs, log: Logger): Analysis =
@@ -98,29 +79,3 @@ object Compiler
agg(scalac, javac, sources, classpath, classesDirectory, options, javacOptions, analysisMap, definesClass, maxErrors, order, skip)(log)
}
}
-
-private[sbt] class JavacLogger(log: Logger) extends ProcessLogger {
- import scala.collection.mutable.ListBuffer
- import Level.{Info, Warn, Error, Value => LogLevel}
-
- private val msgs: ListBuffer[(LogLevel, String)] = new ListBuffer()
-
- def info(s: => String): Unit =
- synchronized { msgs += ((Info, s)) }
-
- def error(s: => String): Unit =
- synchronized { msgs += ((Error, s)) }
-
- def buffer[T](f: => T): T = f
-
- private def print(desiredLevel: LogLevel)(t: (LogLevel, String)) = t match {
- case (Info, msg) => log.info(msg)
- case (Error, msg) => log.log(desiredLevel, msg)
- }
-
- def flush(exitCode: Int): Unit = {
- val level = if (exitCode == 0) Warn else Error
- msgs foreach print(level)
- msgs.clear()
- }
-}
View
6 main/actions/Doc.scala
@@ -17,7 +17,7 @@ package sbt
object Doc {
def apply(maximumErrors: Int, compiler: AnalyzingCompiler) = new Scaladoc(maximumErrors, compiler)
- def apply(maximumErrors: Int, compiler: JavaCompiler) = new Javadoc(maximumErrors, compiler)
+ def apply(maximumErrors: Int, compiler: sbt.compiler.Javadoc) = new Javadoc(maximumErrors, compiler)
}
sealed trait Doc {
type Gen = (Seq[File], Seq[File], File, Seq[String], Int, Logger) => Unit
@@ -62,11 +62,11 @@ final class Scaladoc(maximumErrors: Int, compiler: AnalyzingCompiler) extends Do
generate("Scala", label, compiler.doc, sources, classpath, outputDirectory, options, maximumErrors, log)
}
}
-final class Javadoc(maximumErrors: Int, compiler: JavaCompiler) extends Doc
+final class Javadoc(maximumErrors: Int, doc: sbt.compiler.Javadoc) extends Doc
{
def apply(label: String, sources: Seq[File], classpath: Seq[File], outputDirectory: File, options: Seq[String], log: Logger)
{
// javadoc doesn't handle *.scala properly, so we evict them from javadoc sources list.
- generate("Java", label, compiler.doc, sources.filterNot(_.name.endsWith(".scala")), classpath, outputDirectory, options, maximumErrors, log)
+ generate("Java", label, doc.doc, sources.filterNot(_.name.endsWith(".scala")), classpath, outputDirectory, options, maximumErrors, log)
}
}
View
7 project/Sbt.scala
@@ -58,7 +58,7 @@ object Sbt extends Build
// Path, IO (formerly FileUtilities), NameFilter and other I/O utility classes
lazy val ioSub = testedBaseProject(utilPath / "io", "IO") dependsOn(controlSub)
// Utilities related to reflection, managing Scala versions, and custom class loaders
- lazy val classpathSub = baseProject(utilPath / "classpath", "Classpath") dependsOn(launchInterfaceSub, ioSub) settings(scalaCompiler)
+ lazy val classpathSub = baseProject(utilPath / "classpath", "Classpath") dependsOn(launchInterfaceSub, interfaceSub, ioSub) settings(scalaCompiler)
// Command line-related utilities.
lazy val completeSub = testedBaseProject(utilPath / "complete", "Completion") dependsOn(collectionSub, controlSub, ioSub) settings(jline)
// logging
@@ -102,10 +102,11 @@ object Sbt extends Build
// Persists the incremental data structures using SBinary
lazy val compilePersistSub = baseProject(compilePath / "persist", "Persist") dependsOn(compileIncrementalSub, apiSub) settings(sbinary)
// sbt-side interface to compiler. Calls compiler-side interface reflectively
- lazy val compilerSub = testedBaseProject(compilePath, "Compile") dependsOn(launchInterfaceSub, interfaceSub % "compile;test->test", ivySub, ioSub, classpathSub,
+ lazy val compilerSub = testedBaseProject(compilePath, "Compile") dependsOn(launchInterfaceSub, interfaceSub % "compile;test->test", logSub, ioSub, classpathSub,
logSub % "test->test", launchSub % "test->test", apiSub % "test") settings( compilerSettings : _*)
lazy val compilerIntegrationSub = baseProject(compilePath / "integration", "Compiler Integration") dependsOn(
compileIncrementalSub, compilerSub, compilePersistSub, apiSub, classfileSub)
+ lazy val compilerIvySub = baseProject(compilePath / "ivy", "Compiler Ivy Integration") dependsOn(ivySub, compilerSub )
lazy val scriptedBaseSub = baseProject(scriptedPath / "base", "Scripted Framework") dependsOn(ioSub, processSub)
lazy val scriptedSbtSub = baseProject(scriptedPath / "sbt", "Scripted sbt") dependsOn(ioSub, logSub, processSub, scriptedBaseSub, launchInterfaceSub % "provided")
@@ -114,7 +115,7 @@ object Sbt extends Build
// Implementation and support code for defining actions.
lazy val actionsSub = baseProject(mainPath / "actions", "Actions") dependsOn(
- classpathSub, completeSub, apiSub, compilerIntegrationSub,
+ classpathSub, completeSub, apiSub, compilerIntegrationSub, compilerIvySub,
interfaceSub, ioSub, ivySub, logSub, processSub, runSub, stdTaskSub, taskSub, trackingSub, testingSub)
lazy val commandSub = testedBaseProject(commandPath, "Command") dependsOn(interfaceSub, ioSub, launchInterfaceSub, logSub, completeSub, classpathSub)
View
4 sbt/package.scala
@@ -20,6 +20,10 @@ package object sbt extends sbt.std.TaskExtra with sbt.Types with sbt.ProcessExtr
type File = java.io.File
type URI = java.net.URI
type URL = java.net.URL
+ type CompileOrder = xsbti.compile.CompileOrder
+ val JavaThenScala = xsbti.compile.CompileOrder.JavaThenScala
+ val ScalaThenJava = xsbti.compile.CompileOrder.ScalaThenJava
+ val Mixed = xsbti.compile.CompileOrder.Mixed
implicit def maybeToOption[S](m: xsbti.Maybe[S]): Option[S] =
if(m.isDefined) Some(m.get) else None
View
6 util/classpath/ScalaInstance.scala
@@ -10,8 +10,12 @@ package sbt
* for the compiler itself.
* The 'version' field is the version used to obtain the Scala classes. This is typically the version for the maven repository.
* The 'actualVersion' field should be used to uniquely identify the compiler. It is obtained from the compiler.properties file.*/
-final class ScalaInstance(val version: String, val loader: ClassLoader, val libraryJar: File, val compilerJar: File, val extraJars: Seq[File], val explicitActual: Option[String])
+final class ScalaInstance(val version: String, val loader: ClassLoader, val libraryJar: File, val compilerJar: File, val extraJars: Seq[File], val explicitActual: Option[String]) extends xsbti.compile.ScalaInstance
{
+ // These are to implement xsbti.ScalaInstance
+ def otherJars: Array[File] = extraJars.toArray
+ def allJars: Array[File] = jars.toArray
+
require(version.indexOf(' ') < 0, "Version cannot contain spaces (was '" + version + "')")
def jars = libraryJar :: compilerJar :: extraJars.toList
/** Gets the version of Scala in the compiler.properties file from the loader. This version may be different than that given by 'version'*/

No commit comments for this range

Something went wrong with that request. Please try again.