More careful handling of sbt task dependencies

E.g. ensure no sbt classifiers tasks get evaluated when doing simple
updates
This commit is contained in:
Alexandre Archambault 2017-09-08 16:29:47 +02:00
parent 308f77e3a0
commit ca5ac162f2
1 changed files with 370 additions and 332 deletions

View File

@ -57,7 +57,7 @@ object Tasks {
"https://repo1.maven.org/" "https://repo1.maven.org/"
) )
def coursierResolversTask: Def.Initialize[sbt.Task[Seq[Resolver]]] = Def.task { def coursierResolversTask: Def.Initialize[sbt.Task[Seq[Resolver]]] = Def.taskDyn {
def url(res: Resolver): Option[String] = def url(res: Resolver): Option[String] =
res match { res match {
@ -75,28 +75,37 @@ object Tasks {
def slowRepo(res: Resolver): Boolean = def slowRepo(res: Resolver): Boolean =
url(res).exists(u => slowReposBase.exists(u.startsWith)) url(res).exists(u => slowReposBase.exists(u.startsWith))
val extRes = externalResolvers.value
val isSbtPlugin = sbtPlugin.value
val sbtRes = sbtResolver.value
val bootResOpt = bootResolvers.value val bootResOpt = bootResolvers.value
val overrideFlag = overrideBuildResolvers.value val overrideFlag = overrideBuildResolvers.value
val reorderResolvers = coursierReorderResolvers.value
val result = bootResOpt.filter(_ => overrideFlag).getOrElse { val resultTask = bootResOpt.filter(_ => overrideFlag) match {
var resolvers = extRes case Some(r) => Def.task(r)
if (isSbtPlugin) case None =>
resolvers = Seq( Def.taskDyn {
sbtRes, val extRes = externalResolvers.value
Classpaths.sbtPluginReleases val isSbtPlugin = sbtPlugin.value
) ++ resolvers if (isSbtPlugin)
resolvers Def.task {
Seq(
sbtResolver.value,
Classpaths.sbtPluginReleases
) ++ extRes
}
else
Def.task(extRes)
}
} }
if (reorderResolvers && result.exists(fastRepo) && result.exists(slowRepo)) { Def.task {
val (slow, other) = result.partition(slowRepo) val result = resultTask.value
other ++ slow val reorderResolvers = coursierReorderResolvers.value
} else
result if (reorderResolvers && result.exists(fastRepo) && result.exists(slowRepo)) {
val (slow, other) = result.partition(slowRepo)
other ++ slow
} else
result
}
} }
def coursierRecursiveResolversTask: Def.Initialize[sbt.Task[Seq[Resolver]]] = def coursierRecursiveResolversTask: Def.Initialize[sbt.Task[Seq[Resolver]]] =
@ -346,9 +355,12 @@ object Tasks {
def coursierConfigurationsTask(shadedConfig: Option[(String, String)]) = Def.task { def coursierConfigurationsTask(shadedConfig: Option[(String, String)]) = Def.task {
val configs0 = ivyConfigurations.value.map { config => val configs0 = ivyConfigurations
config.name -> config.extendsConfigs.map(_.name) .value
}.toMap .map { config =>
config.name -> config.extendsConfigs.map(_.name)
}
.toMap
def allExtends(c: String) = { def allExtends(c: String) = {
// possibly bad complexity // possibly bad complexity
@ -544,26 +556,17 @@ object Tasks {
def resolutionsTask( def resolutionsTask(
sbtClassifiers: Boolean = false sbtClassifiers: Boolean = false
): Def.Initialize[sbt.Task[Map[Set[String], coursier.Resolution]]] = Def.task { ): Def.Initialize[sbt.Task[Map[Set[String], coursier.Resolution]]] = Def.taskDyn {
// let's update only one module at once, for a better output val projectName = thisProjectRef.value.project
// Downloads are already parallel, no need to parallelize further anyway
synchronized {
val cm = coursierSbtClassifiersModule.value val sv = scalaVersion.value
val sbv = scalaBinaryVersion.value
val projectName = thisProjectRef.value.project val currentProjectTask: sbt.Def.Initialize[sbt.Task[(Project, Seq[(Module, String, URL, Boolean)], Seq[Set[String]])]] =
val baseConfigGraphs = coursierConfigGraphs.value if (sbtClassifiers)
Def.task {
val sv = scalaVersion.value val cm = coursierSbtClassifiersModule.value
val sbv = scalaBinaryVersion.value
val proj = coursierProject.value
val publications = coursierPublications.value
val fallbackDeps = coursierFallbackDependencies.value
val (currentProject, fallbackDependencies, configGraphs) =
if (sbtClassifiers) {
val proj = FromSbt.sbtClassifiersProject(cm, sv, sbv) val proj = FromSbt.sbtClassifiersProject(cm, sv, sbv)
val fallbackDeps = FromSbt.fallbackDependencies( val fallbackDeps = FromSbt.fallbackDependencies(
@ -573,87 +576,76 @@ object Tasks {
) )
(proj, fallbackDeps, Vector(cm.configurations.map(_.name).toSet)) (proj, fallbackDeps, Vector(cm.configurations.map(_.name).toSet))
} else }
(proj.copy(publications = publications), fallbackDeps, baseConfigGraphs) else
Def.task {
val baseConfigGraphs = coursierConfigGraphs.value
(coursierProject.value.copy(publications = coursierPublications.value), coursierFallbackDependencies.value, baseConfigGraphs)
}
val interProjectDependencies = coursierInterProjectDependencies.value val interProjectDependencies = coursierInterProjectDependencies.value
val parallelDownloads = coursierParallelDownloads.value val parallelDownloads = coursierParallelDownloads.value
val checksums = coursierChecksums.value val checksums = coursierChecksums.value
val maxIterations = coursierMaxIterations.value val maxIterations = coursierMaxIterations.value
val cachePolicies = coursierCachePolicies.value val cachePolicies = coursierCachePolicies.value
val ttl = coursierTtl.value val ttl = coursierTtl.value
val cache = coursierCache.value val cache = coursierCache.value
val log = streams.value.log val log = streams.value.log
// are these always defined? (e.g. for Java only projects?) // are these always defined? (e.g. for Java only projects?)
val so = scalaOrganization.value val so = scalaOrganization.value
val userForceVersions = dependencyOverrides.value.map( val userForceVersions = dependencyOverrides
FromSbt.moduleVersion(_, sv, sbv) .value
).toMap .map(FromSbt.moduleVersion(_, sv, sbv))
.toMap
val sbtResolvers = coursierSbtResolvers.value val resolversTask =
val defaultResolvers = coursierRecursiveResolvers.value if (sbtClassifiers)
Def.task(coursierSbtResolvers.value)
else
Def.task(coursierRecursiveResolvers.value.distinct)
val resolvers = val verbosityLevel = coursierVerbosity.value
if (sbtClassifiers)
sbtResolvers
else
defaultResolvers.distinct
val parentProjectCache: ProjectCache = coursierParentProjectCache.value val userEnabledProfiles = mavenProfiles.value
.get(resolvers)
.map(_.foldLeft[ProjectCache](Map.empty)(_ ++ _))
.getOrElse(Map.empty)
// TODO Warn about possible duplicated modules from source repositories? val typelevel = scalaOrganization.value == Typelevel.typelevelOrg
val verbosityLevel = coursierVerbosity.value val globalPluginsRepos =
for (p <- globalPluginPatterns(sbtBinaryVersion.value))
yield IvyRepository.fromPattern(
p,
withChecksums = false,
withSignatures = false,
withArtifacts = false
)
val userEnabledProfiles = mavenProfiles.value val interProjectRepo = InterProjectRepository(interProjectDependencies)
val typelevel = scalaOrganization.value == Typelevel.typelevelOrg val ivyHome = sys.props.getOrElse(
"ivy.home",
new File(sys.props("user.home")).toURI.getPath + ".ivy2"
)
if (verbosityLevel >= 2) { val sbtIvyHome = sys.props.getOrElse(
log.info("InterProjectRepository") "sbt.ivy.home",
for (p <- interProjectDependencies) ivyHome
log.info(s" ${p.module}:${p.version}") )
}
val globalPluginsRepos = val ivyProperties = Map(
for (p <- globalPluginPatterns(sbtBinaryVersion.value)) "ivy.home" -> ivyHome,
yield IvyRepository.fromPattern( "sbt.ivy.home" -> sbtIvyHome
p, ) ++ sys.props
withChecksums = false,
withSignatures = false,
withArtifacts = false
)
val interProjectRepo = InterProjectRepository(interProjectDependencies) val useSbtCredentials = coursierUseSbtCredentials.value
val ivyHome = sys.props.getOrElse( val authenticationByHostTask =
"ivy.home", if (useSbtCredentials)
new File(sys.props("user.home")).toURI.getPath + ".ivy2" Def.task {
) sbt.Keys.credentials.value
val sbtIvyHome = sys.props.getOrElse(
"sbt.ivy.home",
ivyHome
)
val ivyProperties = Map(
"ivy.home" -> ivyHome,
"sbt.ivy.home" -> sbtIvyHome
) ++ sys.props
val useSbtCredentials = coursierUseSbtCredentials.value
val sbtCreds = sbt.Keys.credentials.value
val authenticationByHost =
if (useSbtCredentials)
sbtCreds
.flatMap { .flatMap {
case dc: sbt.DirectCredentials => List(dc) case dc: sbt.DirectCredentials => List(dc)
case fc: sbt.FileCredentials => case fc: sbt.FileCredentials =>
@ -668,10 +660,24 @@ object Tasks {
c.host -> Authentication(c.userName, c.passwd) c.host -> Authentication(c.userName, c.passwd)
} }
.toMap .toMap
else }
Map.empty[String, Authentication] else
Def.task(Map.empty[String, Authentication])
val authenticationByRepositoryId = coursierCredentials.value.mapValues(_.authentication) val authenticationByRepositoryId = coursierCredentials.value.mapValues(_.authentication)
Def.task {
val (currentProject, fallbackDependencies, configGraphs) = currentProjectTask.value
val resolvers = resolversTask.value
val parentProjectCache: ProjectCache = coursierParentProjectCache.value
.get(resolvers)
.map(_.foldLeft[ProjectCache](Map.empty)(_ ++ _))
.getOrElse(Map.empty)
// TODO Warn about possible duplicated modules from source repositories?
val authenticationByHost = authenticationByHostTask.value
val fallbackDependenciesRepositories = val fallbackDependenciesRepositories =
if (fallbackDependencies.isEmpty) if (fallbackDependencies.isEmpty)
@ -687,6 +693,12 @@ object Tasks {
) )
} }
if (verbosityLevel >= 2) {
log.info("InterProjectRepository")
for (p <- interProjectDependencies)
log.info(s" ${p.module}:${p.version}")
}
def withAuthenticationByHost(repo: Repository, credentials: Map[String, Authentication]): Repository = { def withAuthenticationByHost(repo: Repository, credentials: Map[String, Authentication]): Repository = {
def httpHost(s: String) = def httpHost(s: String) =
@ -724,15 +736,15 @@ object Tasks {
val repositories = val repositories =
internalRepositories ++ internalRepositories ++
resolvers.flatMap { resolver => resolvers.flatMap { resolver =>
FromSbt.repository( FromSbt.repository(
resolver, resolver,
ivyProperties, ivyProperties,
log, log,
authenticationByRepositoryId.get(resolver.name) authenticationByRepositoryId.get(resolver.name)
) )
}.map(withAuthenticationByHost(_, authenticationByHost)) ++ }.map(withAuthenticationByHost(_, authenticationByHost)) ++
fallbackDependenciesRepositories fallbackDependenciesRepositories
def startRes(configs: Set[String]) = Resolution( def startRes(configs: Set[String]) = Resolution(
currentProject currentProject
@ -870,19 +882,24 @@ object Tasks {
val allStartRes = configGraphs.map(configs => configs -> startRes(configs)).toMap val allStartRes = configGraphs.map(configs => configs -> startRes(configs)).toMap
resolutionsCache.getOrElseUpdate( // let's update only one module at once, for a better output
ResolutionCacheKey( // Downloads are already parallel, no need to parallelize further anyway
currentProject, synchronized {
repositories,
userEnabledProfiles, resolutionsCache.getOrElseUpdate(
allStartRes, ResolutionCacheKey(
sbtClassifiers currentProject,
), repositories,
allStartRes.map { userEnabledProfiles,
case (config, startRes) => allStartRes,
config -> resolution(startRes) sbtClassifiers
} ),
) allStartRes.map {
case (config, startRes) =>
config -> resolution(startRes)
}
)
}
} }
} }
@ -891,47 +908,39 @@ object Tasks {
sbtClassifiers: Boolean = false, sbtClassifiers: Boolean = false,
ignoreArtifactErrors: Boolean = false, ignoreArtifactErrors: Boolean = false,
includeSignatures: Boolean = false includeSignatures: Boolean = false
) = Def.task { ) = Def.taskDyn {
// let's update only one module at once, for a better output val projectName = thisProjectRef.value.project
// Downloads are already parallel, no need to parallelize further anyway
synchronized {
lazy val cm = coursierSbtClassifiersModule.value val parallelDownloads = coursierParallelDownloads.value
val artifactsChecksums = coursierArtifactsChecksums.value
val cachePolicies = coursierCachePolicies.value
val ttl = coursierTtl.value
val cache = coursierCache.value
lazy val projectName = thisProjectRef.value.project val log = streams.value.log
val parallelDownloads = coursierParallelDownloads.value val verbosityLevel = coursierVerbosity.value
val artifactsChecksums = coursierArtifactsChecksums.value
val cachePolicies = coursierCachePolicies.value
val ttl = coursierTtl.value
val cache = coursierCache.value
val log = streams.value.log val resTask: sbt.Def.Initialize[sbt.Task[Seq[Resolution]]] =
if (withClassifiers && sbtClassifiers)
Def.task(Seq(coursierSbtClassifiersResolution.value))
else
Def.task(coursierResolutions.value.values.toVector)
val verbosityLevel = coursierVerbosity.value val classifiersTask: sbt.Def.Initialize[sbt.Task[Option[Seq[String]]]] =
if (withClassifiers) {
val classifiersRes = coursierSbtClassifiersResolution.value if (sbtClassifiers)
val mainRes = coursierResolutions.value Def.task(Some(coursierSbtClassifiersModule.value.classifiers))
val res =
if (withClassifiers && sbtClassifiers)
Seq(classifiersRes)
else else
mainRes.values.toVector Def.task(Some(transitiveClassifiers.value))
} else
Def.task(None)
val trClassifiers = transitiveClassifiers.value Def.task {
val classifiers = val classifiers = classifiersTask.value
if (withClassifiers) val res = resTask.value
Some {
if (sbtClassifiers)
cm.classifiers
else
trClassifiers
}
else
None
val allArtifacts0 = val allArtifacts0 =
classifiers match { classifiers match {
@ -948,64 +957,69 @@ object Tasks {
else else
allArtifacts0 allArtifacts0
var pool: ExecutorService = null // let's update only one module at once, for a better output
var artifactsLogger: TermDisplay = null // Downloads are already parallel, no need to parallelize further anyway
synchronized {
val printOptionalMessage = verbosityLevel >= 0 && verbosityLevel <= 1 var pool: ExecutorService = null
var artifactsLogger: TermDisplay = null
val artifactFilesOrErrors = try { val printOptionalMessage = verbosityLevel >= 0 && verbosityLevel <= 1
pool = Executors.newFixedThreadPool(parallelDownloads, Strategy.DefaultDaemonThreadFactory)
artifactsLogger = createLogger()
val artifactFileOrErrorTasks = allArtifacts.toVector.distinct.map { a => val artifactFilesOrErrors = try {
def f(p: CachePolicy) = pool = Executors.newFixedThreadPool(parallelDownloads, Strategy.DefaultDaemonThreadFactory)
Cache.file( artifactsLogger = createLogger()
a,
cache,
p,
checksums = artifactsChecksums,
logger = Some(artifactsLogger),
pool = pool,
ttl = ttl
)
cachePolicies.tail val artifactFileOrErrorTasks = allArtifacts.toVector.distinct.map { a =>
.foldLeft(f(cachePolicies.head))(_ orElse f(_)) def f(p: CachePolicy) =
.run Cache.file(
.map((a, _)) a,
} cache,
p,
checksums = artifactsChecksums,
logger = Some(artifactsLogger),
pool = pool,
ttl = ttl
)
val artifactInitialMessage = cachePolicies.tail
if (verbosityLevel >= 0) .foldLeft(f(cachePolicies.head))(_ orElse f(_))
s"Fetching artifacts of $projectName" + .run
(if (sbtClassifiers) " (sbt classifiers)" else "") .map((a, _))
else }
""
if (verbosityLevel >= 2) val artifactInitialMessage =
log.info(artifactInitialMessage) if (verbosityLevel >= 0)
s"Fetching artifacts of $projectName" +
artifactsLogger.init(if (printOptionalMessage) log.info(artifactInitialMessage))
Task.gatherUnordered(artifactFileOrErrorTasks).unsafePerformSyncAttempt match {
case -\/(ex) =>
ResolutionError.UnknownDownloadException(ex)
.throwException()
case \/-(l) =>
l.toMap
}
} finally {
if (pool != null)
pool.shutdown()
if (artifactsLogger != null)
if ((artifactsLogger.stopDidPrintSomething() && printOptionalMessage) || verbosityLevel >= 2)
log.info(
s"Fetched artifacts of $projectName" +
(if (sbtClassifiers) " (sbt classifiers)" else "") (if (sbtClassifiers) " (sbt classifiers)" else "")
) else
} ""
artifactFilesOrErrors if (verbosityLevel >= 2)
log.info(artifactInitialMessage)
artifactsLogger.init(if (printOptionalMessage) log.info(artifactInitialMessage))
Task.gatherUnordered(artifactFileOrErrorTasks).unsafePerformSyncAttempt match {
case -\/(ex) =>
ResolutionError.UnknownDownloadException(ex)
.throwException()
case \/-(l) =>
l.toMap
}
} finally {
if (pool != null)
pool.shutdown()
if (artifactsLogger != null)
if ((artifactsLogger.stopDidPrintSomething() && printOptionalMessage) || verbosityLevel >= 2)
log.info(
s"Fetched artifacts of $projectName" +
(if (sbtClassifiers) " (sbt classifiers)" else "")
)
}
artifactFilesOrErrors
}
} }
} }
@ -1088,7 +1102,7 @@ object Tasks {
sbtClassifiers: Boolean = false, sbtClassifiers: Boolean = false,
ignoreArtifactErrors: Boolean = false, ignoreArtifactErrors: Boolean = false,
includeSignatures: Boolean = false includeSignatures: Boolean = false
) = Def.task { ) = Def.taskDyn {
def grouped[K, V](map: Seq[(K, V)])(mapKey: K => K): Map[K, Seq[V]] = def grouped[K, V](map: Seq[(K, V)])(mapKey: K => K): Map[K, Seq[V]] =
map.groupBy { case (k, _) => mapKey(k) }.map { map.groupBy { case (k, _) => mapKey(k) }.map {
@ -1096,49 +1110,94 @@ object Tasks {
k -> l.map { case (_, v) => v } k -> l.map { case (_, v) => v }
} }
// let's update only one module at once, for a better output val so = scalaOrganization.value
// Downloads are already parallel, no need to parallelize further anyway val internalSbtScalaProvider = appConfiguration.value.provider.scalaProvider
synchronized { val sbtBootJarOverrides = SbtBootJars(
so, // this seems plain wrong - this assumes that the scala org of the project is the same
// as the one that started SBT. This will scrap the scala org specific JARs by the ones
// that booted SBT, even if the latter come from the standard org.scala-lang org.
// But SBT itself does it this way, and not doing so may make two different versions
// of the scala JARs land in the classpath...
internalSbtScalaProvider.version(),
internalSbtScalaProvider.jars()
)
val so = scalaOrganization.value val sv = scalaVersion.value
val internalSbtScalaProvider = appConfiguration.value.provider.scalaProvider val sbv = scalaBinaryVersion.value
val sbtBootJarOverrides = SbtBootJars(
so, // this seems plain wrong - this assumes that the scala org of the project is the same
// as the one that started SBT. This will scrap the scala org specific JARs by the ones
// that booted SBT, even if the latter come from the standard org.scala-lang org.
// But SBT itself does it this way, and not doing so may make two different versions
// of the scala JARs land in the classpath...
internalSbtScalaProvider.version(),
internalSbtScalaProvider.jars()
)
val cm = coursierSbtClassifiersModule.value val currentProjectTask =
if (sbtClassifiers)
Def.task(FromSbt.sbtClassifiersProject(coursierSbtClassifiersModule.value, sv, sbv))
else
Def.task {
val proj = coursierProject.value
val publications = coursierPublications.value
val sv = scalaVersion.value
val sbv = scalaBinaryVersion.value
val proj = coursierProject.value
val publications = coursierPublications.value
val currentProject =
if (sbtClassifiers)
FromSbt.sbtClassifiersProject(cm, sv, sbv)
else
proj.copy(publications = publications) proj.copy(publications = publications)
}
val log = streams.value.log val log = streams.value.log
val verbosityLevel = coursierVerbosity.value val verbosityLevel = coursierVerbosity.value
val classifiersRes = coursierSbtClassifiersResolution.value val resTask =
val mainRes = coursierResolutions.value if (withClassifiers && sbtClassifiers)
val configs0 = coursierConfigurations.value Def.task {
val cm = coursierSbtClassifiersModule.value
val res = val classifiersRes = coursierSbtClassifiersResolution.value
if (withClassifiers && sbtClassifiers)
Map(cm.configurations.map(c => c.name).toSet -> classifiersRes) Map(cm.configurations.map(c => c.name).toSet -> classifiersRes)
}
else
Def.task(coursierResolutions.value)
// we should be able to call .value on that one here, its conditions don't originate from other tasks
val artifactFilesOrErrors0Task =
if (withClassifiers) {
if (sbtClassifiers)
Keys.coursierSbtClassifiersArtifacts
else else
mainRes Keys.coursierClassifiersArtifacts
} else if (includeSignatures)
Keys.coursierSignedArtifacts
else
Keys.coursierArtifacts
val configsTask: sbt.Def.Initialize[sbt.Task[Map[String, Set[String]]]] =
if (withClassifiers && sbtClassifiers)
Def.task {
val cm = coursierSbtClassifiersModule.value
cm.configurations.map(c => c.name -> Set(c.name)).toMap
}
else
Def.task {
val configs0 = coursierConfigurations.value
shadedConfigOpt.fold(configs0) {
case (baseConfig, shadedConfig) =>
(configs0 - shadedConfig) + (
baseConfig -> (configs0.getOrElse(baseConfig, Set()) - shadedConfig)
)
}
}
val classifiersTask: sbt.Def.Initialize[sbt.Task[Option[Seq[String]]]] =
if (withClassifiers) {
if (sbtClassifiers)
Def.task {
val cm = coursierSbtClassifiersModule.value
Some(cm.classifiers)
}
else
Def.task(Some(transitiveClassifiers.value))
} else
Def.task(None)
Def.task {
val currentProject = currentProjectTask.value
val res = resTask.value
val artifactFilesOrErrors0 = artifactFilesOrErrors0Task.value
val classifiers = classifiersTask.value
val configs = configsTask.value
val configResolutions = res.flatMap { val configResolutions = res.flatMap {
case (configs, r) => case (configs, r) =>
@ -1157,17 +1216,6 @@ object Tasks {
} }
) )
val configs =
if (withClassifiers && sbtClassifiers)
cm.configurations.map(c => c.name -> Set(c.name)).toMap
else
shadedConfigOpt.fold(configs0) {
case (baseConfig, shadedConfig) =>
(configs0 - shadedConfig) + (
baseConfig -> (configs0.getOrElse(baseConfig, Set()) - shadedConfig)
)
}
if (verbosityLevel >= 2) { if (verbosityLevel >= 2) {
val finalDeps = dependenciesWithConfig( val finalDeps = dependenciesWithConfig(
configResolutions, configResolutions,
@ -1180,31 +1228,6 @@ object Tasks {
log.info(repr.split('\n').map(" " + _).mkString("\n")) log.info(repr.split('\n').map(" " + _).mkString("\n"))
} }
val trClassifiers = transitiveClassifiers.value
val classifiers =
if (withClassifiers)
Some {
if (sbtClassifiers)
cm.classifiers
else
trClassifiers
}
else
None
val artifactFilesOrErrors0 = (
if (withClassifiers) {
if (sbtClassifiers)
Keys.coursierSbtClassifiersArtifacts
else
Keys.coursierClassifiersArtifacts
} else if (includeSignatures)
Keys.coursierSignedArtifacts
else
Keys.coursierArtifacts
).value
val artifactFiles = artifactFilesOrErrors0.collect { val artifactFiles = artifactFilesOrErrors0.collect {
case (artifact, \/-(file)) => case (artifact, \/-(file)) =>
artifact -> file artifact -> file
@ -1251,16 +1274,21 @@ object Tasks {
) )
} }
reportsCache.getOrElseUpdate( // let's update only one module at once, for a better output
ReportCacheKey( // Downloads are already parallel, no need to parallelize further anyway
currentProject, synchronized {
res,
withClassifiers, reportsCache.getOrElseUpdate(
sbtClassifiers, ReportCacheKey(
ignoreArtifactErrors currentProject,
), res,
report withClassifiers,
) sbtClassifiers,
ignoreArtifactErrors
),
report
)
}
} }
} }
@ -1268,61 +1296,71 @@ object Tasks {
inverse: Boolean, inverse: Boolean,
sbtClassifiers: Boolean = false, sbtClassifiers: Boolean = false,
ignoreArtifactErrors: Boolean = false ignoreArtifactErrors: Boolean = false
) = Def.task { ) = Def.taskDyn {
lazy val projectName = thisProjectRef.value.project val projectName = thisProjectRef.value.project
val cm = coursierSbtClassifiersModule.value val currentProjectTask =
val sv = scalaVersion.value
val sbv = scalaBinaryVersion.value
val proj = coursierProject.value
val publications = coursierPublications.value
val currentProject =
if (sbtClassifiers) if (sbtClassifiers)
FromSbt.sbtClassifiersProject(cm, sv, sbv) Def.task {
val sv = scalaVersion.value
val sbv = scalaBinaryVersion.value
val cm = coursierSbtClassifiersModule.value
FromSbt.sbtClassifiersProject(cm, sv, sbv)
}
else else
proj.copy(publications = publications) Def.task {
val proj = coursierProject.value
val classifiersRes = coursierSbtClassifiersResolution.value val publications = coursierPublications.value
val mainRes = coursierResolutions.value proj.copy(publications = publications)
}
val resolutions =
if (sbtClassifiers)
Map(currentProject.configurations.keySet -> classifiersRes)
else
mainRes
val config = configuration.value.name val config = configuration.value.name
val configs = coursierConfigurations.value val configs = coursierConfigurations.value
val includedConfigs = configs.getOrElse(config, Set.empty) + config val includedConfigs = configs.getOrElse(config, Set.empty) + config
for { Def.taskDyn {
(subGraphConfigs, res) <- resolutions val currentProject = currentProjectTask.value
if subGraphConfigs.exists(includedConfigs)
} {
val dependencies0 = currentProject.dependencies.collect { val resolutionsTask =
case (cfg, dep) if includedConfigs(cfg) && subGraphConfigs(cfg) => dep if (sbtClassifiers)
}.sortBy { dep => Def.task {
(dep.module.organization, dep.module.name, dep.version) val classifiersRes = coursierSbtClassifiersResolution.value
} Map(currentProject.configurations.keySet -> classifiersRes)
}
else
Def.task(coursierResolutions.value)
val subRes = res.subset(dependencies0.toSet) Def.task {
val resolutions = resolutionsTask.value
// use sbt logging? for {
println( (subGraphConfigs, res) <- resolutions
s"$projectName (configurations ${subGraphConfigs.toVector.sorted.mkString(", ")})" + "\n" + if subGraphConfigs.exists(includedConfigs)
Print.dependencyTree( } {
dependencies0,
subRes, val dependencies0 = currentProject.dependencies.collect {
printExclusions = true, case (cfg, dep) if includedConfigs(cfg) && subGraphConfigs(cfg) => dep
inverse, }.sortBy { dep =>
colors = !sys.props.get("sbt.log.noformat").toSeq.contains("true") (dep.module.organization, dep.module.name, dep.version)
}
val subRes = res.subset(dependencies0.toSet)
// use sbt logging?
println(
s"$projectName (configurations ${subGraphConfigs.toVector.sorted.mkString(", ")})" + "\n" +
Print.dependencyTree(
dependencies0,
subRes,
printExclusions = true,
inverse,
colors = !sys.props.get("sbt.log.noformat").toSeq.contains("true")
)
) )
) }
}
} }
} }