Merge pull request #2197 from Duhemm/fix-2196

Fixes #2196, Specify the compiler bridge module in a setting
This commit is contained in:
eugene yokota 2015-09-08 23:23:48 -04:00
commit 5401a77b86
5 changed files with 40 additions and 59 deletions

View File

@ -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)

View File

@ -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) =

View File

@ -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)
}

View File

@ -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,

View File

@ -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)