Permalink
Browse files

- Stuart's improvements to triggered execution

- continue splitting original sbt module
 * separated process, testing modules
 * various IO, logging, classpath migration
 * split out javac interface
  • Loading branch information...
1 parent 37185c0 commit 6f3c69943505584f2db2800cd17f4eb9715d28d1 @harrah committed Jul 5, 2010
Showing with 497 additions and 643 deletions.
  1. +17 −14 compile/AnalyzingCompiler.scala
  2. +0 −10 compile/CompileLogger.scala
  3. +5 −1 compile/CompilerArguments.scala
  4. +5 −2 compile/ComponentCompiler.scala
  5. +66 −0 compile/JavaCompiler.scala
  6. +1 −1 compile/NOTICE
  7. +6 −2 compile/RawCompiler.scala
  8. +3 −0 compile/discover/NOTICE
  9. +3 −0 compile/inc/NOTICE
  10. +12 −2 compile/inc/notes
  11. +1 −1 compile/interface/API.scala
  12. +3 −0 compile/persist/NOTICE
  13. +2 −4 ivy/src/test/scala/ComponentManagerTest.scala
  14. +1 −3 ivy/src/test/scala/TestIvyLogger.scala
  15. +4 −4 main/AggressiveCompile.scala
  16. +3 −3 main/AggressiveCompiler.scala
  17. +17 −9 project/build/XSbt.scala
  18. +0 −85 sbt/src/main/scala/sbt/Compile.scala
  19. +1 −4 sbt/src/main/scala/sbt/Logger.scala
  20. +2 −1 sbt/src/main/scala/sbt/Main.scala
  21. +0 −87 sbt/src/main/scala/sbt/Pack.scala
  22. +0 −31 sbt/src/main/scala/sbt/SourceModificationWatch.scala
  23. +0 −84 sbt/src/test/scala/sbt/FileUtilitiesSpecification.scala
  24. +0 −182 sbt/src/test/scala/sbt/ReflectSpecification.scala
  25. +3 −0 testing/NOTICE
  26. +11 −11 {sbt/src/main/scala/sbt → testing}/TestFramework.scala
  27. 0 {sbt/src/main/scala/sbt → testing}/TestReportListener.scala
  28. 0 {sbt/src/main/scala/sbt → testing}/impl/TestParser.scala
  29. 0 {sbt/src/main/scala/sbt → testing}/impl/TestStatusReporter.scala
  30. +2 −1 util/classpath/ClassLoaders.scala
  31. +24 −43 {sbt/src/main/scala/sbt → util/classpath}/ClasspathUtilities.scala
  32. +2 −1 util/classpath/DualLoader.scala
  33. 0 {sbt/src/main/scala/sbt → util/classpath}/ModuleUtilities.scala
  34. +1 −1 util/classpath/NOTICE
  35. +1 −1 {sbt/src/main/scala/sbt → util/classpath}/ReflectUtilities.scala
  36. +4 −1 {compile → util/classpath}/ScalaInstance.scala
  37. +3 −0 util/complete/NOTICE
  38. +19 −4 util/io/IO.scala
  39. +79 −0 util/io/Pack.scala
  40. +2 −1 util/io/Path.scala
  41. +37 −0 util/io/SourceModificationWatch.scala
  42. +78 −0 util/io/src/test/scala/FileUtilitiesSpecification.scala
  43. +3 −3 util/log/BufferedLogger.scala
  44. +24 −0 util/log/FullLogger.scala
  45. +19 −11 util/log/Logger.scala
  46. +2 −2 util/log/LoggerWriter.scala
  47. +0 −2 {sbt/src/main/scala/sbt → util/process}/Process.scala
  48. +4 −4 {sbt/src/main/scala/sbt/impl → util/process}/ProcessImpl.scala
  49. +14 −15 {sbt/src/test/scala/sbt → util/process/src/test/scala}/ProcessSpecification.scala
  50. +13 −12 {sbt/src/test/scala/sbt → util/process/src/test/scala}/TestedProcess.scala
@@ -1,6 +1,9 @@
-package xsbt
+/* sbt -- Simple Build Tool
+ * Copyright 2009, 2010 Mark Harrah
+ */
+package sbt
+package compile
- import sbt.ComponentManager
import xsbti.{AnalysisCallback, Logger => xLogger}
import java.io.File
import java.net.{URL, URLClassLoader}
@@ -9,34 +12,34 @@ package xsbt
* 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: CompileLogger) extends NotNull
+class AnalyzingCompiler(val scalaInstance: ScalaInstance, val manager: ComponentManager, val cp: ClasspathOptions, log: Logger) extends NotNull
{
- def this(scalaInstance: ScalaInstance, manager: ComponentManager, log: CompileLogger) = this(scalaInstance, manager, ClasspathOptions.auto, log)
- def apply(sources: Seq[File], classpath: Seq[File], outputDirectory: File, options: Seq[String], callback: AnalysisCallback, maximumErrors: Int, log: CompileLogger)
+ def this(scalaInstance: ScalaInstance, manager: ComponentManager, log: Logger) = this(scalaInstance, manager, 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)
compile(arguments, callback, maximumErrors, log)
}
- def compile(arguments: Seq[String], callback: AnalysisCallback, maximumErrors: Int, log: CompileLogger)
+ def compile(arguments: Seq[String], callback: AnalysisCallback, maximumErrors: Int, log: Logger)
{
call("xsbt.CompilerInterface", log)(
classOf[Array[String]], classOf[AnalysisCallback], classOf[Int], classOf[xLogger] ) (
arguments.toArray[String] : Array[String], callback, maximumErrors: java.lang.Integer, log )
}
- def doc(sources: Seq[File], classpath: Seq[File], outputDirectory: File, options: Seq[String], maximumErrors: Int, log: CompileLogger): Unit =
+ def doc(sources: Seq[File], classpath: Seq[File], outputDirectory: File, options: Seq[String], maximumErrors: Int, log: Logger): Unit =
{
val arguments = (new CompilerArguments(scalaInstance, cp))(sources, classpath, outputDirectory, options)
call("xsbt.ScaladocInterface", log) (classOf[Array[String]], classOf[Int], classOf[xLogger]) (arguments.toArray[String] : Array[String], maximumErrors: java.lang.Integer, log)
}
- def console(classpath: Seq[File], options: Seq[String], initialCommands: String, log: CompileLogger): Unit =
+ def console(classpath: Seq[File], options: Seq[String], initialCommands: String, log: Logger): Unit =
{
val arguments = new CompilerArguments(scalaInstance, cp)
val classpathString = CompilerArguments.absString(arguments.finishClasspath(classpath))
val bootClasspath = if(cp.autoBoot) arguments.createBootClasspath else ""
call("xsbt.ConsoleInterface", log) (classOf[Array[String]], classOf[String], classOf[String], classOf[String], classOf[xLogger]) (options.toArray[String]: Array[String], bootClasspath, classpathString, initialCommands, log)
}
- def force(log: CompileLogger): Unit = getInterfaceJar(log)
- private def call(interfaceClassName: String, log: CompileLogger)(argTypes: Class[_]*)(args: AnyRef*)
+ def force(log: Logger): Unit = getInterfaceJar(log)
+ private def call(interfaceClassName: String, log: Logger)(argTypes: Class[_]*)(args: AnyRef*)
{
val interfaceClass = getInterfaceClass(interfaceClassName, log)
val interface = interfaceClass.newInstance.asInstanceOf[AnyRef]
@@ -50,20 +53,20 @@ class AnalyzingCompiler(val scalaInstance: ScalaInstance, val manager: Component
val dual = createDualLoader(scalaInstance.loader, getClass.getClassLoader) // this goes to scalaLoader for scala classes and sbtLoader for xsbti classes
new URLClassLoader(Array(interfaceJar.toURI.toURL), dual)
}
- private def getInterfaceClass(name: String, log: CompileLogger) = Class.forName(name, true, loader)
- private def getInterfaceJar(log: CompileLogger) =
+ 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: CompileLogger) = new ComponentCompiler(new RawCompiler(scalaInstance, ClasspathOptions.auto, log), manager)
+ 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.")
val notXsbtiFilter = (name: String) => !xsbtiFilter(name)
- new DualLoader(scalaLoader, notXsbtiFilter, x => true, sbtLoader, xsbtiFilter, x => false)
+ new classpath.DualLoader(scalaLoader, notXsbtiFilter, x => true, sbtLoader, xsbtiFilter, x => false)
}
override def toString = "Analyzing compiler (Scala " + scalaInstance.actualVersion + ")"
}
@@ -1,10 +0,0 @@
-package xsbt
-
-trait CompileLogger extends xsbti.Logger with NotNull
-{
- def info(msg: => String)
- def debug(msg: => String)
- def warn(msg: => String)
- def error(msg: => String)
- def trace(t: => Throwable)
-}
@@ -1,4 +1,8 @@
-package xsbt
+/* sbt -- Simple Build Tool
+ * Copyright 2009, 2010 Mark Harrah
+ */
+package sbt
+package compile
import java.io.File
import CompilerArguments.{abs, absString}
@@ -1,7 +1,10 @@
-package xsbt
+/* sbt -- Simple Build Tool
+ * Copyright 2009, 2010 Mark Harrah
+ */
+package sbt
+package compile
import java.io.File
-import sbt.{ComponentManager, IfMissing, InvalidComponent}
object ComponentCompiler
{
View
@@ -0,0 +1,66 @@
+/* sbt -- Simple Build Tool
+ * Copyright 2008, 2009, 2010 Mark Harrah, Seth Tisue
+ */
+package sbt
+package compile
+
+ import java.io.File
+
+trait JavaCompiler
+{
+ def apply(sources: Seq[File], classpath: Seq[File], outputDirectory: File, options: Seq[String])(implicit log: Logger): Unit
+}
+object JavaCompiler
+{
+ def construct(f: (Seq[String], Logger) => Int, cp: ClasspathOptions, scalaInstance: ScalaInstance): JavaCompiler =
+ new JavaCompiler {
+ def apply(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 = new ClasspathOptions(false, cp.compiler, false)
+ val arguments = (new CompilerArguments(scalaInstance, javaCp))(sources, augmentedClasspath, outputDirectory, options)
+ log.debug("running javac with arguments:\n\t" + arguments.mkString("\n\t"))
+ val code: Int = f(arguments, log)
+ log.debug("javac returned exit code: " + code)
+ if( code != 0 ) throw new CompileFailed(arguments.toArray, "javac returned nonzero exit code")
+ }
+ }
+ def directOrFork(cp: ClasspathOptions, scalaInstance: ScalaInstance): JavaCompiler = construct(directOrForkJavac, cp, scalaInstance)
+ def direct(cp: ClasspathOptions, scalaInstance: ScalaInstance): JavaCompiler = construct(directJavac, cp, scalaInstance)
+ def fork(cp: ClasspathOptions, scalaInstance: ScalaInstance): JavaCompiler = construct(forkJavac, cp, scalaInstance)
+
+ val directOrForkJavac = (arguments: Seq[String], log: Logger) =>
+ try { directJavac(arguments, log) }
+ catch { case e: ClassNotFoundException =>
+ log.debug("com.sun.tools.javac.Main not found; forking javac instead")
+ forkJavac(arguments, log)
+ }
+
+ val forkJavac = (arguments: Seq[String], log: Logger) =>
+ {
+ def externalJavac(argFile: File) = Process("javac", ("@" + normalizeSlash(argFile.getAbsolutePath)) :: Nil) ! log
+ withArgumentFile(arguments)(externalJavac)
+ }
+ val directJavac = (arguments: Seq[String], log: Logger) =>
+ {
+ val writer = new java.io.PrintWriter(new LoggerWriter(log, Level.Error))
+ val argsArray = arguments.toArray
+ val javac = Class.forName("com.sun.tools.javac.Main")
+ log.debug("Calling javac directly.")
+ javac.getDeclaredMethod("compile", classOf[Array[String]], classOf[java.io.PrintWriter])
+ .invoke(null, argsArray, writer)
+ .asInstanceOf[java.lang.Integer]
+ .intValue
+ }
+ def withArgumentFile[T](args: Seq[String])(f: File => T): T =
+ {
+ import IO.{Newline, withTemporaryDirectory, write}
+ withTemporaryDirectory { tmp =>
+ val argFile = new File(tmp, "argfile")
+ write(argFile, args.map(escapeSpaces).mkString(Newline))
+ f(argFile)
+ }
+ }
+ // javac's argument file seems to allow naive space escaping with quotes. escaping a quote with a backslash does not work
+ def escapeSpaces(s: String): String = '\"' + normalizeSlash(s) + '\"'
+ def normalizeSlash(s: String) = s.replace(File.separatorChar, '/')
+}
View
@@ -1,3 +1,3 @@
Simple Build Tool: Compile Component
-Copyright 2009, 2010 Mark Harrah, Jason Zaugg
+Copyright 2009, 2010 Mark Harrah, Seth Tisue, Jason Zaugg
Licensed under BSD-style license (see LICENSE)
@@ -1,12 +1,16 @@
-package xsbt
+/* sbt -- Simple Build Tool
+ * Copyright 2009, 2010 Mark Harrah
+ */
+package sbt
+package compile
import java.io.File
/** A basic interface to the compiler. It is called in the same virtual machine, but no dependency analysis is done. This
* 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: CompileLogger)
+class RawCompiler(val scalaInstance: ScalaInstance, cp: ClasspathOptions, log: Logger)
{
def apply(sources: Seq[File], classpath: Seq[File], outputDirectory: File, options: Seq[String])
{
View
@@ -0,0 +1,3 @@
+Simple Build Tool: Discovery Component
+Copyright 2010 Mark Harrah
+Licensed under BSD-style license (see LICENSE)
View
@@ -0,0 +1,3 @@
+Simple Build Tool: Incremental Logic Component
+Copyright 2010 Mark Harrah
+Licensed under BSD-style license (see LICENSE)
View
@@ -4,8 +4,18 @@ Tradiationally, there has been a main group and a test group.
Each Analysis is associated with one or more classpath entries. Typically, it will be associated with the output directory and/or any artifacts produced from that output directory.
-Need to be able to process Source and extract classes {C} s.t. C <: D for D in {D} or C or one of its non-private methods is annotated with annotation A in {A} or C.main(args: Array[String]) exists
-
For Java sources, need to write a (File, Set[File]) => Source function that reads an API from a class file. The compile function passed to IncrementalCompile needs to handle compiling Java sources in the proper order
Need to handle entries removed from classpath. Could be done similarly to how Locate is used for getting the API for a dependency. In this case, we'd get the Stamp for a binary dependency.
+
+Post-analysis
+ - need to handle inherited definitions
+
+Need builder component:
+ Processor[D]
+ def process(command: String, arg: String, current: State[D]): Result[State[D]]
+ Initial[D]
+ def init: State[D]
+ State[D]
+ value: D
+ processors: Map[String, Processor[D]]
@@ -300,7 +300,7 @@ final class API(val global: Global, val callback: xsbti.AnalysisCallback) extend
}
def isTopLevel(sym: Symbol): Boolean =
(sym ne null) && (sym != NoSymbol) && !sym.isImplClass && !sym.isNestedClass && sym.isStatic &&
- !sym.hasFlag(Flags.SYNTHETIC) && !sym.hasFlag(Flags.JAVA)
+ !sym.hasFlag(Flags.SYNTHETIC)// && !sym.hasFlag(Flags.JAVA)
}
// In 2.8, attributes is renamed to annotations
View
@@ -0,0 +1,3 @@
+Simple Build Tool: Analysis Store Component
+Copyright 2010 Mark Harrah
+Licensed under BSD-style license (see LICENSE)
@@ -1,10 +1,8 @@
package sbt
-import xsbt.{BufferedLogger, FileUtilities}
-
import java.io.File
import org.specs._
-import FileUtilities.{createDirectory, delete, touch, withTemporaryDirectory}
+import IO.{createDirectory, delete, touch, withTemporaryDirectory}
import org.apache.ivy.util.ChecksumHelper
import IfMissing.Fail
@@ -76,7 +74,7 @@ object ComponentManagerTest extends Specification
manager.define(id, files)
f(files)
}
- private def writeRandomContent(file: File) = FileUtilities.write(file, randomString)
+ private def writeRandomContent(file: File) = IO.write(file, randomString)
private def randomString = "asdf"
private def withManager[T](f: ComponentManager => T): T =
TestIvyLogger( logger => withTemporaryDirectory { temp => f(new ComponentManager(xsbt.boot.Locks, new xsbt.boot.ComponentProvider(temp), logger)) } )
@@ -1,8 +1,6 @@
package sbt
-import xsbt.{BufferedLogger, ConsoleLogger, Level}
-
-class TestIvyLogger extends BufferedLogger(new ConsoleLogger) with IvyLogger { def verbose(msg: => String) = info(msg) }
+class TestIvyLogger extends BufferedLogger(new ConsoleLogger) with IvyLogger
object TestIvyLogger
{
def apply[T](f: IvyLogger => T): T =
@@ -6,7 +6,7 @@ package sbt
import inc._
import java.io.File
- import xsbt.{AnalyzingCompiler, CompileLogger, CompilerArguments}
+ import sbt.compile.{AnalyzingCompiler, CompilerArguments}
import xsbti.api.Source
import xsbti.AnalysisCallback
import CompileSetup._
@@ -18,7 +18,7 @@ final class CompileConfiguration(val sources: Seq[File], val classpath: Seq[File
class AggressiveCompile(cacheDirectory: File)
{
- def apply(sources: Seq[File], classpath: Seq[File], outputDirectory: File, options: Seq[String], compiler: AnalyzingCompiler, log: CompileLogger): Analysis =
+ def apply(sources: Seq[File], classpath: Seq[File], outputDirectory: File, options: Seq[String], compiler: AnalyzingCompiler, log: Logger): Analysis =
{
val setup = new CompileSetup(outputDirectory, new CompileOptions(options), compiler.scalaInstance.actualVersion, CompileOrder.Mixed)
compile1(sources, classpath, setup, store, Map.empty, compiler, log)
@@ -27,15 +27,15 @@ class AggressiveCompile(cacheDirectory: File)
def withBootclasspath(args: CompilerArguments, classpath: Seq[File]): Seq[File] =
args.bootClasspath ++ classpath
- def compile1(sources: Seq[File], classpath: Seq[File], setup: CompileSetup, store: AnalysisStore, analysis: Map[File, Analysis], compiler: AnalyzingCompiler, log: CompileLogger): Analysis =
+ def compile1(sources: Seq[File], classpath: Seq[File], setup: CompileSetup, store: AnalysisStore, analysis: Map[File, Analysis], compiler: AnalyzingCompiler, log: Logger): Analysis =
{
val (previousAnalysis, previousSetup) = extract(store.get())
val config = new CompileConfiguration(sources, classpath, previousAnalysis, previousSetup, setup, analysis.get _, 100, compiler)
val result = compile2(config, log)
store.set(result, setup)
result
}
- def compile2(config: CompileConfiguration, log: CompileLogger)(implicit equiv: Equiv[CompileSetup]): Analysis =
+ def compile2(config: CompileConfiguration, log: Logger)(implicit equiv: Equiv[CompileSetup]): Analysis =
{
import config._
import currentSetup._
@@ -3,7 +3,7 @@
*/
package sbt
- import xsbt.{AnalyzingCompiler, CompileLogger, ScalaInstance}
+ import sbt.compile.AnalyzingCompiler
import java.io.File
import System.{currentTimeMillis => now}
import Path._
@@ -23,13 +23,13 @@ class AggressiveCompiler extends xsbti.AppMain
def run(command: String, args: List[String], cwd: Path, app: xsbti.AppProvider): Boolean =
{
val launcher = app.scalaProvider.launcher
- val sources = cwd ** "*.scala"
+ val sources = cwd ** ("*.scala" | "*.java")
val target = cwd / "target"
val outputDirectory = target / "classes"
val classpath = outputDirectory +++ (cwd * "*.jar") +++(cwd * (-"project")).descendentsExcept( "*.jar", "project" || HiddenFileFilter)
val cacheDirectory = target / "cache"
val options = args.tail.toSeq
- val log = new ConsoleLogger with CompileLogger with sbt.IvyLogger
+ val log = new ConsoleLogger with Logger with sbt.IvyLogger
val componentManager = new ComponentManager(launcher.globalLock, app.components, log)
val compiler = new AnalyzingCompiler(ScalaInstance(args.head, launcher), componentManager, log)
Oops, something went wrong.

0 comments on commit 6f3c699

Please sign in to comment.