From f73dac68fd04fa408f81481ef919117d76ff4dcc Mon Sep 17 00:00:00 2001 From: Alexandre Archambault Date: Tue, 5 Apr 2016 16:24:39 +0200 Subject: [PATCH] Try not flooding the terminal with ignored errors... ...in updateClassifiers. Also fail if an artifact cannot be fetched in update. A bit risky - might unveil locked errors, that ought to be circumvented. --- build.sbt | 4 ++ cache/src/main/scala/coursier/FileError.scala | 45 ++++++++++++--- .../scala-2.10/coursier/CoursierPlugin.scala | 4 +- .../main/scala-2.10/coursier/Settings.scala | 6 +- .../src/main/scala-2.10/coursier/Tasks.scala | 56 ++++++++++++++----- 5 files changed, 88 insertions(+), 27 deletions(-) diff --git a/build.sbt b/build.sbt index 4c19e46ec..ef12e0509 100644 --- a/build.sbt +++ b/build.sbt @@ -226,6 +226,10 @@ lazy val cache = project import com.typesafe.tools.mima.core.ProblemFilters._ Seq( + // Since 1.0.0-M11 + // Add constructor parameter on FileError - shouldn't be built by users anyway + ProblemFilters.exclude[MissingMethodProblem]("coursier.FileError.this"), + ProblemFilters.exclude[MissingMethodProblem]("coursier.FileError#Recoverable.this"), // Since 1.0.0-M10 // methods that should have been private anyway ProblemFilters.exclude[MissingMethodProblem]("coursier.TermDisplay.update"), diff --git a/cache/src/main/scala/coursier/FileError.scala b/cache/src/main/scala/coursier/FileError.scala index 4386a0e98..f1a3bce34 100644 --- a/cache/src/main/scala/coursier/FileError.scala +++ b/cache/src/main/scala/coursier/FileError.scala @@ -2,26 +2,41 @@ package coursier import java.io.File -sealed abstract class FileError(val message: String) extends Product with Serializable +sealed abstract class FileError( + val `type`: String, + val message: String +) extends Product with Serializable object FileError { - final case class DownloadError(reason: String) extends FileError(s"Download error: $reason") + final case class DownloadError(reason: String) extends FileError( + "download error", + reason + ) final case class NotFound( file: String, permanent: Option[Boolean] = None - ) extends FileError(s"Not found: $file") + ) extends FileError( + "not found", + file + ) final case class ChecksumNotFound( sumType: String, file: String - ) extends FileError(s"$sumType checksum not found: $file") + ) extends FileError( + "checksum not found", + file + ) final case class ChecksumFormatError( sumType: String, file: String - ) extends FileError(s"Unrecognized $sumType checksum format in $file") + ) extends FileError( + "checksum format error", + file + ) final case class WrongChecksum( sumType: String, @@ -29,10 +44,22 @@ object FileError { expected: String, file: String, sumFile: String - ) extends FileError(s"$sumType checksum validation failed: $file") + ) extends FileError( + "wrong checksum", + file + ) - sealed abstract class Recoverable(message: String) extends FileError(message) - final case class Locked(file: File) extends Recoverable(s"Locked: $file") - final case class ConcurrentDownload(url: String) extends Recoverable(s"Concurrent download: $url") + sealed abstract class Recoverable( + `type`: String, + message: String + ) extends FileError(`type`, message) + final case class Locked(file: File) extends Recoverable( + "locked", + file.toString + ) + final case class ConcurrentDownload(url: String) extends Recoverable( + "concurrent download", + url + ) } diff --git a/plugin/src/main/scala-2.10/coursier/CoursierPlugin.scala b/plugin/src/main/scala-2.10/coursier/CoursierPlugin.scala index 308295082..548a6077f 100644 --- a/plugin/src/main/scala-2.10/coursier/CoursierPlugin.scala +++ b/plugin/src/main/scala-2.10/coursier/CoursierPlugin.scala @@ -1,7 +1,5 @@ package coursier -import java.io.File - import sbt._ import sbt.Keys._ @@ -43,7 +41,7 @@ object CoursierPlugin extends AutoPlugin { coursierFallbackDependencies <<= Tasks.coursierFallbackDependenciesTask, coursierCache := Cache.default, update <<= Tasks.updateTask(withClassifiers = false), - updateClassifiers <<= Tasks.updateTask(withClassifiers = true), + updateClassifiers <<= Tasks.updateTask(withClassifiers = true, ignoreArtifactErrors = true), updateSbtClassifiers in Defaults.TaskGlobal <<= Tasks.updateTask(withClassifiers = true, sbtClassifiers = true), coursierProject <<= Tasks.coursierProjectTask, coursierProjects <<= Tasks.coursierProjectsTask, diff --git a/plugin/src/main/scala-2.10/coursier/Settings.scala b/plugin/src/main/scala-2.10/coursier/Settings.scala index 2a63999be..a62f8899e 100644 --- a/plugin/src/main/scala-2.10/coursier/Settings.scala +++ b/plugin/src/main/scala-2.10/coursier/Settings.scala @@ -4,7 +4,11 @@ import scala.util.{Failure, Success, Try} object Settings { - private val baseDefaultVerbosityLevel = 0 + private lazy val baseDefaultVerbosityLevel = + if (System.console() == null) // non interactive mode + 0 + else + 1 def defaultVerbosityLevel: Int = { diff --git a/plugin/src/main/scala-2.10/coursier/Tasks.scala b/plugin/src/main/scala-2.10/coursier/Tasks.scala index 49d3af66c..7c4c3e175 100644 --- a/plugin/src/main/scala-2.10/coursier/Tasks.scala +++ b/plugin/src/main/scala-2.10/coursier/Tasks.scala @@ -185,7 +185,11 @@ object Tasks { Module("org.scala-lang", "scalap") -> scalaVersion ) - def updateTask(withClassifiers: Boolean, sbtClassifiers: Boolean = false) = Def.task { + def updateTask( + withClassifiers: Boolean, + sbtClassifiers: Boolean = false, + ignoreArtifactErrors: Boolean = false + ) = Def.task { def grouped[K, V](map: Seq[(K, V)]): Map[K, Seq[V]] = map.groupBy { case (k, _) => k }.map { @@ -375,7 +379,7 @@ object Tasks { s"${dep.module}:${dep.version}:${dep.configuration}" }.sorted.distinct - if (verbosityLevel >= 1) { + if (verbosityLevel >= 2) { val repoReprs = repositories.map { case r: IvyRepository => s"ivy:${r.pattern}" @@ -396,7 +400,7 @@ object Tasks { if (verbosityLevel >= 0) log.info(s"Resolving ${currentProject.module.organization}:${currentProject.module.name}:${currentProject.version}") - if (verbosityLevel >= 1) + if (verbosityLevel >= 2) for (depRepr <- depsRepr(currentProject.dependencies)) log.info(s" $depRepr") @@ -467,7 +471,7 @@ object Tasks { if (verbosityLevel >= 0) log.info("Resolution done") - if (verbosityLevel >= 1) { + if (verbosityLevel >= 2) { val finalDeps = Config.dependenciesWithConfig( res, depsByConfig.map { case (k, l) => k -> l.toSet }, @@ -532,18 +536,42 @@ object Tasks { if (verbosityLevel >= 0) log.info("Fetching artifacts: done") - def artifactFileOpt(artifact: Artifact) = { - val fileOrError = artifactFilesOrErrors.getOrElse(artifact, -\/("Not downloaded")) + val artifactFiles = artifactFilesOrErrors.collect { + case (artifact, \/-(file)) => + artifact -> file + } - fileOrError match { - case \/-(file) => - if (file.toString.contains("file:/")) - throw new Exception(s"Wrong path: $file") - Some(file) - case -\/(err) => - log.error(s"${artifact.url}: $err") - None + val artifactErrors = artifactFilesOrErrors.toVector.collect { + case (_, -\/(err)) => + err + } + + if (artifactErrors.nonEmpty) { + val groupedArtifactErrors = artifactErrors + .groupBy(_.`type`) + .mapValues(_.map(_.message).sorted) + .toVector + .sortBy(_._1) + + for ((type0, errors) <- groupedArtifactErrors) { + log.error(s"${errors.size} $type0") + + if (!ignoreArtifactErrors || verbosityLevel >= 1) + for (err <- errors) + log.error(" " + err) } + + if (!ignoreArtifactErrors) + throw new Exception(s"Encountered ${artifactErrors.length} errors (see above messages)") + } + + def artifactFileOpt(artifact: Artifact) = { + val res = artifactFiles.get(artifact) + + if (res.isEmpty) + log.error(s"${artifact.url} not downloaded (should not happen)") + + res } writeIvyFiles()