From 40bf599f4a4ac9fac07869c87ac5901cbb8d14f9 Mon Sep 17 00:00:00 2001 From: Josh Suereth Date: Tue, 4 Nov 2014 11:08:50 -0500 Subject: [PATCH] Deprecating old APIs and attempting to document behavior correctly. * Removed as many binary incompatibilities as I could find. * Deprecating old APIs * Attempt to construct new nomenclature that fits the design of Incremental API. * Add as much documentation as I was comfortable writing (from my understanding of things). --- .../sbt/compiler/AggressiveCompile.scala | 35 +-- .../sbt/compiler/CompileConfiguration.scala | 41 ++++ .../sbt/compiler/IncrementalCompiler.scala | 16 +- .../sbt/compiler/MixedAnalyzingCompiler.scala | 229 ++++++++++++++++++ .../main/java/xsbti/compile/GlobalsCache.java | 3 + .../actions/src/main/scala/sbt/Compiler.scala | 29 ++- main/src/main/scala/sbt/Defaults.scala | 20 +- main/src/main/scala/sbt/Keys.scala | 3 +- 8 files changed, 334 insertions(+), 42 deletions(-) create mode 100644 compile/integration/src/main/scala/sbt/compiler/CompileConfiguration.scala create mode 100644 compile/integration/src/main/scala/sbt/compiler/MixedAnalyzingCompiler.scala diff --git a/compile/integration/src/main/scala/sbt/compiler/AggressiveCompile.scala b/compile/integration/src/main/scala/sbt/compiler/AggressiveCompile.scala index 8241bd3ed..4aa7a2a22 100644 --- a/compile/integration/src/main/scala/sbt/compiler/AggressiveCompile.scala +++ b/compile/integration/src/main/scala/sbt/compiler/AggressiveCompile.scala @@ -20,11 +20,9 @@ import xsbti.api.Source import xsbti.compile.{ CompileOrder, DependencyChanges, GlobalsCache, Output, SingleOutput, MultipleOutput, CompileProgress } import CompileOrder.{ JavaThenScala, Mixed, ScalaThenJava } -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 { +@deprecated("0.13.8", "Use MixedAnalyzingCompiler instead.") +class AggressiveCompile(cacheFile: File) { + @deprecated("0.13.8", "Use MixedAnalyzingCompiler.analyzingCompile instead.") def apply(compiler: AnalyzingCompiler, javac: xsbti.compile.JavaCompiler, sources: Seq[File], classpath: Seq[File], @@ -33,20 +31,17 @@ class AggressiveCompile { 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, CompileSetup, Boolean) = + incrementalCompilerOptions: IncOptions)(implicit log: Logger): Analysis = { val setup = new CompileSetup(output, new CompileOptions(options, javacOptions), compiler.scalaInstance.actualVersion, compileOrder, incrementalCompilerOptions.nameHashing) - val (analysis, modified) = compile1(sources, classpath, setup, progress, previousAnalysis, previousSetup, analysisMap, definesClass, + compile1(sources, classpath, setup, progress, store, analysisMap, definesClass, compiler, javac, reporter, skip, cache, incrementalCompilerOptions) - (analysis, setup, modified) } def withBootclasspath(args: CompilerArguments, classpath: Seq[File]): Seq[File] = @@ -55,23 +50,25 @@ class AggressiveCompile { def compile1(sources: Seq[File], classpath: Seq[File], setup: CompileSetup, progress: Option[CompileProgress], - previousAnalysis: Analysis, - previousSetup: Option[CompileSetup], + store: AnalysisStore, analysis: File => Option[Analysis], definesClass: DefinesClass, compiler: AnalyzingCompiler, javac: xsbti.compile.JavaCompiler, reporter: Reporter, skip: Boolean, cache: GlobalsCache, - incrementalCompilerOptions: IncOptions)(implicit log: Logger): (Analysis, Boolean) = + incrementalCompilerOptions: IncOptions)(implicit log: Logger): Analysis = { + val (previousAnalysis, previousSetup) = extract(store.get(), incrementalCompilerOptions) if (skip) - (previousAnalysis, false) + previousAnalysis else { val config = new CompileConfiguration(sources, classpath, previousAnalysis, previousSetup, setup, progress, analysis, definesClass, reporter, compiler, javac, cache, incrementalCompilerOptions) val (modified, result) = compile2(config) - (result, modified) + if (modified) + store.set(result, setup) + result } } def compile2(config: CompileConfiguration)(implicit log: Logger, equiv: Equiv[CompileSetup]): (Boolean, Analysis) = @@ -177,12 +174,20 @@ class AggressiveCompile { 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)))) + } +@deprecated("0.13.8", "Use MixedAnalyzingCompiler instead.") object AggressiveCompile { import collection.mutable import java.lang.ref.{ Reference, SoftReference } diff --git a/compile/integration/src/main/scala/sbt/compiler/CompileConfiguration.scala b/compile/integration/src/main/scala/sbt/compiler/CompileConfiguration.scala new file mode 100644 index 000000000..d5e6b0a91 --- /dev/null +++ b/compile/integration/src/main/scala/sbt/compiler/CompileConfiguration.scala @@ -0,0 +1,41 @@ +package sbt.compiler + +import java.io.File + +import sbt.CompileSetup +import sbt.inc.{ IncOptions, Analysis } +import sbt.inc.Locate._ +import xsbti.Reporter +import xsbti.compile.{ GlobalsCache, CompileProgress } + +/** + * Configuration used for running an analyzing compiler (a compiler which can extract dependencies between source files and JARs). + * + * @param sources + * @param classpath + * @param previousAnalysis + * @param previousSetup + * @param currentSetup + * @param progress + * @param getAnalysis + * @param definesClass + * @param reporter + * @param compiler + * @param javac + * @param cache + * @param incOptions + */ +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) diff --git a/compile/integration/src/main/scala/sbt/compiler/IncrementalCompiler.scala b/compile/integration/src/main/scala/sbt/compiler/IncrementalCompiler.scala index e2f7cd1d1..7c13a821f 100644 --- a/compile/integration/src/main/scala/sbt/compiler/IncrementalCompiler.scala +++ b/compile/integration/src/main/scala/sbt/compiler/IncrementalCompiler.scala @@ -6,31 +6,37 @@ import sbt.inc.{ Analysis, IncOptions, TextAnalysisFormat } import xsbti.{ Logger, Maybe } import xsbti.compile._ +/** + * An implementation of the incremetnal compiler that can compile inputs and dump out source dependency analysis. + */ 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 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) val (previousAnalysis, previousSetup) = { - AggressiveCompile.staticCachedStore(setup.cacheFile()).get().map { + MixedAnalyzingCompiler.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 + MixedAnalyzingCompiler.analyzingCompile(scalac, javac, sources, classpath, output, cache, m2o(progress), scalacOptions, javacOptions, previousAnalysis, + previousSetup, aMap, defClass, reporter, order, skip, incOptions)(log).analysis } private[this] def m2o[S](opt: Maybe[S]): Option[S] = if (opt.isEmpty) None else Some(opt.get) + @deprecated("0.13.8", "A constructor is no longer needed.") def newScalaCompiler(instance: ScalaInstance, interfaceJar: File, options: ClasspathOptions, log: Logger): AnalyzingCompiler = - new AnalyzingCompiler(instance, CompilerInterfaceProvider.constant(interfaceJar), options, log) + new AnalyzingCompiler(instance, CompilerInterfaceProvider.constant(interfaceJar), options) + + def newScalaCompiler(instance: ScalaInstance, interfaceJar: File, options: ClasspathOptions): AnalyzingCompiler = + new AnalyzingCompiler(instance, CompilerInterfaceProvider.constant(interfaceJar), options) def compileInterfaceJar(label: String, sourceJar: File, targetJar: File, interfaceJar: File, instance: ScalaInstance, log: Logger) { val raw = new RawCompiler(instance, sbt.ClasspathOptions.auto, log) diff --git a/compile/integration/src/main/scala/sbt/compiler/MixedAnalyzingCompiler.scala b/compile/integration/src/main/scala/sbt/compiler/MixedAnalyzingCompiler.scala new file mode 100644 index 000000000..4fe5729b5 --- /dev/null +++ b/compile/integration/src/main/scala/sbt/compiler/MixedAnalyzingCompiler.scala @@ -0,0 +1,229 @@ +package sbt.compiler + +import java.io.File +import java.lang.ref.{ SoftReference, Reference } + +import sbt.classfile.Analyze +import sbt.classpath.ClasspathUtilities +import sbt.inc.Locate.DefinesClass +import sbt._ +import sbt.inc._ +import sbt.inc.Locate +import xsbti.{ AnalysisCallback, Reporter } +import xsbti.api.Source +import xsbti.compile.CompileOrder._ +import xsbti.compile._ + +/** + * This is a compiler that mixes the `sbt.compiler.AnalyzingCompiler` for Scala incremental compilation + * with a `xsbti.JavaCompiler`, allowing cross-compilation of mixed Java/Scala projects with analysis output. + */ +object MixedAnalyzingCompiler { + /** The result of running the compilation. */ + final case class Result(analysis: Analysis, setup: CompileSetup, hasModified: Boolean) + + /** + * This will run a mixed-compilation of Java/Scala sources + * @param scalac An instances of the Scalac compiler which can also extract "Analysis" (dependencies) + * @param javac An instance of the Javac compiler. + * @param sources The set of sources to compile + * @param classpath The classpath to use when compiling. + * @param output Configuration for where to output .class files. + * @param cache The caching mechanism to use instead of insantiating new compiler instances. + * @param progress Progress listening for the compilation process. TODO - Feed this through the Javac Compiler! + * @param options Options for the Scala compiler + * @param javacOptions Options for the Java compiler + * @param previousAnalysis The previous dependency Analysis object/ + * @param previousSetup The previous compilation setup (if any) + * @param analysisMap A map of file to the dependency analysis of that file. + * @param definesClass A mehcnaism of looking up whether or not a JAR defines a particular Class. + * @param reporter Where we sent all compilation error/warning events + * @param compileOrder The order we'd like to mix compilation. JavaThenScala, ScalaThenJava or Mixed. + * @param skip IF true, we skip compilation and just return the previous analysis file. + * @param incrementalCompilerOptions Options specific to incremental compilation. + * @param log The location where we write log messages. + * @return The full configuration used to instantiate this mixed-analyzing compiler, the set of extracted dependencies and + * whether or not any file were modified. + */ + def analyzingCompile(scalac: AnalyzingCompiler, + javac: xsbti.compile.JavaCompiler, + sources: Seq[File], + classpath: Seq[File], + output: Output, + cache: GlobalsCache, + 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): Result = + { + val setup = new CompileSetup(output, new CompileOptions(options, javacOptions), + scalac.scalaInstance.actualVersion, compileOrder, incrementalCompilerOptions.nameHashing) + val (analysis, modified) = compile1(sources, classpath, setup, progress, previousAnalysis, previousSetup, analysisMap, definesClass, + scalac, javac, reporter, skip, cache, incrementalCompilerOptions) + Result(analysis, setup, modified) + } + + def withBootclasspath(args: CompilerArguments, classpath: Seq[File]): Seq[File] = + args.bootClasspathFor(classpath) ++ args.extClasspath ++ args.finishClasspath(classpath) + + /** + * The first level of compilation. This checks to see if we need to skip compiling because of the skip flag, + * IF we're not skipping, this setups up the `CompileConfiguration` and delegates to `compile2` + */ + private def compile1(sources: Seq[File], + classpath: Seq[File], + setup: CompileSetup, progress: Option[CompileProgress], + 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, Boolean) = + { + if (skip) + (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) + (result, modified) + } + } + /** + * This runs the actual compilation of Java + Scala. There are two helper methods which + * actually perform the compilation of Java or Scala. This method uses the compile order to determine + * which files to pass to which compilers. + */ + private def compile2(config: CompileConfiguration)(implicit log: Logger, equiv: Equiv[CompileSetup]): (Boolean, Analysis) = + { + import config._ + import currentSetup._ + val absClasspath = classpath.map(_.getAbsoluteFile) + val apiOption = (api: Either[Boolean, Source]) => api.right.toOption + val cArgs = new CompilerArguments(compiler.scalaInstance, compiler.cp) + val searchClasspath = explicitBootClasspath(options.options) ++ withBootclasspath(cArgs, absClasspath) + val entry = Locate.entry(searchClasspath, definesClass) + + val compile0 = (include: Set[File], changes: DependencyChanges, callback: AnalysisCallback) => { + val outputDirs = outputDirectories(output) + outputDirs foreach (IO.createDirectory) + val incSrc = sources.filter(include) + val (javaSrcs, scalaSrcs) = incSrc partition javaOnly + logInputs(log, javaSrcs.size, scalaSrcs.size, outputDirs) + def compileScala() = + if (!scalaSrcs.isEmpty) { + val sources = if (order == Mixed) incSrc else scalaSrcs + val arguments = cArgs(Nil, absClasspath, None, options.options) + timed("Scala compilation", log) { + compiler.compile(sources, changes, arguments, output, callback, reporter, config.cache, log, progress) + } + } + def compileJava() = + if (!javaSrcs.isEmpty) { + import Path._ + @annotation.tailrec def ancestor(f1: File, f2: File): Boolean = + if (f2 eq null) false else if (f1 == f2) true else ancestor(f1, f2.getParentFile) + + val chunks: Map[Option[File], Seq[File]] = output match { + case single: SingleOutput => Map(Some(single.outputDirectory) -> javaSrcs) + case multi: MultipleOutput => + javaSrcs groupBy { src => + multi.outputGroups find { out => ancestor(out.sourceDirectory, src) } map (_.outputDirectory) + } + } + chunks.get(None) foreach { srcs => + log.error("No output directory mapped for: " + srcs.map(_.getAbsolutePath).mkString(",")) + } + val memo = for ((Some(outputDirectory), srcs) <- chunks) yield { + val classesFinder = PathFinder(outputDirectory) ** "*.class" + (classesFinder, classesFinder.get, srcs) + } + + val loader = ClasspathUtilities.toLoader(searchClasspath) + timed("Java compilation", log) { + try javac.compileWithReporter(javaSrcs.toArray, absClasspath.toArray, output, options.javacOptions.toArray, reporter, log) + catch { + // Handle older APIs + case _: NoSuchMethodError => + javac.compile(javaSrcs.toArray, absClasspath.toArray, output, options.javacOptions.toArray, log) + } + } + + def readAPI(source: File, classes: Seq[Class[_]]): Set[String] = { + val (api, inherits) = ClassToAPI.process(classes) + callback.api(source, api) + inherits.map(_.getName) + } + + timed("Java analysis", log) { + for ((classesFinder, oldClasses, srcs) <- memo) { + val newClasses = Set(classesFinder.get: _*) -- oldClasses + Analyze(newClasses.toSeq, srcs, log)(callback, loader, readAPI) + } + } + } + if (order == JavaThenScala) { compileJava(); compileScala() } else { compileScala(); compileJava() } + } + + val sourcesSet = sources.toSet + val analysis = previousSetup match { + case Some(previous) if previous.nameHashing != currentSetup.nameHashing => + // if the value of `nameHashing` flag has changed we have to throw away + // previous Analysis completely and start with empty Analysis object + // that supports the particular value of the `nameHashing` flag. + // Otherwise we'll be getting UnsupportedOperationExceptions + Analysis.empty(currentSetup.nameHashing) + case Some(previous) if equiv.equiv(previous, currentSetup) => previousAnalysis + case _ => Incremental.prune(sourcesSet, previousAnalysis) + } + IncrementalCompile(sourcesSet, entry, compile0, analysis, getAnalysis, output, log, incOptions) + } + private[this] def outputDirectories(output: Output): Seq[File] = output match { + case single: SingleOutput => List(single.outputDirectory) + case mult: MultipleOutput => mult.outputGroups map (_.outputDirectory) + } + private[this] def timed[T](label: String, log: Logger)(t: => T): T = + { + val start = System.nanoTime + val result = t + val elapsed = System.nanoTime - start + log.debug(label + " took " + (elapsed / 1e9) + " s") + result + } + private[this] def logInputs(log: Logger, javaCount: Int, scalaCount: Int, outputDirs: Seq[File]) { + val scalaMsg = Analysis.counted("Scala source", "", "s", scalaCount) + val javaMsg = Analysis.counted("Java source", "", "s", javaCount) + val combined = scalaMsg ++ javaMsg + if (!combined.isEmpty) + log.info(combined.mkString("Compiling ", " and ", " to " + outputDirs.map(_.getAbsolutePath).mkString(",") + "...")) + } + /** Returns true if the file is java. */ + 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) + + private[this] val cache = new collection.mutable.HashMap[File, Reference[AnalysisStore]] + private def staticCache(file: File, backing: => AnalysisStore): AnalysisStore = + synchronized { + cache get file flatMap { ref => Option(ref.get) } getOrElse { + val b = backing + cache.put(file, new SoftReference(b)) + b + } + } + + /** Create a an analysis store cache at the desired location. */ + def staticCachedStore(cacheFile: File) = staticCache(cacheFile, AnalysisStore.sync(AnalysisStore.cached(FileBasedStore(cacheFile)))) + +} diff --git a/interface/src/main/java/xsbti/compile/GlobalsCache.java b/interface/src/main/java/xsbti/compile/GlobalsCache.java index a3a412836..d9aa1c017 100644 --- a/interface/src/main/java/xsbti/compile/GlobalsCache.java +++ b/interface/src/main/java/xsbti/compile/GlobalsCache.java @@ -3,6 +3,9 @@ package xsbti.compile; import xsbti.Logger; import xsbti.Reporter; +/** + * An interface which lets us know how to retrieve cached compiler instances form the current JVM. + */ public interface GlobalsCache { public CachedCompiler apply(String[] args, Output output, boolean forceNew, CachedCompilerProvider provider, Logger log, Reporter reporter); diff --git a/main/actions/src/main/scala/sbt/Compiler.scala b/main/actions/src/main/scala/sbt/Compiler.scala index 0d2ed5ad7..ff3f28f65 100644 --- a/main/actions/src/main/scala/sbt/Compiler.scala +++ b/main/actions/src/main/scala/sbt/Compiler.scala @@ -18,10 +18,10 @@ object Compiler { 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 } + /** The instances of Scalac/Javac used to compile the current project. */ final case class Compilers(scalac: AnalyzingCompiler, javac: JavaTool) { final def newJavac: Option[IncrementalCompilerJavaTools] = javac match { @@ -29,12 +29,9 @@ object Compiler { case _ => None } } - final case class NewCompilers(scalac: AnalyzingCompiler, javac: JavaTools) -======= - final case class Compilers(scalac: AnalyzingCompiler, javac: JavaTool) + /** The previous source dependency analysis result from compilation. */ 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 + type CompileResult = MixedAnalyzingCompiler.Result def inputs(classpath: Seq[File], sources: Seq[File], classesDirectory: File, options: Seq[String], javacOptions: Seq[String], maxErrors: Int, sourcePositionMappers: Seq[Position => Option[Position]], @@ -86,27 +83,37 @@ object Compiler { val launcher = app.provider.scalaProvider.launcher val componentManager = new ComponentManager(launcher.globalLock, app.provider.components, Option(launcher.ivyHome), log) val provider = ComponentCompiler.interfaceProvider(componentManager) - new AnalyzingCompiler(instance, provider, cpOptions, log) + new AnalyzingCompiler(instance, provider, cpOptions) } - def apply(in: Inputs, log: Logger): AnalysisResult = + + @deprecated("0.13.8", "Use the `compile` method instead.") + def apply(in: Inputs, log: Logger): Analysis = { 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): AnalysisResult = + @deprecated("0.13.8", "Use the `compile` method instead.") + def apply(in: Inputs, log: Logger, reporter: xsbti.Reporter): Analysis = compile(in, log, reporter).analysis + def compile(in: Inputs, log: Logger): CompileResult = + { + import in.compilers._ + import in.config._ + import in.incSetup._ + compile(in, log, new LoggerReporter(maxErrors, log, sourcePositionMapper)) + } + def compile(in: Inputs, log: Logger, reporter: xsbti.Reporter): CompileResult = { import in.compilers._ import in.config._ import in.incSetup._ - val agg = new AggressiveCompile(cacheFile) // Here is some trickery to choose the more recent (reporter-using) java compiler rather // than the previously defined versions. // TODO - Remove this hackery in sbt 1.0. 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, + MixedAnalyzingCompiler.analyzingCompile(scalac, javacChosen, sources, classpath, CompileOutput(classesDirectory), cache, None, options, javacOptions, in.previousAnalysis.analysis, in.previousAnalysis.setup, analysisMap, definesClass, reporter, order, skip, incOptions)(log) } diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index 210db6b3a..8f0b2b7e0 100755 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -15,7 +15,7 @@ import CrossVersion.{ binarySbtVersion, binaryScalaVersion, partialVersion } import complete._ import std.TaskExtra._ import sbt.inc.{ Analysis, FileValueCache, IncOptions, Locate } -import sbt.compiler.AggressiveCompile +import sbt.compiler.{ MixedAnalyzingCompiler, AggressiveCompile } import testing.{ Framework, Runner, AnnotatedFingerprint, SubclassFingerprint } import sys.error @@ -650,7 +650,7 @@ object Defaults extends BuildCommon { key in TaskGlobal <<= packageTask, packageConfiguration <<= packageConfigurationTask, mappings <<= mappingsTask, - packagedArtifact := (artifact.value, key.value), + packagedArtifact := (artifact.value -> key.value), artifact <<= artifactSetting, artifactPath <<= artifactPathSetting(artifact) )) @@ -784,14 +784,14 @@ object Defaults extends BuildCommon { 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 = + private[this] def compileIncrementalTaskImpl(s: TaskStreams, ci: Compiler.Inputs, reporter: Option[xsbti.Reporter]): Compiler.CompileResult = { 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"))) val i = ci.copy(compilers = onArgs(ci.compilers)) try reporter match { - case Some(reporter) => Compiler(i, s.log, reporter) - case None => Compiler(i, s.log) + case Some(reporter) => Compiler.compile(i, s.log, reporter) + case None => Compiler.compile(i, s.log) } finally x.close() // workaround for #937 } @@ -823,9 +823,9 @@ object Defaults extends BuildCommon { }, saveAnalysis := { val setup: Compiler.IncSetup = compileIncSetup.value - val analysisResult: Compiler.AnalysisResult = compileIncremental.value - if (analysisResult.modified) { - val store = AggressiveCompile.staticCachedStore(setup.cacheFile) + val analysisResult: Compiler.CompileResult = compileIncremental.value + if (analysisResult.hasModified) { + val store = MixedAnalyzingCompiler.staticCachedStore(setup.cacheFile) store.set(analysisResult.analysis, analysisResult.setup) } analysisResult.analysis @@ -1031,7 +1031,7 @@ object Classpaths { packagedArtifacts :== Map.empty, crossTarget := target.value, makePom := { val config = makePomConfiguration.value; IvyActions.makePom(ivyModule.value, config, streams.value.log); config.file }, - packagedArtifact in makePom := (artifact in makePom value, makePom value), + packagedArtifact in makePom := ((artifact in makePom).value -> makePom.value), deliver <<= deliverTask(deliverConfiguration), deliverLocal <<= deliverTask(deliverLocalConfiguration), publish <<= publishTask(publishConfiguration, deliver), @@ -1510,7 +1510,7 @@ object Classpaths { def visit(p: ProjectRef, c: Configuration) { val applicableConfigs = allConfigs(c) for (ac <- applicableConfigs) // add all configurations in this project - visited add (p, ac.name) + visited add (p -> ac.name) val masterConfs = names(getConfigurations(projectRef, data)) for (ResolvedClasspathDependency(dep, confMapping) <- deps.classpath(p)) { diff --git a/main/src/main/scala/sbt/Keys.scala b/main/src/main/scala/sbt/Keys.scala index cbc27853f..53ce20f87 100644 --- a/main/src/main/scala/sbt/Keys.scala +++ b/main/src/main/scala/sbt/Keys.scala @@ -9,6 +9,7 @@ import Def.ScopedKey import complete._ import inc.Analysis import inc.Locate.DefinesClass +import sbt.compiler.MixedAnalyzingCompiler import std.TaskExtra._ import xsbti.compile.{ CompileOrder, GlobalsCache } import scala.xml.{ Node => XNode, NodeSeq } @@ -141,7 +142,7 @@ 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 compileIncremental = TaskKey[Compiler.CompileResult]("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)