Merge branch 'pr/335' into wip/integration

# Conflicts:
#	internal/zinc-ivy-integration/src/main/scala/sbt/internal/inc/ZincComponentCompiler.scala
#	project/Dependencies.scala
This commit is contained in:
Eugene Yokota 2017-07-15 15:36:37 -04:00
commit 7284e7b5b6
3 changed files with 86 additions and 138 deletions

View File

@ -9,9 +9,8 @@ package xsbti.compile;
import sbt.internal.inc.ZincComponentCompiler;
import sbt.internal.inc.ZincComponentManager;
import sbt.internal.librarymanagement.IvyConfiguration;
import sbt.librarymanagement.DependencyResolution;
import sbt.librarymanagement.Resolver;
import sbt.librarymanagement.ResolversSyntax;
import scala.None$;
import xsbti.ComponentProvider;
import xsbti.GlobalLock;
@ -24,7 +23,7 @@ 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 ResolversSyntax#DefaultMavenRepository()} et al.
* instantiate them via {@link Resolver#mavenCentral()} et al.
*
* @return A local ivy resolver.
*/
@ -32,26 +31,6 @@ public interface ZincBridgeProvider {
return ZincComponentCompiler.LocalResolver();
}
/**
* Get the default ivy configuration to retrieve compiler components.
* <p>
* This method is useful to invoke {@link ZincBridgeProvider#getProvider(File, GlobalLock, ComponentProvider, IvyConfiguration, Logger)}.
* <p>
* In order to know which arguments to pass, reading the
* <a href="http://ant.apache.org/ivy/history/latest-milestone/concept.html">ivy main concepts</a>
* may be useful.
*
* @param baseDirectory The base directory for ivy.
* @param ivyHome The home for ivy.
* @param resolvers The resolvers to be used (usually local and Maven).
* See {@link ZincBridgeProvider#getProvider(File, GlobalLock, ComponentProvider, IvyConfiguration, Logger)}
* and {@link ResolversSyntax}.
* @return A default ivy configuration ready for fetching Zinc compiler components.
*/
public static IvyConfiguration getDefaultConfiguration(File baseDirectory, File ivyHome, Resolver[] resolvers, Logger logger) {
return ZincComponentCompiler.getDefaultConfiguration(baseDirectory, ivyHome, resolvers, logger);
}
/**
* 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.
@ -86,16 +65,16 @@ public interface ZincBridgeProvider {
* @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 ivyConfiguration The ivy configuration used internally by the provider.
* @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,
IvyConfiguration ivyConfiguration,
DependencyResolution dependencyResolution,
Logger logger) {
ZincComponentManager manager = new ZincComponentManager(lock, componentProvider, None$.empty(), logger);
return ZincComponentCompiler.interfaceProvider(manager, ivyConfiguration, scalaJarsTarget);
return ZincComponentCompiler.interfaceProvider(manager, dependencyResolution, scalaJarsTarget);
}
}

View File

@ -58,7 +58,7 @@ private[sbt] object ZincComponentCompiler {
private class ZincCompilerBridgeProvider(
userProvidedBridgeSources: Option[ModuleID],
manager: ZincComponentManager,
ivyConfiguration: IvyConfiguration,
dependencyResolution: DependencyResolution,
scalaJarsTarget: File
) extends CompilerBridgeProvider {
@ -74,7 +74,8 @@ private[sbt] object ZincComponentCompiler {
import InterfaceUtil.{ toSupplier => f0 }
val autoClasspath = ClasspathOptionsUtil.auto
val raw = new RawCompiler(scalaInstance, autoClasspath, logger)
val zinc = new ZincComponentCompiler(raw, manager, ivyConfiguration, bridgeSources, logger)
val zinc =
new ZincComponentCompiler(raw, manager, dependencyResolution, bridgeSources, logger)
logger.debug(f0(s"Getting $bridgeSources for Scala ${scalaInstance.version}"))
zinc.compiledBridgeJar
}
@ -100,9 +101,17 @@ private[sbt] object ZincComponentCompiler {
val scalaCompiler = ModuleID(ScalaOrganization, ScalaCompilerID, scalaVersion)
val dependencies = Vector(scalaLibrary, scalaCompiler).map(_.withConfigurations(CompileConf))
val wrapper = dummyModule.withConfigurations(CompileConf)
val ivySbt: IvySbt = new IvySbt(ivyConfiguration)
val ivyModule = ZincIvyActions.getModule(ivySbt, wrapper, dependencies)
ZincIvyActions.update(ivyModule, scalaJarsTarget, noSource = true, fullLogger) match {
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."
@ -138,17 +147,17 @@ private[sbt] object ZincComponentCompiler {
// Used by ZincUtil.
def interfaceProvider(compilerBridgeSource: ModuleID,
manager: ZincComponentManager,
ivyConfiguration: IvyConfiguration,
dependencyResolution: DependencyResolution,
scalaJarsTarget: File): CompilerBridgeProvider =
new ZincCompilerBridgeProvider(Some(compilerBridgeSource),
manager,
ivyConfiguration,
dependencyResolution,
scalaJarsTarget)
def interfaceProvider(manager: ZincComponentManager,
ivyConfiguration: IvyConfiguration,
dependencyResolution: DependencyResolution,
scalaJarsTarget: File): CompilerBridgeProvider =
new ZincCompilerBridgeProvider(None, manager, ivyConfiguration, scalaJarsTarget)
new ZincCompilerBridgeProvider(None, manager, dependencyResolution, scalaJarsTarget)
private final val LocalIvy = s"$${user.home}/.ivy2/local/${Resolver.localBasePattern}"
final val LocalResolver: Resolver = {
@ -183,43 +192,22 @@ private[sbt] object ZincComponentCompiler {
new DefaultComponentProvider(targetDir)
}
def getDefaultConfiguration(baseDirectory: File,
ivyHome: File,
resolvers0: Array[Resolver],
log: xsbti.Logger): IvyConfiguration = {
import sbt.io.syntax._
val resolvers = resolvers0.toVector
val chainResolver = ChainedResolver("zinc-chain", resolvers)
new InlineIvyConfiguration(
paths = IvyPaths(baseDirectory, Some(ivyHome)),
resolvers = resolvers,
otherResolvers = Vector.empty,
moduleConfigurations = Vector(ModuleConfiguration("*", chainResolver)),
lock = None,
checksums = Vector.empty,
managedChecksums = false,
resolutionCacheDir = Some(ivyHome / "resolution-cache"),
updateOptions = UpdateOptions(),
log = log
)
}
}
/**
* Component compiler which is able to to retrieve the compiler bridge sources
* `sourceModule` using Ivy.
* `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,
ivyConfiguration: IvyConfiguration,
dependencyResolution: DependencyResolution,
bridgeSources: ModuleID,
log: Logger
) {
import sbt.internal.util.{ BufferedLogger, FullLogger }
private final val ivySbt: IvySbt = new IvySbt(ivyConfiguration)
private final val buffered = new BufferedLogger(FullLogger(log))
def compiledBridgeJar: File = {
@ -248,19 +236,6 @@ private[inc] class ZincComponentCompiler(
s"$id$binSeparator${scalaVersion}__$javaClassVersion"
}
/**
* Returns an ivy module that will wrap and download a given `moduleID`.
*
* @param moduleID The `moduleID` that needs to be wrapped in a dummy module to be downloaded.
*/
private[inc] def wrapDependencyInModule(moduleID: ModuleID): IvySbt#Module = {
import ZincComponentCompiler.{ sbtOrgTemp, modulePrefixTemp }
val sha1 = Hash.toHex(Hash(moduleID.name))
val dummyID = ModuleID(sbtOrgTemp, s"$modulePrefixTemp$sha1", moduleID.revision)
.withConfigurations(moduleID.configurations)
ZincIvyActions.getModule(ivySbt, dummyID, Vector(moduleID))
}
/**
* Resolves the compiler bridge sources, compiles them and installs the sbt component
* in the local filesystem to make sure that it's reused the next time is required.
@ -269,12 +244,17 @@ private[inc] class ZincComponentCompiler(
*/
private def compileAndInstall(compilerBridgeId: String): Unit = {
import UnresolvedWarning.unresolvedWarningLines
val ivyModuleForBridge = wrapDependencyInModule(bridgeSources)
val moduleForBridge =
dependencyResolution.wrapDependencyInModule(bridgeSources)
IO.withTemporaryDirectory { binaryDirectory =>
val target = new File(binaryDirectory, s"$compilerBridgeId.jar")
buffered bufferQuietly {
IO.withTemporaryDirectory { retrieveDirectory =>
ZincIvyActions.update(ivyModuleForBridge, retrieveDirectory, false, buffered) match {
ZincLMHelper.update(dependencyResolution,
moduleForBridge,
retrieveDirectory,
false,
buffered) match {
case Left(uw) =>
val mod = bridgeSources.toString
val unresolvedLines = unresolvedWarningLines.showLines(uw).mkString("\n")
@ -295,70 +275,23 @@ private[inc] class ZincComponentCompiler(
}
object ZincIvyActions {
type IvyModule = IvySbt#Module
/** Define the default configurations for a Zinc module wrapper. */
private final val DefaultConfigurations: Vector[Configuration] =
Vector(Configurations.Component, Configurations.Compile)
/**
* Create a module from its dummy wrapper and its dependencies.
*
* @param wrapper The ModuleID wrapper that will download the dependencies.
* @param deps The dependencies to be downloaded.
* @return A fully-fledged ivy module to be used for [[IvyActions]].
*/
private[inc] def getModule(ivySbt: IvySbt,
wrapper: ModuleID,
deps: Vector[ModuleID]): IvyModule = {
val moduleInfo = ModuleInfo(wrapper.name)
val componentIvySettings = InlineConfiguration(
validate = false,
ivyScala = None,
module = wrapper,
moduleInfo = moduleInfo,
dependencies = deps
).withConfigurations(DefaultConfigurations)
new ivySbt.Module(componentIvySettings)
}
// The implementation of this method is linked to `wrapDependencyInModule`
private def prettyPrintDependency(module: IvyModule): String = {
module.moduleSettings match {
case ic: InlineConfiguration =>
// Pretty print the module as `ModuleIDExtra.toStringImpl` does.
ic.dependencies.map(m => s"${m.organization}:${m.name}:${m.revision}").mkString(", ")
case _ => sys.error("Fatal: configuration to download was not inline.")
}
}
private object ZincLMHelper {
private final val warningConf = UnresolvedWarningConfiguration()
private final val defaultRetrievePattern = Resolver.defaultRetrievePattern
private def defaultUpdateConfiguration(targetDir: File, noSource: Boolean): UpdateConfiguration = {
val retrieve = RetrieveConfiguration(targetDir, defaultRetrievePattern, false, None)
val logLevel = UpdateLogging.DownloadOnly
val defaultExcluded = Set("doc")
val finalExcluded = if (noSource) defaultExcluded + "src" else defaultExcluded
val artifactFilter = ArtifactTypeFilter.forbid(finalExcluded)
UpdateConfiguration(retrieve = Some(retrieve),
missingOk = false,
logging = logLevel,
artifactFilter = artifactFilter,
offline = false,
frozen = false)
}
private[inc] final val DefaultConfigurations: Vector[Configuration] =
Vector(Configurations.Component, Configurations.Compile)
private[inc] def update(module: IvyModule,
private[inc] def update(dependencyResolution: DependencyResolution,
module: ModuleDescriptor,
retrieveDirectory: File,
noSource: Boolean = false,
logger: Logger): Either[UnresolvedWarning, Vector[File]] = {
import IvyActions.updateEither
val updateConfiguration = defaultUpdateConfiguration(retrieveDirectory, noSource)
val dependencies = prettyPrintDependency(module)
logger.info(s"Attempting to fetch $dependencies.")
val clockForCache = LogicalClock.unknown
updateEither(module, updateConfiguration, warningConf, clockForCache, None, logger) match {
dependencyResolution.update(module, updateConfiguration, warningConf, logger) match {
case Left(unresolvedWarning) =>
logger.debug(s"Couldn't retrieve module(s) ${prettyPrintDependency(module)}.")
Left(unresolvedWarning)
@ -370,4 +303,28 @@ object ZincIvyActions {
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

@ -1,20 +1,13 @@
package sbt.internal.inc
import java.io.File
import java.util.concurrent.Callable
import sbt.io.IO
import sbt.io.syntax._
import sbt.librarymanagement.{
DefaultMavenRepository,
FileRepository,
Patterns,
Resolver,
UpdateOptions
}
import sbt.librarymanagement._
import sbt.librarymanagement.ivy._
import sbt.util.Logger
import xsbti.compile.CompilerBridgeProvider
import xsbti.{ ComponentProvider, GlobalLock }
/**
* Base class for test suites that must be able to fetch and compile the compiler bridge.
@ -26,9 +19,9 @@ abstract class BridgeProviderSpecification extends UnitSpec {
def currentTarget: File = currentBase / "target" / "ivyhome"
def currentManaged: File = currentBase / "target" / "lib_managed"
val resolvers = Array(ZincComponentCompiler.LocalResolver, DefaultMavenRepository)
val resolvers = Array(ZincComponentCompiler.LocalResolver, Resolver.mavenCentral)
private val ivyConfiguration =
ZincComponentCompiler.getDefaultConfiguration(currentBase, currentTarget, resolvers, log)
getDefaultConfiguration(currentBase, currentTarget, resolvers, log)
def secondaryCacheDirectory: File = {
val target = file("target").getAbsoluteFile
@ -40,7 +33,8 @@ abstract class BridgeProviderSpecification extends UnitSpec {
val secondaryCache = Some(secondaryCacheDirectory)
val componentProvider = ZincComponentCompiler.getDefaultComponentProvider(targetDir)
val manager = new ZincComponentManager(lock, componentProvider, secondaryCache, log)
ZincComponentCompiler.interfaceProvider(manager, ivyConfiguration, currentManaged)
val dependencyResolution = IvyDependencyResolution(ivyConfiguration)
ZincComponentCompiler.interfaceProvider(manager, dependencyResolution, currentManaged)
}
def getCompilerBridge(targetDir: File, log: Logger, scalaVersion: String): File = {
@ -58,4 +52,22 @@ abstract class BridgeProviderSpecification extends UnitSpec {
val provider = getZincProvider(targetDir, logger)
provider.fetchScalaInstance(scalaVersion, logger)
}
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)
}
}