Clean stuff

This commit is contained in:
Alexandre Archambault 2017-07-15 17:19:06 +02:00
parent 744e6186d6
commit 2cd1a3b0b1
5 changed files with 120 additions and 97 deletions

View File

@ -6,6 +6,8 @@ import java.net.{ HttpURLConnection, URL, URLConnection }
import scala.language.higherKinds
import scalaz.{ EitherT, Monad }
import scalaz.syntax.monad._
import scalaz.Scalaz.ToEitherOps
object FallbackDependenciesRepository {
@ -15,12 +17,12 @@ object FallbackDependenciesRepository {
// E.g. https://github.com/NetLogo/NetLogo/releases/download/5.3.1/NetLogo.jar
// returning 403s. Hence the second attempt below.
val firstAttemptOpt = url.getProtocol match {
case "file" =>
Some(new File(url.getPath).exists()) // FIXME Escaping / de-escaping needed here?
val protocolSpecificAttemptOpt = {
case "http" | "https" =>
def ifFile: Boolean =
new File(url.getPath).exists() // FIXME Escaping / de-escaping needed here?
def ifHttp: Option[Boolean] = {
// HEAD request attempt, adapted from http://stackoverflow.com/questions/22541629/android-how-can-i-make-an-http-head-request/22545275#22545275
var conn: HttpURLConnection = null
@ -31,34 +33,43 @@ object FallbackDependenciesRepository {
conn.setRequestMethod("HEAD")
conn.getInputStream.close()
Some(true)
} catch {
case _: FileNotFoundException =>
Some(false)
case _: IOException => // error other than not found
None
} finally {
}
catch {
case _: FileNotFoundException => Some(false)
case _: IOException => None // error other than not found
}
finally {
if (conn != null)
coursier.Cache.closeConn(conn)
}
case _ =>
None
}
url.getProtocol match {
case "file" => Some(ifFile)
case "http" | "https" => ifHttp
case _ => None
}
}
firstAttemptOpt.getOrElse {
def genericAttempt: Boolean = {
var conn: URLConnection = null
try {
conn = url.openConnection()
// NOT setting request type to HEAD here.
conn.getInputStream.close()
true
} catch {
case _: IOException =>
false
} finally {
}
catch {
case _: IOException => false
}
finally {
if (conn != null)
coursier.Cache.closeConn(conn)
}
}
protocolSpecificAttemptOpt
.getOrElse(genericAttempt)
}
}
@ -67,22 +78,23 @@ final case class FallbackDependenciesRepository(
fallbacks: Map[(Module, String), (URL, Boolean)]
) extends Repository {
private val source: Artifact.Source = new Artifact.Source {
def artifacts(
dependency: Dependency,
project: Project,
overrideClassifiers: Option[Seq[String]]
) =
fallbacks.get(dependency.moduleVersion) match {
case None => Nil
case Some((url, changing)) =>
val url0 = url.toString
val ext = url0.substring(url0.lastIndexOf('.') + 1)
Seq(
Artifact(url0, Map.empty, Map.empty, Attributes(ext, ""), changing, None)
)
}
}
private val source: Artifact.Source =
new Artifact.Source {
def artifacts(
dependency: Dependency,
project: Project,
overrideClassifiers: Option[Seq[String]]
) =
fallbacks
.get(dependency.moduleVersion)
.toSeq
.map {
case (url, changing) =>
val url0 = url.toString
val ext = url0.substring(url0.lastIndexOf('.') + 1)
Artifact(url0, Map.empty, Map.empty, Attributes(ext, ""), changing, None)
}
}
def find[F[_]](
module: Module,
@ -90,25 +102,22 @@ final case class FallbackDependenciesRepository(
fetch: Fetch.Content[F]
)(implicit
F: Monad[F]
): EitherT[F, String, (Artifact.Source, Project)] =
fallbacks.get((module, version)) match {
case None =>
EitherT.left(F.point("No fallback URL found"))
): EitherT[F, String, (Artifact.Source, Project)] = {
case Some((url, _)) =>
val res = fallbacks
.get((module, version))
.fold("No fallback URL found".left[(Artifact.Source, Project)]) {
case (url, _) =>
val urlStr = url.toExternalForm
val idx = urlStr.lastIndexOf('/')
val urlStr = url.toExternalForm
val idx = urlStr.lastIndexOf('/')
if (idx < 0 || urlStr.endsWith("/"))
EitherT.left(F.point(s"$url doesn't point to a file"))
else {
val (dirUrlStr, fileName) = urlStr.splitAt(idx + 1)
if (idx < 0 || urlStr.endsWith("/"))
s"$url doesn't point to a file".left
else {
val (dirUrlStr, fileName) = urlStr.splitAt(idx + 1)
// Not sure F.point will make that run like Task.apply would have
// if F = Task
EitherT.right(F.point(FallbackDependenciesRepository.exists(url))).flatMap { exists =>
if (exists) {
if (FallbackDependenciesRepository.exists(url)) {
val proj = Project(
module,
version,
@ -126,10 +135,12 @@ final case class FallbackDependenciesRepository(
Info.empty
)
EitherT.right(F.point((source, proj)))
(source, proj).right
} else
EitherT.left(F.point(s"$fileName not found under $dirUrlStr"))
s"$fileName not found under $dirUrlStr".left
}
}
}
}
EitherT(res.point)
}
}

View File

@ -2,28 +2,27 @@ package coursier
import scala.language.higherKinds
import scalaz.{ -\/, \/-, Monad, EitherT }
import scalaz.{EitherT, Monad}
import scalaz.syntax.monad._
import scalaz.syntax.std.option._
final case class InterProjectRepository(projects: Seq[Project]) extends Repository {
private val map = projects
.map { proj => proj.moduleVersion -> proj }
.map(proj => proj.moduleVersion -> proj)
.toMap
def find[F[_]](
def find[F[_]: Monad](
module: Module,
version: String,
fetch: Fetch.Content[F]
)(implicit
F: Monad[F]
): EitherT[F, String, (Artifact.Source, Project)] = {
val res = map.get((module, version)) match {
case Some(proj) =>
\/-((Artifact.Source.empty, proj))
case None =>
-\/("Not found")
}
EitherT(F.point(res))
val res = map
.get((module, version))
.toRightDisjunction("Not found")
.map((Artifact.Source.empty, _))
EitherT(res.point)
}
}

View File

@ -3,7 +3,8 @@ package coursier
import scala.collection.mutable.ArrayBuffer
sealed abstract class ResolutionError extends Product with Serializable {
def cause: Option[Throwable] = this match {
final def cause: Option[Throwable] = this match {
case ResolutionError.MaximumIterationsReached => None
case ResolutionError.UnknownException(ex) => Some(ex)
case ResolutionError.UnknownDownloadException(ex) => Some(ex)
@ -12,10 +13,10 @@ sealed abstract class ResolutionError extends Product with Serializable {
case _: ResolutionError.DownloadErrors => None
}
def message: String = this match {
final def message: String = this match {
case ResolutionError.MaximumIterationsReached =>
"Maximum number of iteration of dependency resolution reached"
case ResolutionError.UnknownException(ex) =>
case ResolutionError.UnknownException(_) =>
"Exception during resolution"
case ResolutionError.UnknownDownloadException(ex) =>
"Error while downloading / verifying artifacts"
@ -29,10 +30,10 @@ sealed abstract class ResolutionError extends Product with Serializable {
err.description(verbose = true)
}
def exception(): ResolutionException =
final def exception(): ResolutionException =
new ResolutionException(this)
def throwException(): Nothing =
final def throwException(): Nothing =
throw exception()
}
@ -49,40 +50,44 @@ object ResolutionError {
def grouped(errs: Seq[String]) =
errs
.map { s =>
val idx = s.indexOf(": ")
if (idx >= 0)
(s.take(idx), s.drop(idx + ": ".length))
else
("", s)
s.split(": ", 2) match {
case Array(k, v) => (k, v)
case _ => ("", s)
}
}
.groupBy(_._1)
.mapValues(_.map(_._2))
.toVector
.sortBy(_._1)
val lines = new ArrayBuffer[String]
lines += s"Encountered ${errors.length} error(s) in dependency resolution:"
val lines = new ArrayBuffer[String]
def print(s: String, indentLevel: Int = 0) =
lines += " " * indentLevel * 2 + s
def result = lines.mkString("\n")
print(s"Encountered ${errors.length} error(s) in dependency resolution:")
for (((mod, ver), errs) <- errors) {
lines += s" $mod:$ver:"
print(s"$mod:$ver:", 1)
for ((type0, errs0) <- grouped(errs))
if (type0.isEmpty)
for (err <- errs0)
lines += s" $err"
print(err, 2)
else
errs0 match {
case Seq(err) =>
lines += s" $type0: $err"
print(s"$type0: $err", 2)
case _ =>
lines += s" $type0:"
print(s"$type0:", 2)
for (err <- errs0)
lines += s" $err"
print(err, 3)
}
}
lines.mkString("\n")
result
}
}
@ -96,16 +101,21 @@ object ResolutionError {
.toVector
.sortBy(_._1)
val b = new ArrayBuffer[String]
val lines = new ArrayBuffer[String]
def print(s: String, indentLevel: Int = 0) =
lines += " " * indentLevel * 2 + s
def result = lines.mkString("\n")
for ((type0, errors) <- groupedArtifactErrors) {
b += s"${errors.size} $type0"
print(s"${errors.size} $type0")
if (verbose)
for (err <- errors)
b += " " + err
print(err, 1)
}
b.mkString("\n")
result
}
}
}

View File

@ -8,11 +8,13 @@ object SbtBootJars {
scalaVersion: String,
jars: Seq[File]
): Map[(Module, String), File] =
jars.collect {
case jar if jar.getName.endsWith(".jar") =>
val name = jar.getName.stripSuffix(".jar")
val mod = Module(scalaOrg, name)
jars
.collect {
case jar if jar.getName.endsWith(".jar") =>
val name = jar.getName.stripSuffix(".jar")
val mod = Module(scalaOrg, name)
(mod, scalaVersion) -> jar
}.toMap
(mod, scalaVersion) -> jar
}
.toMap
}

View File

@ -6,7 +6,7 @@ import scala.util.{Failure, Success, Try}
object Settings {
private lazy val baseDefaultVerbosityLevel =
private val baseDefaultVerbosityLevel =
if (System.console() == null) // non interactive mode
0
else
@ -15,17 +15,18 @@ object Settings {
def defaultVerbosityLevel(logger: Logger): Int = {
def fromOption(value: Option[String], description: String): Option[Int] =
value.filter(_.nonEmpty).flatMap {
str =>
value
.filter(_.nonEmpty)
.flatMap { str =>
Try(str.toInt) match {
case Success(level) => Some(level)
case Failure(ex) =>
case Failure(_) =>
logger.warn(
s"unrecognized $description value (should be an integer), ignoring it."
)
None
}
}
}
val fromEnv = fromOption(
sys.env.get("COURSIER_VERBOSITY"),