mirror of https://github.com/sbt/sbt.git
Merge remote-tracking branch 'zinc-lm-intergration/bring-back-a-piece-of-zinc' into zinc-lm-integration
* zinc-lm-intergration/bring-back-a-piece-of-zinc: (90 commits) Add scala-integration resolver call it compiler-bridge_2.13 bump Scala bridge to use 2.13.0-RC1 Break the dependency on LM, and thus Ivy Skip Scala 2.10 and Scala 2.11 components for JDK 11 Refactor compiler bridge unit test Fix the several typos detected by github.com/client9/misspell Got rid of multiple warnigns include only scala-library into the boot classpath during run Drop "final" modifier from private case classes, to prevent false positive. Refer https://issues.scala-lang.org/browse/SI-4440 Support scala 2.13.0-pre-* & 2.13.0-M1 Split compiler bridge tests to another subproject Remove unused imports + variables Add back, re-configure & re-enable Scalafmt Use Scala 2.12.3 Remove any reference to `F0` and `F1` Adapt Zinc to use the new LibraryManagement API Fix ScalaFmt wiring Add scalaCompiler variant that accepts ModuleID Bump all the modules ...
This commit is contained in:
commit
b9b520f79e
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* 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 xsbti.compile;
|
||||
|
||||
import sbt.internal.inc.ZincComponentCompiler;
|
||||
import sbt.internal.inc.ZincComponentManager;
|
||||
import sbt.librarymanagement.DependencyResolution;
|
||||
import sbt.librarymanagement.Resolver;
|
||||
import scala.None$;
|
||||
import xsbti.ComponentProvider;
|
||||
import xsbti.GlobalLock;
|
||||
import xsbti.Logger;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public interface ZincBridgeProvider {
|
||||
/**
|
||||
* Returns an ivy resolver to resolve dependencies locally in the default `.ivy2/local`.
|
||||
* <p>
|
||||
* For those users interested in using Internet resolvers like Maven Central, you can
|
||||
* instantiate them via {@link Resolver#mavenCentral()} et al.
|
||||
*
|
||||
* @return A local ivy resolver.
|
||||
*/
|
||||
public static Resolver getLocalResolver() {
|
||||
return ZincComponentCompiler.LocalResolver();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a global lock that does nothing but calling the callable to synchronize
|
||||
* across threads. The lock file is used to resolve and download dependencies via ivy.
|
||||
* <p>
|
||||
* This operation is necessary to invoke {@link ZincBridgeProvider#getProvider(File, GlobalLock, ComponentProvider, IvyConfiguration, Logger)}.
|
||||
*
|
||||
* @return A default global lock.
|
||||
*/
|
||||
public static GlobalLock getDefaultLock() {
|
||||
return ZincComponentCompiler.getDefaultLock();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a default component provider that retrieves and installs component managers
|
||||
* (like the compiled bridge sources) under a given target directory.
|
||||
* <p>
|
||||
* This is the most simplistic implementation of a component provider. If you need more
|
||||
* advanced feature, like management of component via proxies (for companies) or access to
|
||||
* other servers, you need to implement your own component provider.
|
||||
*
|
||||
* @param componentsRoot The directory in which components will be installed and retrieved.
|
||||
* @return A default component provider.
|
||||
*/
|
||||
public static ComponentProvider getDefaultComponentProvider(File componentsRoot) {
|
||||
return ZincComponentCompiler.getDefaultComponentProvider(componentsRoot);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a compiler bridge provider that allows the user to fetch Scala and a compiled bridge.
|
||||
*
|
||||
* @param scalaJarsTarget The place where the downloaded Scala jars should be placed.
|
||||
* @param lock The lock file used internally by Ivy to synchronize the dependency resolution.
|
||||
* @param componentProvider A provider capable of retrieving existing components or installing
|
||||
* new ones. The component provider manages compiled bridge sources.
|
||||
* @param dependencyResolution The library management module to use to retrieve the bridge.
|
||||
* @param logger The logger.
|
||||
* @return A compiler bridge provider capable of fetching scala jars and the compiler bridge.
|
||||
*/
|
||||
public static CompilerBridgeProvider getProvider(File scalaJarsTarget,
|
||||
GlobalLock lock,
|
||||
ComponentProvider componentProvider,
|
||||
DependencyResolution dependencyResolution,
|
||||
Logger logger) {
|
||||
ZincComponentManager manager = new ZincComponentManager(lock, componentProvider, None$.empty(), logger);
|
||||
return ZincComponentCompiler.interfaceProvider(manager, dependencyResolution, scalaJarsTarget);
|
||||
}
|
||||
}
|
||||
|
|
@ -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"))
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* 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
|
||||
|
||||
sealed trait IfMissing
|
||||
|
||||
object IfMissing {
|
||||
def fail: IfMissing = Fail
|
||||
|
||||
/** f is expected to call ZincComponentManager.define. */
|
||||
def define(useSecondaryCache: Boolean, f: => Unit): IfMissing = new Define(useSecondaryCache, f)
|
||||
object Fail extends IfMissing
|
||||
final class Define(val useSecondaryCache: Boolean, define: => Unit) extends IfMissing {
|
||||
def run(): Unit = define
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* 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
|
||||
|
||||
import java.util.Properties
|
||||
|
||||
/** Defines utilities to load Java properties from the JVM. */
|
||||
private[inc] object ResourceLoader {
|
||||
def getPropertiesFor(resource: String, classLoader: ClassLoader): Properties = {
|
||||
val properties = new java.util.Properties
|
||||
val propertiesStream = getClass.getResource(resource).openStream
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,339 @@
|
|||
/*
|
||||
* 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
|
||||
package internal
|
||||
package inc
|
||||
|
||||
import java.io.File
|
||||
import java.util.concurrent.Callable
|
||||
|
||||
import sbt.internal.inc.classpath.ClasspathUtilities
|
||||
import sbt.io.IO
|
||||
import sbt.internal.librarymanagement._
|
||||
import sbt.internal.util.FullLogger
|
||||
import sbt.librarymanagement._
|
||||
import sbt.librarymanagement.syntax._
|
||||
import sbt.util.{ InterfaceUtil, Logger }
|
||||
import xsbti.{ ComponentProvider, GlobalLock }
|
||||
import xsbti.compile.{ ClasspathOptionsUtil, CompilerBridgeProvider }
|
||||
|
||||
private[sbt] object ZincComponentCompiler {
|
||||
final val binSeparator = "-bin_"
|
||||
final val javaClassVersion = System.getProperty("java.class.version")
|
||||
|
||||
private[inc] final val sbtOrgTemp = JsonUtil.sbtOrgTemp
|
||||
private[inc] final val modulePrefixTemp = "temp-module-"
|
||||
|
||||
private final val ZincVersionPropertyFile = "/incrementalcompiler.version.properties"
|
||||
private final val ZincVersionProperty = "version"
|
||||
private[sbt] final lazy val incrementalVersion: String = {
|
||||
val cl = this.getClass.getClassLoader
|
||||
ResourceLoader.getPropertiesFor(ZincVersionPropertyFile, cl).getProperty(ZincVersionProperty)
|
||||
}
|
||||
|
||||
private val CompileConf = Some(Configurations.Compile.name)
|
||||
private[sbt] def getDefaultBridgeModule(scalaVersion: String): ModuleID = {
|
||||
def compilerBridgeId(scalaVersion: String) = {
|
||||
scalaVersion match {
|
||||
case sc if (sc startsWith "2.10.") => "compiler-bridge_2.10"
|
||||
case sc if (sc startsWith "2.11.") => "compiler-bridge_2.11"
|
||||
case sc if (sc startsWith "2.12.") => "compiler-bridge_2.12"
|
||||
case "2.13.0-M1" => "compiler-bridge_2.12"
|
||||
case _ => "compiler-bridge_2.13"
|
||||
}
|
||||
}
|
||||
import xsbti.ArtifactInfo.SbtOrganization
|
||||
val bridgeId = compilerBridgeId(scalaVersion)
|
||||
ModuleID(SbtOrganization, bridgeId, incrementalVersion)
|
||||
.withConfigurations(CompileConf)
|
||||
.sources()
|
||||
}
|
||||
|
||||
/** Defines the internal implementation of a bridge provider. */
|
||||
private class ZincCompilerBridgeProvider(
|
||||
userProvidedBridgeSources: Option[ModuleID],
|
||||
manager: ZincComponentManager,
|
||||
dependencyResolution: DependencyResolution,
|
||||
scalaJarsTarget: File
|
||||
) extends CompilerBridgeProvider {
|
||||
|
||||
/**
|
||||
* Defines a richer interface for Scala users that want to pass in an explicit module id.
|
||||
*
|
||||
* Note that this method cannot be defined in [[CompilerBridgeProvider]] because [[ModuleID]]
|
||||
* is a Scala-defined class to which the compiler bridge cannot depend on.
|
||||
*/
|
||||
def compiledBridge(bridgeSources: ModuleID,
|
||||
scalaInstance: xsbti.compile.ScalaInstance,
|
||||
logger: xsbti.Logger): File = {
|
||||
import InterfaceUtil.{ toSupplier => f0 }
|
||||
val autoClasspath = ClasspathOptionsUtil.auto
|
||||
val raw = new RawCompiler(scalaInstance, autoClasspath, logger)
|
||||
val zinc =
|
||||
new ZincComponentCompiler(raw, manager, dependencyResolution, bridgeSources, logger)
|
||||
logger.debug(f0(s"Getting $bridgeSources for Scala ${scalaInstance.version}"))
|
||||
zinc.compiledBridgeJar
|
||||
}
|
||||
|
||||
override def fetchCompiledBridge(scalaInstance: xsbti.compile.ScalaInstance,
|
||||
logger: xsbti.Logger): File = {
|
||||
val scalaVersion = scalaInstance.actualVersion()
|
||||
val bridgeSources = userProvidedBridgeSources getOrElse getDefaultBridgeModule(scalaVersion)
|
||||
compiledBridge(bridgeSources, scalaInstance, logger)
|
||||
}
|
||||
|
||||
private 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 UnresolvedWarning.unresolvedWarningLines
|
||||
val fullLogger = new FullLogger(logger)
|
||||
val CompileConf = Some(Configurations.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 moduleDescriptorConfiguration =
|
||||
ModuleDescriptorConfiguration(wrapper, ModuleInfo(wrapper.name))
|
||||
.withDependencies(dependencies)
|
||||
.withConfigurations(ZincLMHelper.DefaultConfigurations)
|
||||
|
||||
val moduleDescriptor = dependencyResolution.moduleDescriptor(moduleDescriptorConfiguration)
|
||||
ZincLMHelper.update(dependencyResolution,
|
||||
moduleDescriptor,
|
||||
scalaJarsTarget,
|
||||
noSource = true,
|
||||
fullLogger) match {
|
||||
case Left(uw) =>
|
||||
val unresolvedLines = unresolvedWarningLines.showLines(uw).mkString("\n")
|
||||
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 fetchScalaInstance(scalaVersion: String,
|
||||
logger: xsbti.Logger): xsbti.compile.ScalaInstance = {
|
||||
val scalaArtifacts = getScalaArtifacts(scalaVersion, logger)
|
||||
val scalaCompiler = scalaArtifacts.compiler
|
||||
val scalaLibrary = scalaArtifacts.library
|
||||
val jarsToLoad = (scalaCompiler +: scalaLibrary +: scalaArtifacts.others).toArray
|
||||
assert(jarsToLoad.forall(_.exists), "One or more jar(s) in the Scala instance do not exist.")
|
||||
val loaderLibraryOnly = ClasspathUtilities.toLoader(Vector(scalaLibrary))
|
||||
val loader = ClasspathUtilities.toLoader(jarsToLoad.toVector filterNot { _ == scalaLibrary },
|
||||
loaderLibraryOnly)
|
||||
val properties = ResourceLoader.getSafePropertiesFor("compiler.properties", loader)
|
||||
val loaderVersion = Option(properties.getProperty("version.number"))
|
||||
val scalaV = loaderVersion.getOrElse("unknown")
|
||||
new ScalaInstance(scalaV,
|
||||
loader,
|
||||
loaderLibraryOnly,
|
||||
scalaLibrary,
|
||||
scalaCompiler,
|
||||
jarsToLoad,
|
||||
loaderVersion)
|
||||
}
|
||||
}
|
||||
|
||||
// Used by ZincUtil.
|
||||
def interfaceProvider(compilerBridgeSource: ModuleID,
|
||||
manager: ZincComponentManager,
|
||||
dependencyResolution: DependencyResolution,
|
||||
scalaJarsTarget: File): CompilerBridgeProvider =
|
||||
new ZincCompilerBridgeProvider(Some(compilerBridgeSource),
|
||||
manager,
|
||||
dependencyResolution,
|
||||
scalaJarsTarget)
|
||||
|
||||
def interfaceProvider(manager: ZincComponentManager,
|
||||
dependencyResolution: DependencyResolution,
|
||||
scalaJarsTarget: File): CompilerBridgeProvider =
|
||||
new ZincCompilerBridgeProvider(None, manager, dependencyResolution, scalaJarsTarget)
|
||||
|
||||
private final val LocalIvy = s"$${user.home}/.ivy2/local/${Resolver.localBasePattern}"
|
||||
final val LocalResolver: Resolver = {
|
||||
val toUse = Vector(LocalIvy)
|
||||
val ivyPatterns = Patterns().withIsMavenCompatible(false)
|
||||
val finalPatterns = ivyPatterns.withIvyPatterns(toUse).withArtifactPatterns(toUse)
|
||||
FileRepository("local", Resolver.defaultFileConfiguration, finalPatterns)
|
||||
}
|
||||
|
||||
def getDefaultLock: GlobalLock = new GlobalLock {
|
||||
override def apply[T](file: File, callable: Callable[T]): T = callable.call()
|
||||
}
|
||||
|
||||
/** Defines a default component provider that manages the component in a given directory. */
|
||||
private final class DefaultComponentProvider(targetDir: File) extends ComponentProvider {
|
||||
import sbt.io.syntax._
|
||||
private val LockFile = targetDir / "lock"
|
||||
override def lockFile(): File = LockFile
|
||||
override def componentLocation(id: String): File = targetDir / id
|
||||
override def component(componentID: String): Array[File] =
|
||||
IO.listFiles(targetDir / componentID)
|
||||
override def defineComponent(componentID: String, files: Array[File]): Unit =
|
||||
files.foreach(f => IO.copyFile(f, targetDir / componentID / f.getName))
|
||||
override def addToComponent(componentID: String, files: Array[File]): Boolean = {
|
||||
defineComponent(componentID, files)
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
def getDefaultComponentProvider(targetDir: File): ComponentProvider = {
|
||||
require(targetDir.isDirectory)
|
||||
new DefaultComponentProvider(targetDir)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Component compiler which is able to to retrieve the compiler bridge sources
|
||||
* `sourceModule` using a `DependencyResolution` instance.
|
||||
* The compiled classes are cached using the provided component manager according
|
||||
* to the actualVersion field of the RawCompiler.
|
||||
*/
|
||||
private[inc] class ZincComponentCompiler(
|
||||
compiler: RawCompiler,
|
||||
manager: ZincComponentManager,
|
||||
dependencyResolution: DependencyResolution,
|
||||
bridgeSources: ModuleID,
|
||||
log: Logger
|
||||
) {
|
||||
import sbt.internal.util.{ BufferedLogger, FullLogger }
|
||||
private final val buffered = new BufferedLogger(FullLogger(log))
|
||||
|
||||
def compiledBridgeJar: File = {
|
||||
val jarBinaryName = createBridgeSourcesID(bridgeSources)
|
||||
manager.file(jarBinaryName)(IfMissing.define(true, compileAndInstall(jarBinaryName)))
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the id for the compiler interface component.
|
||||
*
|
||||
* The ID contains the following parts:
|
||||
* - The organization, name and revision.
|
||||
* - The bin separator to make clear the jar represents binaries.
|
||||
* - The Scala version for which the compiler interface is meant to.
|
||||
* - The JVM class version.
|
||||
*
|
||||
* Example: "org.scala-sbt-compiler-bridge-1.0.0-bin_2.11.7__50.0".
|
||||
*
|
||||
* @param sources The moduleID representing the compiler bridge sources.
|
||||
* @return The complete jar identifier for the bridge sources.
|
||||
*/
|
||||
private def createBridgeSourcesID(sources: ModuleID): String = {
|
||||
import ZincComponentCompiler.{ binSeparator, javaClassVersion }
|
||||
val id = s"${sources.organization}-${sources.name}-${sources.revision}"
|
||||
val scalaVersion = compiler.scalaInstance.actualVersion()
|
||||
s"$id$binSeparator${scalaVersion}__$javaClassVersion"
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @param compilerBridgeId The identifier for the compiler bridge sources.
|
||||
*/
|
||||
private def compileAndInstall(compilerBridgeId: String): Unit = {
|
||||
import UnresolvedWarning.unresolvedWarningLines
|
||||
val moduleForBridge =
|
||||
dependencyResolution.wrapDependencyInModule(bridgeSources)
|
||||
IO.withTemporaryDirectory { binaryDirectory =>
|
||||
val target = new File(binaryDirectory, s"$compilerBridgeId.jar")
|
||||
buffered bufferQuietly {
|
||||
IO.withTemporaryDirectory { retrieveDirectory =>
|
||||
ZincLMHelper.update(dependencyResolution,
|
||||
moduleForBridge,
|
||||
retrieveDirectory,
|
||||
false,
|
||||
buffered) match {
|
||||
case Left(uw) =>
|
||||
val mod = bridgeSources.toString
|
||||
val unresolvedLines = unresolvedWarningLines.showLines(uw).mkString("\n")
|
||||
val unretrievedMessage = s"The compiler bridge sources $mod could not be retrieved."
|
||||
throw new InvalidComponent(s"$unretrievedMessage\n$unresolvedLines")
|
||||
|
||||
case Right(allArtifacts) =>
|
||||
val (srcs, xsbtiJars) = allArtifacts.partition(_.getName.endsWith("-sources.jar"))
|
||||
val toCompileID = bridgeSources.name
|
||||
AnalyzingCompiler.compileSources(srcs, target, xsbtiJars, toCompileID, compiler, log)
|
||||
manager.define(compilerBridgeId, Seq(target))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private object ZincLMHelper {
|
||||
|
||||
private final val warningConf = UnresolvedWarningConfiguration()
|
||||
private final val defaultRetrievePattern = Resolver.defaultRetrievePattern
|
||||
private[inc] final val DefaultConfigurations: Vector[Configuration] =
|
||||
Vector(Configurations.Component, Configurations.Compile)
|
||||
|
||||
private[inc] def update(dependencyResolution: DependencyResolution,
|
||||
module: ModuleDescriptor,
|
||||
retrieveDirectory: File,
|
||||
noSource: Boolean = false,
|
||||
logger: Logger): Either[UnresolvedWarning, Vector[File]] = {
|
||||
val updateConfiguration = defaultUpdateConfiguration(retrieveDirectory, noSource)
|
||||
val dependencies = prettyPrintDependency(module)
|
||||
logger.info(s"Attempting to fetch $dependencies.")
|
||||
dependencyResolution.update(module, updateConfiguration, warningConf, logger) match {
|
||||
case Left(unresolvedWarning) =>
|
||||
logger.debug(s"Couldn't retrieve module(s) ${prettyPrintDependency(module)}.")
|
||||
Left(unresolvedWarning)
|
||||
|
||||
case Right(updateReport) =>
|
||||
val allFiles = updateReport.allFiles
|
||||
logger.debug(s"Files retrieved for ${prettyPrintDependency(module)}:")
|
||||
logger.debug(allFiles mkString ", ")
|
||||
Right(allFiles)
|
||||
}
|
||||
}
|
||||
|
||||
private def defaultUpdateConfiguration(
|
||||
targetDir: File,
|
||||
noSource: Boolean
|
||||
): UpdateConfiguration = {
|
||||
val retrieve = RetrieveConfiguration()
|
||||
.withRetrieveDirectory(targetDir)
|
||||
.withOutputPattern(defaultRetrievePattern)
|
||||
val logLevel = UpdateLogging.DownloadOnly
|
||||
val defaultExcluded = Set("doc")
|
||||
val finalExcluded = if (noSource) defaultExcluded + "src" else defaultExcluded
|
||||
val artifactFilter = ArtifactTypeFilter.forbid(finalExcluded)
|
||||
UpdateConfiguration()
|
||||
.withRetrieveManaged(retrieve)
|
||||
.withLogging(logLevel)
|
||||
.withArtifactFilter(artifactFilter)
|
||||
}
|
||||
|
||||
private def prettyPrintDependency(module: ModuleDescriptor): String = {
|
||||
module.directDependencies
|
||||
.map { m =>
|
||||
// Pretty print the module as `ModuleIDExtra.toStringImpl` does.
|
||||
s"${m.organization}:${m.name}:${m.revision}"
|
||||
}
|
||||
.mkString(", ")
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
/*
|
||||
* 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
|
||||
package internal
|
||||
package inc
|
||||
|
||||
import java.io.File
|
||||
import java.util.concurrent.Callable
|
||||
|
||||
import sbt.internal.util.FullLogger
|
||||
import sbt.io.IO
|
||||
|
||||
/**
|
||||
* A component manager provides access to the pieces of zinc that are distributed as components.
|
||||
* Compiler bridge is distributed as a source jar so that it can be compiled against a specific
|
||||
* version of Scala.
|
||||
*
|
||||
* The component manager provides services to install and retrieve components to the local filesystem.
|
||||
* This is used for compiled source jars so that the compilation need not be repeated for other projects on the same
|
||||
* machine.
|
||||
*/
|
||||
class ZincComponentManager(globalLock: xsbti.GlobalLock,
|
||||
provider: xsbti.ComponentProvider,
|
||||
secondaryCacheDir: Option[File],
|
||||
log0: xsbti.Logger) {
|
||||
val log = new FullLogger(log0)
|
||||
|
||||
/** Get all of the files for component 'id', throwing an exception if no files exist for the component. */
|
||||
def files(id: String)(ifMissing: IfMissing): Iterable[File] = {
|
||||
def notFound = invalid("Could not find required component '" + id + "'")
|
||||
def getOrElse(orElse: => Iterable[File]): Iterable[File] = {
|
||||
val existing = provider.component(id)
|
||||
if (existing.isEmpty) orElse
|
||||
else existing
|
||||
}
|
||||
|
||||
def createAndCache = {
|
||||
ifMissing match {
|
||||
case IfMissing.Fail => notFound
|
||||
case d: IfMissing.Define =>
|
||||
d.run() // this is expected to have called define.
|
||||
if (d.useSecondaryCache) {
|
||||
cacheToSecondaryCache(id)
|
||||
}
|
||||
getOrElse(notFound)
|
||||
}
|
||||
}
|
||||
|
||||
def fromSecondary: Iterable[File] = {
|
||||
lockSecondaryCache {
|
||||
update(id)
|
||||
getOrElse(createAndCache)
|
||||
}.getOrElse(notFound)
|
||||
}
|
||||
|
||||
lockLocalCache(getOrElse(fromSecondary))
|
||||
}
|
||||
|
||||
/** Get the file for component 'id', throwing an exception if no files or multiple files exist for the component. */
|
||||
def file(id: String)(ifMissing: IfMissing): File = {
|
||||
files(id)(ifMissing).toList match {
|
||||
case x :: Nil => x
|
||||
case xs =>
|
||||
invalid("Expected single file for component '" + id + "', found: " + xs.mkString(", "))
|
||||
}
|
||||
}
|
||||
|
||||
/** Associate a component id to a series of jars. */
|
||||
def define(id: String, files: Iterable[File]): Unit =
|
||||
lockLocalCache(provider.defineComponent(id, files.toSeq.toArray))
|
||||
|
||||
/** This is used to lock the local cache in project/boot/. By checking the local cache first, we can avoid grabbing a global lock. */
|
||||
private def lockLocalCache[T](action: => T): T = lock(provider.lockFile)(action)
|
||||
|
||||
/** This is used to ensure atomic access to components in the global Ivy cache.*/
|
||||
private def lockSecondaryCache[T](action: => T): Option[T] =
|
||||
secondaryCacheDir map { dir =>
|
||||
val lockFile = new File(dir, ".sbt.cache.lock")
|
||||
lock(lockFile)(action)
|
||||
}
|
||||
private def lock[T](file: File)(action: => T): T =
|
||||
globalLock(file, new Callable[T] { def call = action })
|
||||
|
||||
private def invalid(msg: String) = throw new InvalidComponent(msg)
|
||||
|
||||
/** Retrieve the file for component 'id' from the secondary cache. */
|
||||
private def update(id: String): Unit = {
|
||||
secondaryCacheDir foreach { dir =>
|
||||
val file = seondaryCacheFile(id, dir)
|
||||
if (file.exists) {
|
||||
define(id, Seq(file))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Install the files for component 'id' to the secondary cache. */
|
||||
private def cacheToSecondaryCache(id: String): Unit = {
|
||||
val fromPrimaryCache = file(id)(IfMissing.fail)
|
||||
secondaryCacheDir match {
|
||||
case Some(dir) =>
|
||||
val file = seondaryCacheFile(id, dir)
|
||||
IO.copyFile(fromPrimaryCache, file)
|
||||
case _ => ()
|
||||
}
|
||||
()
|
||||
}
|
||||
private val sbtOrg = xsbti.ArtifactInfo.SbtOrganization
|
||||
private def seondaryCacheFile(id: String, dir: File): File = {
|
||||
val fileName = id + "-" + ZincComponentManager.stampedVersion + ".jar"
|
||||
new File(new File(dir, sbtOrg), fileName)
|
||||
}
|
||||
}
|
||||
|
||||
object ZincComponentManager {
|
||||
lazy val (version, timestamp) = {
|
||||
val properties = new java.util.Properties
|
||||
val propertiesStream = versionResource.openStream
|
||||
try { properties.load(propertiesStream) } finally { propertiesStream.close() }
|
||||
(properties.getProperty("version"), properties.getProperty("timestamp"))
|
||||
}
|
||||
lazy val stampedVersion = version + "_" + timestamp
|
||||
|
||||
import java.net.URL
|
||||
private def versionResource: URL =
|
||||
getClass.getResource("/incrementalcompiler.version.properties")
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* 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
|
||||
|
||||
import java.io.File
|
||||
import java.net.URLClassLoader
|
||||
|
||||
import sbt.librarymanagement.{ DependencyResolution, ModuleID }
|
||||
import sbt.internal.inc.classpath.ClassLoaderCache
|
||||
import xsbti._
|
||||
import xsbti.compile._
|
||||
|
||||
object ZincLmUtil {
|
||||
import xsbti.compile.ScalaInstance
|
||||
|
||||
/**
|
||||
* Instantiate a Scala compiler that is instrumented to analyze dependencies.
|
||||
* This Scala compiler is useful to create your own instance of incremental
|
||||
* compilation.
|
||||
*/
|
||||
def scalaCompiler(
|
||||
scalaInstance: ScalaInstance,
|
||||
classpathOptions: ClasspathOptions,
|
||||
globalLock: GlobalLock,
|
||||
componentProvider: ComponentProvider,
|
||||
secondaryCacheDir: Option[File],
|
||||
dependencyResolution: DependencyResolution,
|
||||
compilerBridgeSource: ModuleID,
|
||||
scalaJarsTarget: File,
|
||||
log: Logger
|
||||
): AnalyzingCompiler = {
|
||||
val compilerBridgeProvider = ZincComponentCompiler.interfaceProvider(
|
||||
compilerBridgeSource,
|
||||
new ZincComponentManager(globalLock, componentProvider, secondaryCacheDir, log),
|
||||
dependencyResolution,
|
||||
scalaJarsTarget,
|
||||
)
|
||||
val loader = Some(new ClassLoaderCache(new URLClassLoader(new Array(0))))
|
||||
new AnalyzingCompiler(scalaInstance, compilerBridgeProvider, classpathOptions, _ => (), loader)
|
||||
}
|
||||
|
||||
def getDefaultBridgeModule(scalaVersion: String): ModuleID =
|
||||
ZincComponentCompiler.getDefaultBridgeModule(scalaVersion)
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
package sbt.internal.inc
|
||||
|
||||
import java.io.File
|
||||
|
||||
import sbt.io.syntax._
|
||||
import sbt.librarymanagement._
|
||||
import sbt.librarymanagement.ivy._
|
||||
import sbt.util.Logger
|
||||
import xsbti.compile.CompilerBridgeProvider
|
||||
|
||||
/**
|
||||
* Base class for test suites that must be able to fetch and compile the compiler bridge.
|
||||
*
|
||||
* This is a very good example on how to instantiate the compiler bridge provider.
|
||||
*/
|
||||
abstract class IvyBridgeProviderSpecification extends UnitSpec with AbstractBridgeProviderTestkit {
|
||||
def currentBase: File = new File(".")
|
||||
def currentTarget: File = currentBase / "target" / "ivyhome"
|
||||
def currentManaged: File = currentBase / "target" / "lib_managed"
|
||||
|
||||
val resolvers = Array(
|
||||
ZincComponentCompiler.LocalResolver,
|
||||
Resolver.mavenCentral,
|
||||
MavenRepository("scala-integration",
|
||||
"https://scala-ci.typesafe.com/artifactory/scala-integration/")
|
||||
)
|
||||
private val ivyConfiguration =
|
||||
getDefaultConfiguration(currentBase, currentTarget, resolvers, log)
|
||||
|
||||
def secondaryCacheDirectory: File = {
|
||||
val target = file("target").getAbsoluteFile
|
||||
target / "zinc-components"
|
||||
}
|
||||
|
||||
def getZincProvider(targetDir: File, log: Logger): CompilerBridgeProvider = {
|
||||
val lock = ZincComponentCompiler.getDefaultLock
|
||||
val secondaryCache = Some(secondaryCacheDirectory)
|
||||
val componentProvider = ZincComponentCompiler.getDefaultComponentProvider(targetDir)
|
||||
val manager = new ZincComponentManager(lock, componentProvider, secondaryCache, log)
|
||||
val dependencyResolution = IvyDependencyResolution(ivyConfiguration)
|
||||
ZincComponentCompiler.interfaceProvider(manager, dependencyResolution, currentManaged)
|
||||
}
|
||||
|
||||
private def getDefaultConfiguration(baseDirectory: File,
|
||||
ivyHome: File,
|
||||
resolvers0: Array[Resolver],
|
||||
log: xsbti.Logger): InlineIvyConfiguration = {
|
||||
import sbt.io.syntax._
|
||||
val resolvers = resolvers0.toVector
|
||||
val chainResolver = ChainedResolver("zinc-chain", resolvers)
|
||||
InlineIvyConfiguration()
|
||||
.withPaths(IvyPaths(baseDirectory, Some(ivyHome)))
|
||||
.withResolvers(resolvers)
|
||||
.withModuleConfigurations(Vector(ModuleConfiguration("*", chainResolver)))
|
||||
.withLock(None)
|
||||
.withChecksums(Vector.empty)
|
||||
.withResolutionCacheDir(ivyHome / "resolution-cache")
|
||||
.withUpdateOptions(UpdateOptions())
|
||||
.withLog(log)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
package sbt.internal.inc
|
||||
|
||||
import sbt.internal.util.ConsoleLogger
|
||||
import sbt.io.IO
|
||||
|
||||
class ZincComponentCompilerSpec extends IvyBridgeProviderSpecification {
|
||||
val scala2105 = "2.10.5"
|
||||
val scala2106 = "2.10.6"
|
||||
val scala2118 = "2.11.8"
|
||||
val scala21111 = "2.11.11"
|
||||
val scala2121 = "2.12.1"
|
||||
val scala2122 = "2.12.2"
|
||||
val scala2123 = "2.12.3"
|
||||
val scala2130RC1 = "2.13.0-RC1"
|
||||
def isJava8: Boolean = sys.props("java.specification.version") == "1.8"
|
||||
|
||||
val logger = ConsoleLogger()
|
||||
it should "compile the bridge for Scala 2.10.5 and 2.10.6" in {
|
||||
if (isJava8) {
|
||||
IO.withTemporaryDirectory(t => getCompilerBridge(t, logger, scala2105) should exist)
|
||||
IO.withTemporaryDirectory(t => getCompilerBridge(t, logger, scala2106) should exist)
|
||||
} else ()
|
||||
}
|
||||
|
||||
it should "compile the bridge for Scala 2.11.8 and 2.11.11" in {
|
||||
if (isJava8) {
|
||||
IO.withTemporaryDirectory(t => getCompilerBridge(t, logger, scala2118) should exist)
|
||||
IO.withTemporaryDirectory(t => getCompilerBridge(t, logger, scala21111) should exist)
|
||||
} else ()
|
||||
}
|
||||
|
||||
it should "compile the bridge for Scala 2.12.2" in {
|
||||
IO.withTemporaryDirectory(t => getCompilerBridge(t, logger, scala2121) should exist)
|
||||
IO.withTemporaryDirectory(t => getCompilerBridge(t, logger, scala2122) should exist)
|
||||
IO.withTemporaryDirectory(t => getCompilerBridge(t, logger, scala2123) should exist)
|
||||
}
|
||||
|
||||
it should "compile the bridge for Scala 2.13.0-RC1" in {
|
||||
IO.withTemporaryDirectory(t => getCompilerBridge(t, logger, scala2130RC1) should exist)
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue