diff --git a/compile/integration/src/main/scala/sbt/compiler/AggressiveCompile.scala b/compile/integration/src/main/scala/sbt/compiler/AggressiveCompile.scala index c4ce04804..8241bd3ed 100644 --- a/compile/integration/src/main/scala/sbt/compiler/AggressiveCompile.scala +++ b/compile/integration/src/main/scala/sbt/compiler/AggressiveCompile.scala @@ -24,7 +24,7 @@ final class CompileConfiguration(val sources: Seq[File], val classpath: Seq[File val previousAnalysis: Analysis, val previousSetup: Option[CompileSetup], val currentSetup: CompileSetup, val progress: Option[CompileProgress], val getAnalysis: File => Option[Analysis], val definesClass: DefinesClass, val reporter: Reporter, val compiler: AnalyzingCompiler, val javac: xsbti.compile.JavaCompiler, val cache: GlobalsCache, val incOptions: IncOptions) -class AggressiveCompile(cacheFile: File) { +class AggressiveCompile { def apply(compiler: AnalyzingCompiler, javac: xsbti.compile.JavaCompiler, sources: Seq[File], classpath: Seq[File], @@ -33,17 +33,20 @@ class AggressiveCompile(cacheFile: File) { progress: Option[CompileProgress] = None, options: Seq[String] = Nil, javacOptions: Seq[String] = Nil, + previousAnalysis: Analysis, + previousSetup: Option[CompileSetup], analysisMap: File => Option[Analysis] = { _ => None }, definesClass: DefinesClass = Locate.definesClass _, reporter: Reporter, compileOrder: CompileOrder = Mixed, skip: Boolean = false, - incrementalCompilerOptions: IncOptions)(implicit log: Logger): Analysis = + incrementalCompilerOptions: IncOptions)(implicit log: Logger): (Analysis, CompileSetup, Boolean) = { val setup = new CompileSetup(output, new CompileOptions(options, javacOptions), compiler.scalaInstance.actualVersion, compileOrder, incrementalCompilerOptions.nameHashing) - compile1(sources, classpath, setup, progress, store, analysisMap, definesClass, + val (analysis, modified) = compile1(sources, classpath, setup, progress, previousAnalysis, previousSetup, analysisMap, definesClass, compiler, javac, reporter, skip, cache, incrementalCompilerOptions) + (analysis, setup, modified) } def withBootclasspath(args: CompilerArguments, classpath: Seq[File]): Seq[File] = @@ -52,25 +55,23 @@ class AggressiveCompile(cacheFile: File) { def compile1(sources: Seq[File], classpath: Seq[File], setup: CompileSetup, progress: Option[CompileProgress], - store: AnalysisStore, + previousAnalysis: Analysis, + previousSetup: Option[CompileSetup], analysis: File => Option[Analysis], definesClass: DefinesClass, compiler: AnalyzingCompiler, javac: xsbti.compile.JavaCompiler, reporter: Reporter, skip: Boolean, cache: GlobalsCache, - incrementalCompilerOptions: IncOptions)(implicit log: Logger): Analysis = + incrementalCompilerOptions: IncOptions)(implicit log: Logger): (Analysis, Boolean) = { - val (previousAnalysis, previousSetup) = extract(store.get(), incrementalCompilerOptions) if (skip) - previousAnalysis + (previousAnalysis, false) else { val config = new CompileConfiguration(sources, classpath, previousAnalysis, previousSetup, setup, progress, analysis, definesClass, reporter, compiler, javac, cache, incrementalCompilerOptions) val (modified, result) = compile2(config) - if (modified) - store.set(result, setup) - result + (result, modified) } } def compile2(config: CompileConfiguration)(implicit log: Logger, equiv: Equiv[CompileSetup]): (Boolean, Analysis) = @@ -176,17 +177,11 @@ class AggressiveCompile(cacheFile: File) { if (!combined.isEmpty) log.info(combined.mkString("Compiling ", " and ", " to " + outputDirs.map(_.getAbsolutePath).mkString(",") + "...")) } - private def extract(previous: Option[(Analysis, CompileSetup)], incOptions: IncOptions): (Analysis, Option[CompileSetup]) = - previous match { - case Some((an, setup)) => (an, Some(setup)) - case None => (Analysis.empty(nameHashing = incOptions.nameHashing), None) - } def javaOnly(f: File) = f.getName.endsWith(".java") private[this] def explicitBootClasspath(options: Seq[String]): Seq[File] = options.dropWhile(_ != CompilerArguments.BootClasspathOption).drop(1).take(1).headOption.toList.flatMap(IO.parseClasspath) - val store = AggressiveCompile.staticCache(cacheFile, AnalysisStore.sync(AnalysisStore.cached(FileBasedStore(cacheFile)))) } object AggressiveCompile { import collection.mutable @@ -200,6 +195,9 @@ object AggressiveCompile { b } } + + def staticCachedStore(cacheFile: File) = staticCache(cacheFile, AnalysisStore.sync(AnalysisStore.cached(FileBasedStore(cacheFile)))) + @deprecated("0.13.8", "Deprecated in favor of new sbt.compiler.javac package.") def directOrFork(instance: ScalaInstance, cpOptions: ClasspathOptions, javaHome: Option[File]): JavaTool = if (javaHome.isDefined) diff --git a/compile/integration/src/main/scala/sbt/compiler/IncrementalCompiler.scala b/compile/integration/src/main/scala/sbt/compiler/IncrementalCompiler.scala index b7a4b6c57..e2f7cd1d1 100644 --- a/compile/integration/src/main/scala/sbt/compiler/IncrementalCompiler.scala +++ b/compile/integration/src/main/scala/sbt/compiler/IncrementalCompiler.scala @@ -12,12 +12,19 @@ object IC extends IncrementalCompiler[Analysis, AnalyzingCompiler] { 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 agg = new AggressiveCompile val aMap = (f: File) => m2o(analysisMap(f)) val defClass = (f: File) => { val dc = definesClass(f); (name: String) => dc.apply(name) } val incOptions = IncOptions.fromStringMap(incrementalCompilerOptions) - agg(scalac, javac, sources, classpath, output, cache, m2o(progress), scalacOptions, javacOptions, aMap, - defClass, reporter, order, skip, incOptions)(log) + val (previousAnalysis, previousSetup) = { + AggressiveCompile.staticCachedStore(setup.cacheFile()).get().map { + case (a, s) => (a, Some(s)) + } getOrElse { + (Analysis.empty(nameHashing = incOptions.nameHashing), None) + } + } + agg(scalac, javac, sources, classpath, output, cache, m2o(progress), scalacOptions, javacOptions, previousAnalysis, + previousSetup, aMap, defClass, reporter, order, skip, incOptions)(log)._1 } private[this] def m2o[S](opt: Maybe[S]): Option[S] = if (opt.isEmpty) None else Some(opt.get) diff --git a/main/actions/src/main/scala/sbt/Compiler.scala b/main/actions/src/main/scala/sbt/Compiler.scala index 672e4105e..0d2ed5ad7 100644 --- a/main/actions/src/main/scala/sbt/Compiler.scala +++ b/main/actions/src/main/scala/sbt/Compiler.scala @@ -15,9 +15,10 @@ import java.io.File object Compiler { val DefaultMaxErrors = 100 - final case class Inputs(compilers: Compilers, config: Options, incSetup: IncSetup) + final case class Inputs(compilers: Compilers, config: Options, incSetup: IncSetup, previousAnalysis: PreviousAnalysis) final case class Options(classpath: Seq[File], sources: Seq[File], classesDirectory: File, options: Seq[String], javacOptions: Seq[String], maxErrors: Int, sourcePositionMapper: Position => Position, order: CompileOrder) final case class IncSetup(analysisMap: File => Option[Analysis], definesClass: DefinesClass, skip: Boolean, cacheFile: File, cache: GlobalsCache, incOptions: IncOptions) +<<<<<<< HEAD private[sbt] trait JavaToolWithNewInterface extends JavaTool { def newJavac: IncrementalCompilerJavaTools } @@ -29,12 +30,20 @@ object Compiler { } } final case class NewCompilers(scalac: AnalyzingCompiler, javac: JavaTools) +======= + final case class Compilers(scalac: AnalyzingCompiler, javac: JavaTool) + final case class PreviousAnalysis(analysis: Analysis, setup: Option[CompileSetup]) + final case class AnalysisResult(analysis: Analysis, setup: CompileSetup, modified: Boolean) +>>>>>>> Allow bytecode enhancement to update analysis - def inputs(classpath: Seq[File], sources: Seq[File], classesDirectory: File, options: Seq[String], javacOptions: Seq[String], maxErrors: Int, sourcePositionMappers: Seq[Position => Option[Position]], order: CompileOrder)(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, sourcePositionMappers: Seq[Position => Option[Position]], + order: CompileOrder, previousAnalysis: PreviousAnalysis)(implicit compilers: Compilers, incSetup: IncSetup, log: Logger): Inputs = new Inputs( compilers, new Options(classpath, sources, classesDirectory, options, javacOptions, maxErrors, foldMappers(sourcePositionMappers), order), - incSetup + incSetup, + previousAnalysis ) def compilers(cpOptions: ClasspathOptions)(implicit app: AppConfiguration, log: Logger): Compilers = @@ -79,14 +88,14 @@ object Compiler { val provider = ComponentCompiler.interfaceProvider(componentManager) new AnalyzingCompiler(instance, provider, cpOptions, log) } - def apply(in: Inputs, log: Logger): Analysis = + def apply(in: Inputs, log: Logger): AnalysisResult = { import in.compilers._ import in.config._ import in.incSetup._ apply(in, log, new LoggerReporter(maxErrors, log, sourcePositionMapper)) } - def apply(in: Inputs, log: Logger, reporter: xsbti.Reporter): Analysis = + def apply(in: Inputs, log: Logger, reporter: xsbti.Reporter): AnalysisResult = { import in.compilers._ import in.config._ @@ -98,7 +107,7 @@ object Compiler { val javacChosen: xsbti.compile.JavaCompiler = in.compilers.newJavac.map(_.xsbtiCompiler).getOrElse(in.compilers.javac) agg(scalac, javacChosen, sources, classpath, CompileOutput(classesDirectory), cache, None, options, javacOptions, - analysisMap, definesClass, reporter, order, skip, incOptions)(log) + in.previousAnalysis.analysis, in.previousAnalysis.setup, analysisMap, definesClass, reporter, order, skip, incOptions)(log) } private[sbt] def foldMappers[A](mappers: Seq[A => Option[A]]) = diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index 40645e4fe..210db6b3a 100755 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -14,7 +14,8 @@ import Configurations.{ Compile, CompilerPlugin, IntegrationTest, names, Provide import CrossVersion.{ binarySbtVersion, binaryScalaVersion, partialVersion } import complete._ import std.TaskExtra._ -import inc.{ FileValueCache, IncOptions, Locate } +import sbt.inc.{ Analysis, FileValueCache, IncOptions, Locate } +import sbt.compiler.AggressiveCompile import testing.{ Framework, Runner, AnnotatedFingerprint, SubclassFingerprint } import sys.error @@ -246,8 +247,9 @@ object Defaults extends BuildCommon { def compilersSetting = compilers := Compiler.compilers(scalaInstance.value, classpathOptions.value, javaHome.value)(appConfiguration.value, streams.value.log) - lazy val configTasks = docTaskSettings(doc) ++ inTask(compile)(compileInputsSettings) ++ configGlobal ++ Seq( - compile <<= compileTask tag (Tags.Compile, Tags.CPU), + lazy val configTasks = docTaskSettings(doc) ++ inTask(compile)(compileInputsSettings) ++ configGlobal ++ compileAnalysisSettings ++ Seq( + compile <<= compileTask, + compileIncremental <<= compileIncrementalTask tag (Tags.Compile, Tags.CPU), printWarnings <<= printWarningsTask, compileAnalysisFilename := { // Here, if the user wants cross-scala-versioning, we also append it @@ -778,8 +780,11 @@ object Defaults extends BuildCommon { @deprecated("Use inTask(compile)(compileInputsSettings)", "0.13.0") def compileTaskSettings: Seq[Setting[_]] = inTask(compile)(compileInputsSettings) - def compileTask: Initialize[Task[inc.Analysis]] = Def.task { compileTaskImpl(streams.value, (compileInputs in compile).value, (compilerReporter in compile).value) } - private[this] def compileTaskImpl(s: TaskStreams, ci: Compiler.Inputs, reporter: Option[xsbti.Reporter]): inc.Analysis = + def compileTask: Initialize[Task[inc.Analysis]] = Def.task { saveAnalysis.value } + def compileIncrementalTask = Def.task { + compileIncrementalTaskImpl(streams.value, (compileInputs in compile).value, (compilerReporter in compile).value) + } + private[this] def compileIncrementalTaskImpl(s: TaskStreams, ci: Compiler.Inputs, reporter: Option[xsbti.Reporter]): Compiler.AnalysisResult = { lazy val x = s.text(ExportStream) def onArgs(cs: Compiler.Compilers) = cs.copy(scalac = cs.scalac.onArgs(exported(x, "scalac")), javac = cs.javac.onArgs(exported(x, "javac"))) @@ -803,9 +808,29 @@ object Defaults extends BuildCommon { def compileInputsSettings: Seq[Setting[_]] = Seq(compileInputs := { val cp = classDirectory.value +: data(dependencyClasspath.value) - Compiler.inputs(cp, sources.value, classDirectory.value, scalacOptions.value, javacOptions.value, maxErrors.value, sourcePositionMappers.value, compileOrder.value)(compilers.value, compileIncSetup.value, streams.value.log) + Compiler.inputs(cp, sources.value, classDirectory.value, scalacOptions.value, javacOptions.value, + maxErrors.value, sourcePositionMappers.value, compileOrder.value, readAnalysis.value)(compilers.value, compileIncSetup.value, streams.value.log) }, compilerReporter := None) + def compileAnalysisSettings: Seq[Setting[_]] = Seq( + readAnalysis := { + val setup: Compiler.IncSetup = compileIncSetup.value + val store = AggressiveCompile.staticCachedStore(setup.cacheFile) + store.get() match { + case Some((an, setup)) => Compiler.PreviousAnalysis(an, Some(setup)) + case None => Compiler.PreviousAnalysis(Analysis.empty(nameHashing = setup.incOptions.nameHashing), None) + } + }, + saveAnalysis := { + val setup: Compiler.IncSetup = compileIncSetup.value + val analysisResult: Compiler.AnalysisResult = compileIncremental.value + if (analysisResult.modified) { + val store = AggressiveCompile.staticCachedStore(setup.cacheFile) + store.set(analysisResult.analysis, analysisResult.setup) + } + analysisResult.analysis + } + ) def printWarningsTask: Initialize[Task[Unit]] = (streams, compile, maxErrors, sourcePositionMappers) map { (s, analysis, max, spms) => diff --git a/main/src/main/scala/sbt/Keys.scala b/main/src/main/scala/sbt/Keys.scala index 8795d0795..cbc27853f 100644 --- a/main/src/main/scala/sbt/Keys.scala +++ b/main/src/main/scala/sbt/Keys.scala @@ -141,6 +141,9 @@ object Keys { val consoleQuick = TaskKey[Unit]("console-quick", "Starts the Scala interpreter with the project dependencies on the classpath.", ATask, console) val consoleProject = TaskKey[Unit]("console-project", "Starts the Scala interpreter with the sbt and the build definition on the classpath and useful imports.", AMinusTask) val compile = TaskKey[Analysis]("compile", "Compiles sources.", APlusTask) + val compileIncremental = TaskKey[Compiler.AnalysisResult]("compileIncremental", "Actually runs the incremental compliation", DTask) + val readAnalysis = TaskKey[Compiler.PreviousAnalysis]("readAnalysis", "Read the incremental compiler analysis from disk", DTask) + val saveAnalysis = TaskKey[Analysis]("saveAnalysis", "Save the incremental compiler analysis to disk", DTask) val compilers = TaskKey[Compiler.Compilers]("compilers", "Defines the Scala and Java compilers to use for compilation.", DTask) val compileAnalysisFilename = TaskKey[String]("compileAnalysisFilename", "Defines the filename used to store the incremental compiler analysis file (inside the streams cacheDirectory).", DTask) val compileIncSetup = TaskKey[Compiler.IncSetup]("inc-compile-setup", "Configures aspects of incremental compilation.", DTask)