mirror of https://github.com/sbt/sbt.git
Merge pull request #311 from alexarchambault/topic/develop
Various fixes
This commit is contained in:
commit
3a79f0a924
|
|
@ -3,7 +3,7 @@ package coursier
|
||||||
import java.io.{ OutputStreamWriter, File }
|
import java.io.{ OutputStreamWriter, File }
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
||||||
import java.util.concurrent.Executors
|
import java.util.concurrent.{ ExecutorService, Executors }
|
||||||
|
|
||||||
import coursier.core.{ Authentication, Publication }
|
import coursier.core.{ Authentication, Publication }
|
||||||
import coursier.ivy.IvyRepository
|
import coursier.ivy.IvyRepository
|
||||||
|
|
@ -225,6 +225,7 @@ object Tasks {
|
||||||
private case class ResolutionCacheKey(
|
private case class ResolutionCacheKey(
|
||||||
project: Project,
|
project: Project,
|
||||||
repositories: Seq[Repository],
|
repositories: Seq[Repository],
|
||||||
|
userEnabledProfiles: Set[String],
|
||||||
resolution: Resolution,
|
resolution: Resolution,
|
||||||
sbtClassifiers: Boolean
|
sbtClassifiers: Boolean
|
||||||
)
|
)
|
||||||
|
|
@ -255,6 +256,8 @@ object Tasks {
|
||||||
private def projectDescription(project: Project) =
|
private def projectDescription(project: Project) =
|
||||||
s"${project.module.organization}:${project.module.name}:${project.version}"
|
s"${project.module.organization}:${project.module.name}:${project.version}"
|
||||||
|
|
||||||
|
private def createLogger() = new TermDisplay(new OutputStreamWriter(System.err))
|
||||||
|
|
||||||
def resolutionTask(
|
def resolutionTask(
|
||||||
sbtClassifiers: Boolean = false
|
sbtClassifiers: Boolean = false
|
||||||
) = Def.task {
|
) = Def.task {
|
||||||
|
|
@ -492,108 +495,113 @@ object Tasks {
|
||||||
fallbackDependenciesRepositories
|
fallbackDependenciesRepositories
|
||||||
|
|
||||||
def resolution = {
|
def resolution = {
|
||||||
val pool = Executors.newFixedThreadPool(parallelDownloads, Strategy.DefaultDaemonThreadFactory)
|
var pool: ExecutorService = null
|
||||||
|
var resLogger: TermDisplay = null
|
||||||
|
|
||||||
def createLogger() = new TermDisplay(new OutputStreamWriter(System.err))
|
try {
|
||||||
|
pool = Executors.newFixedThreadPool(parallelDownloads, Strategy.DefaultDaemonThreadFactory)
|
||||||
|
resLogger = createLogger()
|
||||||
|
|
||||||
val resLogger = createLogger()
|
val fetch = Fetch.from(
|
||||||
|
repositories,
|
||||||
|
Cache.fetch(cache, cachePolicies.head, checksums = checksums, logger = Some(resLogger), pool = pool, ttl = ttl),
|
||||||
|
cachePolicies.tail.map(p =>
|
||||||
|
Cache.fetch(cache, p, checksums = checksums, logger = Some(resLogger), pool = pool, ttl = ttl)
|
||||||
|
): _*
|
||||||
|
)
|
||||||
|
|
||||||
val fetch = Fetch.from(
|
def depsRepr(deps: Seq[(String, Dependency)]) =
|
||||||
repositories,
|
deps.map { case (config, dep) =>
|
||||||
Cache.fetch(cache, cachePolicies.head, checksums = checksums, logger = Some(resLogger), pool = pool, ttl = ttl),
|
s"${dep.module}:${dep.version}:$config->${dep.configuration}"
|
||||||
cachePolicies.tail.map(p =>
|
}.sorted.distinct
|
||||||
Cache.fetch(cache, p, checksums = checksums, logger = Some(resLogger), pool = pool, ttl = ttl)
|
|
||||||
): _*
|
|
||||||
)
|
|
||||||
|
|
||||||
def depsRepr(deps: Seq[(String, Dependency)]) =
|
if (verbosityLevel >= 2) {
|
||||||
deps.map { case (config, dep) =>
|
val repoReprs = repositories.map {
|
||||||
s"${dep.module}:${dep.version}:$config->${dep.configuration}"
|
case r: IvyRepository =>
|
||||||
}.sorted.distinct
|
s"ivy:${r.pattern}"
|
||||||
|
case r: InterProjectRepository =>
|
||||||
|
"inter-project"
|
||||||
|
case r: MavenRepository =>
|
||||||
|
r.root
|
||||||
|
case r =>
|
||||||
|
// should not happen
|
||||||
|
r.toString
|
||||||
|
}
|
||||||
|
|
||||||
if (verbosityLevel >= 2) {
|
log.info(
|
||||||
val repoReprs = repositories.map {
|
"Repositories:\n" +
|
||||||
case r: IvyRepository =>
|
repoReprs.map(" " + _).mkString("\n")
|
||||||
s"ivy:${r.pattern}"
|
)
|
||||||
case r: InterProjectRepository =>
|
|
||||||
"inter-project"
|
|
||||||
case r: MavenRepository =>
|
|
||||||
r.root
|
|
||||||
case r =>
|
|
||||||
// should not happen
|
|
||||||
r.toString
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info(
|
if (verbosityLevel >= 0)
|
||||||
"Repositories:\n" +
|
log.info(
|
||||||
repoReprs.map(" " + _).mkString("\n")
|
s"Updating ${projectDescription(currentProject)}" +
|
||||||
)
|
(if (sbtClassifiers) " (sbt classifiers)" else "")
|
||||||
}
|
)
|
||||||
|
if (verbosityLevel >= 2)
|
||||||
|
for (depRepr <- depsRepr(currentProject.dependencies))
|
||||||
|
log.info(s" $depRepr")
|
||||||
|
|
||||||
if (verbosityLevel >= 0)
|
resLogger.init()
|
||||||
log.info(
|
|
||||||
s"Updating ${projectDescription(currentProject)}" +
|
|
||||||
(if (sbtClassifiers) " (sbt classifiers)" else "")
|
|
||||||
)
|
|
||||||
if (verbosityLevel >= 2)
|
|
||||||
for (depRepr <- depsRepr(currentProject.dependencies))
|
|
||||||
log.info(s" $depRepr")
|
|
||||||
|
|
||||||
resLogger.init()
|
val res = startRes
|
||||||
|
.process
|
||||||
|
.run(fetch, maxIterations)
|
||||||
|
.attemptRun
|
||||||
|
.leftMap(ex =>
|
||||||
|
ResolutionError.UnknownException(ex)
|
||||||
|
.throwException()
|
||||||
|
)
|
||||||
|
.merge
|
||||||
|
|
||||||
val res = startRes
|
if (!res.isDone)
|
||||||
.process
|
ResolutionError.MaximumIterationsReached
|
||||||
.run(fetch, maxIterations)
|
|
||||||
.attemptRun
|
|
||||||
.leftMap(ex =>
|
|
||||||
ResolutionError.UnknownException(ex)
|
|
||||||
.throwException()
|
.throwException()
|
||||||
)
|
|
||||||
.merge
|
|
||||||
|
|
||||||
resLogger.stop()
|
if (res.conflicts.nonEmpty) {
|
||||||
|
val projCache = res.projectCache.mapValues { case (_, p) => p }
|
||||||
|
|
||||||
|
ResolutionError.Conflicts(
|
||||||
|
"Conflict(s) in dependency resolution:\n " +
|
||||||
|
Print.dependenciesUnknownConfigs(res.conflicts.toVector, projCache)
|
||||||
|
).throwException()
|
||||||
|
}
|
||||||
|
|
||||||
if (!res.isDone)
|
if (res.errors.nonEmpty) {
|
||||||
ResolutionError.MaximumIterationsReached
|
val internalRepositoriesLen = internalRepositories.length
|
||||||
.throwException()
|
val errors =
|
||||||
|
if (repositories.length > internalRepositoriesLen)
|
||||||
if (res.conflicts.nonEmpty) {
|
|
||||||
val projCache = res.projectCache.mapValues { case (_, p) => p }
|
|
||||||
|
|
||||||
ResolutionError.Conflicts(
|
|
||||||
"Conflict(s) in dependency resolution:\n " +
|
|
||||||
Print.dependenciesUnknownConfigs(res.conflicts.toVector, projCache)
|
|
||||||
).throwException()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (res.errors.nonEmpty) {
|
|
||||||
val internalRepositoriesLen = internalRepositories.length
|
|
||||||
val errors =
|
|
||||||
if (repositories.length > internalRepositoriesLen)
|
|
||||||
// drop internal repository errors
|
// drop internal repository errors
|
||||||
res.errors.map {
|
res.errors.map {
|
||||||
case (dep, errs) =>
|
case (dep, errs) =>
|
||||||
dep -> errs.drop(internalRepositoriesLen)
|
dep -> errs.drop(internalRepositoriesLen)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
res.errors
|
res.errors
|
||||||
|
|
||||||
ResolutionError.MetadataDownloadErrors(errors)
|
ResolutionError.MetadataDownloadErrors(errors)
|
||||||
.throwException()
|
.throwException()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (verbosityLevel >= 0)
|
||||||
|
log.info(s"Resolved ${projectDescription(currentProject)} dependencies")
|
||||||
|
|
||||||
|
res
|
||||||
|
} finally {
|
||||||
|
if (pool != null)
|
||||||
|
pool.shutdown()
|
||||||
|
if (resLogger != null)
|
||||||
|
resLogger.stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (verbosityLevel >= 0)
|
|
||||||
log.info(s"Resolved ${projectDescription(currentProject)} dependencies")
|
|
||||||
|
|
||||||
res
|
|
||||||
}
|
}
|
||||||
|
|
||||||
resolutionsCache.getOrElseUpdate(
|
resolutionsCache.getOrElseUpdate(
|
||||||
ResolutionCacheKey(
|
ResolutionCacheKey(
|
||||||
currentProject,
|
currentProject,
|
||||||
repositories,
|
repositories,
|
||||||
startRes.copy(filter = None),
|
userEnabledProfiles,
|
||||||
|
startRes.copy(filter = None, profileActivation = None),
|
||||||
sbtClassifiers
|
sbtClassifiers
|
||||||
),
|
),
|
||||||
resolution
|
resolution
|
||||||
|
|
@ -687,138 +695,144 @@ object Tasks {
|
||||||
}.value
|
}.value
|
||||||
|
|
||||||
def report = {
|
def report = {
|
||||||
val pool = Executors.newFixedThreadPool(parallelDownloads, Strategy.DefaultDaemonThreadFactory)
|
var pool: ExecutorService = null
|
||||||
|
var artifactsLogger: TermDisplay = null
|
||||||
|
|
||||||
def createLogger() = new TermDisplay(new OutputStreamWriter(System.err))
|
try {
|
||||||
|
pool = Executors.newFixedThreadPool(parallelDownloads, Strategy.DefaultDaemonThreadFactory)
|
||||||
|
|
||||||
val depsByConfig = grouped(currentProject.dependencies)
|
val depsByConfig = grouped(currentProject.dependencies)
|
||||||
|
|
||||||
val configs = coursierConfigurations.value
|
val configs = coursierConfigurations.value
|
||||||
|
|
||||||
if (verbosityLevel >= 2) {
|
if (verbosityLevel >= 2) {
|
||||||
val finalDeps = Config.dependenciesWithConfig(
|
val finalDeps = Config.dependenciesWithConfig(
|
||||||
res,
|
res,
|
||||||
depsByConfig.map { case (k, l) => k -> l.toSet },
|
depsByConfig.map { case (k, l) => k -> l.toSet },
|
||||||
configs
|
configs
|
||||||
)
|
|
||||||
|
|
||||||
val projCache = res.projectCache.mapValues { case (_, p) => p }
|
|
||||||
val repr = Print.dependenciesUnknownConfigs(finalDeps.toVector, projCache)
|
|
||||||
log.info(repr.split('\n').map(" "+_).mkString("\n"))
|
|
||||||
}
|
|
||||||
|
|
||||||
val classifiers =
|
|
||||||
if (withClassifiers)
|
|
||||||
Some {
|
|
||||||
if (sbtClassifiers)
|
|
||||||
cm.classifiers
|
|
||||||
else
|
|
||||||
transitiveClassifiers.value
|
|
||||||
}
|
|
||||||
else
|
|
||||||
None
|
|
||||||
|
|
||||||
val allArtifacts =
|
|
||||||
classifiers match {
|
|
||||||
case None => res.artifacts
|
|
||||||
case Some(cl) => res.classifiersArtifacts(cl)
|
|
||||||
}
|
|
||||||
|
|
||||||
val artifactsLogger = createLogger()
|
|
||||||
|
|
||||||
val artifactFileOrErrorTasks = allArtifacts.toVector.map { a =>
|
|
||||||
def f(p: CachePolicy) =
|
|
||||||
Cache.file(
|
|
||||||
a,
|
|
||||||
cache,
|
|
||||||
p,
|
|
||||||
checksums = artifactsChecksums,
|
|
||||||
logger = Some(artifactsLogger),
|
|
||||||
pool = pool,
|
|
||||||
ttl = ttl
|
|
||||||
)
|
)
|
||||||
|
|
||||||
cachePolicies.tail
|
val projCache = res.projectCache.mapValues { case (_, p) => p }
|
||||||
.foldLeft(f(cachePolicies.head))(_ orElse f(_))
|
val repr = Print.dependenciesUnknownConfigs(finalDeps.toVector, projCache)
|
||||||
.run
|
log.info(repr.split('\n').map(" " + _).mkString("\n"))
|
||||||
.map((a, _))
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (verbosityLevel >= 0)
|
val classifiers =
|
||||||
log.info(
|
if (withClassifiers)
|
||||||
s"Fetching artifacts of ${projectDescription(currentProject)}" +
|
Some {
|
||||||
(if (sbtClassifiers) " (sbt classifiers)" else "")
|
if (sbtClassifiers)
|
||||||
|
cm.classifiers
|
||||||
|
else
|
||||||
|
transitiveClassifiers.value
|
||||||
|
}
|
||||||
|
else
|
||||||
|
None
|
||||||
|
|
||||||
|
val allArtifacts =
|
||||||
|
classifiers match {
|
||||||
|
case None => res.artifacts
|
||||||
|
case Some(cl) => res.classifiersArtifacts(cl)
|
||||||
|
}
|
||||||
|
|
||||||
|
artifactsLogger = createLogger()
|
||||||
|
|
||||||
|
val artifactFileOrErrorTasks = allArtifacts.toVector.map { a =>
|
||||||
|
def f(p: CachePolicy) =
|
||||||
|
Cache.file(
|
||||||
|
a,
|
||||||
|
cache,
|
||||||
|
p,
|
||||||
|
checksums = artifactsChecksums,
|
||||||
|
logger = Some(artifactsLogger),
|
||||||
|
pool = pool,
|
||||||
|
ttl = ttl
|
||||||
|
)
|
||||||
|
|
||||||
|
cachePolicies.tail
|
||||||
|
.foldLeft(f(cachePolicies.head))(_ orElse f(_))
|
||||||
|
.run
|
||||||
|
.map((a, _))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (verbosityLevel >= 0)
|
||||||
|
log.info(
|
||||||
|
s"Fetching artifacts of ${projectDescription(currentProject)}" +
|
||||||
|
(if (sbtClassifiers) " (sbt classifiers)" else "")
|
||||||
|
)
|
||||||
|
|
||||||
|
artifactsLogger.init()
|
||||||
|
|
||||||
|
val artifactFilesOrErrors = Task.gatherUnordered(artifactFileOrErrorTasks).attemptRun match {
|
||||||
|
case -\/(ex) =>
|
||||||
|
ResolutionError.UnknownDownloadException(ex)
|
||||||
|
.throwException()
|
||||||
|
case \/-(l) =>
|
||||||
|
l.toMap
|
||||||
|
}
|
||||||
|
|
||||||
|
if (verbosityLevel >= 0)
|
||||||
|
log.info(
|
||||||
|
s"Fetched artifacts of ${projectDescription(currentProject)}" +
|
||||||
|
(if (sbtClassifiers) " (sbt classifiers)" else "")
|
||||||
|
)
|
||||||
|
|
||||||
|
val artifactFiles = artifactFilesOrErrors.collect {
|
||||||
|
case (artifact, \/-(file)) =>
|
||||||
|
artifact -> file
|
||||||
|
}
|
||||||
|
|
||||||
|
val artifactErrors = artifactFilesOrErrors.toVector.collect {
|
||||||
|
case (_, -\/(err)) =>
|
||||||
|
err
|
||||||
|
}
|
||||||
|
|
||||||
|
if (artifactErrors.nonEmpty) {
|
||||||
|
val error = ResolutionError.DownloadErrors(artifactErrors)
|
||||||
|
|
||||||
|
if (ignoreArtifactErrors)
|
||||||
|
log.warn(error.description(verbosityLevel >= 1))
|
||||||
|
else
|
||||||
|
error.throwException()
|
||||||
|
}
|
||||||
|
|
||||||
|
// can be non empty only if ignoreArtifactErrors is true
|
||||||
|
val erroredArtifacts = artifactFilesOrErrors.collect {
|
||||||
|
case (artifact, -\/(_)) =>
|
||||||
|
artifact
|
||||||
|
}.toSet
|
||||||
|
|
||||||
|
def artifactFileOpt(artifact: Artifact) = {
|
||||||
|
val artifact0 = artifact
|
||||||
|
.copy(attributes = Attributes()) // temporary hack :-(
|
||||||
|
val res = artifactFiles.get(artifact0)
|
||||||
|
|
||||||
|
if (res.isEmpty && !erroredArtifacts(artifact0))
|
||||||
|
log.error(s"${artifact.url} not downloaded (should not happen)")
|
||||||
|
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
writeIvyFiles()
|
||||||
|
|
||||||
|
ToSbt.updateReport(
|
||||||
|
depsByConfig,
|
||||||
|
res,
|
||||||
|
configs,
|
||||||
|
classifiers,
|
||||||
|
artifactFileOpt
|
||||||
)
|
)
|
||||||
|
} finally {
|
||||||
artifactsLogger.init()
|
if (pool != null)
|
||||||
|
pool.shutdown()
|
||||||
val artifactFilesOrErrors = Task.gatherUnordered(artifactFileOrErrorTasks).attemptRun match {
|
if (artifactsLogger != null)
|
||||||
case -\/(ex) =>
|
artifactsLogger.stop()
|
||||||
ResolutionError.UnknownDownloadException(ex)
|
|
||||||
.throwException()
|
|
||||||
case \/-(l) =>
|
|
||||||
l.toMap
|
|
||||||
}
|
}
|
||||||
|
|
||||||
artifactsLogger.stop()
|
|
||||||
|
|
||||||
if (verbosityLevel >= 0)
|
|
||||||
log.info(
|
|
||||||
s"Fetched artifacts of ${projectDescription(currentProject)}" +
|
|
||||||
(if (sbtClassifiers) " (sbt classifiers)" else "")
|
|
||||||
)
|
|
||||||
|
|
||||||
val artifactFiles = artifactFilesOrErrors.collect {
|
|
||||||
case (artifact, \/-(file)) =>
|
|
||||||
artifact -> file
|
|
||||||
}
|
|
||||||
|
|
||||||
val artifactErrors = artifactFilesOrErrors.toVector.collect {
|
|
||||||
case (_, -\/(err)) =>
|
|
||||||
err
|
|
||||||
}
|
|
||||||
|
|
||||||
if (artifactErrors.nonEmpty) {
|
|
||||||
val error = ResolutionError.DownloadErrors(artifactErrors)
|
|
||||||
|
|
||||||
if (ignoreArtifactErrors)
|
|
||||||
log.warn(error.description(verbosityLevel >= 1))
|
|
||||||
else
|
|
||||||
error.throwException()
|
|
||||||
}
|
|
||||||
|
|
||||||
// can be non empty only if ignoreArtifactErrors is true
|
|
||||||
val erroredArtifacts = artifactFilesOrErrors.collect {
|
|
||||||
case (artifact, -\/(_)) =>
|
|
||||||
artifact
|
|
||||||
}.toSet
|
|
||||||
|
|
||||||
def artifactFileOpt(artifact: Artifact) = {
|
|
||||||
val artifact0 = artifact
|
|
||||||
.copy(attributes = Attributes()) // temporary hack :-(
|
|
||||||
val res = artifactFiles.get(artifact0)
|
|
||||||
|
|
||||||
if (res.isEmpty && !erroredArtifacts(artifact0))
|
|
||||||
log.error(s"${artifact.url} not downloaded (should not happen)")
|
|
||||||
|
|
||||||
res
|
|
||||||
}
|
|
||||||
|
|
||||||
writeIvyFiles()
|
|
||||||
|
|
||||||
ToSbt.updateReport(
|
|
||||||
depsByConfig,
|
|
||||||
res,
|
|
||||||
configs,
|
|
||||||
classifiers,
|
|
||||||
artifactFileOpt
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
reportsCache.getOrElseUpdate(
|
reportsCache.getOrElseUpdate(
|
||||||
ReportCacheKey(
|
ReportCacheKey(
|
||||||
currentProject,
|
currentProject,
|
||||||
res,
|
res.copy(filter = None, profileActivation = None),
|
||||||
withClassifiers,
|
withClassifiers,
|
||||||
sbtClassifiers
|
sbtClassifiers
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ package test
|
||||||
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.math.BigInteger
|
import java.math.BigInteger
|
||||||
import java.util.concurrent.Executors
|
|
||||||
|
|
||||||
import utest._
|
import utest._
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue