mirror of https://github.com/sbt/sbt.git
Merge pull request #4617 from dwijnand/zinc-lm-integration
In-source zinc's LM integration code
This commit is contained in:
commit
1106422fb9
37
build.sbt
37
build.sbt
|
|
@ -89,15 +89,18 @@ def baseSettings: Seq[Setting[_]] =
|
||||||
def testedBaseSettings: Seq[Setting[_]] =
|
def testedBaseSettings: Seq[Setting[_]] =
|
||||||
baseSettings ++ testDependencies
|
baseSettings ++ testDependencies
|
||||||
|
|
||||||
val mimaSettings = Def settings (
|
def sbt10Plus = Seq(
|
||||||
|
"1.0.0", "1.0.1", "1.0.2", "1.0.3", "1.0.4",
|
||||||
|
"1.1.0", "1.1.1", "1.1.2", "1.1.3", "1.1.4", "1.1.5", "1.1.6",
|
||||||
|
"1.2.0", "1.2.1", /*DOA,*/ "1.2.3", "1.2.4", /*DOA,*/ "1.2.6", "1.2.7", "1.2.8",
|
||||||
|
) ++ sbt13Plus
|
||||||
|
def sbt13Plus = Seq() // Add sbt 1.3+ stable versions when released
|
||||||
|
|
||||||
|
def mimaSettings = mimaSettingsSince(sbt10Plus)
|
||||||
|
def mimaSettingsSince(versions: Seq[String]) = Def settings (
|
||||||
mimaPreviousArtifacts := {
|
mimaPreviousArtifacts := {
|
||||||
Seq(
|
val crossVersion = if (crossPaths.value) CrossVersion.binary else CrossVersion.disabled
|
||||||
"1.0.0", "1.0.1", "1.0.2", "1.0.3", "1.0.4",
|
versions.map(v => organization.value % moduleName.value % v cross crossVersion).toSet
|
||||||
"1.1.0", "1.1.1", "1.1.2", "1.1.3", "1.1.4", "1.1.5", "1.1.6",
|
|
||||||
"1.2.0", "1.2.1", "1.2.3"
|
|
||||||
).map { v =>
|
|
||||||
organization.value % moduleName.value % v cross (if (crossPaths.value) CrossVersion.binary else CrossVersion.disabled)
|
|
||||||
}.toSet
|
|
||||||
},
|
},
|
||||||
mimaBinaryIssueFilters ++= Seq(
|
mimaBinaryIssueFilters ++= Seq(
|
||||||
// Changes in the internal package
|
// Changes in the internal package
|
||||||
|
|
@ -425,7 +428,6 @@ lazy val actionsProj = (project in file("main-actions"))
|
||||||
addSbtCompilerClasspath,
|
addSbtCompilerClasspath,
|
||||||
addSbtCompilerApiInfo,
|
addSbtCompilerApiInfo,
|
||||||
addSbtLmCore,
|
addSbtLmCore,
|
||||||
addSbtCompilerIvyIntegration,
|
|
||||||
addSbtZinc
|
addSbtZinc
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -576,11 +578,25 @@ lazy val mainSettingsProj = (project in file("main-settings"))
|
||||||
addSbtLmCore
|
addSbtLmCore
|
||||||
)
|
)
|
||||||
|
|
||||||
|
lazy val zincLmIntegrationProj = (project in file("zinc-lm-integration"))
|
||||||
|
.enablePlugins(BuildInfoPlugin)
|
||||||
|
.settings(
|
||||||
|
name := "Zinc LM Integration",
|
||||||
|
testedBaseSettings,
|
||||||
|
buildInfo in Compile := Nil, // Only generate build info for tests
|
||||||
|
BuildInfoPlugin.buildInfoScopedSettings(Test),
|
||||||
|
buildInfoPackage in Test := "sbt.internal.inc",
|
||||||
|
buildInfoObject in Test := "ZincLmIntegrationBuildInfo",
|
||||||
|
buildInfoKeys in Test := List[BuildInfoKey]("zincVersion" -> zincVersion),
|
||||||
|
mimaSettingsSince(sbt13Plus),
|
||||||
|
)
|
||||||
|
.configure(addSbtZincCompileCore, addSbtLmCore, addSbtLmIvyTest)
|
||||||
|
|
||||||
// The main integration project for sbt. It brings all of the projects together, configures them, and provides for overriding conventions.
|
// The main integration project for sbt. It brings all of the projects together, configures them, and provides for overriding conventions.
|
||||||
lazy val mainProj = (project in file("main"))
|
lazy val mainProj = (project in file("main"))
|
||||||
.enablePlugins(ContrabandPlugin)
|
.enablePlugins(ContrabandPlugin)
|
||||||
.dependsOn(logicProj, actionsProj, mainSettingsProj, runProj, commandProj, collectionProj,
|
.dependsOn(logicProj, actionsProj, mainSettingsProj, runProj, commandProj, collectionProj,
|
||||||
scriptedSbtReduxProj, scriptedPluginProj)
|
scriptedSbtReduxProj, scriptedPluginProj, zincLmIntegrationProj)
|
||||||
.settings(
|
.settings(
|
||||||
testedBaseSettings,
|
testedBaseSettings,
|
||||||
name := "Main",
|
name := "Main",
|
||||||
|
|
@ -805,6 +821,7 @@ def allProjects =
|
||||||
actionsProj,
|
actionsProj,
|
||||||
commandProj,
|
commandProj,
|
||||||
mainSettingsProj,
|
mainSettingsProj,
|
||||||
|
zincLmIntegrationProj,
|
||||||
mainProj,
|
mainProj,
|
||||||
sbtProj,
|
sbtProj,
|
||||||
bundledLauncherProj,
|
bundledLauncherProj,
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ import sbt.Scope.{ GlobalScope, ThisScope, fillTaskAxis }
|
||||||
import sbt.internal.CommandStrings.ExportStream
|
import sbt.internal.CommandStrings.ExportStream
|
||||||
import sbt.internal._
|
import sbt.internal._
|
||||||
import sbt.internal.inc.JavaInterfaceUtil._
|
import sbt.internal.inc.JavaInterfaceUtil._
|
||||||
import sbt.internal.inc.ZincUtil
|
import sbt.internal.inc.{ ZincLmUtil, ZincUtil }
|
||||||
import sbt.internal.io.{ Source, WatchState }
|
import sbt.internal.io.{ Source, WatchState }
|
||||||
import sbt.internal.librarymanagement.{ CustomHttp => _, _ }
|
import sbt.internal.librarymanagement.{ CustomHttp => _, _ }
|
||||||
import sbt.internal.librarymanagement.mavenint.{
|
import sbt.internal.librarymanagement.mavenint.{
|
||||||
|
|
@ -477,7 +477,7 @@ object Defaults extends BuildCommon {
|
||||||
IvyActions.cleanCachedResolutionCache(ivyModule.value, streams.value.log)
|
IvyActions.cleanCachedResolutionCache(ivyModule.value, streams.value.log)
|
||||||
},
|
},
|
||||||
scalaCompilerBridgeBinaryJar := None,
|
scalaCompilerBridgeBinaryJar := None,
|
||||||
scalaCompilerBridgeSource := ZincUtil.getDefaultBridgeModule(scalaVersion.value),
|
scalaCompilerBridgeSource := ZincLmUtil.getDefaultBridgeModule(scalaVersion.value),
|
||||||
)
|
)
|
||||||
// must be a val: duplication detected by object identity
|
// must be a val: duplication detected by object identity
|
||||||
private[this] lazy val compileBaseGlobal: Seq[Setting[_]] = globalDefaults(
|
private[this] lazy val compileBaseGlobal: Seq[Setting[_]] = globalDefaults(
|
||||||
|
|
@ -539,7 +539,7 @@ object Defaults extends BuildCommon {
|
||||||
compilerBridgeJar = jar
|
compilerBridgeJar = jar
|
||||||
)
|
)
|
||||||
case _ =>
|
case _ =>
|
||||||
ZincUtil.scalaCompiler(
|
ZincLmUtil.scalaCompiler(
|
||||||
scalaInstance = scalaInstance.value,
|
scalaInstance = scalaInstance.value,
|
||||||
classpathOptions = classpathOptions.value,
|
classpathOptions = classpathOptions.value,
|
||||||
globalLock = launcher.globalLock,
|
globalLock = launcher.globalLock,
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ package internal
|
||||||
|
|
||||||
import sbt.util.Logger
|
import sbt.util.Logger
|
||||||
import sbt.internal.util.JLine
|
import sbt.internal.util.JLine
|
||||||
import sbt.internal.inc.{ ScalaInstance, ZincUtil }
|
import sbt.internal.inc.{ ScalaInstance, ZincLmUtil, ZincUtil }
|
||||||
import xsbti.compile.ClasspathOptionsUtil
|
import xsbti.compile.ClasspathOptionsUtil
|
||||||
|
|
||||||
object ConsoleProject {
|
object ConsoleProject {
|
||||||
|
|
@ -41,7 +41,7 @@ object ConsoleProject {
|
||||||
compilerBridgeJar = jar
|
compilerBridgeJar = jar
|
||||||
)
|
)
|
||||||
case None =>
|
case None =>
|
||||||
ZincUtil.scalaCompiler(
|
ZincLmUtil.scalaCompiler(
|
||||||
scalaInstance = scalaInstance,
|
scalaInstance = scalaInstance,
|
||||||
classpathOptions = ClasspathOptionsUtil.repl,
|
classpathOptions = ClasspathOptionsUtil.repl,
|
||||||
globalLock = launcher.globalLock,
|
globalLock = launcher.globalLock,
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ import Keys.{
|
||||||
import Project.inScope
|
import Project.inScope
|
||||||
import sbt.internal.inc.classpath.ClasspathUtilities
|
import sbt.internal.inc.classpath.ClasspathUtilities
|
||||||
import sbt.librarymanagement.ivy.{ InlineIvyConfiguration, IvyDependencyResolution, IvyPaths }
|
import sbt.librarymanagement.ivy.{ InlineIvyConfiguration, IvyDependencyResolution, IvyPaths }
|
||||||
import sbt.internal.inc.{ ZincUtil, ScalaInstance }
|
import sbt.internal.inc.{ ZincLmUtil, ZincUtil, ScalaInstance }
|
||||||
import sbt.internal.util.Attributed.data
|
import sbt.internal.util.Attributed.data
|
||||||
import sbt.internal.util.Types.const
|
import sbt.internal.util.Types.const
|
||||||
import sbt.internal.util.{ Attributed, Settings, ~> }
|
import sbt.internal.util.{ Attributed, Settings, ~> }
|
||||||
|
|
@ -93,14 +93,14 @@ private[sbt] object Load {
|
||||||
val si = ScalaInstance(scalaProvider.version, scalaProvider.launcher)
|
val si = ScalaInstance(scalaProvider.version, scalaProvider.launcher)
|
||||||
val zincDir = BuildPaths.getZincDirectory(state, globalBase)
|
val zincDir = BuildPaths.getZincDirectory(state, globalBase)
|
||||||
val classpathOptions = ClasspathOptionsUtil.boot
|
val classpathOptions = ClasspathOptionsUtil.boot
|
||||||
val scalac = ZincUtil.scalaCompiler(
|
val scalac = ZincLmUtil.scalaCompiler(
|
||||||
scalaInstance = si,
|
scalaInstance = si,
|
||||||
classpathOptions = classpathOptions,
|
classpathOptions = classpathOptions,
|
||||||
globalLock = launcher.globalLock,
|
globalLock = launcher.globalLock,
|
||||||
componentProvider = app.provider.components,
|
componentProvider = app.provider.components,
|
||||||
secondaryCacheDir = Option(zincDir),
|
secondaryCacheDir = Option(zincDir),
|
||||||
dependencyResolution = dependencyResolution,
|
dependencyResolution = dependencyResolution,
|
||||||
compilerBridgeSource = ZincUtil.getDefaultBridgeModule(scalaProvider.version),
|
compilerBridgeSource = ZincLmUtil.getDefaultBridgeModule(scalaProvider.version),
|
||||||
scalaJarsTarget = zincDir,
|
scalaJarsTarget = zincDir,
|
||||||
log = log
|
log = log
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ object Dependencies {
|
||||||
case Some(version) => version
|
case Some(version) => version
|
||||||
case _ => "1.3.0-M3"
|
case _ => "1.3.0-M3"
|
||||||
}
|
}
|
||||||
private val zincVersion = "1.3.0-M3"
|
val zincVersion = "1.3.0-M4"
|
||||||
|
|
||||||
private val sbtIO = "org.scala-sbt" %% "io" % ioVersion
|
private val sbtIO = "org.scala-sbt" %% "io" % ioVersion
|
||||||
|
|
||||||
|
|
@ -29,7 +29,7 @@ object Dependencies {
|
||||||
private val utilScripted = "org.scala-sbt" %% "util-scripted" % utilVersion
|
private val utilScripted = "org.scala-sbt" %% "util-scripted" % utilVersion
|
||||||
|
|
||||||
private val libraryManagementCore = "org.scala-sbt" %% "librarymanagement-core" % lmVersion
|
private val libraryManagementCore = "org.scala-sbt" %% "librarymanagement-core" % lmVersion
|
||||||
private val libraryManagementImpl = "org.scala-sbt" %% "librarymanagement-ivy" % lmVersion
|
private val libraryManagementIvy = "org.scala-sbt" %% "librarymanagement-ivy" % lmVersion
|
||||||
|
|
||||||
val launcherVersion = "1.0.4"
|
val launcherVersion = "1.0.4"
|
||||||
val launcherInterface = "org.scala-sbt" % "launcher-interface" % launcherVersion
|
val launcherInterface = "org.scala-sbt" % "launcher-interface" % launcherVersion
|
||||||
|
|
@ -41,9 +41,9 @@ object Dependencies {
|
||||||
private val compilerClasspath = "org.scala-sbt" %% "zinc-classpath" % zincVersion
|
private val compilerClasspath = "org.scala-sbt" %% "zinc-classpath" % zincVersion
|
||||||
private val compilerApiInfo = "org.scala-sbt" %% "zinc-apiinfo" % zincVersion
|
private val compilerApiInfo = "org.scala-sbt" %% "zinc-apiinfo" % zincVersion
|
||||||
private val compilerBridge = "org.scala-sbt" %% "compiler-bridge" % zincVersion
|
private val compilerBridge = "org.scala-sbt" %% "compiler-bridge" % zincVersion
|
||||||
private val compilerIvyIntegration = "org.scala-sbt" %% "zinc-ivy-integration" % zincVersion
|
|
||||||
private val zinc = "org.scala-sbt" %% "zinc" % zincVersion
|
private val zinc = "org.scala-sbt" %% "zinc" % zincVersion
|
||||||
private val zincCompile = "org.scala-sbt" %% "zinc-compile" % zincVersion
|
private val zincCompile = "org.scala-sbt" %% "zinc-compile" % zincVersion
|
||||||
|
private val zincCompileCore = "org.scala-sbt" %% "zinc-compile-core" % zincVersion
|
||||||
|
|
||||||
def getSbtModulePath(key: String, name: String) = {
|
def getSbtModulePath(key: String, name: String) = {
|
||||||
val localProps = new java.util.Properties()
|
val localProps = new java.util.Properties()
|
||||||
|
|
@ -58,11 +58,19 @@ object Dependencies {
|
||||||
lazy val sbtLmPath = getSbtModulePath("sbtlm.path", "sbt/lm")
|
lazy val sbtLmPath = getSbtModulePath("sbtlm.path", "sbt/lm")
|
||||||
lazy val sbtZincPath = getSbtModulePath("sbtzinc.path", "sbt/zinc")
|
lazy val sbtZincPath = getSbtModulePath("sbtzinc.path", "sbt/zinc")
|
||||||
|
|
||||||
def addSbtModule(p: Project, path: Option[String], projectName: String, m: ModuleID) =
|
def addSbtModule(
|
||||||
|
p: Project,
|
||||||
|
path: Option[String],
|
||||||
|
projectName: String,
|
||||||
|
moduleId: ModuleID,
|
||||||
|
c: Option[Configuration] = None
|
||||||
|
) = {
|
||||||
|
val m = moduleId.withConfigurations(c.map(_.name))
|
||||||
path match {
|
path match {
|
||||||
case Some(f) => p dependsOn ProjectRef(file(f), projectName)
|
case Some(f) => p dependsOn ClasspathDependency(ProjectRef(file(f), projectName), c.map(_.name))
|
||||||
case None => p settings (libraryDependencies += m, dependencyOverrides += m)
|
case None => p settings (libraryDependencies += m, dependencyOverrides += m)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def addSbtIO(p: Project): Project = addSbtModule(p, sbtIoPath, "io", sbtIO)
|
def addSbtIO(p: Project): Project = addSbtModule(p, sbtIoPath, "io", sbtIO)
|
||||||
|
|
||||||
|
|
@ -84,7 +92,9 @@ object Dependencies {
|
||||||
def addSbtLmCore(p: Project): Project =
|
def addSbtLmCore(p: Project): Project =
|
||||||
addSbtModule(p, sbtLmPath, "lmCore", libraryManagementCore)
|
addSbtModule(p, sbtLmPath, "lmCore", libraryManagementCore)
|
||||||
def addSbtLmImpl(p: Project): Project =
|
def addSbtLmImpl(p: Project): Project =
|
||||||
addSbtModule(p, sbtLmPath, "lmImpl", libraryManagementImpl)
|
addSbtModule(p, sbtLmPath, "lmImpl", libraryManagementIvy)
|
||||||
|
def addSbtLmIvyTest(p: Project): Project =
|
||||||
|
addSbtModule(p, sbtLmPath, "lmIvy", libraryManagementIvy, Some(Test))
|
||||||
|
|
||||||
def addSbtCompilerInterface(p: Project): Project =
|
def addSbtCompilerInterface(p: Project): Project =
|
||||||
addSbtModule(p, sbtZincPath, "compilerInterface212", compilerInterface)
|
addSbtModule(p, sbtZincPath, "compilerInterface212", compilerInterface)
|
||||||
|
|
@ -94,11 +104,11 @@ object Dependencies {
|
||||||
addSbtModule(p, sbtZincPath, "zincApiInfo212", compilerApiInfo)
|
addSbtModule(p, sbtZincPath, "zincApiInfo212", compilerApiInfo)
|
||||||
def addSbtCompilerBridge(p: Project): Project =
|
def addSbtCompilerBridge(p: Project): Project =
|
||||||
addSbtModule(p, sbtZincPath, "compilerBridge212", compilerBridge)
|
addSbtModule(p, sbtZincPath, "compilerBridge212", compilerBridge)
|
||||||
def addSbtCompilerIvyIntegration(p: Project): Project =
|
|
||||||
addSbtModule(p, sbtZincPath, "zincIvyIntegration", compilerIvyIntegration)
|
|
||||||
def addSbtZinc(p: Project): Project = addSbtModule(p, sbtZincPath, "zinc", zinc)
|
def addSbtZinc(p: Project): Project = addSbtModule(p, sbtZincPath, "zinc", zinc)
|
||||||
def addSbtZincCompile(p: Project): Project =
|
def addSbtZincCompile(p: Project): Project =
|
||||||
addSbtModule(p, sbtZincPath, "zincCompile", zincCompile)
|
addSbtModule(p, sbtZincPath, "zincCompile", zincCompile)
|
||||||
|
def addSbtZincCompileCore(p: Project): Project =
|
||||||
|
addSbtModule(p, sbtZincPath, "zincCompileCore", zincCompileCore)
|
||||||
|
|
||||||
val lmCoursierVersion = "1.1.0-M14-1"
|
val lmCoursierVersion = "1.1.0-M14-1"
|
||||||
val lmCoursierShaded = "io.get-coursier" %% "lm-coursier-shaded" % lmCoursierVersion
|
val lmCoursierShaded = "io.get-coursier" %% "lm-coursier-shaded" % lmCoursierVersion
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,80 @@
|
||||||
|
/*
|
||||||
|
* sbt
|
||||||
|
* Copyright 2011 - 2018, Lightbend, Inc.
|
||||||
|
* Copyright 2008 - 2010, Mark Harrah
|
||||||
|
* Licensed under Apache License 2.0 (see 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 @@
|
||||||
|
/*
|
||||||
|
* sbt
|
||||||
|
* Copyright 2011 - 2018, Lightbend, Inc.
|
||||||
|
* Copyright 2008 - 2010, Mark Harrah
|
||||||
|
* Licensed under Apache License 2.0 (see 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 @@
|
||||||
|
/*
|
||||||
|
* sbt
|
||||||
|
* Copyright 2011 - 2018, Lightbend, Inc.
|
||||||
|
* Copyright 2008 - 2010, Mark Harrah
|
||||||
|
* Licensed under Apache License 2.0 (see 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,35 @@
|
||||||
|
/*
|
||||||
|
* sbt
|
||||||
|
* Copyright 2011 - 2018, Lightbend, Inc.
|
||||||
|
* Copyright 2008 - 2010, Mark Harrah
|
||||||
|
* Licensed under Apache License 2.0 (see 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,361 @@
|
||||||
|
/*
|
||||||
|
* sbt
|
||||||
|
* Copyright 2011 - 2018, Lightbend, Inc.
|
||||||
|
* Copyright 2008 - 2010, Mark Harrah
|
||||||
|
* Licensed under Apache License 2.0 (see 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,137 @@
|
||||||
|
/*
|
||||||
|
* sbt
|
||||||
|
* Copyright 2011 - 2018, Lightbend, Inc.
|
||||||
|
* Copyright 2008 - 2010, Mark Harrah
|
||||||
|
* Licensed under Apache License 2.0 (see 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 @@
|
||||||
|
/*
|
||||||
|
* sbt
|
||||||
|
* Copyright 2011 - 2018, Lightbend, Inc.
|
||||||
|
* Copyright 2008 - 2010, Mark Harrah
|
||||||
|
* Licensed under Apache License 2.0 (see 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,86 @@
|
||||||
|
/*
|
||||||
|
* sbt
|
||||||
|
* Copyright 2011 - 2018, Lightbend, Inc.
|
||||||
|
* Copyright 2008 - 2010, Mark Harrah
|
||||||
|
* Licensed under Apache License 2.0 (see LICENSE)
|
||||||
|
*/
|
||||||
|
|
||||||
|
package sbt.internal.inc
|
||||||
|
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
import sbt.io.IO
|
||||||
|
import sbt.io.syntax._
|
||||||
|
import sbt.librarymanagement._
|
||||||
|
import sbt.librarymanagement.ivy._
|
||||||
|
import sbt.util.Logger
|
||||||
|
import xsbti.compile.CompilerBridgeProvider
|
||||||
|
import org.scalatest._
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 FlatSpec with Matchers {
|
||||||
|
def currentBase: File = new File(".")
|
||||||
|
def currentTarget: File = currentBase / "target" / "ivyhome"
|
||||||
|
def currentManaged: File = currentBase / "target" / "lib_managed"
|
||||||
|
def secondaryCacheDirectory: File = file("target").getAbsoluteFile / "zinc-components"
|
||||||
|
|
||||||
|
val resolvers = Array(
|
||||||
|
ZincComponentCompiler.LocalResolver,
|
||||||
|
Resolver.mavenCentral,
|
||||||
|
MavenRepository(
|
||||||
|
"scala-integration",
|
||||||
|
"https://scala-ci.typesafe.com/artifactory/scala-integration/"
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
private def ivyConfiguration(log: Logger) =
|
||||||
|
getDefaultConfiguration(currentBase, currentTarget, resolvers, log)
|
||||||
|
|
||||||
|
def getZincProvider(bridge: ModuleID, 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(log))
|
||||||
|
ZincComponentCompiler.interfaceProvider(bridge, manager, dependencyResolution, currentManaged)
|
||||||
|
}
|
||||||
|
|
||||||
|
def getCompilerBridge(targetDir: File, log: Logger, scalaVersion: String): File = {
|
||||||
|
val bridge0 = ZincComponentCompiler.getDefaultBridgeModule(scalaVersion)
|
||||||
|
// redefine the compiler bridge version
|
||||||
|
// using the version of zinc used during testing
|
||||||
|
// this way when building with zinc as a source dependency
|
||||||
|
// these specs don't go looking for some SHA-suffixed compiler bridge
|
||||||
|
val bridge1 = bridge0.withRevision(ZincLmIntegrationBuildInfo.zincVersion)
|
||||||
|
val provider = getZincProvider(bridge1, targetDir, log)
|
||||||
|
val scalaInstance = provider.fetchScalaInstance(scalaVersion, log)
|
||||||
|
val bridge = provider.fetchCompiledBridge(scalaInstance, log)
|
||||||
|
val target = targetDir / s"target-bridge-$scalaVersion.jar"
|
||||||
|
IO.copyFile(bridge, target)
|
||||||
|
target
|
||||||
|
}
|
||||||
|
|
||||||
|
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,55 @@
|
||||||
|
/*
|
||||||
|
* sbt
|
||||||
|
* Copyright 2011 - 2018, Lightbend, Inc.
|
||||||
|
* Copyright 2008 - 2010, Mark Harrah
|
||||||
|
* Licensed under Apache License 2.0 (see LICENSE)
|
||||||
|
*/
|
||||||
|
|
||||||
|
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 scala2130M2 = "2.13.0-M2"
|
||||||
|
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-M2" in {
|
||||||
|
IO.withTemporaryDirectory(t => getCompilerBridge(t, logger, scala2130M2) 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