mirror of https://github.com/sbt/sbt.git
Merge pull request #1454 from sbt/wip/resolve-consolidation
Consolidated resolution
This commit is contained in:
commit
5b070b9dcc
|
|
@ -4,6 +4,7 @@
|
||||||
package sbt
|
package sbt
|
||||||
|
|
||||||
import Resolver.PluginPattern
|
import Resolver.PluginPattern
|
||||||
|
import ivyint.{ ConsolidatedResolveEngine, ConsolidatedResolveCache }
|
||||||
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
|
|
@ -14,12 +15,14 @@ import CS.singleton
|
||||||
import org.apache.ivy.Ivy
|
import org.apache.ivy.Ivy
|
||||||
import org.apache.ivy.core.{ IvyPatternHelper, LogOptions }
|
import org.apache.ivy.core.{ IvyPatternHelper, LogOptions }
|
||||||
import org.apache.ivy.core.cache.{ CacheMetadataOptions, DefaultRepositoryCacheManager, ModuleDescriptorWriter }
|
import org.apache.ivy.core.cache.{ CacheMetadataOptions, DefaultRepositoryCacheManager, ModuleDescriptorWriter }
|
||||||
|
import org.apache.ivy.core.event.EventManager
|
||||||
import org.apache.ivy.core.module.descriptor.{ Artifact => IArtifact, DefaultArtifact, DefaultDependencyArtifactDescriptor, MDArtifact }
|
import org.apache.ivy.core.module.descriptor.{ Artifact => IArtifact, DefaultArtifact, DefaultDependencyArtifactDescriptor, MDArtifact }
|
||||||
import org.apache.ivy.core.module.descriptor.{ DefaultDependencyDescriptor, DefaultModuleDescriptor, DependencyDescriptor, ModuleDescriptor, License }
|
import org.apache.ivy.core.module.descriptor.{ DefaultDependencyDescriptor, DefaultModuleDescriptor, DependencyDescriptor, ModuleDescriptor, License }
|
||||||
import org.apache.ivy.core.module.descriptor.{ OverrideDependencyDescriptorMediator }
|
import org.apache.ivy.core.module.descriptor.{ OverrideDependencyDescriptorMediator }
|
||||||
import org.apache.ivy.core.module.id.{ ArtifactId, ModuleId, ModuleRevisionId }
|
import org.apache.ivy.core.module.id.{ ArtifactId, ModuleId, ModuleRevisionId }
|
||||||
import org.apache.ivy.core.resolve.{ IvyNode, ResolveData, ResolvedModuleRevision }
|
import org.apache.ivy.core.resolve.{ IvyNode, ResolveData, ResolvedModuleRevision, ResolveEngine }
|
||||||
import org.apache.ivy.core.settings.IvySettings
|
import org.apache.ivy.core.settings.IvySettings
|
||||||
|
import org.apache.ivy.core.sort.SortEngine
|
||||||
import org.apache.ivy.plugins.latest.LatestRevisionStrategy
|
import org.apache.ivy.plugins.latest.LatestRevisionStrategy
|
||||||
import org.apache.ivy.plugins.matcher.PatternMatcher
|
import org.apache.ivy.plugins.matcher.PatternMatcher
|
||||||
import org.apache.ivy.plugins.parser.m2.PomModuleDescriptorParser
|
import org.apache.ivy.plugins.parser.m2.PomModuleDescriptorParser
|
||||||
|
|
@ -28,6 +31,7 @@ import org.apache.ivy.util.{ Message, MessageLogger }
|
||||||
import org.apache.ivy.util.extendable.ExtendableItem
|
import org.apache.ivy.util.extendable.ExtendableItem
|
||||||
|
|
||||||
import scala.xml.{ NodeSeq, Text }
|
import scala.xml.{ NodeSeq, Text }
|
||||||
|
import scala.collection.mutable
|
||||||
|
|
||||||
final class IvySbt(val configuration: IvyConfiguration) {
|
final class IvySbt(val configuration: IvyConfiguration) {
|
||||||
import configuration.baseDirectory
|
import configuration.baseDirectory
|
||||||
|
|
@ -76,7 +80,23 @@ final class IvySbt(val configuration: IvyConfiguration) {
|
||||||
}
|
}
|
||||||
private lazy val ivy: Ivy =
|
private lazy val ivy: Ivy =
|
||||||
{
|
{
|
||||||
val i = new Ivy() { private val loggerEngine = new SbtMessageLoggerEngine; override def getLoggerEngine = loggerEngine }
|
val i = new Ivy() {
|
||||||
|
private val loggerEngine = new SbtMessageLoggerEngine
|
||||||
|
override def getLoggerEngine = loggerEngine
|
||||||
|
override def bind(): Unit = {
|
||||||
|
val prOpt = Option(getSettings.getResolver(ProjectResolver.InterProject)) map { case pr: ProjectResolver => pr }
|
||||||
|
// We inject the deps we need before we can hook our resolve engine.
|
||||||
|
setSortEngine(new SortEngine(getSettings))
|
||||||
|
setEventManager(new EventManager())
|
||||||
|
if (configuration.updateOptions.consolidatedResolution) {
|
||||||
|
setResolveEngine(new ResolveEngine(getSettings, getEventManager, getSortEngine) with ConsolidatedResolveEngine {
|
||||||
|
val consolidatedResolveCache = IvySbt.consolidatedResolveCache
|
||||||
|
val projectResolver = prOpt
|
||||||
|
})
|
||||||
|
} else setResolveEngine(new ResolveEngine(getSettings, getEventManager, getSortEngine))
|
||||||
|
super.bind()
|
||||||
|
}
|
||||||
|
}
|
||||||
i.setSettings(settings)
|
i.setSettings(settings)
|
||||||
i.bind()
|
i.bind()
|
||||||
i.getLoggerEngine.pushLogger(new IvyLoggerInterface(configuration.log))
|
i.getLoggerEngine.pushLogger(new IvyLoggerInterface(configuration.log))
|
||||||
|
|
@ -103,6 +123,18 @@ final class IvySbt(val configuration: IvyConfiguration) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cleans consolidated resolution cache.
|
||||||
|
* @param md - module descriptor of the original Ivy graph.
|
||||||
|
*/
|
||||||
|
private[sbt] def cleanConsolidatedResolutionCache(md: ModuleDescriptor, log: Logger): Unit =
|
||||||
|
withIvy(log) { i =>
|
||||||
|
val prOpt = Option(i.getSettings.getResolver(ProjectResolver.InterProject)) map { case pr: ProjectResolver => pr }
|
||||||
|
if (configuration.updateOptions.consolidatedResolution) {
|
||||||
|
IvySbt.consolidatedResolveCache.clean(md, prOpt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
final class Module(rawModuleSettings: ModuleSettings) {
|
final class Module(rawModuleSettings: ModuleSettings) {
|
||||||
val moduleSettings: ModuleSettings = IvySbt.substituteCross(rawModuleSettings)
|
val moduleSettings: ModuleSettings = IvySbt.substituteCross(rawModuleSettings)
|
||||||
def owner = IvySbt.this
|
def owner = IvySbt.this
|
||||||
|
|
@ -204,6 +236,7 @@ private object IvySbt {
|
||||||
val DefaultIvyFilename = "ivy.xml"
|
val DefaultIvyFilename = "ivy.xml"
|
||||||
val DefaultMavenFilename = "pom.xml"
|
val DefaultMavenFilename = "pom.xml"
|
||||||
val DefaultChecksums = Seq("sha1", "md5")
|
val DefaultChecksums = Seq("sha1", "md5")
|
||||||
|
private[sbt] val consolidatedResolveCache: ConsolidatedResolveCache = new ConsolidatedResolveCache()
|
||||||
|
|
||||||
def defaultIvyFile(project: File) = new File(project, DefaultIvyFilename)
|
def defaultIvyFile(project: File) = new File(project, DefaultIvyFilename)
|
||||||
def defaultIvyConfiguration(project: File) = new File(project, DefaultIvyConfigFilename)
|
def defaultIvyConfiguration(project: File) = new File(project, DefaultIvyConfigFilename)
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,15 @@ object IvyActions {
|
||||||
iv.getSettings.getRepositoryCacheManagers.foreach(_.clean())
|
iv.getSettings.getRepositoryCacheManagers.foreach(_.clean())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cleans the consolidated resolution cache, if any.
|
||||||
|
* This is called by clean.
|
||||||
|
*/
|
||||||
|
private[sbt] def cleanConsolidatedResolutionCache(module: IvySbt#Module, log: Logger): Unit =
|
||||||
|
module.withModule(log) { (ivy, md, default) =>
|
||||||
|
module.owner.cleanConsolidatedResolutionCache(md, log)
|
||||||
|
}
|
||||||
|
|
||||||
/** Creates a Maven pom from the given Ivy configuration*/
|
/** Creates a Maven pom from the given Ivy configuration*/
|
||||||
def makePom(module: IvySbt#Module, configuration: MakePomConfiguration, log: Logger) {
|
def makePom(module: IvySbt#Module, configuration: MakePomConfiguration, log: Logger) {
|
||||||
import configuration.{ allRepositories, moduleInfo, configurations, extra, file, filterRepositories, process, includeTypes }
|
import configuration.{ allRepositories, moduleInfo, configurations, extra, file, filterRepositories, process, includeTypes }
|
||||||
|
|
|
||||||
|
|
@ -16,27 +16,42 @@ sealed trait IvyConfiguration {
|
||||||
def baseDirectory: File
|
def baseDirectory: File
|
||||||
def log: Logger
|
def log: Logger
|
||||||
def withBase(newBaseDirectory: File): This
|
def withBase(newBaseDirectory: File): This
|
||||||
|
def updateOptions: UpdateOptions
|
||||||
}
|
}
|
||||||
final class InlineIvyConfiguration(val paths: IvyPaths, val resolvers: Seq[Resolver], val otherResolvers: Seq[Resolver],
|
final class InlineIvyConfiguration(val paths: IvyPaths, val resolvers: Seq[Resolver], val otherResolvers: Seq[Resolver],
|
||||||
val moduleConfigurations: Seq[ModuleConfiguration], val localOnly: Boolean, val lock: Option[xsbti.GlobalLock],
|
val moduleConfigurations: Seq[ModuleConfiguration], val localOnly: Boolean, val lock: Option[xsbti.GlobalLock],
|
||||||
val checksums: Seq[String], val resolutionCacheDir: Option[File], val log: Logger) extends IvyConfiguration {
|
val checksums: Seq[String], val resolutionCacheDir: Option[File], val updateOptions: UpdateOptions,
|
||||||
@deprecated("Use the variant that accepts the resolution cache location.", "0.13.0")
|
val log: Logger) extends IvyConfiguration {
|
||||||
|
@deprecated("Use the variant that accepts resolutionCacheDir and updateOptions.", "0.13.0")
|
||||||
def this(paths: IvyPaths, resolvers: Seq[Resolver], otherResolvers: Seq[Resolver],
|
def this(paths: IvyPaths, resolvers: Seq[Resolver], otherResolvers: Seq[Resolver],
|
||||||
moduleConfigurations: Seq[ModuleConfiguration], localOnly: Boolean, lock: Option[xsbti.GlobalLock],
|
moduleConfigurations: Seq[ModuleConfiguration], localOnly: Boolean, lock: Option[xsbti.GlobalLock],
|
||||||
checksums: Seq[String], log: Logger) =
|
checksums: Seq[String], log: Logger) =
|
||||||
this(paths, resolvers, otherResolvers, moduleConfigurations, localOnly, lock, checksums, None, log)
|
this(paths, resolvers, otherResolvers, moduleConfigurations, localOnly, lock, checksums, None, UpdateOptions(), log)
|
||||||
|
|
||||||
|
@deprecated("Use the variant that accepts updateOptions.", "0.13.6")
|
||||||
|
def this(paths: IvyPaths, resolvers: Seq[Resolver], otherResolvers: Seq[Resolver],
|
||||||
|
moduleConfigurations: Seq[ModuleConfiguration], localOnly: Boolean, lock: Option[xsbti.GlobalLock],
|
||||||
|
checksums: Seq[String], resolutionCacheDir: Option[File], log: Logger) =
|
||||||
|
this(paths, resolvers, otherResolvers, moduleConfigurations, localOnly, lock, checksums, resolutionCacheDir, UpdateOptions(), log)
|
||||||
|
|
||||||
type This = InlineIvyConfiguration
|
type This = InlineIvyConfiguration
|
||||||
def baseDirectory = paths.baseDirectory
|
def baseDirectory = paths.baseDirectory
|
||||||
def withBase(newBase: File) = new InlineIvyConfiguration(paths.withBase(newBase), resolvers, otherResolvers, moduleConfigurations, localOnly, lock, checksums, resolutionCacheDir, log)
|
def withBase(newBase: File) = new InlineIvyConfiguration(paths.withBase(newBase), resolvers, otherResolvers, moduleConfigurations, localOnly, lock, checksums,
|
||||||
def changeResolvers(newResolvers: Seq[Resolver]) = new InlineIvyConfiguration(paths, newResolvers, otherResolvers, moduleConfigurations, localOnly, lock, checksums, resolutionCacheDir, log)
|
resolutionCacheDir, updateOptions, log)
|
||||||
|
def changeResolvers(newResolvers: Seq[Resolver]) = new InlineIvyConfiguration(paths, newResolvers, otherResolvers, moduleConfigurations, localOnly, lock, checksums,
|
||||||
|
resolutionCacheDir, updateOptions, log)
|
||||||
}
|
}
|
||||||
final class ExternalIvyConfiguration(val baseDirectory: File, val uri: URI, val lock: Option[xsbti.GlobalLock], val extraResolvers: Seq[Resolver], val log: Logger) extends IvyConfiguration {
|
final class ExternalIvyConfiguration(val baseDirectory: File, val uri: URI, val lock: Option[xsbti.GlobalLock],
|
||||||
|
val extraResolvers: Seq[Resolver], val updateOptions: UpdateOptions, val log: Logger) extends IvyConfiguration {
|
||||||
|
@deprecated("Use the variant that accepts updateOptions.", "0.13.6")
|
||||||
|
def this(baseDirectory: File, uri: URI, lock: Option[xsbti.GlobalLock], extraResolvers: Seq[Resolver], log: Logger) =
|
||||||
|
this(baseDirectory, uri, lock, extraResolvers, UpdateOptions(), log)
|
||||||
|
|
||||||
type This = ExternalIvyConfiguration
|
type This = ExternalIvyConfiguration
|
||||||
def withBase(newBase: File) = new ExternalIvyConfiguration(newBase, uri, lock, extraResolvers, log)
|
def withBase(newBase: File) = new ExternalIvyConfiguration(newBase, uri, lock, extraResolvers, log)
|
||||||
}
|
}
|
||||||
object ExternalIvyConfiguration {
|
object ExternalIvyConfiguration {
|
||||||
def apply(baseDirectory: File, file: File, lock: Option[xsbti.GlobalLock], log: Logger) = new ExternalIvyConfiguration(baseDirectory, file.toURI, lock, Nil, log)
|
def apply(baseDirectory: File, file: File, lock: Option[xsbti.GlobalLock], log: Logger) = new ExternalIvyConfiguration(baseDirectory, file.toURI, lock, Nil, UpdateOptions(), log)
|
||||||
}
|
}
|
||||||
|
|
||||||
object IvyConfiguration {
|
object IvyConfiguration {
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,8 @@ class ProjectResolver(name: String, map: Map[ModuleRevisionId, ModuleDescriptor]
|
||||||
map get revisionId map constructResult
|
map get revisionId map constructResult
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private[sbt] def getModuleDescriptor(revisionId: ModuleRevisionId): Option[ModuleDescriptor] = map.get(revisionId)
|
||||||
|
|
||||||
def report(revisionId: ModuleRevisionId): MetadataArtifactDownloadReport =
|
def report(revisionId: ModuleRevisionId): MetadataArtifactDownloadReport =
|
||||||
{
|
{
|
||||||
val artifact = DefaultArtifact.newIvyArtifact(revisionId, new Date)
|
val artifact = DefaultArtifact.newIvyArtifact(revisionId, new Date)
|
||||||
|
|
@ -87,3 +89,7 @@ class ProjectResolver(name: String, map: Map[ModuleRevisionId, ModuleDescriptor]
|
||||||
def setSettings(settings: ResolverSettings) { this.settings = Some(settings) }
|
def setSettings(settings: ResolverSettings) { this.settings = Some(settings) }
|
||||||
def getRepositoryCacheManager = settings match { case Some(s) => s.getDefaultRepositoryCacheManager; case None => sys.error("No settings defined for ProjectResolver") }
|
def getRepositoryCacheManager = settings match { case Some(s) => s.getDefaultRepositoryCacheManager; case None => sys.error("No settings defined for ProjectResolver") }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object ProjectResolver {
|
||||||
|
private[sbt] val InterProject = "inter-project"
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
package sbt
|
||||||
|
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents configurable options for update task.
|
||||||
|
* While UpdateConfiguration is passed into update at runtime,
|
||||||
|
* UpdateOption is intended to be used while setting up the Ivy object.
|
||||||
|
*
|
||||||
|
* See also UpdateConfiguration in IvyActions.scala.
|
||||||
|
*/
|
||||||
|
final class UpdateOptions(
|
||||||
|
/** If set to true, use consolidated resolution. */
|
||||||
|
val consolidatedResolution: Boolean) {
|
||||||
|
|
||||||
|
def withConsolidatedResolution(consolidatedResolution: Boolean): UpdateOptions =
|
||||||
|
copy(consolidatedResolution = consolidatedResolution)
|
||||||
|
|
||||||
|
private[sbt] def copy(
|
||||||
|
consolidatedResolution: Boolean = this.consolidatedResolution): UpdateOptions =
|
||||||
|
new UpdateOptions(consolidatedResolution)
|
||||||
|
}
|
||||||
|
|
||||||
|
object UpdateOptions {
|
||||||
|
def apply(): UpdateOptions =
|
||||||
|
new UpdateOptions(false)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,120 @@
|
||||||
|
package sbt
|
||||||
|
package ivyint
|
||||||
|
|
||||||
|
import java.io.File
|
||||||
|
import collection.concurrent
|
||||||
|
import org.apache.ivy.core
|
||||||
|
import core.resolve._
|
||||||
|
import core.module.id.ModuleRevisionId
|
||||||
|
import core.report.ResolveReport
|
||||||
|
import core.module.descriptor.{ DefaultModuleDescriptor, ModuleDescriptor, DependencyDescriptor }
|
||||||
|
import core.{ IvyPatternHelper, LogOptions }
|
||||||
|
import org.apache.ivy.util.Message
|
||||||
|
|
||||||
|
private[sbt] object ConsolidatedResolveCache {
|
||||||
|
def createID(organization: String, name: String, revision: String) =
|
||||||
|
ModuleRevisionId.newInstance(organization, name, revision)
|
||||||
|
def sbtOrgTemp = "org.scala-sbt.temp"
|
||||||
|
}
|
||||||
|
|
||||||
|
private[sbt] class ConsolidatedResolveCache() {
|
||||||
|
import ConsolidatedResolveCache._
|
||||||
|
val resolveReportCache: concurrent.Map[ModuleRevisionId, ResolveReport] = concurrent.TrieMap()
|
||||||
|
val resolvePropertiesCache: concurrent.Map[ModuleRevisionId, String] = concurrent.TrieMap()
|
||||||
|
val directDependencyCache: concurrent.Map[ModuleDescriptor, Vector[DependencyDescriptor]] = concurrent.TrieMap()
|
||||||
|
|
||||||
|
def clean(md0: ModuleDescriptor, prOpt: Option[ProjectResolver]): Unit = {
|
||||||
|
val mrid0 = md0.getModuleRevisionId
|
||||||
|
val md1 = if (mrid0.getOrganisation == sbtOrgTemp) md0
|
||||||
|
else buildConsolidatedModuleDescriptor(md0, prOpt)
|
||||||
|
val mrid1 = md1.getModuleRevisionId
|
||||||
|
resolveReportCache.remove(mrid1)
|
||||||
|
resolvePropertiesCache.remove(mrid1)
|
||||||
|
}
|
||||||
|
|
||||||
|
def directDependencies(md0: ModuleDescriptor): Vector[DependencyDescriptor] =
|
||||||
|
directDependencyCache.getOrElseUpdate(md0, md0.getDependencies.toVector)
|
||||||
|
|
||||||
|
def buildConsolidatedModuleDescriptor(md0: ModuleDescriptor, prOpt: Option[ProjectResolver]): DefaultModuleDescriptor = {
|
||||||
|
def expandInternalDeps(dep: DependencyDescriptor): Vector[DependencyDescriptor] =
|
||||||
|
prOpt map {
|
||||||
|
_.getModuleDescriptor(dep.getDependencyRevisionId) match {
|
||||||
|
case Some(internal) => directDependencies(internal) flatMap expandInternalDeps
|
||||||
|
case _ => Vector(dep)
|
||||||
|
}
|
||||||
|
} getOrElse Vector(dep)
|
||||||
|
val expanded = directDependencies(md0) flatMap expandInternalDeps
|
||||||
|
val depStrings = expanded map { dep =>
|
||||||
|
val mrid = dep.getDependencyRevisionId
|
||||||
|
val confMap = (dep.getModuleConfigurations map { conf =>
|
||||||
|
conf + "->(" + dep.getDependencyConfigurations(conf).mkString(",") + ")"
|
||||||
|
})
|
||||||
|
mrid.toString + ";" + confMap.mkString(";")
|
||||||
|
}
|
||||||
|
val depsString = depStrings.distinct.sorted.mkString("\n")
|
||||||
|
val sha1 = Hash.toHex(Hash(depsString))
|
||||||
|
// println("sha1: " + sha1)
|
||||||
|
val md1 = new DefaultModuleDescriptor(createID(sbtOrgTemp, "temp-resolve-" + sha1, "1.0"), "release", null, false)
|
||||||
|
md1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private[sbt] trait ConsolidatedResolveEngine extends ResolveEngine {
|
||||||
|
import ConsolidatedResolveCache._
|
||||||
|
|
||||||
|
private[sbt] def consolidatedResolveCache: ConsolidatedResolveCache
|
||||||
|
private[sbt] def projectResolver: Option[ProjectResolver]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve dependencies of a module described by a module descriptor.
|
||||||
|
*/
|
||||||
|
override def resolve(md0: ModuleDescriptor, options0: ResolveOptions): ResolveReport = {
|
||||||
|
val cache = consolidatedResolveCache
|
||||||
|
val cacheManager = getSettings.getResolutionCacheManager
|
||||||
|
val md1 = cache.buildConsolidatedModuleDescriptor(md0, projectResolver)
|
||||||
|
val md1mrid = md1.getModuleRevisionId
|
||||||
|
|
||||||
|
def doWork: (ResolveReport, String) = {
|
||||||
|
if (options0.getLog != LogOptions.LOG_QUIET) {
|
||||||
|
Message.info("Consolidating managed dependencies to " + md1mrid.toString + " ...")
|
||||||
|
}
|
||||||
|
md1.setLastModified(System.currentTimeMillis)
|
||||||
|
for {
|
||||||
|
x <- md0.getConfigurations
|
||||||
|
} yield md1.addConfiguration(x)
|
||||||
|
|
||||||
|
for {
|
||||||
|
x <- md0.getDependencies
|
||||||
|
} yield md1.addDependency(x)
|
||||||
|
|
||||||
|
val options1 = new ResolveOptions(options0)
|
||||||
|
options1.setOutputReport(false)
|
||||||
|
val report0 = super.resolve(md1, options1)
|
||||||
|
val ivyPropertiesInCache1 = cacheManager.getResolvedIvyPropertiesInCache(md1.getResolvedModuleRevisionId)
|
||||||
|
val prop0 =
|
||||||
|
if (ivyPropertiesInCache1.exists) IO.read(ivyPropertiesInCache1)
|
||||||
|
else ""
|
||||||
|
if (options0.isOutputReport) {
|
||||||
|
this.outputReport(report0, cacheManager, options0)
|
||||||
|
}
|
||||||
|
cache.resolveReportCache(md1mrid) = report0
|
||||||
|
cache.resolvePropertiesCache(md1mrid) = prop0
|
||||||
|
(report0, prop0)
|
||||||
|
}
|
||||||
|
|
||||||
|
val (report0, prop0) = (cache.resolveReportCache.get(md1mrid), cache.resolvePropertiesCache.get(md1mrid)) match {
|
||||||
|
case (Some(report), Some(prop)) =>
|
||||||
|
if (options0.getLog != LogOptions.LOG_QUIET) {
|
||||||
|
Message.info("Found consolidated dependency " + md1mrid.toString + " ...")
|
||||||
|
}
|
||||||
|
(report, prop)
|
||||||
|
case _ => doWork
|
||||||
|
}
|
||||||
|
cacheManager.saveResolvedModuleDescriptor(md0)
|
||||||
|
if (prop0 != "") {
|
||||||
|
val ivyPropertiesInCache0 = cacheManager.getResolvedIvyPropertiesInCache(md0.getResolvedModuleRevisionId)
|
||||||
|
IO.write(ivyPropertiesInCache0, prop0)
|
||||||
|
}
|
||||||
|
report0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -108,7 +108,8 @@ object Defaults extends BuildCommon {
|
||||||
pomExtra :== NodeSeq.Empty,
|
pomExtra :== NodeSeq.Empty,
|
||||||
pomPostProcess :== idFun,
|
pomPostProcess :== idFun,
|
||||||
pomAllRepositories :== false,
|
pomAllRepositories :== false,
|
||||||
pomIncludeRepository :== Classpaths.defaultRepositoryFilter
|
pomIncludeRepository :== Classpaths.defaultRepositoryFilter,
|
||||||
|
updateOptions := UpdateOptions()
|
||||||
)
|
)
|
||||||
|
|
||||||
/** Core non-plugin settings for sbt builds. These *must* be on every build or the sbt engine will fail to run at all. */
|
/** Core non-plugin settings for sbt builds. These *must* be on every build or the sbt engine will fail to run at all. */
|
||||||
|
|
@ -218,7 +219,11 @@ object Defaults extends BuildCommon {
|
||||||
sbt.inc.ClassfileManager.transactional(crossTarget.value / "classes.bak", sbt.Logger.Null)),
|
sbt.inc.ClassfileManager.transactional(crossTarget.value / "classes.bak", sbt.Logger.Null)),
|
||||||
scalaInstance <<= scalaInstanceTask,
|
scalaInstance <<= scalaInstanceTask,
|
||||||
crossVersion := (if (crossPaths.value) CrossVersion.binary else CrossVersion.Disabled),
|
crossVersion := (if (crossPaths.value) CrossVersion.binary else CrossVersion.Disabled),
|
||||||
crossTarget := makeCrossTarget(target.value, scalaBinaryVersion.value, sbtBinaryVersion.value, sbtPlugin.value, crossPaths.value)
|
crossTarget := makeCrossTarget(target.value, scalaBinaryVersion.value, sbtBinaryVersion.value, sbtPlugin.value, crossPaths.value),
|
||||||
|
clean := {
|
||||||
|
val _ = clean.value
|
||||||
|
IvyActions.cleanConsolidatedResolutionCache(ivyModule.value, streams.value.log)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
// 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(Seq(
|
private[this] lazy val compileBaseGlobal: Seq[Setting[_]] = globalDefaults(Seq(
|
||||||
|
|
@ -1075,6 +1080,7 @@ object Classpaths {
|
||||||
projectID <<= pluginProjectID,
|
projectID <<= pluginProjectID,
|
||||||
projectDescriptors <<= depMap,
|
projectDescriptors <<= depMap,
|
||||||
updateConfiguration := new UpdateConfiguration(retrieveConfiguration.value, false, ivyLoggingLevel.value),
|
updateConfiguration := new UpdateConfiguration(retrieveConfiguration.value, false, ivyLoggingLevel.value),
|
||||||
|
updateOptions := (updateOptions in Global).value,
|
||||||
retrieveConfiguration := { if (retrieveManaged.value) Some(new RetrieveConfiguration(managedDirectory.value, retrievePattern.value)) else None },
|
retrieveConfiguration := { if (retrieveManaged.value) Some(new RetrieveConfiguration(managedDirectory.value, retrievePattern.value)) else None },
|
||||||
ivyConfiguration <<= mkIvyConfiguration,
|
ivyConfiguration <<= mkIvyConfiguration,
|
||||||
ivyConfigurations := {
|
ivyConfigurations := {
|
||||||
|
|
@ -1162,7 +1168,8 @@ object Classpaths {
|
||||||
val explicit = buildStructure.value.units(thisProjectRef.value.build).unit.plugins.pluginData.resolvers
|
val explicit = buildStructure.value.units(thisProjectRef.value.build).unit.plugins.pluginData.resolvers
|
||||||
explicit orElse bootRepositories(appConfiguration.value) getOrElse externalResolvers.value
|
explicit orElse bootRepositories(appConfiguration.value) getOrElse externalResolvers.value
|
||||||
},
|
},
|
||||||
ivyConfiguration := new InlineIvyConfiguration(ivyPaths.value, externalResolvers.value, Nil, Nil, offline.value, Option(lock(appConfiguration.value)), checksums.value, Some(target.value / "resolution-cache"), streams.value.log),
|
ivyConfiguration := new InlineIvyConfiguration(ivyPaths.value, externalResolvers.value, Nil, Nil, offline.value, Option(lock(appConfiguration.value)),
|
||||||
|
checksums.value, Some(target.value / "resolution-cache"), UpdateOptions(), streams.value.log),
|
||||||
ivySbt <<= ivySbt0,
|
ivySbt <<= ivySbt0,
|
||||||
classifiersModule <<= (projectID, sbtDependency, transitiveClassifiers, loadedBuild, thisProjectRef) map { (pid, sbtDep, classifiers, lb, ref) =>
|
classifiersModule <<= (projectID, sbtDependency, transitiveClassifiers, loadedBuild, thisProjectRef) map { (pid, sbtDep, classifiers, lb, ref) =>
|
||||||
val pluginClasspath = lb.units(ref.build).unit.plugins.fullClasspath
|
val pluginClasspath = lb.units(ref.build).unit.plugins.fullClasspath
|
||||||
|
|
@ -1312,7 +1319,7 @@ object Classpaths {
|
||||||
|
|
||||||
def projectResolverTask: Initialize[Task[Resolver]] =
|
def projectResolverTask: Initialize[Task[Resolver]] =
|
||||||
projectDescriptors map { m =>
|
projectDescriptors map { m =>
|
||||||
new RawRepository(new ProjectResolver("inter-project", m))
|
new RawRepository(new ProjectResolver(ProjectResolver.InterProject, m))
|
||||||
}
|
}
|
||||||
|
|
||||||
def analyzed[T](data: T, analysis: inc.Analysis) = Attributed.blank(data).put(Keys.analysis, analysis)
|
def analyzed[T](data: T, analysis: inc.Analysis) = Attributed.blank(data).put(Keys.analysis, analysis)
|
||||||
|
|
@ -1340,11 +1347,13 @@ object Classpaths {
|
||||||
def unmanagedDependencies: Initialize[Task[Classpath]] =
|
def unmanagedDependencies: Initialize[Task[Classpath]] =
|
||||||
(thisProjectRef, configuration, settingsData, buildDependencies) flatMap unmanagedDependencies0
|
(thisProjectRef, configuration, settingsData, buildDependencies) flatMap unmanagedDependencies0
|
||||||
def mkIvyConfiguration: Initialize[Task[IvyConfiguration]] =
|
def mkIvyConfiguration: Initialize[Task[IvyConfiguration]] =
|
||||||
(fullResolvers, ivyPaths, otherResolvers, moduleConfigurations, offline, checksums in update, appConfiguration, target, streams) map { (rs, paths, other, moduleConfs, off, check, app, t, s) =>
|
(fullResolvers, ivyPaths, otherResolvers, moduleConfigurations, offline, checksums in update, appConfiguration,
|
||||||
warnResolversConflict(rs ++: other, s.log)
|
target, updateOptions, streams) map { (rs, paths, other, moduleConfs, off, check, app, t, uo, s) =>
|
||||||
val resCacheDir = t / "resolution-cache"
|
warnResolversConflict(rs ++: other, s.log)
|
||||||
new InlineIvyConfiguration(paths, rs, other, moduleConfs, off, Option(lock(app)), check, Some(resCacheDir), s.log)
|
val resCacheDir = t / "resolution-cache"
|
||||||
}
|
|
||||||
|
new InlineIvyConfiguration(paths, rs, other, moduleConfs, off, Option(lock(app)), check, Some(resCacheDir), uo, s.log)
|
||||||
|
}
|
||||||
|
|
||||||
import java.util.LinkedHashSet
|
import java.util.LinkedHashSet
|
||||||
import collection.JavaConversions.asScalaSet
|
import collection.JavaConversions.asScalaSet
|
||||||
|
|
@ -1648,13 +1657,13 @@ trait BuildExtra extends BuildCommon {
|
||||||
externalIvySettingsURI(Def.value(url.toURI), addMultiResolver)
|
externalIvySettingsURI(Def.value(url.toURI), addMultiResolver)
|
||||||
def externalIvySettingsURI(uri: Initialize[URI], addMultiResolver: Boolean = true): Setting[Task[IvyConfiguration]] =
|
def externalIvySettingsURI(uri: Initialize[URI], addMultiResolver: Boolean = true): Setting[Task[IvyConfiguration]] =
|
||||||
{
|
{
|
||||||
val other = (baseDirectory, appConfiguration, projectResolver, streams).identityMap
|
val other = (baseDirectory, appConfiguration, projectResolver, updateOptions, streams).identityMap
|
||||||
ivyConfiguration <<= (uri zipWith other) {
|
ivyConfiguration <<= (uri zipWith other) {
|
||||||
case (u, otherTask) =>
|
case (u, otherTask) =>
|
||||||
otherTask map {
|
otherTask map {
|
||||||
case (base, app, pr, s) =>
|
case (base, app, pr, uo, s) =>
|
||||||
val extraResolvers = if (addMultiResolver) pr :: Nil else Nil
|
val extraResolvers = if (addMultiResolver) pr :: Nil else Nil
|
||||||
new ExternalIvyConfiguration(base, u, Option(lock(app)), extraResolvers, s.log)
|
new ExternalIvyConfiguration(base, u, Option(lock(app)), extraResolvers, uo, s.log)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -242,6 +242,7 @@ object Keys {
|
||||||
val moduleSettings = TaskKey[ModuleSettings]("module-settings", "Module settings, which configure dependency management for a specific module, such as a project.", DTask)
|
val moduleSettings = TaskKey[ModuleSettings]("module-settings", "Module settings, which configure dependency management for a specific module, such as a project.", DTask)
|
||||||
val unmanagedBase = SettingKey[File]("unmanaged-base", "The default directory for manually managed libraries.", ASetting)
|
val unmanagedBase = SettingKey[File]("unmanaged-base", "The default directory for manually managed libraries.", ASetting)
|
||||||
val updateConfiguration = SettingKey[UpdateConfiguration]("update-configuration", "Configuration for resolving and retrieving managed dependencies.", DSetting)
|
val updateConfiguration = SettingKey[UpdateConfiguration]("update-configuration", "Configuration for resolving and retrieving managed dependencies.", DSetting)
|
||||||
|
val updateOptions = SettingKey[UpdateOptions]("update-options", "Options for resolving managed dependencies.", DSetting)
|
||||||
val ivySbt = TaskKey[IvySbt]("ivy-sbt", "Provides the sbt interface to Ivy.", CTask)
|
val ivySbt = TaskKey[IvySbt]("ivy-sbt", "Provides the sbt interface to Ivy.", CTask)
|
||||||
val ivyModule = TaskKey[IvySbt#Module]("ivy-module", "Provides the sbt interface to a configured Ivy module.", CTask)
|
val ivyModule = TaskKey[IvySbt#Module]("ivy-module", "Provides the sbt interface to a configured Ivy module.", CTask)
|
||||||
val updateCacheName = TaskKey[String]("updateCacheName", "Defines the directory name used to store the update cache files (inside the streams cacheDirectory).", DTask)
|
val updateCacheName = TaskKey[String]("updateCacheName", "Defines the directory name used to store the update cache files (inside the streams cacheDirectory).", DTask)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
[413]: https://github.com/sbt/sbt/issues/413
|
||||||
|
[1454]: https://github.com/sbt/sbt/pull/1454
|
||||||
|
|
||||||
|
### Consolidated resolution
|
||||||
|
|
||||||
|
sbt 0.13.6 adds a new setting key called `updateOptions`, which can be used to enable consolidated resolution for `update` task.
|
||||||
|
|
||||||
|
updateOptions := updateOptions.value.withConsolidatedResolution(true)
|
||||||
|
|
||||||
|
This feature is specifically targeted to address [Ivy resolution is beging slow for multi-module projects #413][413]. Consolidated resolution aims to fix this issue by artificially constructing an Ivy dependency graph for the unique managed dependencies. If two subprojects introduce identical external dependencies, both subprojects should consolidate to the same graph, and therefore resolve immediately for the second `update`. [#1454][1454]
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
[sbt](http://www.scala-sbt.org/) is the interactive build tool.
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
public class A {
|
||||||
|
public static final int x = 3;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
public final class C {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
System.out.println(A.x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
lazy val check = taskKey[Unit]("Runs the check")
|
||||||
|
|
||||||
|
def commonSettings: Seq[Def.Setting[_]] =
|
||||||
|
Seq(
|
||||||
|
ivyPaths := new IvyPaths( (baseDirectory in ThisBuild).value, Some((target in LocalRootProject).value / "ivy-cache")),
|
||||||
|
libraryDependencies := Seq("net.sf.json-lib" % "json-lib" % "2.4" classifier "jdk15" intransitive()),
|
||||||
|
autoScalaLibrary := false, // avoid downloading fresh scala-library/scala-compiler
|
||||||
|
managedScalaInstance := false,
|
||||||
|
updateOptions := updateOptions.value.withConsolidatedResolution(true)
|
||||||
|
)
|
||||||
|
lazy val root = (project in file(".")).settings(
|
||||||
|
organization in ThisBuild := "org.example",
|
||||||
|
version in ThisBuild := "1.0"
|
||||||
|
)
|
||||||
|
|
||||||
|
lazy val a = project.
|
||||||
|
settings(commonSettings: _*).
|
||||||
|
settings(
|
||||||
|
artifact in (Compile, packageBin) := Artifact("demo")
|
||||||
|
)
|
||||||
|
|
||||||
|
lazy val b = project.
|
||||||
|
settings(commonSettings: _*).
|
||||||
|
settings(
|
||||||
|
check := {
|
||||||
|
val report = update.value
|
||||||
|
val configurationReport = (report.configurations find {_.configuration == "compile"}).head
|
||||||
|
val x = configurationReport.modules match {
|
||||||
|
case Seq(moduleReport) =>
|
||||||
|
moduleReport.module match {
|
||||||
|
case ModuleID("net.sf.json-lib", "json-lib", "2.4", _, _, _, _, _, _, _, _) => ()
|
||||||
|
case x => sys.error("Unexpected module: " + x.toString)
|
||||||
|
}
|
||||||
|
case x => sys.error("Unexpected modules: " + x.toString)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
lazy val c = project.
|
||||||
|
settings(commonSettings: _*).
|
||||||
|
settings(
|
||||||
|
libraryDependencies := Seq(organization.value %% "a" % version.value)
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
> a/publishLocal
|
||||||
|
|
||||||
|
> b/check
|
||||||
|
|
||||||
|
> c/run
|
||||||
Loading…
Reference in New Issue