mirror of https://github.com/sbt/sbt.git
Keep resolution error infos in ad hoc ADT
This commit is contained in:
parent
201ef286db
commit
e688828f7a
|
|
@ -0,0 +1,74 @@
|
|||
package coursier
|
||||
|
||||
sealed abstract class ResolutionError extends Product with Serializable {
|
||||
def cause: Option[Throwable] = this match {
|
||||
case ResolutionError.MaximumIterationsReached => None
|
||||
case ResolutionError.UnknownException(ex) => Some(ex)
|
||||
case ResolutionError.UnknownDownloadException(ex) => Some(ex)
|
||||
case _: ResolutionError.Conflicts => None
|
||||
case _: ResolutionError.MetadataDownloadErrors => None
|
||||
case _: ResolutionError.DownloadErrors => None
|
||||
}
|
||||
|
||||
def message: String = this match {
|
||||
case ResolutionError.MaximumIterationsReached =>
|
||||
"Maximum number of iteration of dependency resolution reached"
|
||||
case ResolutionError.UnknownException(ex) =>
|
||||
"Exception during resolution"
|
||||
case ResolutionError.UnknownDownloadException(ex) =>
|
||||
"Error while downloading / verifying artifacts"
|
||||
case ResolutionError.Conflicts(description) =>
|
||||
description
|
||||
|
||||
case ResolutionError.MetadataDownloadErrors(errors) =>
|
||||
s"Encountered ${errors.length} error(s) in dependency resolution:\n" +
|
||||
errors.map {
|
||||
case (dep, errs) =>
|
||||
s" ${dep.module}:${dep.version}:\n" +
|
||||
errs
|
||||
.map(" " + _.replace("\n", " \n"))
|
||||
.mkString("\n")
|
||||
}.mkString("\n")
|
||||
|
||||
case err: ResolutionError.DownloadErrors =>
|
||||
err.description(verbose = true)
|
||||
}
|
||||
|
||||
def exception(): ResolutionException =
|
||||
new ResolutionException(this)
|
||||
|
||||
def throwException(): Nothing =
|
||||
throw exception()
|
||||
}
|
||||
|
||||
object ResolutionError {
|
||||
|
||||
case object MaximumIterationsReached extends ResolutionError
|
||||
case class UnknownException(ex: Throwable) extends ResolutionError
|
||||
case class UnknownDownloadException(ex: Throwable) extends ResolutionError
|
||||
case class Conflicts(description: String) extends ResolutionError
|
||||
case class MetadataDownloadErrors(errors: Seq[(Dependency, Seq[String])]) extends ResolutionError
|
||||
|
||||
case class DownloadErrors(errors: Seq[FileError]) extends ResolutionError {
|
||||
|
||||
def description(verbose: Boolean): String = {
|
||||
|
||||
val groupedArtifactErrors = errors
|
||||
.groupBy(_.`type`)
|
||||
.mapValues(_.map(_.message).sorted)
|
||||
.toVector
|
||||
.sortBy(_._1)
|
||||
|
||||
val b = new StringBuilder
|
||||
|
||||
for ((type0, errors) <- groupedArtifactErrors) {
|
||||
b ++= s"${errors.size} $type0"
|
||||
if (verbose)
|
||||
for (err <- errors)
|
||||
b ++= " " + err
|
||||
}
|
||||
|
||||
b.result()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,10 @@
|
|||
package coursier
|
||||
|
||||
final class ResolutionException(
|
||||
val message: String,
|
||||
val cause: Throwable = null
|
||||
val error: ResolutionError
|
||||
) extends Exception(
|
||||
message,
|
||||
cause,
|
||||
error.message,
|
||||
error.cause.orNull,
|
||||
true,
|
||||
false // don't keep stack trace around (improves readability from the SBT console)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -506,35 +506,31 @@ object Tasks {
|
|||
.process
|
||||
.run(fetch, maxIterations)
|
||||
.attemptRun
|
||||
.leftMap(ex => throw new ResolutionException("Exception during resolution", ex))
|
||||
.leftMap(ex =>
|
||||
ResolutionError.UnknownException(ex)
|
||||
.throwException()
|
||||
)
|
||||
.merge
|
||||
|
||||
resLogger.stop()
|
||||
|
||||
|
||||
if (!res.isDone)
|
||||
throw new ResolutionException("Maximum number of iteration of dependency resolution reached")
|
||||
ResolutionError.MaximumIterationsReached
|
||||
.throwException()
|
||||
|
||||
if (res.conflicts.nonEmpty) {
|
||||
val projCache = res.projectCache.mapValues { case (_, p) => p }
|
||||
|
||||
throw new ResolutionException(
|
||||
ResolutionError.Conflicts(
|
||||
"Conflict(s) in dependency resolution:\n " +
|
||||
Print.dependenciesUnknownConfigs(res.conflicts.toVector, projCache)
|
||||
)
|
||||
).throwException()
|
||||
}
|
||||
|
||||
if (res.errors.nonEmpty)
|
||||
throw new ResolutionException(
|
||||
s"Encountered ${res.errors.length} error(s) in dependency resolution:\n" +
|
||||
res.errors.map {
|
||||
case (dep, errs) =>
|
||||
s" ${dep.module}:${dep.version}:\n" +
|
||||
errs
|
||||
.map(" " + _.replace("\n", " \n"))
|
||||
.mkString("\n")
|
||||
}.mkString("\n")
|
||||
)
|
||||
ResolutionError.MetadataDownloadErrors(res.errors)
|
||||
.throwException()
|
||||
|
||||
if (verbosityLevel >= 0)
|
||||
log.info(s"Resolved ${projectDescription(currentProject)} dependencies")
|
||||
|
|
@ -703,7 +699,8 @@ object Tasks {
|
|||
|
||||
val artifactFilesOrErrors = Task.gatherUnordered(artifactFileOrErrorTasks).attemptRun match {
|
||||
case -\/(ex) =>
|
||||
throw new ResolutionException("Error while downloading / verifying artifacts", ex)
|
||||
ResolutionError.UnknownDownloadException(ex)
|
||||
.throwException()
|
||||
case \/-(l) =>
|
||||
l.toMap
|
||||
}
|
||||
|
|
@ -727,29 +724,12 @@ object Tasks {
|
|||
}
|
||||
|
||||
if (artifactErrors.nonEmpty) {
|
||||
val groupedArtifactErrors = artifactErrors
|
||||
.groupBy(_.`type`)
|
||||
.mapValues(_.map(_.message).sorted)
|
||||
.toVector
|
||||
.sortBy(_._1)
|
||||
|
||||
val b = new StringBuilder
|
||||
|
||||
for ((type0, errors) <- groupedArtifactErrors) {
|
||||
def msg = s"${errors.size} $type0"
|
||||
b ++= msg
|
||||
|
||||
if (!ignoreArtifactErrors || verbosityLevel >= 1)
|
||||
for (err <- errors)
|
||||
b ++= " " + err
|
||||
}
|
||||
val error = ResolutionError.DownloadErrors(artifactErrors)
|
||||
|
||||
if (ignoreArtifactErrors)
|
||||
log.warn(b.result())
|
||||
log.warn(error.description(verbosityLevel >= 1))
|
||||
else
|
||||
throw new ResolutionException(
|
||||
s"Encountered ${artifactErrors.length} errors:\n" + b.result()
|
||||
)
|
||||
error.throwException()
|
||||
}
|
||||
|
||||
// can be non empty only if ignoreArtifactErrors is true
|
||||
|
|
|
|||
Loading…
Reference in New Issue