From 90a8423d8e20b90b327f5a8893a4fe7460ac67e7 Mon Sep 17 00:00:00 2001 From: Martin Duhem Date: Wed, 15 Jul 2015 10:01:11 +0200 Subject: [PATCH] Find most specific version of compiler interface sources This commit introduces a mechanism that allows sbt to find the most specific version of the compiler interface sources that exists using Ivy. For instance, when asked for a compiler interface for Scala 2.11.8-M2, sbt will look for sources for: - 2.11.8-M2 ; - 2.11.8 ; - 2.11 ; - the default sources. This commit also modifies the build definition by removing the precompiled projects and configuring the compiler-interface project so that it publishes its source artifacts in a Maven-friendly format. --- build.sbt | 81 +--------- .../sbt/compiler/ComponentCompiler.scala | 143 +++++++++++++++++- ivy/src/main/scala/sbt/ComponentManager.scala | 5 +- ivy/src/main/scala/sbt/Configuration.scala | 1 + ivy/src/main/scala/sbt/VersionNumber.scala | 5 + ivy/src/test/scala/VersionNumberSpec.scala | 20 ++- .../actions/src/main/scala/sbt/Compiler.scala | 24 +++ main/src/main/scala/sbt/Defaults.scala | 2 +- .../dependency-management/mvn-local/build.sbt | 3 +- 9 files changed, 204 insertions(+), 80 deletions(-) diff --git a/build.sbt b/build.sbt index 9fd4f9173..19061a285 100644 --- a/build.sbt +++ b/build.sbt @@ -81,17 +81,6 @@ lazy val bundledLauncherProj = packageBin in Compile := sbtLaunchJar.value ) - -// This is used only for command aggregation -lazy val allPrecompiled: Project = (project in file("all-precompiled")). - aggregate(precompiled282, precompiled292, precompiled293). - settings( - buildLevelSettings, - minimalSettings, - publish := {}, - publishLocal := {} - ) - /* ** subproject declarations ** */ // defines Java structures used across Scala versions, such as the API structures and relationships extracted by @@ -199,7 +188,7 @@ lazy val logProj = (project in utilPath / "log"). testedBaseSettings, name := "Logging", libraryDependencies += jline - ) + ) // Relation lazy val relationProj = (project in utilPath / "relation"). @@ -317,7 +306,7 @@ lazy val compileInterfaceProj = (project in compilePath / "interface"). dependsOn(interfaceProj % "compile;test->test", ioProj % "test->test", logProj % "test->test", /*launchProj % "test->test",*/ apiProj % "test->test"). settings( baseSettings, - precompiledSettings, + libraryDependencies += scalaCompiler.value % "provided", name := "Compiler Interface", exportJars := true, // we need to fork because in unit tests we set usejavacp = true which means @@ -327,13 +316,10 @@ lazy val compileInterfaceProj = (project in compilePath / "interface"). // needed because we fork tests and tests are ran in parallel so we have multiple Scala // compiler instances that are memory hungry javaOptions in Test += "-Xmx1G", - artifact in (Compile, packageSrc) := Artifact(srcID).copy(configurations = Compile :: Nil).extra("e:component" -> srcID) + publishArtifact in (Compile, packageSrc) := true, + publishMavenStyle := true ) -lazy val precompiled282 = precompiled(scala282) -lazy val precompiled292 = precompiled(scala292) -lazy val precompiled293 = precompiled(scala293) - // Implements the core functionality of detecting and propagating changes incrementally. // Defines the data structures for representing file fingerprints and relationships and the overall source analysis lazy val compileIncrementalProj = (project in compilePath / "inc"). @@ -442,7 +428,7 @@ lazy val mainProj = (project in mainPath). // technically, we need a dependency on all of mainProj's dependencies, but we don't do that since this is strictly an integration project // with the sole purpose of providing certain identifiers without qualification (with a package object) lazy val sbtProj = (project in sbtPath). - dependsOn(mainProj, compileInterfaceProj, precompiled282, precompiled292, precompiled293, scriptedSbtProj % "test->test"). + dependsOn(mainProj, compileInterfaceProj, scriptedSbtProj % "test->test"). settings( baseSettings, name := "sbt", @@ -512,7 +498,7 @@ def otherRootSettings = Seq( } )) lazy val docProjects: ScopeFilter = ScopeFilter( - inAnyProject -- inProjects(sbtRoot, sbtProj, scriptedBaseProj, scriptedSbtProj, scriptedPluginProj, precompiled282, precompiled292, precompiled293, mavenResolverPluginProj), + inAnyProject -- inProjects(sbtRoot, sbtProj, scriptedBaseProj, scriptedSbtProj, scriptedPluginProj, mavenResolverPluginProj), inConfigurations(Compile) ) def fullDocSettings = Util.baseScalacOptions ++ Docs.settings ++ Sxr.settings ++ Seq( @@ -539,36 +525,6 @@ def utilPath = file("util") def compilePath = file("compile") def mainPath = file("main") -def precompiledSettings = Seq( - artifact in packageBin <<= (appConfiguration, scalaVersion) { (app, sv) => - val launcher = app.provider.scalaProvider.launcher - val bincID = binID + "_" + ScalaInstance(sv, launcher).actualVersion - Artifact(binID) extra ("e:component" -> bincID) - }, - target <<= (target, scalaVersion) { (base, sv) => base / ("precompiled_" + sv) }, - scalacOptions := Nil, - ivyScala ~= { _.map(_.copy(checkExplicit = false, overrideScalaVersion = false)) }, - exportedProducts in Compile := Nil, - libraryDependencies += scalaCompiler.value % "provided" -) - -def precompiled(scalav: String): Project = Project(id = normalize("Precompiled " + scalav.replace('.', '_')), base = compilePath / "interface"). - dependsOn(interfaceProj). - settings( - baseSettings, - precompiledSettings, - name := "Precompiled " + scalav.replace('.', '_'), - scalaHome := None, - scalaVersion <<= (scalaVersion in ThisBuild) { sbtScalaV => - assert(sbtScalaV != scalav, "Precompiled compiler interface cannot have the same Scala version (" + scalav + ") as sbt.") - scalav - }, - crossScalaVersions := Seq(scalav), - // we disable compiling and running tests in precompiled Projprojects of compiler interface - // so we do not need to worry about cross-versioning testing dependencies - sources in Test := Nil - ) - lazy val safeUnitTests = taskKey[Unit]("Known working tests (for both 2.10 and 2.11)") lazy val safeProjects: ScopeFilter = ScopeFilter( inProjects(mainSettingsProj, mainProj, ivyProj, completeProj, @@ -616,36 +572,14 @@ def customCommands: Seq[Setting[_]] = Seq( }, commands += Command.command("release-sbt-local") { state => "clean" :: - "allPrecompiled/clean" :: - "allPrecompiled/compile" :: - "allPrecompiled/publishLocal" :: "so compile" :: "so publishLocal" :: "reload" :: state }, - /** There are several complications with sbt's build. - * First is the fact that interface project is a Java-only project - * that uses source generator from datatype subproject in Scala 2.10.4, - * which is depended on by Scala 2.8.2, Scala 2.9.2, and Scala 2.9.3 precompiled project. - * - * Second is the fact that sbt project (currently using Scala 2.10.4) depends on - * the precompiled projects (that uses Scala 2.8.2 etc.) - * - * Finally, there's the fact that all subprojects are released with crossPaths - * turned off for the sbt's Scala version 2.10.4, but some of them are also - * cross published against 2.11.1 with crossPaths turned on. - * - * Because of the way ++ (and its improved version wow) is implemented - * precompiled compiler briges are handled outside of doge aggregation on root. - * `so compile` handles 2.10.x/2.11.x cross building. - */ commands += Command.command("release-sbt") { state => // TODO - Any sort of validation "clean" :: - "allPrecompiled/clean" :: - "allPrecompiled/compile" :: - "allPrecompiled/publishSigned" :: "conscript-configs" :: "so compile" :: "so publishSigned" :: @@ -656,9 +590,6 @@ def customCommands: Seq[Setting[_]] = Seq( commands += Command.command("release-nightly") { state => "stamp-version" :: "clean" :: - "allPrecompiled/clean" :: - "allPrecompiled/compile" :: - "allPrecompiled/publish" :: "compile" :: "publish" :: "bintrayRelease" :: diff --git a/compile/ivy/src/main/scala/sbt/compiler/ComponentCompiler.scala b/compile/ivy/src/main/scala/sbt/compiler/ComponentCompiler.scala index 24d4f0530..3192e42c6 100644 --- a/compile/ivy/src/main/scala/sbt/compiler/ComponentCompiler.scala +++ b/compile/ivy/src/main/scala/sbt/compiler/ComponentCompiler.scala @@ -5,6 +5,7 @@ package sbt package compiler import java.io.File +import scala.util.Try object ComponentCompiler { val xsbtiID = "xsbti" @@ -14,6 +15,7 @@ object ComponentCompiler { val compilerInterfaceSrcID = compilerInterfaceID + srcExtension val javaVersion = System.getProperty("java.class.version") + @deprecated("Use `interfaceProvider(ComponentManager, IvyConfiguration)`.", "0.13.10") def interfaceProvider(manager: ComponentManager): CompilerInterfaceProvider = new CompilerInterfaceProvider { def apply(scalaInstance: xsbti.compile.ScalaInstance, log: Logger): File = { @@ -23,12 +25,23 @@ object ComponentCompiler { componentCompiler(compilerInterfaceID) } } + + def interfaceProvider(manager: ComponentManager, ivyConfiguration: IvyConfiguration): 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 IvyComponentCompiler(new RawCompiler(scalaInstance, ClasspathOptions.auto, log), manager, ivyConfiguration, log) + 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 * to the actualVersion field of the RawCompiler. */ +@deprecated("Replaced by IvyComponentCompiler.", "0.13.10") class ComponentCompiler(compiler: RawCompiler, manager: ComponentManager) { import ComponentCompiler._ def apply(id: String): File = @@ -64,4 +77,132 @@ class ComponentCompiler(compiler: RawCompiler, manager: ComponentManager) { manager.define(binID, Seq(targetJar)) } } -} \ No newline at end of file +} + +/** + * Component compiler which is able to find the most specific version available of + * the compiler interface sources using Ivy. + * The compiled classes are cached using the provided component manager according + * to the actualVersion field of the RawCompiler. + */ +private[compiler] class IvyComponentCompiler(compiler: RawCompiler, manager: ComponentManager, ivyConfiguration: IvyConfiguration, log: Logger) { + import ComponentCompiler._ + + private val sbtOrgTemp = JsonUtil.sbtOrgTemp + private val modulePrefixTemp = "temp-module-" + private val ivySbt: IvySbt = new IvySbt(ivyConfiguration) + private val sbtVersion = ComponentManager.version + + def apply(id: String): File = { + val binID = binaryID(id) + manager.file(binID)(new IfMissing.Define(true, compileAndInstall(id, binID))) + } + + private def binaryID(id: String): String = { + val base = id + binSeparator + compiler.scalaInstance.actualVersion + base + "__" + javaVersion + } + + private def compileAndInstall(id: String, binID: String): Unit = { + def interfaceSources(moduleVersions: Vector[VersionNumber]): Iterable[File] = + moduleVersions match { + case Vector() => + def getAndDefineDefaultSources() = + update(getModule(id))(_.getName endsWith "-sources.jar") map { sourcesJar => + manager.define(id, sourcesJar) + sourcesJar + } getOrElse (throw new InvalidComponent(s"Couldn't retrieve default sources: module '$id'")) + + log.debug(s"Fetching default sources: module '$id'") + manager.files(id)(new IfMissing.Fallback(getAndDefineDefaultSources())) + + case version +: rest => + val moduleName = s"${id}_$version" + def getAndDefineVersionSpecificSources() = + update(getModule(moduleName))(_.getName endsWith "-sources.jar") map { sourcesJar => + manager.define(moduleName, sourcesJar) + sourcesJar + } getOrElse interfaceSources(rest) + + log.debug(s"Fetching version-specific sources: module '$moduleName'") + manager.files(moduleName)(new IfMissing.Fallback(getAndDefineVersionSpecificSources())) + } + IO.withTemporaryDirectory { binaryDirectory => + + val targetJar = new File(binaryDirectory, s"$binID.jar") + val xsbtiJars = manager.files(xsbtiID)(IfMissing.Fail) + + val sourceModuleVersions = VersionNumber(compiler.scalaInstance.actualVersion).cascadingVersions + AnalyzingCompiler.compileSources(interfaceSources(sourceModuleVersions), targetJar, xsbtiJars, id, compiler, log) + + manager.define(binID, Seq(targetJar)) + + } + } + + /** + * Returns a dummy module that depends on "org.scala-sbt" % `id` % `sbtVersion`. + * Note: Sbt's implementation of Ivy requires us to do this, because only the dependencies + * of the specified module will be downloaded. + */ + private def getModule(id: String): ivySbt.Module = { + val sha1 = Hash.toHex(Hash(id)) + val dummyID = ModuleID(sbtOrgTemp, modulePrefixTemp + sha1, sbtVersion, Some("component")) + val moduleID = ModuleID(xsbti.ArtifactInfo.SbtOrganization, id, sbtVersion, Some("component")).sources() + getModule(dummyID, Seq(moduleID)) + } + + private def getModule(moduleID: ModuleID, deps: Seq[ModuleID], uo: UpdateOptions = UpdateOptions()): ivySbt.Module = { + val moduleSetting = InlineConfiguration( + module = moduleID, + moduleInfo = ModuleInfo(moduleID.name), + dependencies = deps, + configurations = Seq(Configurations.Component), + ivyScala = None) + + new ivySbt.Module(moduleSetting) + } + + private def dependenciesNames(module: ivySbt.Module): String = module.moduleSettings match { + // `module` is a dummy module, we will only fetch its dependencies. + case ic: InlineConfiguration => + ic.dependencies map { + case mID: ModuleID => + import mID._ + s"$organization % $name % $revision" + } mkString ", " + case _ => + s"unknown" + } + + private def update(module: ivySbt.Module)(predicate: File => Boolean): Option[Seq[File]] = { + + val retrieveDirectory = new File(ivyConfiguration.baseDirectory, "component") + val retrieveConfiguration = new RetrieveConfiguration(retrieveDirectory, Resolver.defaultRetrievePattern, false) + val updateConfiguration = new UpdateConfiguration(Some(retrieveConfiguration), true, UpdateLogging.DownloadOnly) + + log.info(s"Attempting to fetch ${dependenciesNames(module)}. This operation may fail.") + IvyActions.updateEither(module, updateConfiguration, UnresolvedWarningConfiguration(), LogicalClock.unknown, None, log) match { + case Left(unresolvedWarning) => + log.debug("Couldn't retrieve module ${dependenciesNames(module)}.") + None + + case Right(updateReport) => + val allFiles = + for { + conf <- updateReport.configurations + m <- conf.modules + (_, f) <- m.artifacts + } yield f + + log.debug(s"Files retrieved for ${dependenciesNames(module)}:") + log.debug(allFiles mkString ", ") + + allFiles filter predicate match { + case Seq() => None + case files => Some(files) + } + + } + } +} diff --git a/ivy/src/main/scala/sbt/ComponentManager.scala b/ivy/src/main/scala/sbt/ComponentManager.scala index 2d6c5a447..bdf78b9ec 100644 --- a/ivy/src/main/scala/sbt/ComponentManager.scala +++ b/ivy/src/main/scala/sbt/ComponentManager.scala @@ -39,6 +39,8 @@ class ComponentManager(globalLock: xsbti.GlobalLock, provider: xsbti.ComponentPr d() if (d.cache) cache(id) getOrElse(notFound) + case f: IfMissing.Fallback => + f() } lockLocalCache { getOrElse(fromGlobal) } @@ -73,6 +75,7 @@ sealed trait IfMissing extends NotNull object IfMissing { object Fail extends IfMissing final class Define(val cache: Boolean, define: => Unit) extends IfMissing { def apply() = define } + final class Fallback(f: => Iterable[File]) extends IfMissing { def apply() = f } } object ComponentManager { lazy val (version, timestamp) = @@ -86,4 +89,4 @@ object ComponentManager { import java.net.URL private def versionResource: URL = getClass.getResource("/xsbt.version.properties") -} \ No newline at end of file +} diff --git a/ivy/src/main/scala/sbt/Configuration.scala b/ivy/src/main/scala/sbt/Configuration.scala index d666b32bc..d2307b89d 100644 --- a/ivy/src/main/scala/sbt/Configuration.scala +++ b/ivy/src/main/scala/sbt/Configuration.scala @@ -44,6 +44,7 @@ object Configurations { lazy val ScalaTool = config("scala-tool") hide lazy val CompilerPlugin = config("plugin") hide + lazy val Component = config("component") hide private[sbt] val DefaultMavenConfiguration = defaultConfiguration(true) private[sbt] val DefaultIvyConfiguration = defaultConfiguration(false) diff --git a/ivy/src/main/scala/sbt/VersionNumber.scala b/ivy/src/main/scala/sbt/VersionNumber.scala index 182d44edc..a5d1d494b 100644 --- a/ivy/src/main/scala/sbt/VersionNumber.scala +++ b/ivy/src/main/scala/sbt/VersionNumber.scala @@ -13,6 +13,11 @@ final class VersionNumber private[sbt] ( else Some(numbers(idx)) def size: Int = numbers.size + /** The vector of version numbers from more to less specific from this version number. */ + lazy val cascadingVersions: Vector[VersionNumber] = + (Vector(this) ++ + (numbers.inits filter (_.length >= 2) map (VersionNumber(_, Nil, Nil)))).distinct + private[this] val versionStr: String = numbers.mkString(".") + (tags match { diff --git a/ivy/src/test/scala/VersionNumberSpec.scala b/ivy/src/test/scala/VersionNumberSpec.scala index 7b836050f..68bc2ad6e 100644 --- a/ivy/src/test/scala/VersionNumberSpec.scala +++ b/ivy/src/test/scala/VersionNumberSpec.scala @@ -10,15 +10,18 @@ class VersionNumberSpec extends Specification { 1 should ${beParsedAs("1", Seq(1), Seq(), Seq())} ${breakDownTo("1", Some(1))} + ${generateCorrectCascadingNumbers("1", Seq("1"))} 1.0 should ${beParsedAs("1.0", Seq(1, 0), Seq(), Seq())} ${breakDownTo("1.0", Some(1), Some(0))} + ${generateCorrectCascadingNumbers("1.0", Seq("1.0"))} 1.0.0 should ${beParsedAs("1.0.0", Seq(1, 0, 0), Seq(), Seq())} ${breakDownTo("1.0.0", Some(1), Some(0), Some(0))} - + ${generateCorrectCascadingNumbers("1.0.0", Seq("1.0.0", "1.0"))} + ${beSemVerCompatWith("1.0.0", "1.0.1")} ${beSemVerCompatWith("1.0.0", "1.1.1")} ${notBeSemVerCompatWith("1.0.0", "2.0.0")} @@ -32,10 +35,12 @@ class VersionNumberSpec extends Specification { 1.0.0.0 should ${beParsedAs("1.0.0.0", Seq(1, 0, 0, 0), Seq(), Seq())} ${breakDownTo("1.0.0.0", Some(1), Some(0), Some(0), Some(0))} + ${generateCorrectCascadingNumbers("1.0.0.0", Seq("1.0.0.0", "1.0.0", "1.0"))} 0.12.0 should ${beParsedAs("0.12.0", Seq(0, 12, 0), Seq(), Seq())} ${breakDownTo("0.12.0", Some(0), Some(12), Some(0))} + ${generateCorrectCascadingNumbers("0.12.0", Seq("0.12.0", "0.12"))} ${notBeSemVerCompatWith("0.12.0", "0.12.0-RC1")} ${notBeSemVerCompatWith("0.12.0", "0.12.1")} @@ -47,6 +52,7 @@ class VersionNumberSpec extends Specification { 0.1.0-SNAPSHOT should ${beParsedAs("0.1.0-SNAPSHOT", Seq(0, 1, 0), Seq("SNAPSHOT"), Seq())} + ${generateCorrectCascadingNumbers("0.1.0-SNAPSHOT", Seq("0.1.0-SNAPSHOT", "0.1.0", "0.1"))} ${beSemVerCompatWith("0.1.0-SNAPSHOT", "0.1.0-SNAPSHOT")} ${notBeSemVerCompatWith("0.1.0-SNAPSHOT", "0.1.0")} @@ -58,15 +64,20 @@ class VersionNumberSpec extends Specification { 0.1.0-M1 should ${beParsedAs("0.1.0-M1", Seq(0, 1, 0), Seq("M1"), Seq())} + ${generateCorrectCascadingNumbers("0.1.0-M1", Seq("0.1.0-M1", "0.1.0", "0.1"))} 0.1.0-RC1 should ${beParsedAs("0.1.0-RC1", Seq(0, 1, 0), Seq("RC1"), Seq())} + ${generateCorrectCascadingNumbers("0.1.0-RC1", Seq("0.1.0-RC1", "0.1.0", "0.1"))} 0.1.0-MSERVER-1 should ${beParsedAs("0.1.0-MSERVER-1", Seq(0, 1, 0), Seq("MSERVER", "1"), Seq())} + ${generateCorrectCascadingNumbers("0.1.0-MSERVER-1", Seq("0.1.0-MSERVER-1", "0.1.0", "0.1"))} + 2.10.4-20140115-000117-b3a-sources should ${beParsedAs("2.10.4-20140115-000117-b3a-sources", Seq(2, 10, 4), Seq("20140115", "000117", "b3a", "sources"), Seq())} + ${generateCorrectCascadingNumbers("2.10.4-20140115-000117-b3a-sources", Seq("2.10.4-20140115-000117-b3a-sources", "2.10.4", "2.10"))} ${beSemVerCompatWith("2.10.4-20140115-000117-b3a-sources", "2.0.0")} @@ -74,12 +85,15 @@ class VersionNumberSpec extends Specification { 20140115000117-b3a-sources should ${beParsedAs("20140115000117-b3a-sources", Seq(20140115000117L), Seq("b3a", "sources"), Seq())} + ${generateCorrectCascadingNumbers("20140115000117-b3a-sources", Seq("20140115000117-b3a-sources"))} 1.0.0-alpha+001+002 should ${beParsedAs("1.0.0-alpha+001+002", Seq(1, 0, 0), Seq("alpha"), Seq("+001", "+002"))} + ${generateCorrectCascadingNumbers("1.0.0-alpha+001+002", Seq("1.0.0-alpha+001+002", "1.0.0", "1.0"))} non.space.!?string should ${beParsedAs("non.space.!?string", Seq(), Seq(), Seq("non.space.!?string"))} + ${generateCorrectCascadingNumbers("non.space.!?string", Seq("non.space.!?string"))} space !?string should ${beParsedAsError("space !?string")} @@ -119,4 +133,8 @@ class VersionNumberSpec extends Specification { VersionNumber.SecondSegment.isCompatible(VersionNumber(v1), VersionNumber(v2)) must_== true def notBeSecSegCompatWith(v1: String, v2: String) = VersionNumber.SecondSegment.isCompatible(VersionNumber(v1), VersionNumber(v2)) must_== false + def generateCorrectCascadingNumbers(s: String, ns: Seq[String]) = { + val versionNumbers = ns.toVector map VersionNumber.apply + VersionNumber(s).cascadingVersions must_== versionNumbers + } } diff --git a/main/actions/src/main/scala/sbt/Compiler.scala b/main/actions/src/main/scala/sbt/Compiler.scala index 6aebcc0ec..e855eb296 100644 --- a/main/actions/src/main/scala/sbt/Compiler.scala +++ b/main/actions/src/main/scala/sbt/Compiler.scala @@ -54,6 +54,7 @@ object Compiler { def compilers(instance: ScalaInstance, cpOptions: ClasspathOptions)(implicit app: AppConfiguration, log: Logger): Compilers = compilers(instance, cpOptions, None) + @deprecated("Use `compilers(ScalaInstance, ClasspathOptions, Option[File], IvyConfiguration)`.") def compilers(instance: ScalaInstance, cpOptions: ClasspathOptions, javaHome: Option[File])(implicit app: AppConfiguration, log: Logger): Compilers = { val javac = @@ -68,6 +69,21 @@ object Compiler { } compilers(instance, cpOptions, CheaterJavaTool(javac2, javac)) } + def compilers(instance: ScalaInstance, cpOptions: ClasspathOptions, javaHome: Option[File], ivyConfiguration: IvyConfiguration)(implicit app: AppConfiguration, log: Logger): Compilers = + { + val javac = + AggressiveCompile.directOrFork(instance, cpOptions, javaHome) + val javac2 = + JavaTools.directOrFork(instance, cpOptions, javaHome) + // Hackery to enable both the new and deprecated APIs to coexist peacefully. + case class CheaterJavaTool(newJavac: IncrementalCompilerJavaTools, delegate: JavaTool) extends JavaTool with JavaToolWithNewInterface { + def compile(contract: JavacContract, sources: Seq[File], classpath: Seq[File], outputDirectory: File, options: Seq[String])(implicit log: Logger): Unit = + javac.compile(contract, sources, classpath, outputDirectory, options)(log) + def onArgs(f: Seq[String] => Unit): JavaTool = CheaterJavaTool(newJavac, delegate.onArgs(f)) + } + val scalac = scalaCompiler(instance, cpOptions, ivyConfiguration) + new Compilers(scalac, javac) + } @deprecated("Deprecated in favor of new sbt.compiler.javac package.", "0.13.8") def compilers(instance: ScalaInstance, cpOptions: ClasspathOptions, javac: sbt.compiler.JavaCompiler.Fork)(implicit app: AppConfiguration, log: Logger): Compilers = { @@ -80,6 +96,7 @@ object Compiler { val scalac = scalaCompiler(instance, cpOptions) new Compilers(scalac, javac) } + @deprecated("Use `scalaCompiler(ScalaInstance, ClasspathOptions, IvyConfiguration)`.", "0.13.10") def scalaCompiler(instance: ScalaInstance, cpOptions: ClasspathOptions)(implicit app: AppConfiguration, log: Logger): AnalyzingCompiler = { val launcher = app.provider.scalaProvider.launcher @@ -87,6 +104,13 @@ object Compiler { val provider = ComponentCompiler.interfaceProvider(componentManager) new AnalyzingCompiler(instance, provider, cpOptions) } + def scalaCompiler(instance: ScalaInstance, cpOptions: ClasspathOptions, ivyConfiguration: IvyConfiguration)(implicit app: AppConfiguration, log: Logger): AnalyzingCompiler = + { + val launcher = app.provider.scalaProvider.launcher + val componentManager = new ComponentManager(launcher.globalLock, app.provider.components, Option(launcher.ivyHome), log) + val provider = ComponentCompiler.interfaceProvider(componentManager, ivyConfiguration) + new AnalyzingCompiler(instance, provider, cpOptions) + } @deprecated("Use the `compile` method instead.", "0.13.8") def apply(in: Inputs, log: Logger): Analysis = { diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index cd05b9c77..e96a390cc 100755 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -261,7 +261,7 @@ object Defaults extends BuildCommon { if (plugin) scalaBase / ("sbt-" + sbtv) else scalaBase } - def compilersSetting = compilers := Compiler.compilers(scalaInstance.value, classpathOptions.value, javaHome.value)(appConfiguration.value, streams.value.log) + def compilersSetting = compilers := Compiler.compilers(scalaInstance.value, classpathOptions.value, javaHome.value, ivyConfiguration.value)(appConfiguration.value, streams.value.log) lazy val configTasks = docTaskSettings(doc) ++ inTask(compile)(compileInputsSettings) ++ configGlobal ++ compileAnalysisSettings ++ Seq( compile <<= compileTask, diff --git a/sbt/src/sbt-test/dependency-management/mvn-local/build.sbt b/sbt/src/sbt-test/dependency-management/mvn-local/build.sbt index 10b0d8003..edfe34b9c 100644 --- a/sbt/src/sbt-test/dependency-management/mvn-local/build.sbt +++ b/sbt/src/sbt-test/dependency-management/mvn-local/build.sbt @@ -4,7 +4,8 @@ def commonSettings: Seq[Def.Setting[_]] = dependencyCacheDirectory := (baseDirectory in LocalRootProject).value / "dependency", scalaVersion := "2.10.4", organization in ThisBuild := "org.example", - version in ThisBuild := "1.0-SNAPSHOT" + version in ThisBuild := "1.0-SNAPSHOT", + resolvers += Resolver.file("old-local", file(sys.props("user.home") + "/.ivy2/local"))(Resolver.ivyStylePatterns) ) lazy val main = project.