mirror of https://github.com/sbt/sbt.git
Add `getScalaInstance` to `CompilerBridgeProvider`
This commit is contained in:
parent
d48f65a8a7
commit
62a5037d23
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Zinc - The incremental compiler for Scala.
|
||||
* Copyright 2011 - 2017, Lightbend, Inc.
|
||||
* Copyright 2008 - 2010, Mark Harrah
|
||||
* This software is released under the terms written in LICENSE.
|
||||
*/
|
||||
|
||||
package sbt.internal.inc
|
||||
|
||||
class InvalidComponent(msg: String, cause: Throwable) extends RuntimeException(msg, cause) {
|
||||
def this(msg: String) = this(msg, null)
|
||||
}
|
||||
|
||||
final class MissingScalaJar(msg: String, cause: Throwable) extends RuntimeException(msg, cause) {
|
||||
def this(msg: String) = this(msg, null)
|
||||
}
|
||||
|
||||
object MissingScalaJar {
|
||||
def missingTemplate(missing: String): String =
|
||||
s"The $missing could not be found in your cache nor downloaded from the Internet."
|
||||
def compiler: MissingScalaJar = new MissingScalaJar(missingTemplate("Scala compiler"))
|
||||
def library: MissingScalaJar = new MissingScalaJar(missingTemplate("Scala library"))
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
/*
|
||||
* Zinc - The incremental compiler for Scala.
|
||||
* Copyright 2011 - 2017, Lightbend, Inc.
|
||||
* Copyright 2008 - 2010, Mark Harrah
|
||||
* This software is released under the terms written in LICENSE.
|
||||
*/
|
||||
|
||||
package sbt.internal.inc
|
||||
|
||||
class InvalidComponent(msg: String, cause: Throwable) extends RuntimeException(msg, cause) {
|
||||
def this(msg: String) = this(msg, null)
|
||||
}
|
||||
|
|
@ -17,4 +17,13 @@ private[inc] object ResourceLoader {
|
|||
try { properties.load(propertiesStream) } finally { propertiesStream.close() }
|
||||
properties
|
||||
}
|
||||
|
||||
def getSafePropertiesFor(resource: String, classLoader: ClassLoader): Properties = {
|
||||
val properties = new Properties
|
||||
val propertiesStream = classLoader.getResourceAsStream(resource)
|
||||
try { properties.load(propertiesStream) } catch { case _: Exception => } finally {
|
||||
if (propertiesStream ne null) propertiesStream.close()
|
||||
}
|
||||
properties
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,32 +11,17 @@ package inc
|
|||
|
||||
import java.io.File
|
||||
|
||||
import sbt.internal.inc.classpath.ClasspathUtilities
|
||||
import sbt.io.{ Hash, IO }
|
||||
import sbt.internal.librarymanagement.{
|
||||
InlineConfiguration,
|
||||
IvyActions,
|
||||
IvyConfiguration,
|
||||
IvySbt,
|
||||
JsonUtil,
|
||||
LogicalClock,
|
||||
RetrieveConfiguration,
|
||||
UnresolvedWarning,
|
||||
UnresolvedWarningConfiguration
|
||||
}
|
||||
import sbt.librarymanagement.{
|
||||
ArtifactTypeFilter,
|
||||
Configurations,
|
||||
ModuleID,
|
||||
ModuleInfo,
|
||||
Resolver,
|
||||
UpdateConfiguration,
|
||||
UpdateLogging,
|
||||
UpdateOptions
|
||||
}
|
||||
import sbt.internal.librarymanagement._
|
||||
import sbt.internal.util.FullLogger
|
||||
import sbt.librarymanagement._
|
||||
import sbt.librarymanagement.syntax._
|
||||
import sbt.util.{ InterfaceUtil, Logger }
|
||||
import xsbti.compile.CompilerBridgeProvider
|
||||
|
||||
import scala.reflect.internal.util.ScalaClassLoader.URLClassLoader
|
||||
|
||||
private[sbt] object ZincComponentCompiler {
|
||||
final val binSeparator = "-bin_"
|
||||
final val javaClassVersion = System.getProperty("java.class.version")
|
||||
|
|
@ -59,11 +44,60 @@ private[sbt] object ZincComponentCompiler {
|
|||
override def getCompiledBridge(scalaInstance: xsbti.compile.ScalaInstance,
|
||||
logger: xsbti.Logger): File = {
|
||||
val autoClasspath = ClasspathOptionsUtil.auto
|
||||
val bridgeCompiler = new RawCompiler(scalaInstance, autoClasspath, logger)
|
||||
val ivyComponent =
|
||||
new ZincComponentCompiler(bridgeCompiler, manager, ivyConfiguration, bridgeModule, logger)
|
||||
val raw = new RawCompiler(scalaInstance, autoClasspath, logger)
|
||||
val zinc = new ZincComponentCompiler(raw, manager, ivyConfiguration, bridgeModule, logger)
|
||||
logger.debug(InterfaceUtil.f0(s"Getting $bridgeModule for Scala ${scalaInstance.version}"))
|
||||
ivyComponent.getCompiledBridgeJar
|
||||
zinc.getCompiledBridgeJar
|
||||
}
|
||||
|
||||
private final case class ScalaArtifacts(compiler: File, library: File, others: Vector[File])
|
||||
|
||||
private def getScalaArtifacts(scalaVersion: String, logger: xsbti.Logger): ScalaArtifacts = {
|
||||
def isPrefixedWith(artifact: File, prefix: String) = artifact.getName.startsWith(prefix)
|
||||
|
||||
import xsbti.ArtifactInfo._
|
||||
import Configurations.Compile
|
||||
import UnresolvedWarning.unresolvedWarningLines
|
||||
val fullLogger = new FullLogger(logger)
|
||||
val CompileConf = Some(Compile.name)
|
||||
val dummyModule = ModuleID(JsonUtil.sbtOrgTemp, s"tmp-scala-$scalaVersion", scalaVersion)
|
||||
val scalaLibrary = ModuleID(ScalaOrganization, ScalaLibraryID, scalaVersion)
|
||||
val scalaCompiler = ModuleID(ScalaOrganization, ScalaCompilerID, scalaVersion)
|
||||
val dependencies = Vector(scalaLibrary, scalaCompiler).map(_.withConfigurations(CompileConf))
|
||||
val wrapper = dummyModule.withConfigurations(CompileConf)
|
||||
val ivySbt: IvySbt = new IvySbt(ivyConfiguration)
|
||||
val ivyModule = ZincIvyActions.getModule(ivySbt, wrapper, dependencies)
|
||||
IO.withTemporaryDirectory { retrieveDirectory =>
|
||||
ZincIvyActions.update(ivyModule, retrieveDirectory, fullLogger) match {
|
||||
case Left(uw) =>
|
||||
val unresolvedLines = unresolvedWarningLines.showLines(uw)
|
||||
val unretrievedMessage = s"The Scala compiler and library could not be retrieved."
|
||||
throw new InvalidComponent(s"$unretrievedMessage\n$unresolvedLines")
|
||||
case Right(allArtifacts) =>
|
||||
val isScalaCompiler = (f: File) => isPrefixedWith(f, "scala-compiler-")
|
||||
val isScalaLibrary = (f: File) => isPrefixedWith(f, "scala-library-")
|
||||
val maybeScalaCompiler = allArtifacts.find(isScalaCompiler)
|
||||
val maybeScalaLibrary = allArtifacts.find(isScalaLibrary)
|
||||
val others = allArtifacts.filterNot(a => isScalaCompiler(a) || isScalaLibrary(a))
|
||||
val scalaCompiler = maybeScalaCompiler.getOrElse(throw MissingScalaJar.compiler)
|
||||
val scalaLibrary = maybeScalaLibrary.getOrElse(throw MissingScalaJar.library)
|
||||
ScalaArtifacts(scalaCompiler, scalaLibrary, others)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override def getScalaInstance(scalaVersion: String,
|
||||
logger: xsbti.Logger): xsbti.compile.ScalaInstance = {
|
||||
import sbt.io.Path.toURLs
|
||||
val scalaArtifacts = getScalaArtifacts(scalaVersion, logger)
|
||||
val scalaCompiler = scalaArtifacts.compiler
|
||||
val scalaLibrary = scalaArtifacts.library
|
||||
val jarsToLoad = (scalaCompiler +: scalaLibrary +: scalaArtifacts.others).toArray
|
||||
val loader = new URLClassLoader(toURLs(jarsToLoad), ClasspathUtilities.rootLoader)
|
||||
val properties = ResourceLoader.getSafePropertiesFor("compiler.properties", loader)
|
||||
val loaderVersion = Option(properties.getProperty("version.number"))
|
||||
val scalaV = loaderVersion.getOrElse("unknown")
|
||||
new ScalaInstance(scalaV, loader, scalaLibrary, scalaCompiler, jarsToLoad, loaderVersion)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -117,6 +151,19 @@ private[inc] class ZincComponentCompiler(
|
|||
s"$id$binSeparator${scalaVersion}__$javaClassVersion"
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an ivy module that will wrap and download a given `moduleID`.
|
||||
*
|
||||
* @param moduleID The `moduleID` that needs to be wrapped in a dummy module to be downloaded.
|
||||
*/
|
||||
private[inc] def wrapDependencyInModule(moduleID: ModuleID): IvySbt#Module = {
|
||||
import ZincComponentCompiler.{ sbtOrgTemp, modulePrefixTemp }
|
||||
val sha1 = Hash.toHex(Hash(moduleID.name))
|
||||
val dummyID = ModuleID(sbtOrgTemp, s"$modulePrefixTemp$sha1", moduleID.revision)
|
||||
.withConfigurations(moduleID.configurations)
|
||||
ZincIvyActions.getModule(ivySbt, dummyID, Vector(moduleID))
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the compiler bridge sources, compiles them and installs the sbt component
|
||||
* in the local filesystem to make sure that it's reused the next time is required.
|
||||
|
|
@ -130,7 +177,7 @@ private[inc] class ZincComponentCompiler(
|
|||
val target = new File(binaryDirectory, s"$compilerBridgeId.jar")
|
||||
buffered bufferQuietly {
|
||||
IO.withTemporaryDirectory { retrieveDirectory =>
|
||||
update(ivyModuleForBridge, retrieveDirectory) match {
|
||||
ZincIvyActions.update(ivyModuleForBridge, retrieveDirectory, buffered) match {
|
||||
case Left(uw) =>
|
||||
val mod = bridgeSources.toString
|
||||
val unresolvedLines = unresolvedWarningLines.showLines(uw)
|
||||
|
|
@ -149,34 +196,39 @@ private[inc] class ZincComponentCompiler(
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an ivy module that will wrap and download a given `moduleID`.
|
||||
*
|
||||
* @param moduleID The `moduleID` that needs to be wrapped in a dummy module to be downloaded.
|
||||
*/
|
||||
private def wrapDependencyInModule(moduleID: ModuleID): ivySbt.Module = {
|
||||
def getModule(moduleID: ModuleID, deps: Vector[ModuleID], uo: UpdateOptions): ivySbt.Module = {
|
||||
val moduleInfo = ModuleInfo(moduleID.name)
|
||||
val componentIvySettings = InlineConfiguration(
|
||||
validate = false,
|
||||
ivyScala = None,
|
||||
module = moduleID,
|
||||
moduleInfo = moduleInfo,
|
||||
dependencies = deps
|
||||
).withConfigurations(Vector(Configurations.Component))
|
||||
new ivySbt.Module(componentIvySettings)
|
||||
}
|
||||
}
|
||||
|
||||
import ZincComponentCompiler.{ sbtOrgTemp, modulePrefixTemp }
|
||||
val sha1 = Hash.toHex(Hash(moduleID.name))
|
||||
val dummyID = ModuleID(sbtOrgTemp, s"$modulePrefixTemp$sha1", moduleID.revision)
|
||||
.withConfigurations(moduleID.configurations)
|
||||
val defaultUpdateOptions = UpdateOptions()
|
||||
getModule(dummyID, Vector(moduleID), defaultUpdateOptions)
|
||||
object ZincIvyActions {
|
||||
type IvyModule = IvySbt#Module
|
||||
|
||||
/** Define the default configurations for a Zinc module wrapper. */
|
||||
private final val DefaultConfigurations: Vector[Configuration] =
|
||||
Vector(Configurations.Component, Configurations.Compile)
|
||||
private final val DefaultUpdateOptions = UpdateOptions()
|
||||
|
||||
/**
|
||||
* Create a module from its dummy wrapper and its dependencies.
|
||||
*
|
||||
* @param wrapper The ModuleID wrapper that will download the dependencies.
|
||||
* @param deps The dependencies to be downloaded.
|
||||
* @return A fully-fledged ivy module to be used for [[IvyActions]].
|
||||
*/
|
||||
private[inc] def getModule(ivySbt: IvySbt,
|
||||
wrapper: ModuleID,
|
||||
deps: Vector[ModuleID]): IvyModule = {
|
||||
val moduleInfo = ModuleInfo(wrapper.name)
|
||||
val componentIvySettings = InlineConfiguration(
|
||||
validate = false,
|
||||
ivyScala = None,
|
||||
module = wrapper,
|
||||
moduleInfo = moduleInfo,
|
||||
dependencies = deps
|
||||
).withConfigurations(DefaultConfigurations)
|
||||
new ivySbt.Module(componentIvySettings)
|
||||
}
|
||||
|
||||
// The implementation of this method is linked to `wrapDependencyInModule`
|
||||
private def prettyPrintDependency(module: ivySbt.Module): String = {
|
||||
private def prettyPrintDependency(module: IvyModule): String = {
|
||||
module.moduleSettings match {
|
||||
case ic: InlineConfiguration =>
|
||||
// Pretty print the module as `ModuleIDExtra.toStringImpl` does.
|
||||
|
|
@ -196,22 +248,23 @@ private[inc] class ZincComponentCompiler(
|
|||
UpdateConfiguration(Some(retrieve), missingOk = false, logLevel, noDocs)
|
||||
}
|
||||
|
||||
private def update(module: ivySbt.Module,
|
||||
retrieveDirectory: File): Either[UnresolvedWarning, Vector[File]] = {
|
||||
private[inc] def update(module: IvyModule,
|
||||
retrieveDirectory: File,
|
||||
logger: Logger): Either[UnresolvedWarning, Vector[File]] = {
|
||||
import IvyActions.updateEither
|
||||
val updateConfiguration = defaultUpdateConfiguration(retrieveDirectory)
|
||||
val dependencies = prettyPrintDependency(module)
|
||||
buffered.info(s"Attempting to fetch $dependencies. This operation may fail.")
|
||||
logger.info(s"Attempting to fetch $dependencies. This operation may fail.")
|
||||
val clockForCache = LogicalClock.unknown
|
||||
updateEither(module, updateConfiguration, warningConf, clockForCache, None, buffered) match {
|
||||
updateEither(module, updateConfiguration, warningConf, clockForCache, None, logger) match {
|
||||
case Left(unresolvedWarning) =>
|
||||
buffered.debug(s"Couldn't retrieve module ${prettyPrintDependency(module)}.")
|
||||
logger.debug(s"Couldn't retrieve module ${prettyPrintDependency(module)}.")
|
||||
Left(unresolvedWarning)
|
||||
|
||||
case Right(updateReport) =>
|
||||
val allFiles = updateReport.allFiles
|
||||
buffered.debug(s"Files retrieved for ${prettyPrintDependency(module)}:")
|
||||
buffered.debug(allFiles mkString ", ")
|
||||
logger.debug(s"Files retrieved for ${prettyPrintDependency(module)}:")
|
||||
logger.debug(allFiles mkString ", ")
|
||||
Right(allFiles)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue