From e688828f7acab254f469f9c5a29b63ac73a5a0c7 Mon Sep 17 00:00:00 2001 From: Alexandre Archambault Date: Tue, 31 May 2016 13:43:27 +0200 Subject: [PATCH] Keep resolution error infos in ad hoc ADT --- .../scala-2.10/coursier/ResolutionError.scala | 74 +++++++++++++++++++ .../coursier/ResolutionException.scala | 7 +- .../src/main/scala-2.10/coursier/Tasks.scala | 50 ++++--------- 3 files changed, 92 insertions(+), 39 deletions(-) create mode 100644 plugin/src/main/scala-2.10/coursier/ResolutionError.scala diff --git a/plugin/src/main/scala-2.10/coursier/ResolutionError.scala b/plugin/src/main/scala-2.10/coursier/ResolutionError.scala new file mode 100644 index 000000000..632249a95 --- /dev/null +++ b/plugin/src/main/scala-2.10/coursier/ResolutionError.scala @@ -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() + } + } +} diff --git a/plugin/src/main/scala-2.10/coursier/ResolutionException.scala b/plugin/src/main/scala-2.10/coursier/ResolutionException.scala index f59605eda..9f8925a91 100644 --- a/plugin/src/main/scala-2.10/coursier/ResolutionException.scala +++ b/plugin/src/main/scala-2.10/coursier/ResolutionException.scala @@ -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) ) diff --git a/plugin/src/main/scala-2.10/coursier/Tasks.scala b/plugin/src/main/scala-2.10/coursier/Tasks.scala index 21c786708..ed25b114f 100644 --- a/plugin/src/main/scala-2.10/coursier/Tasks.scala +++ b/plugin/src/main/scala-2.10/coursier/Tasks.scala @@ -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