diff --git a/compile/ivy/src/main/scala/sbt/compiler/ComponentCompiler.scala b/compile/ivy/src/main/scala/sbt/compiler/ComponentCompiler.scala index ba478ea61..fa1d57f2d 100644 --- a/compile/ivy/src/main/scala/sbt/compiler/ComponentCompiler.scala +++ b/compile/ivy/src/main/scala/sbt/compiler/ComponentCompiler.scala @@ -15,7 +15,7 @@ object ComponentCompiler { val compilerInterfaceSrcID = compilerInterfaceID + srcExtension val javaVersion = System.getProperty("java.class.version") - @deprecated("Use `interfaceProvider(ComponentManager, IvyConfiguration, File)`.", "0.13.10") + @deprecated("Use `interfaceProvider(ComponentManager, IvyConfiguration, ModuleID)`.", "0.13.10") def interfaceProvider(manager: ComponentManager): CompilerInterfaceProvider = new CompilerInterfaceProvider { def apply(scalaInstance: xsbti.compile.ScalaInstance, log: Logger): File = { @@ -26,13 +26,13 @@ object ComponentCompiler { } } - def interfaceProvider(manager: ComponentManager, ivyConfiguration: IvyConfiguration, bootDirectory: File): CompilerInterfaceProvider = new CompilerInterfaceProvider { + def interfaceProvider(manager: ComponentManager, ivyConfiguration: IvyConfiguration, sourcesModule: ModuleID): 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, bootDirectory, log) - log.debug("Getting " + compilerInterfaceID + " from component compiler for Scala " + scalaInstance.version) - componentCompiler(compilerInterfaceID) + val componentCompiler = new IvyComponentCompiler(new RawCompiler(scalaInstance, ClasspathOptions.auto, log), manager, ivyConfiguration, sourcesModule, log) + log.debug("Getting " + sourcesModule + " from component compiler for Scala " + scalaInstance.version) + componentCompiler() } } } @@ -80,12 +80,12 @@ class ComponentCompiler(compiler: RawCompiler, manager: ComponentManager) { } /** - * Component compiler which is able to find the most specific version available of - * the compiler interface sources using Ivy. + * Component compiler which is able to to retrieve the compiler bridge sources + * `sourceModule` 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, bootDirectory: File, log: Logger) { +private[compiler] class IvyComponentCompiler(compiler: RawCompiler, manager: ComponentManager, ivyConfiguration: IvyConfiguration, sourcesModule: ModuleID, log: Logger) { import ComponentCompiler._ private val sbtOrg = xsbti.ArtifactInfo.SbtOrganization @@ -94,11 +94,11 @@ private[compiler] class IvyComponentCompiler(compiler: RawCompiler, manager: Com private val ivySbt: IvySbt = new IvySbt(ivyConfiguration) private val sbtVersion = ComponentManager.version private val buffered = new BufferedLogger(FullLogger(log)) - private val retrieveDirectory = new File(s"$bootDirectory/scala-${compiler.scalaInstance.version}/$sbtOrg/sbt/$sbtVersion/compiler-interface-srcs") - def apply(id: String): File = { - val binID = binaryID(id) - manager.file(binID)(new IfMissing.Define(true, compileAndInstall(id, binID))) + def apply(): File = { + // binID is of the form "org.example-compilerbridge-1.0.0-bin_2.11.7__50.0" + val binID = binaryID(s"${sourcesModule.organization}-${sourcesModule.name}-${sourcesModule.revision}") + manager.file(binID)(new IfMissing.Define(true, compileAndInstall(binID))) } private def binaryID(id: String): String = { @@ -106,53 +106,36 @@ private[compiler] class IvyComponentCompiler(compiler: RawCompiler, manager: Com 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'")) - - buffered.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) - - buffered.debug(s"Fetching version-specific sources: module '$moduleName'") - manager.files(moduleName)(new IfMissing.Fallback(getAndDefineVersionSpecificSources())) - } + private def compileAndInstall(binID: String): Unit = 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 - val sources = buffered bufferQuietly interfaceSources(sourceModuleVersions) - AnalyzingCompiler.compileSources(sources, targetJar, xsbtiJars, id, compiler, log) + buffered bufferQuietly { - manager.define(binID, Seq(targetJar)) + IO.withTemporaryDirectory { retrieveDirectory => + (update(getModule(sourcesModule), retrieveDirectory)(_.getName endsWith "-sources.jar")) match { + case Some(sources) => + AnalyzingCompiler.compileSources(sources, targetJar, xsbtiJars, sourcesModule.name, compiler, log) + manager.define(binID, Seq(targetJar)) + case None => + throw new InvalidComponent(s"Couldn't retrieve source module: $sourcesModule") + } + } + + } } - } /** - * Returns a dummy module that depends on "org.scala-sbt" % `id` % `sbtVersion`. + * Returns a dummy module that depends on `moduleID`. * 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(sbtOrg, id, sbtVersion, Some("component")).sources() + private def getModule(moduleID: ModuleID): ivySbt.Module = { + val sha1 = Hash.toHex(Hash(moduleID.name)) + val dummyID = ModuleID(sbtOrgTemp, modulePrefixTemp + sha1, moduleID.revision, moduleID.configurations) getModule(dummyID, Seq(moduleID)) } @@ -179,7 +162,7 @@ private[compiler] class IvyComponentCompiler(compiler: RawCompiler, manager: Com s"unknown" } - private def update(module: ivySbt.Module)(predicate: File => Boolean): Option[Seq[File]] = { + private def update(module: ivySbt.Module, retrieveDirectory: File)(predicate: File => Boolean): Option[Seq[File]] = { val retrieveConfiguration = new RetrieveConfiguration(retrieveDirectory, Resolver.defaultRetrievePattern, false) val updateConfiguration = new UpdateConfiguration(Some(retrieveConfiguration), true, UpdateLogging.DownloadOnly) diff --git a/ivy/src/main/scala/sbt/ComponentManager.scala b/ivy/src/main/scala/sbt/ComponentManager.scala index bdf78b9ec..f546295a9 100644 --- a/ivy/src/main/scala/sbt/ComponentManager.scala +++ b/ivy/src/main/scala/sbt/ComponentManager.scala @@ -39,8 +39,6 @@ class ComponentManager(globalLock: xsbti.GlobalLock, provider: xsbti.ComponentPr d() if (d.cache) cache(id) getOrElse(notFound) - case f: IfMissing.Fallback => - f() } lockLocalCache { getOrElse(fromGlobal) } @@ -75,7 +73,6 @@ 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) = diff --git a/main/actions/src/main/scala/sbt/Compiler.scala b/main/actions/src/main/scala/sbt/Compiler.scala index 5953c2a54..062b11696 100644 --- a/main/actions/src/main/scala/sbt/Compiler.scala +++ b/main/actions/src/main/scala/sbt/Compiler.scala @@ -54,7 +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)`.", "0.13.10") + @deprecated("Use `compilers(ScalaInstance, ClasspathOptions, Option[File], IvyConfiguration, ModuleID)`.", "0.13.10") def compilers(instance: ScalaInstance, cpOptions: ClasspathOptions, javaHome: Option[File])(implicit app: AppConfiguration, log: Logger): Compilers = { val javac = @@ -69,7 +69,7 @@ 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 = + def compilers(instance: ScalaInstance, cpOptions: ClasspathOptions, javaHome: Option[File], ivyConfiguration: IvyConfiguration, sourcesModule: ModuleID)(implicit app: AppConfiguration, log: Logger): Compilers = { val javac = AggressiveCompile.directOrFork(instance, cpOptions, javaHome) @@ -81,7 +81,7 @@ object Compiler { 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) + val scalac = scalaCompiler(instance, cpOptions, ivyConfiguration, sourcesModule) new Compilers(scalac, CheaterJavaTool(javac2, javac)) } @deprecated("Deprecated in favor of new sbt.compiler.javac package.", "0.13.8") @@ -96,7 +96,7 @@ object Compiler { val scalac = scalaCompiler(instance, cpOptions) new Compilers(scalac, javac) } - @deprecated("Use `scalaCompiler(ScalaInstance, ClasspathOptions, IvyConfiguration)`.", "0.13.10") + @deprecated("Use `scalaCompiler(ScalaInstance, ClasspathOptions, IvyConfiguration, ModuleID)`.", "0.13.10") def scalaCompiler(instance: ScalaInstance, cpOptions: ClasspathOptions)(implicit app: AppConfiguration, log: Logger): AnalyzingCompiler = { val launcher = app.provider.scalaProvider.launcher @@ -104,12 +104,11 @@ 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 = + def scalaCompiler(instance: ScalaInstance, cpOptions: ClasspathOptions, ivyConfiguration: IvyConfiguration, sourcesModule: ModuleID)(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 bootDirectory = launcher.bootDirectory - val provider = ComponentCompiler.interfaceProvider(componentManager, ivyConfiguration, bootDirectory) + val provider = ComponentCompiler.interfaceProvider(componentManager, ivyConfiguration, sourcesModule) new AnalyzingCompiler(instance, provider, cpOptions) } diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index 9904ee22e..844f8719b 100755 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -232,7 +232,8 @@ object Defaults extends BuildCommon { clean := { val _ = clean.value IvyActions.cleanCachedResolutionCache(ivyModule.value, streams.value.log) - } + }, + scalaCompilerBridgeSource := ModuleID(xsbti.ArtifactInfo.SbtOrganization, "compiler-interface", sbtVersion.value, Some("component")).sources() ) // must be a val: duplication detected by object identity private[this] lazy val compileBaseGlobal: Seq[Setting[_]] = globalDefaults(Seq( @@ -261,7 +262,7 @@ object Defaults extends BuildCommon { if (plugin) scalaBase / ("sbt-" + sbtv) else scalaBase } - def compilersSetting = compilers := Compiler.compilers(scalaInstance.value, classpathOptions.value, javaHome.value, ivyConfiguration.value)(appConfiguration.value, streams.value.log) + def compilersSetting = compilers := Compiler.compilers(scalaInstance.value, classpathOptions.value, javaHome.value, ivyConfiguration.value, scalaCompilerBridgeSource.value)(appConfiguration.value, streams.value.log) lazy val configTasks = docTaskSettings(doc) ++ inTask(compile)(compileInputsSettings) ++ configGlobal ++ compileAnalysisSettings ++ Seq( compile <<= compileTask, diff --git a/main/src/main/scala/sbt/Keys.scala b/main/src/main/scala/sbt/Keys.scala index b5f1d96de..42fa4f659 100644 --- a/main/src/main/scala/sbt/Keys.scala +++ b/main/src/main/scala/sbt/Keys.scala @@ -137,6 +137,7 @@ object Keys { val sbtPlugin = SettingKey[Boolean]("sbt-plugin", "If true, enables adding sbt as a dependency and auto-generation of the plugin descriptor file.", BMinusSetting) val printWarnings = TaskKey[Unit]("print-warnings", "Shows warnings from compilation, including ones that weren't printed initially.", BPlusTask) val fileInputOptions = SettingKey[Seq[String]]("file-input-options", "Options that take file input, which may invalidate the cache.", CSetting) + val scalaCompilerBridgeSource = SettingKey[ModuleID]("scala-compiler-bridge-source", "Configures the module ID of the sources of the compiler bridge.", CSetting) val clean = TaskKey[Unit]("clean", "Deletes files produced by the build, such as generated sources, compiled classes, and task caches.", APlusTask) val console = TaskKey[Unit]("console", "Starts the Scala interpreter with the project classes on the classpath.", APlusTask)