mirror of https://github.com/sbt/sbt.git
Merge pull request #217 from alexarchambault/topic/update-changing
Fix in update changing mode, add benchmark option, use SBT logging, ...
This commit is contained in:
commit
a21ef67c8b
|
|
@ -146,6 +146,11 @@ lazy val core = crossProject
|
||||||
import com.typesafe.tools.mima.core.ProblemFilters._
|
import com.typesafe.tools.mima.core.ProblemFilters._
|
||||||
|
|
||||||
Seq(
|
Seq(
|
||||||
|
// Since 1.0.0-M11
|
||||||
|
// Extra parameter with default value added, problem for forward compatibility only
|
||||||
|
ProblemFilters.exclude[MissingMethodProblem]("coursier.core.ResolutionProcess.next"),
|
||||||
|
// method made final (for - non critical - tail recursion)
|
||||||
|
ProblemFilters.exclude[FinalMethodProblem]("coursier.core.ResolutionProcess.next"),
|
||||||
// Since 1.0.0-M10
|
// Since 1.0.0-M10
|
||||||
ProblemFilters.exclude[IncompatibleResultTypeProblem]("coursier.core.Resolution.withParentConfigurations"),
|
ProblemFilters.exclude[IncompatibleResultTypeProblem]("coursier.core.Resolution.withParentConfigurations"),
|
||||||
// New singleton object, problem for forward compatibility only
|
// New singleton object, problem for forward compatibility only
|
||||||
|
|
@ -221,6 +226,10 @@ lazy val cache = project
|
||||||
import com.typesafe.tools.mima.core.ProblemFilters._
|
import com.typesafe.tools.mima.core.ProblemFilters._
|
||||||
|
|
||||||
Seq(
|
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
|
// Since 1.0.0-M10
|
||||||
// methods that should have been private anyway
|
// methods that should have been private anyway
|
||||||
ProblemFilters.exclude[MissingMethodProblem]("coursier.TermDisplay.update"),
|
ProblemFilters.exclude[MissingMethodProblem]("coursier.TermDisplay.update"),
|
||||||
|
|
|
||||||
|
|
@ -43,8 +43,8 @@ object Cache {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private def withLocal(artifact: Artifact, cache: File): Artifact = {
|
private def localFile(url: String, cache: File): File = {
|
||||||
def local(url: String) =
|
val path =
|
||||||
if (url.startsWith("file:///"))
|
if (url.startsWith("file:///"))
|
||||||
url.stripPrefix("file://")
|
url.stripPrefix("file://")
|
||||||
else if (url.startsWith("file:/"))
|
else if (url.startsWith("file:/"))
|
||||||
|
|
@ -68,19 +68,7 @@ object Cache {
|
||||||
throw new Exception(s"No protocol found in URL $url")
|
throw new Exception(s"No protocol found in URL $url")
|
||||||
}
|
}
|
||||||
|
|
||||||
if (artifact.extra.contains("local"))
|
new File(path)
|
||||||
artifact
|
|
||||||
else
|
|
||||||
artifact.copy(extra = artifact.extra + ("local" ->
|
|
||||||
artifact.copy(
|
|
||||||
url = local(artifact.url),
|
|
||||||
checksumUrls = artifact.checksumUrls
|
|
||||||
.mapValues(local)
|
|
||||||
.toVector
|
|
||||||
.toMap,
|
|
||||||
extra = Map.empty
|
|
||||||
)
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private def readFullyTo(
|
private def readFullyTo(
|
||||||
|
|
@ -296,30 +284,15 @@ object Cache {
|
||||||
|
|
||||||
implicit val pool0 = pool
|
implicit val pool0 = pool
|
||||||
|
|
||||||
val artifact0 = withLocal(artifact, cache)
|
|
||||||
.extra
|
|
||||||
.getOrElse("local", artifact)
|
|
||||||
|
|
||||||
// Reference file - if it exists, and we get not found errors on some URLs, we assume
|
// Reference file - if it exists, and we get not found errors on some URLs, we assume
|
||||||
// we can keep track of these missing, and not try to get them again later.
|
// we can keep track of these missing, and not try to get them again later.
|
||||||
val referenceFileOpt = {
|
val referenceFileOpt = artifact
|
||||||
val referenceOpt = artifact.extra.get("metadata").map(withLocal(_, cache))
|
.extra
|
||||||
val referenceOpt0 = referenceOpt.map(a => a.extra.getOrElse("local", a))
|
.get("metadata")
|
||||||
|
.map(a => localFile(a.url, cache))
|
||||||
referenceOpt0.map(a => new File(a.url))
|
|
||||||
}
|
|
||||||
|
|
||||||
def referenceFileExists: Boolean = referenceFileOpt.exists(_.exists())
|
def referenceFileExists: Boolean = referenceFileOpt.exists(_.exists())
|
||||||
|
|
||||||
val pairs =
|
|
||||||
Seq(artifact0.url -> artifact.url) ++ {
|
|
||||||
checksums
|
|
||||||
.intersect(artifact0.checksumUrls.keySet)
|
|
||||||
.intersect(artifact.checksumUrls.keySet)
|
|
||||||
.toSeq
|
|
||||||
.map(sumType => artifact0.checksumUrls(sumType) -> artifact.checksumUrls(sumType))
|
|
||||||
}
|
|
||||||
|
|
||||||
def urlConn(url0: String) = {
|
def urlConn(url0: String) = {
|
||||||
val conn = url(url0).openConnection() // FIXME Should this be closed?
|
val conn = url(url0).openConnection() // FIXME Should this be closed?
|
||||||
// Dummy user-agent instead of the default "Java/...",
|
// Dummy user-agent instead of the default "Java/...",
|
||||||
|
|
@ -527,7 +500,7 @@ object Cache {
|
||||||
}
|
}
|
||||||
|
|
||||||
cachePolicy match {
|
cachePolicy match {
|
||||||
case CachePolicy.FetchMissing | CachePolicy.LocalOnly =>
|
case CachePolicy.FetchMissing | CachePolicy.LocalOnly | CachePolicy.LocalUpdate | CachePolicy.LocalUpdateChanging =>
|
||||||
validErrFileExists.flatMap { exists =>
|
validErrFileExists.flatMap { exists =>
|
||||||
if (exists)
|
if (exists)
|
||||||
EitherT(Task.now(FileError.NotFound(url, Some(true)).left[Unit]))
|
EitherT(Task.now(FileError.NotFound(url, Some(true)).left[Unit]))
|
||||||
|
|
@ -540,7 +513,7 @@ object Cache {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def checkFileExists(file: File, url: String): EitherT[Task, FileError, Unit] =
|
def checkFileExists(file: File, url: String, log: Boolean = true): EitherT[Task, FileError, Unit] =
|
||||||
EitherT {
|
EitherT {
|
||||||
Task {
|
Task {
|
||||||
if (file.exists()) {
|
if (file.exists()) {
|
||||||
|
|
@ -551,9 +524,17 @@ object Cache {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val urls =
|
||||||
|
artifact.url +: {
|
||||||
|
checksums
|
||||||
|
.intersect(artifact.checksumUrls.keySet)
|
||||||
|
.toSeq
|
||||||
|
.map(artifact.checksumUrls)
|
||||||
|
}
|
||||||
|
|
||||||
val tasks =
|
val tasks =
|
||||||
for ((f, url) <- pairs) yield {
|
for (url <- urls) yield {
|
||||||
val file = new File(f)
|
val file = localFile(url, cache)
|
||||||
|
|
||||||
val res =
|
val res =
|
||||||
if (url.startsWith("file:/")) {
|
if (url.startsWith("file:/")) {
|
||||||
|
|
@ -576,6 +557,8 @@ object Cache {
|
||||||
val cachePolicy0 = cachePolicy match {
|
val cachePolicy0 = cachePolicy match {
|
||||||
case CachePolicy.UpdateChanging if !artifact.changing =>
|
case CachePolicy.UpdateChanging if !artifact.changing =>
|
||||||
CachePolicy.FetchMissing
|
CachePolicy.FetchMissing
|
||||||
|
case CachePolicy.LocalUpdateChanging if !artifact.changing =>
|
||||||
|
CachePolicy.LocalOnly
|
||||||
case other =>
|
case other =>
|
||||||
other
|
other
|
||||||
}
|
}
|
||||||
|
|
@ -583,6 +566,10 @@ object Cache {
|
||||||
cachePolicy0 match {
|
cachePolicy0 match {
|
||||||
case CachePolicy.LocalOnly =>
|
case CachePolicy.LocalOnly =>
|
||||||
checkFileExists(file, url)
|
checkFileExists(file, url)
|
||||||
|
case CachePolicy.LocalUpdateChanging | CachePolicy.LocalUpdate =>
|
||||||
|
checkFileExists(file, url, log = false).flatMap { _ =>
|
||||||
|
update
|
||||||
|
}
|
||||||
case CachePolicy.UpdateChanging | CachePolicy.Update =>
|
case CachePolicy.UpdateChanging | CachePolicy.Update =>
|
||||||
update
|
update
|
||||||
case CachePolicy.FetchMissing =>
|
case CachePolicy.FetchMissing =>
|
||||||
|
|
@ -631,27 +618,26 @@ object Cache {
|
||||||
|
|
||||||
implicit val pool0 = pool
|
implicit val pool0 = pool
|
||||||
|
|
||||||
val artifact0 = withLocal(artifact, cache)
|
val localFile0 = localFile(artifact.url, cache)
|
||||||
.extra
|
|
||||||
.getOrElse("local", artifact)
|
|
||||||
|
|
||||||
EitherT {
|
EitherT {
|
||||||
artifact0.checksumUrls.get(sumType) match {
|
artifact.checksumUrls.get(sumType) match {
|
||||||
case Some(sumFile) =>
|
case Some(sumUrl) =>
|
||||||
|
val sumFile = localFile(sumUrl, cache)
|
||||||
|
|
||||||
Task {
|
Task {
|
||||||
val sumOpt = parseChecksum(
|
val sumOpt = parseChecksum(
|
||||||
new String(NioFiles.readAllBytes(new File(sumFile).toPath), "UTF-8")
|
new String(NioFiles.readAllBytes(sumFile.toPath), "UTF-8")
|
||||||
)
|
)
|
||||||
|
|
||||||
sumOpt match {
|
sumOpt match {
|
||||||
case None =>
|
case None =>
|
||||||
FileError.ChecksumFormatError(sumType, sumFile).left
|
FileError.ChecksumFormatError(sumType, sumFile.getPath).left
|
||||||
|
|
||||||
case Some(sum) =>
|
case Some(sum) =>
|
||||||
val md = MessageDigest.getInstance(sumType)
|
val md = MessageDigest.getInstance(sumType)
|
||||||
|
|
||||||
val f = new File(artifact0.url)
|
val is = new FileInputStream(localFile0)
|
||||||
val is = new FileInputStream(f)
|
|
||||||
try withContent(is, md.update(_, 0, _))
|
try withContent(is, md.update(_, 0, _))
|
||||||
finally is.close()
|
finally is.close()
|
||||||
|
|
||||||
|
|
@ -665,14 +651,14 @@ object Cache {
|
||||||
sumType,
|
sumType,
|
||||||
calculatedSum.toString(16),
|
calculatedSum.toString(16),
|
||||||
sum.toString(16),
|
sum.toString(16),
|
||||||
artifact0.url,
|
localFile0.getPath,
|
||||||
sumFile
|
sumFile.getPath
|
||||||
).left
|
).left
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case None =>
|
case None =>
|
||||||
Task.now(FileError.ChecksumNotFound(sumType, artifact0.url).left)
|
Task.now(FileError.ChecksumNotFound(sumType, localFile0.getPath).left)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,10 @@ object CacheParse {
|
||||||
s.split(',').toVector.traverseU {
|
s.split(',').toVector.traverseU {
|
||||||
case "offline" =>
|
case "offline" =>
|
||||||
Seq(CachePolicy.LocalOnly).successNel
|
Seq(CachePolicy.LocalOnly).successNel
|
||||||
|
case "update-local-changing" =>
|
||||||
|
Seq(CachePolicy.LocalUpdateChanging).successNel
|
||||||
|
case "update-local" =>
|
||||||
|
Seq(CachePolicy.LocalUpdate).successNel
|
||||||
case "update-changing" =>
|
case "update-changing" =>
|
||||||
Seq(CachePolicy.UpdateChanging).successNel
|
Seq(CachePolicy.UpdateChanging).successNel
|
||||||
case "update" =>
|
case "update" =>
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@ sealed abstract class CachePolicy extends Product with Serializable
|
||||||
|
|
||||||
object CachePolicy {
|
object CachePolicy {
|
||||||
case object LocalOnly extends CachePolicy
|
case object LocalOnly extends CachePolicy
|
||||||
|
case object LocalUpdateChanging extends CachePolicy
|
||||||
|
case object LocalUpdate extends CachePolicy
|
||||||
case object UpdateChanging extends CachePolicy
|
case object UpdateChanging extends CachePolicy
|
||||||
case object Update extends CachePolicy
|
case object Update extends CachePolicy
|
||||||
case object FetchMissing extends CachePolicy
|
case object FetchMissing extends CachePolicy
|
||||||
|
|
|
||||||
|
|
@ -2,26 +2,41 @@ package coursier
|
||||||
|
|
||||||
import java.io.File
|
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 {
|
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(
|
final case class NotFound(
|
||||||
file: String,
|
file: String,
|
||||||
permanent: Option[Boolean] = None
|
permanent: Option[Boolean] = None
|
||||||
) extends FileError(s"Not found: $file")
|
) extends FileError(
|
||||||
|
"not found",
|
||||||
|
file
|
||||||
|
)
|
||||||
|
|
||||||
final case class ChecksumNotFound(
|
final case class ChecksumNotFound(
|
||||||
sumType: String,
|
sumType: String,
|
||||||
file: String
|
file: String
|
||||||
) extends FileError(s"$sumType checksum not found: $file")
|
) extends FileError(
|
||||||
|
"checksum not found",
|
||||||
|
file
|
||||||
|
)
|
||||||
|
|
||||||
final case class ChecksumFormatError(
|
final case class ChecksumFormatError(
|
||||||
sumType: String,
|
sumType: String,
|
||||||
file: String
|
file: String
|
||||||
) extends FileError(s"Unrecognized $sumType checksum format in $file")
|
) extends FileError(
|
||||||
|
"checksum format error",
|
||||||
|
file
|
||||||
|
)
|
||||||
|
|
||||||
final case class WrongChecksum(
|
final case class WrongChecksum(
|
||||||
sumType: String,
|
sumType: String,
|
||||||
|
|
@ -29,10 +44,22 @@ object FileError {
|
||||||
expected: String,
|
expected: String,
|
||||||
file: String,
|
file: String,
|
||||||
sumFile: 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)
|
sealed abstract class Recoverable(
|
||||||
final case class Locked(file: File) extends Recoverable(s"Locked: $file")
|
`type`: String,
|
||||||
final case class ConcurrentDownload(url: String) extends Recoverable(s"Concurrent download: $url")
|
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
|
||||||
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -56,10 +56,17 @@ object Terminal {
|
||||||
}
|
}
|
||||||
|
|
||||||
object TermDisplay {
|
object TermDisplay {
|
||||||
private def defaultFallbackMode: Boolean = {
|
def defaultFallbackMode: Boolean = {
|
||||||
val env = sys.env.get("COURSIER_NO_TERM").nonEmpty
|
val env0 = sys.env.get("COURSIER_PROGRESS").map(_.toLowerCase).collect {
|
||||||
|
case "true" | "enable" | "1" => true
|
||||||
|
case "false" | "disable" | "0" => false
|
||||||
|
}
|
||||||
|
def compatibilityEnv = sys.env.get("COURSIER_NO_TERM").nonEmpty
|
||||||
|
|
||||||
def nonInteractive = System.console() == null
|
def nonInteractive = System.console() == null
|
||||||
|
|
||||||
|
val env = env0.getOrElse(compatibilityEnv)
|
||||||
|
|
||||||
env || nonInteractive
|
env || nonInteractive
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -480,7 +487,7 @@ class TermDisplay(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateThread.removeEntry(url, !newUpdate, s"Checked $url") {
|
updateThread.removeEntry(url, !newUpdate, s"Checked $url\n") {
|
||||||
case info: CheckUpdateInfo =>
|
case info: CheckUpdateInfo =>
|
||||||
info.copy(remoteTimeOpt = remoteTimeOpt, isDone = true)
|
info.copy(remoteTimeOpt = remoteTimeOpt, isDone = true)
|
||||||
case _ =>
|
case _ =>
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import java.util.concurrent.Executors
|
||||||
import coursier.ivy.IvyRepository
|
import coursier.ivy.IvyRepository
|
||||||
import coursier.util.{Print, Parse}
|
import coursier.util.{Print, Parse}
|
||||||
|
|
||||||
|
import scala.annotation.tailrec
|
||||||
import scalaz.{Failure, Success, \/-, -\/}
|
import scalaz.{Failure, Success, \/-, -\/}
|
||||||
import scalaz.concurrent.{ Task, Strategy }
|
import scalaz.concurrent.{ Task, Strategy }
|
||||||
|
|
||||||
|
|
@ -201,9 +202,15 @@ class Helper(
|
||||||
filter = Some(dep => keepOptional || !dep.optional)
|
filter = Some(dep => keepOptional || !dep.optional)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val loggerFallbackMode =
|
||||||
|
!progress && TermDisplay.defaultFallbackMode
|
||||||
|
|
||||||
val logger =
|
val logger =
|
||||||
if (verbosityLevel >= 0)
|
if (verbosityLevel >= 0)
|
||||||
Some(new TermDisplay(new OutputStreamWriter(System.err)))
|
Some(new TermDisplay(
|
||||||
|
new OutputStreamWriter(System.err),
|
||||||
|
fallbackMode = loggerFallbackMode
|
||||||
|
))
|
||||||
else
|
else
|
||||||
None
|
None
|
||||||
|
|
||||||
|
|
@ -238,10 +245,108 @@ class Helper(
|
||||||
|
|
||||||
logger.foreach(_.init())
|
logger.foreach(_.init())
|
||||||
|
|
||||||
val res = startRes
|
val res =
|
||||||
.process
|
if (benchmark > 0) {
|
||||||
.run(fetch0, maxIterations)
|
class Counter(var value: Int = 0) {
|
||||||
.run
|
def add(value: Int): Unit = {
|
||||||
|
this.value += value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def timed[T](name: String, counter: Counter, f: Task[T]): Task[T] =
|
||||||
|
Task(System.currentTimeMillis()).flatMap { start =>
|
||||||
|
f.map { t =>
|
||||||
|
val end = System.currentTimeMillis()
|
||||||
|
Console.err.println(s"$name: ${end - start} ms")
|
||||||
|
counter.add((end - start).toInt)
|
||||||
|
t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def helper(proc: ResolutionProcess, counter: Counter, iteration: Int): Task[Resolution] =
|
||||||
|
if (iteration >= maxIterations)
|
||||||
|
Task.now(proc.current)
|
||||||
|
else
|
||||||
|
proc match {
|
||||||
|
case _: core.Done =>
|
||||||
|
Task.now(proc.current)
|
||||||
|
case _ =>
|
||||||
|
val iterationType = proc match {
|
||||||
|
case _: core.Missing => "IO"
|
||||||
|
case _: core.Continue => "calculations"
|
||||||
|
case _ => ???
|
||||||
|
}
|
||||||
|
|
||||||
|
timed(
|
||||||
|
s"Iteration ${iteration + 1} ($iterationType)",
|
||||||
|
counter,
|
||||||
|
proc.next(fetch0, fastForward = false)).flatMap(helper(_, counter, iteration + 1)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
def res = {
|
||||||
|
val iterationCounter = new Counter
|
||||||
|
val resolutionCounter = new Counter
|
||||||
|
|
||||||
|
val res0 = timed(
|
||||||
|
"Resolution",
|
||||||
|
resolutionCounter,
|
||||||
|
helper(
|
||||||
|
startRes.process,
|
||||||
|
iterationCounter,
|
||||||
|
0
|
||||||
|
)
|
||||||
|
).run
|
||||||
|
|
||||||
|
Console.err.println(s"Overhead: ${resolutionCounter.value - iterationCounter.value} ms")
|
||||||
|
|
||||||
|
res0
|
||||||
|
}
|
||||||
|
|
||||||
|
@tailrec
|
||||||
|
def result(warmUp: Int): Resolution =
|
||||||
|
if (warmUp >= benchmark) {
|
||||||
|
Console.err.println("Benchmark resolution")
|
||||||
|
res
|
||||||
|
} else {
|
||||||
|
Console.err.println(s"Warm-up ${warmUp + 1} / $benchmark")
|
||||||
|
res
|
||||||
|
result(warmUp + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
result(0)
|
||||||
|
} else if (benchmark < 0) {
|
||||||
|
|
||||||
|
def res(index: Int) = {
|
||||||
|
val start = System.currentTimeMillis()
|
||||||
|
val res0 = startRes
|
||||||
|
.process
|
||||||
|
.run(fetch0, maxIterations)
|
||||||
|
.run
|
||||||
|
val end = System.currentTimeMillis()
|
||||||
|
|
||||||
|
Console.err.println(s"Resolution ${index + 1} / ${-benchmark}: ${end - start} ms")
|
||||||
|
|
||||||
|
res0
|
||||||
|
}
|
||||||
|
|
||||||
|
@tailrec
|
||||||
|
def result(warmUp: Int): Resolution =
|
||||||
|
if (warmUp >= -benchmark) {
|
||||||
|
Console.err.println("Benchmark resolution")
|
||||||
|
res(warmUp)
|
||||||
|
} else {
|
||||||
|
Console.err.println(s"Warm-up ${warmUp + 1} / ${-benchmark}")
|
||||||
|
res(warmUp)
|
||||||
|
result(warmUp + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
result(0)
|
||||||
|
} else
|
||||||
|
startRes
|
||||||
|
.process
|
||||||
|
.run(fetch0, maxIterations)
|
||||||
|
.run
|
||||||
|
|
||||||
logger.foreach(_.stop())
|
logger.foreach(_.stop())
|
||||||
|
|
||||||
|
|
@ -299,13 +404,19 @@ class Helper(
|
||||||
): Seq[Artifact] = {
|
): Seq[Artifact] = {
|
||||||
|
|
||||||
if (subset == null && verbosityLevel >= 1) {
|
if (subset == null && verbosityLevel >= 1) {
|
||||||
val msg = cachePolicies match {
|
def isLocal(p: CachePolicy) = p match {
|
||||||
case Seq(CachePolicy.LocalOnly) =>
|
case CachePolicy.LocalOnly => true
|
||||||
" Checking artifacts"
|
case CachePolicy.LocalUpdate => true
|
||||||
case _ =>
|
case CachePolicy.LocalUpdateChanging => true
|
||||||
" Fetching artifacts"
|
case _ => false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val msg =
|
||||||
|
if (cachePolicies.forall(isLocal))
|
||||||
|
" Checking artifacts"
|
||||||
|
else
|
||||||
|
" Fetching artifacts"
|
||||||
|
|
||||||
errPrintln(msg)
|
errPrintln(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -333,7 +444,10 @@ class Helper(
|
||||||
|
|
||||||
val logger =
|
val logger =
|
||||||
if (verbosityLevel >= 0)
|
if (verbosityLevel >= 0)
|
||||||
Some(new TermDisplay(new OutputStreamWriter(System.err)))
|
Some(new TermDisplay(
|
||||||
|
new OutputStreamWriter(System.err),
|
||||||
|
fallbackMode = loggerFallbackMode
|
||||||
|
))
|
||||||
else
|
else
|
||||||
None
|
None
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,9 @@ case class CommonOptions(
|
||||||
@Help("Increase verbosity (specify several times to increase more)")
|
@Help("Increase verbosity (specify several times to increase more)")
|
||||||
@Short("v")
|
@Short("v")
|
||||||
verbose: Int @@ Counter,
|
verbose: Int @@ Counter,
|
||||||
|
@Help("Force display of progress bars")
|
||||||
|
@Short("P")
|
||||||
|
progress: Boolean,
|
||||||
@Help("Maximum number of resolution iterations (specify a negative value for unlimited, default: 100)")
|
@Help("Maximum number of resolution iterations (specify a negative value for unlimited, default: 100)")
|
||||||
@Short("N")
|
@Short("N")
|
||||||
maxIterations: Int = 100,
|
maxIterations: Int = 100,
|
||||||
|
|
@ -54,6 +57,10 @@ case class CommonOptions(
|
||||||
@Help("Checksums")
|
@Help("Checksums")
|
||||||
@Value("checksum1,checksum2,... - end with none to allow for no checksum validation if none are available")
|
@Value("checksum1,checksum2,... - end with none to allow for no checksum validation if none are available")
|
||||||
checksum: List[String],
|
checksum: List[String],
|
||||||
|
@Help("Print the duration of each iteration of the resolution")
|
||||||
|
@Short("B")
|
||||||
|
@Value("Number of warm-up resolutions - if negative, doesn't print per iteration benchmark (less overhead)")
|
||||||
|
benchmark: Int,
|
||||||
@Recurse
|
@Recurse
|
||||||
cacheOptions: CacheOptions
|
cacheOptions: CacheOptions
|
||||||
) {
|
) {
|
||||||
|
|
@ -163,7 +170,7 @@ case class BootstrapOptions(
|
||||||
mainClass: String,
|
mainClass: String,
|
||||||
@Short("o")
|
@Short("o")
|
||||||
output: String = "bootstrap",
|
output: String = "bootstrap",
|
||||||
@Short("D")
|
@Short("d")
|
||||||
downloadDir: String,
|
downloadDir: String,
|
||||||
@Short("f")
|
@Short("f")
|
||||||
force: Boolean,
|
force: Boolean,
|
||||||
|
|
@ -172,7 +179,7 @@ case class BootstrapOptions(
|
||||||
standalone: Boolean,
|
standalone: Boolean,
|
||||||
@Help("Set Java properties in the generated launcher.")
|
@Help("Set Java properties in the generated launcher.")
|
||||||
@Value("key=value")
|
@Value("key=value")
|
||||||
@Short("P")
|
@Short("D")
|
||||||
property: List[String],
|
property: List[String],
|
||||||
@Help("Set Java command-line options in the generated launcher.")
|
@Help("Set Java command-line options in the generated launcher.")
|
||||||
@Value("option")
|
@Value("option")
|
||||||
|
|
|
||||||
|
|
@ -33,8 +33,10 @@ sealed abstract class ResolutionProcess {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def next[F[_]](
|
@tailrec
|
||||||
fetch: Fetch.Metadata[F]
|
final def next[F[_]](
|
||||||
|
fetch: Fetch.Metadata[F],
|
||||||
|
fastForward: Boolean = true
|
||||||
)(implicit
|
)(implicit
|
||||||
F: Monad[F]
|
F: Monad[F]
|
||||||
): F[ResolutionProcess] = {
|
): F[ResolutionProcess] = {
|
||||||
|
|
@ -45,7 +47,10 @@ sealed abstract class ResolutionProcess {
|
||||||
case missing0 @ Missing(missing, _, _) =>
|
case missing0 @ Missing(missing, _, _) =>
|
||||||
F.map(fetch(missing))(result => missing0.next(result))
|
F.map(fetch(missing))(result => missing0.next(result))
|
||||||
case cont @ Continue(_, _) =>
|
case cont @ Continue(_, _) =>
|
||||||
cont.nextNoCont.next(fetch)
|
if (fastForward)
|
||||||
|
cont.nextNoCont.next(fetch, fastForward = fastForward)
|
||||||
|
else
|
||||||
|
F.point(cont.next)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -219,7 +219,7 @@ case class MavenRepository(
|
||||||
}
|
}
|
||||||
|
|
||||||
F.bind(findVersioning(module, version, None, fetch).run) { eitherProj =>
|
F.bind(findVersioning(module, version, None, fetch).run) { eitherProj =>
|
||||||
if (eitherProj.isLeft)
|
if (eitherProj.isLeft && version.contains("-SNAPSHOT"))
|
||||||
F.map(withSnapshotVersioning.run)(eitherProj0 =>
|
F.map(withSnapshotVersioning.run)(eitherProj0 =>
|
||||||
if (eitherProj0.isLeft)
|
if (eitherProj0.isLeft)
|
||||||
eitherProj
|
eitherProj
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ object Parse {
|
||||||
case Right(modVer) => values += modVer
|
case Right(modVer) => values += modVer
|
||||||
}
|
}
|
||||||
|
|
||||||
(errors.toSeq, values.toSeq)
|
(errors, values)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -77,7 +77,7 @@ object Parse {
|
||||||
.map((_, version))
|
.map((_, version))
|
||||||
|
|
||||||
case _ =>
|
case _ =>
|
||||||
Left(s"Malformed coordinates: $s")
|
Left(s"Malformed dependency: $s")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -107,7 +107,7 @@ object Parse {
|
||||||
.map((_, version, None))
|
.map((_, version, None))
|
||||||
|
|
||||||
case _ =>
|
case _ =>
|
||||||
Left(s"Malformed coordinates: $s")
|
Left(s"Malformed dependency: $s")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
package coursier
|
package coursier
|
||||||
|
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
import sbt._
|
import sbt._
|
||||||
import sbt.Keys._
|
import sbt.Keys._
|
||||||
|
|
||||||
|
|
@ -43,7 +41,7 @@ object CoursierPlugin extends AutoPlugin {
|
||||||
coursierFallbackDependencies <<= Tasks.coursierFallbackDependenciesTask,
|
coursierFallbackDependencies <<= Tasks.coursierFallbackDependenciesTask,
|
||||||
coursierCache := Cache.default,
|
coursierCache := Cache.default,
|
||||||
update <<= Tasks.updateTask(withClassifiers = false),
|
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),
|
updateSbtClassifiers in Defaults.TaskGlobal <<= Tasks.updateTask(withClassifiers = true, sbtClassifiers = true),
|
||||||
coursierProject <<= Tasks.coursierProjectTask,
|
coursierProject <<= Tasks.coursierProjectTask,
|
||||||
coursierProjects <<= Tasks.coursierProjectsTask,
|
coursierProjects <<= Tasks.coursierProjectsTask,
|
||||||
|
|
|
||||||
|
|
@ -133,7 +133,11 @@ object FromSbt {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
def repository(resolver: Resolver, ivyProperties: Map[String, String]): Option[Repository] =
|
def repository(
|
||||||
|
resolver: Resolver,
|
||||||
|
ivyProperties: Map[String, String],
|
||||||
|
log: sbt.Logger
|
||||||
|
): Option[Repository] =
|
||||||
resolver match {
|
resolver match {
|
||||||
case sbt.MavenRepository(_, root) =>
|
case sbt.MavenRepository(_, root) =>
|
||||||
try {
|
try {
|
||||||
|
|
@ -142,10 +146,10 @@ object FromSbt {
|
||||||
Some(MavenRepository(root0, sbtAttrStub = true))
|
Some(MavenRepository(root0, sbtAttrStub = true))
|
||||||
} catch {
|
} catch {
|
||||||
case e: MalformedURLException =>
|
case e: MalformedURLException =>
|
||||||
Console.err.println(
|
log.warn(
|
||||||
"Warning: error parsing Maven repository base " +
|
"Error parsing Maven repository base " +
|
||||||
root +
|
root +
|
||||||
Option(e.getMessage).map(" ("+_+")").mkString +
|
Option(e.getMessage).map(" (" + _ + ")").mkString +
|
||||||
", ignoring it"
|
", ignoring it"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -177,7 +181,7 @@ object FromSbt {
|
||||||
))
|
))
|
||||||
|
|
||||||
case other =>
|
case other =>
|
||||||
Console.err.println(s"Warning: unrecognized repository ${other.name}, ignoring it")
|
log.warn(s"Unrecognized repository ${other.name}, ignoring it")
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,11 @@ import scala.util.{Failure, Success, Try}
|
||||||
|
|
||||||
object Settings {
|
object Settings {
|
||||||
|
|
||||||
private val baseDefaultVerbosityLevel = 0
|
private lazy val baseDefaultVerbosityLevel =
|
||||||
|
if (System.console() == null) // non interactive mode
|
||||||
|
0
|
||||||
|
else
|
||||||
|
1
|
||||||
|
|
||||||
def defaultVerbosityLevel: Int = {
|
def defaultVerbosityLevel: Int = {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -185,10 +185,11 @@ object Tasks {
|
||||||
Module("org.scala-lang", "scalap") -> scalaVersion
|
Module("org.scala-lang", "scalap") -> scalaVersion
|
||||||
)
|
)
|
||||||
|
|
||||||
def updateTask(withClassifiers: Boolean, sbtClassifiers: Boolean = false) = Def.task {
|
def updateTask(
|
||||||
|
withClassifiers: Boolean,
|
||||||
// SBT logging should be better than that most of the time...
|
sbtClassifiers: Boolean = false,
|
||||||
def errPrintln(s: String): Unit = scala.Console.err.println(s)
|
ignoreArtifactErrors: Boolean = false
|
||||||
|
) = Def.task {
|
||||||
|
|
||||||
def grouped[K, V](map: Seq[(K, V)]): Map[K, Seq[V]] =
|
def grouped[K, V](map: Seq[(K, V)]): Map[K, Seq[V]] =
|
||||||
map.groupBy { case (k, _) => k }.map {
|
map.groupBy { case (k, _) => k }.map {
|
||||||
|
|
@ -252,6 +253,8 @@ object Tasks {
|
||||||
val cachePolicies = coursierCachePolicies.value
|
val cachePolicies = coursierCachePolicies.value
|
||||||
val cache = coursierCache.value
|
val cache = coursierCache.value
|
||||||
|
|
||||||
|
val log = streams.value.log
|
||||||
|
|
||||||
val sv = scalaVersion.value // is this always defined? (e.g. for Java only projects?)
|
val sv = scalaVersion.value // is this always defined? (e.g. for Java only projects?)
|
||||||
val sbv = scalaBinaryVersion.value
|
val sbv = scalaBinaryVersion.value
|
||||||
|
|
||||||
|
|
@ -267,7 +270,7 @@ object Tasks {
|
||||||
rule.configurations.nonEmpty ||
|
rule.configurations.nonEmpty ||
|
||||||
rule.crossVersion != sbt.CrossVersion.Disabled
|
rule.crossVersion != sbt.CrossVersion.Disabled
|
||||||
) {
|
) {
|
||||||
Console.err.println(s"Warning: unsupported exclusion rule $rule")
|
log.warn(s"Unsupported exclusion rule $rule")
|
||||||
anyNonSupportedExclusionRule = true
|
anyNonSupportedExclusionRule = true
|
||||||
Nil
|
Nil
|
||||||
} else
|
} else
|
||||||
|
|
@ -275,7 +278,7 @@ object Tasks {
|
||||||
}.toSet
|
}.toSet
|
||||||
|
|
||||||
if (anyNonSupportedExclusionRule)
|
if (anyNonSupportedExclusionRule)
|
||||||
Console.err.println(s"Only supported exclusion rule fields: organization, name")
|
log.warn("Only supported exclusion rule fields: organization, name")
|
||||||
|
|
||||||
val resolvers =
|
val resolvers =
|
||||||
if (sbtClassifiers)
|
if (sbtClassifiers)
|
||||||
|
|
@ -312,9 +315,9 @@ object Tasks {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (verbosityLevel >= 2) {
|
if (verbosityLevel >= 2) {
|
||||||
println("InterProjectRepository")
|
log.info("InterProjectRepository")
|
||||||
for (p <- projects)
|
for (p <- projects)
|
||||||
println(s" ${p.module}:${p.version}")
|
log.info(s" ${p.module}:${p.version}")
|
||||||
}
|
}
|
||||||
|
|
||||||
val globalPluginsRepo = IvyRepository(
|
val globalPluginsRepo = IvyRepository(
|
||||||
|
|
@ -335,7 +338,7 @@ object Tasks {
|
||||||
globalPluginsRepo,
|
globalPluginsRepo,
|
||||||
interProjectRepo
|
interProjectRepo
|
||||||
) ++ resolvers.flatMap(
|
) ++ resolvers.flatMap(
|
||||||
FromSbt.repository(_, ivyProperties)
|
FromSbt.repository(_, ivyProperties, log)
|
||||||
) ++ {
|
) ++ {
|
||||||
if (fallbackDependencies.isEmpty)
|
if (fallbackDependencies.isEmpty)
|
||||||
Nil
|
Nil
|
||||||
|
|
@ -376,7 +379,7 @@ object Tasks {
|
||||||
s"${dep.module}:${dep.version}:${dep.configuration}"
|
s"${dep.module}:${dep.version}:${dep.configuration}"
|
||||||
}.sorted.distinct
|
}.sorted.distinct
|
||||||
|
|
||||||
if (verbosityLevel >= 1) {
|
if (verbosityLevel >= 2) {
|
||||||
val repoReprs = repositories.map {
|
val repoReprs = repositories.map {
|
||||||
case r: IvyRepository =>
|
case r: IvyRepository =>
|
||||||
s"ivy:${r.pattern}"
|
s"ivy:${r.pattern}"
|
||||||
|
|
@ -389,14 +392,17 @@ object Tasks {
|
||||||
r.toString
|
r.toString
|
||||||
}
|
}
|
||||||
|
|
||||||
errPrintln(s"Repositories:\n${repoReprs.map(" "+_).mkString("\n")}")
|
log.info(
|
||||||
|
"Repositories:\n" +
|
||||||
|
repoReprs.map(" " + _).mkString("\n")
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (verbosityLevel >= 0)
|
if (verbosityLevel >= 0)
|
||||||
errPrintln(s"Resolving ${currentProject.module.organization}:${currentProject.module.name}:${currentProject.version}")
|
log.info(s"Resolving ${currentProject.module.organization}:${currentProject.module.name}:${currentProject.version}")
|
||||||
if (verbosityLevel >= 1)
|
if (verbosityLevel >= 2)
|
||||||
for (depRepr <- depsRepr(currentProject.dependencies))
|
for (depRepr <- depsRepr(currentProject.dependencies))
|
||||||
errPrintln(s" $depRepr")
|
log.info(s" $depRepr")
|
||||||
|
|
||||||
resLogger.init()
|
resLogger.init()
|
||||||
|
|
||||||
|
|
@ -404,26 +410,36 @@ object Tasks {
|
||||||
.process
|
.process
|
||||||
.run(fetch, maxIterations)
|
.run(fetch, maxIterations)
|
||||||
.attemptRun
|
.attemptRun
|
||||||
.leftMap(ex => throw new Exception(s"Exception during resolution", ex))
|
.leftMap(ex => throw new Exception("Exception during resolution", ex))
|
||||||
.merge
|
.merge
|
||||||
|
|
||||||
resLogger.stop()
|
resLogger.stop()
|
||||||
|
|
||||||
|
|
||||||
if (!res.isDone)
|
if (!res.isDone)
|
||||||
throw new Exception(s"Maximum number of iteration of dependency resolution reached")
|
throw new Exception("Maximum number of iteration of dependency resolution reached")
|
||||||
|
|
||||||
if (res.conflicts.nonEmpty) {
|
if (res.conflicts.nonEmpty) {
|
||||||
val projCache = res.projectCache.mapValues { case (_, p) => p }
|
val projCache = res.projectCache.mapValues { case (_, p) => p }
|
||||||
println(s"${res.conflicts.size} conflict(s):\n ${Print.dependenciesUnknownConfigs(res.conflicts.toVector, projCache)}")
|
log.error(
|
||||||
throw new Exception(s"Conflict(s) in dependency resolution")
|
s"${res.conflicts.size} conflict(s):\n" +
|
||||||
|
" " + Print.dependenciesUnknownConfigs(res.conflicts.toVector, projCache)
|
||||||
|
)
|
||||||
|
throw new Exception("Conflict(s) in dependency resolution")
|
||||||
}
|
}
|
||||||
|
|
||||||
if (res.errors.nonEmpty) {
|
if (res.errors.nonEmpty) {
|
||||||
println(s"\n${res.errors.size} error(s):")
|
log.error(
|
||||||
for ((dep, errs) <- res.errors) {
|
s"\n${res.errors.size} error(s):\n" +
|
||||||
println(s" ${dep.module}:${dep.version}:\n${errs.map(" " + _.replace("\n", " \n")).mkString("\n")}")
|
res.errors.map {
|
||||||
}
|
case (dep, errs) =>
|
||||||
|
s" ${dep.module}:${dep.version}:\n" +
|
||||||
|
errs
|
||||||
|
.map(" " + _.replace("\n", " \n"))
|
||||||
|
.mkString("\n")
|
||||||
|
}.mkString("\n")
|
||||||
|
)
|
||||||
|
|
||||||
throw new Exception(s"Encountered ${res.errors.length} error(s) in dependency resolution")
|
throw new Exception(s"Encountered ${res.errors.length} error(s) in dependency resolution")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -454,8 +470,8 @@ object Tasks {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (verbosityLevel >= 0)
|
if (verbosityLevel >= 0)
|
||||||
errPrintln("Resolution done")
|
log.info("Resolution done")
|
||||||
if (verbosityLevel >= 1) {
|
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 },
|
||||||
|
|
@ -464,7 +480,7 @@ object Tasks {
|
||||||
|
|
||||||
val projCache = res.projectCache.mapValues { case (_, p) => p }
|
val projCache = res.projectCache.mapValues { case (_, p) => p }
|
||||||
val repr = Print.dependenciesUnknownConfigs(finalDeps.toVector, projCache)
|
val repr = Print.dependenciesUnknownConfigs(finalDeps.toVector, projCache)
|
||||||
println(repr.split('\n').map(" "+_).mkString("\n"))
|
log.info(repr.split('\n').map(" "+_).mkString("\n"))
|
||||||
}
|
}
|
||||||
|
|
||||||
val classifiers =
|
val classifiers =
|
||||||
|
|
@ -504,13 +520,13 @@ object Tasks {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (verbosityLevel >= 0)
|
if (verbosityLevel >= 0)
|
||||||
errPrintln(s"Fetching artifacts")
|
log.info("Fetching artifacts")
|
||||||
|
|
||||||
artifactsLogger.init()
|
artifactsLogger.init()
|
||||||
|
|
||||||
val artifactFilesOrErrors = Task.gatherUnordered(artifactFileOrErrorTasks).attemptRun match {
|
val artifactFilesOrErrors = Task.gatherUnordered(artifactFileOrErrorTasks).attemptRun match {
|
||||||
case -\/(ex) =>
|
case -\/(ex) =>
|
||||||
throw new Exception(s"Error while downloading / verifying artifacts", ex)
|
throw new Exception("Error while downloading / verifying artifacts", ex)
|
||||||
case \/-(l) =>
|
case \/-(l) =>
|
||||||
l.toMap
|
l.toMap
|
||||||
}
|
}
|
||||||
|
|
@ -518,20 +534,44 @@ object Tasks {
|
||||||
artifactsLogger.stop()
|
artifactsLogger.stop()
|
||||||
|
|
||||||
if (verbosityLevel >= 0)
|
if (verbosityLevel >= 0)
|
||||||
errPrintln(s"Fetching artifacts: done")
|
log.info("Fetching artifacts: done")
|
||||||
|
|
||||||
|
val artifactFiles = artifactFilesOrErrors.collect {
|
||||||
|
case (artifact, \/-(file)) =>
|
||||||
|
artifact -> file
|
||||||
|
}
|
||||||
|
|
||||||
|
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) = {
|
def artifactFileOpt(artifact: Artifact) = {
|
||||||
val fileOrError = artifactFilesOrErrors.getOrElse(artifact, -\/("Not downloaded"))
|
val res = artifactFiles.get(artifact)
|
||||||
|
|
||||||
fileOrError match {
|
if (res.isEmpty)
|
||||||
case \/-(file) =>
|
log.error(s"${artifact.url} not downloaded (should not happen)")
|
||||||
if (file.toString.contains("file:/"))
|
|
||||||
throw new Exception(s"Wrong path: $file")
|
res
|
||||||
Some(file)
|
|
||||||
case -\/(err) =>
|
|
||||||
errPrintln(s"${artifact.url}: $err")
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
writeIvyFiles()
|
writeIvyFiles()
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
addSbtPlugin("org.xerial.sbt" % "sbt-pack" % "0.6.8")
|
addSbtPlugin("org.xerial.sbt" % "sbt-pack" % "0.6.8")
|
||||||
addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.7")
|
addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.8")
|
||||||
addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.0.0")
|
addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.0.0")
|
||||||
addSbtPlugin("org.scoverage" % "sbt-scoverage" % "1.1.0")
|
addSbtPlugin("org.scoverage" % "sbt-scoverage" % "1.1.0")
|
||||||
addSbtPlugin("org.tpolecat" % "tut-plugin" % "0.4.0")
|
addSbtPlugin("org.tpolecat" % "tut-plugin" % "0.4.0")
|
||||||
addSbtPlugin("com.github.alexarchambault" % "coursier-sbt-plugin" % "1.0.0-M8")
|
addSbtPlugin("com.github.alexarchambault" % "coursier-sbt-plugin" % "1.0.0-M10")
|
||||||
addSbtPlugin("com.typesafe.sbt" % "sbt-proguard" % "0.2.2")
|
addSbtPlugin("com.typesafe.sbt" % "sbt-proguard" % "0.2.2")
|
||||||
addSbtPlugin("com.typesafe" % "sbt-mima-plugin" % "0.1.8")
|
addSbtPlugin("com.typesafe" % "sbt-mima-plugin" % "0.1.8")
|
||||||
libraryDependencies += "org.scala-sbt" % "scripted-plugin" % sbtVersion.value
|
libraryDependencies += "org.scala-sbt" % "scripted-plugin" % sbtVersion.value
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue