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:
Dale Wijnand 2019-04-25 11:50:06 +01:00
commit b9b520f79e
No known key found for this signature in database
GPG Key ID: 4F256E3D151DF5EF
9 changed files with 774 additions and 0 deletions

View File

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

View File

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

View File

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

View File

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

View File

@ -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(", ")
}
}

View File

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

View File

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

View File

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

View File

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