Merge pull request #39 from alexarchambault/develop

Last developments
This commit is contained in:
Alexandre Archambault 2015-06-23 00:05:28 +02:00
commit de3b704731
32 changed files with 1279 additions and 1138 deletions

View File

@ -5,7 +5,7 @@ Ensure you have a dependency on its artifact, e.g. add in `build.sbt`,
resolvers += Resolver.sonatypeRepo("snapshots")
libraryDependencies +=
"eu.frowning-lambda" %% "coursier" % "0.1.0-SNAPSHOT"
"com.github.alexarchambault" %% "coursier" % "0.1.0-SNAPSHOT"
```
Then,

View File

@ -27,6 +27,8 @@ case class Coursier(scope: List[String],
base.relativize(f.toURI).getPath
val logger: RemoteLogger with ArtifactDownloaderLogger = new RemoteLogger with ArtifactDownloaderLogger {
def println(s: String) = Console.err.println(s)
def downloading(url: String) =
println(s"Downloading $url")
def downloaded(url: String, success: Boolean) =
@ -91,16 +93,27 @@ case class Coursier(scope: List[String],
).run
if (!res.isDone) {
println(s"Maximum number of iteration reached!")
Console.err.println(s"Maximum number of iteration reached!")
sys exit 1
}
def repr(dep: Dependency) =
s"${dep.module.organization}:${dep.module.name}:${dep.`type`}:${Some(dep.classifier).filter(_.nonEmpty).map(_+":").mkString}${dep.version}"
def repr(dep: Dependency) = {
val (type0, classifier) = dep.artifacts match {
case maven: Artifacts.Maven => (maven.`type`, maven.classifier)
}
// dep.version can be an interval, whereas the one from project can't
val version = res.projectsCache.get(dep.moduleVersion).map(_._2.version).getOrElse(dep.version)
val extra =
if (version == dep.version) ""
else s" ($version for ${dep.version})"
s"${dep.module.organization}:${dep.module.name}:$type0:${Some(classifier).filter(_.nonEmpty).map(_+":").mkString}$version$extra"
}
val trDeps = res.dependencies.toList.sortBy(repr)
println("\n" + trDeps.map(repr).mkString("\n"))
println("\n" + trDeps.map(repr).distinct.mkString("\n"))
if (res.conflicts.nonEmpty) {
// Needs test
@ -143,12 +156,12 @@ case class Coursier(scope: List[String],
(repo, deps) <- sorted
dl = downloaders(repo)
dep <- deps
(_, proj) = res.projectsCache(dep.moduleVersion)
} yield {
dl.artifact(dep, cachePolicy = cachePolicy).run.map {
case -\/(err) =>
println(s"Failed to get ${repr(dep)}: $err")
case \/-(f) =>
println(s"${repr(dep)}:\n ${fileRepr(f)}")
dl.artifacts(dep, proj, cachePolicy = cachePolicy).map { results =>
val errorCount = results.count{case -\/(_) => true; case _ => false}
val resultsRepr = results.map(_.map(fileRepr).merge).map(" " + _).mkString("\n")
println(s"${repr(dep)} (${results.length} artifact(s)${if (errorCount > 0) s", $errorCount error(s)" else ""}):\n$resultsRepr")
}
}

View File

@ -77,13 +77,13 @@ trait Logger {
def other(url: String, msg: String): Unit
}
case class Remote(base: String, logger: Option[Logger] = None) extends Repository {
case class Remote(base: String, logger: Option[Logger] = None) extends MavenRepository {
def find(module: Module,
version: String,
cachePolicy: CachePolicy): EitherT[Task, String, Project] = {
def findNoInterval(module: Module,
version: String,
cachePolicy: CachePolicy): EitherT[Task, String, Project] = {
val relPath = {
val path = {
module.organization.split('.').toSeq ++ Seq(
module.name,
version,
@ -91,7 +91,7 @@ case class Remote(base: String, logger: Option[Logger] = None) extends Repositor
)
} .map(Remote.encodeURIComponent)
val url = base + relPath.mkString("/")
val url = base + path.mkString("/")
EitherT(Task{ implicit ec =>
logger.foreach(_.fetching(url))
@ -111,6 +111,28 @@ case class Remote(base: String, logger: Option[Logger] = None) extends Repositor
def versions(organization: String,
name: String,
cachePolicy: CachePolicy): EitherT[Task, String, Versions] = ???
cachePolicy: CachePolicy): EitherT[Task, String, Versions] = {
val path = {
organization.split('.').toSeq ++ Seq(
name,
"maven-metadata.xml"
)
} .map(Remote.encodeURIComponent)
val url = base + path.mkString("/")
EitherT(Task{ implicit ec =>
logger.foreach(_.fetching(url))
Remote.get(url).recover{case e: Exception => Left(e.getMessage)}.map{ eitherXml =>
logger.foreach(_.fetched(url))
for {
xml <- \/.fromEither(eitherXml)
_ <- if (xml.label == "metadata") \/-(()) else -\/("Metadata not found")
versions <- Xml.versions(xml)
} yield versions
}
})
}
}

View File

@ -32,10 +32,10 @@ package object concurrent {
def runF(implicit ec: ExecutionContext) = Future.traverse(tasks)(_.runF)
}
implicit val taskFunctor: Functor[Task] =
new Functor[Task] {
def map[A, B](fa: Task[A])(f: A => B): Task[B] =
fa.map(f)
implicit val taskMonad: Monad[Task] =
new Monad[Task] {
def point[A](a: => A): Task[A] = Task.now(a)
def bind[A,B](fa: Task[A])(f: A => Task[B]): Task[B] = fa.flatMap(f)
}
}

View File

@ -1,7 +1,26 @@
package coursier.test
import scala.concurrent.{Promise, ExecutionContext, Future}
import scala.scalajs.js
import js.Dynamic.{global => g}
package object compatibility {
implicit val executionContext = scala.scalajs.concurrent.JSExecutionContext.Implicits.queue
lazy val fs = g.require("fs")
def textResource(path: String)(implicit ec: ExecutionContext): Future[String] = {
val p = Promise[String]()
fs.readFile("core/src/test/resources/" + path, "utf-8", {
(err: js.Dynamic, data: js.Dynamic) =>
if (err == null) p.success(data.asInstanceOf[String])
else p.failure(new Exception(err.toString))
()
}: js.Function2[js.Dynamic, js.Dynamic, Unit])
p.future
}
}

View File

@ -21,15 +21,14 @@ case class ArtifactDownloader(root: String, cache: File, logger: Option[Artifact
def artifact(module: Module,
version: String,
classifier: String,
`type`: String,
artifact: Artifacts.Artifact,
cachePolicy: CachePolicy): EitherT[Task, String, File] = {
val relPath =
module.organization.split('.').toSeq ++ Seq(
module.name,
version,
s"${module.name}-$version${Some(classifier).filter(_.nonEmpty).map("-"+_).mkString}.${`type`}"
s"${module.name}-$version${Some(artifact.classifier).filter(_.nonEmpty).map("-"+_).mkString}.${artifact.`type`}"
)
val file = (cache /: relPath)(new File(_, _))
@ -64,19 +63,19 @@ case class ArtifactDownloader(root: String, cache: File, logger: Option[Artifact
val in = new BufferedInputStream(url.openStream(), bufferSize)
try {
val w = new FileOutputStream(file)
val out = new FileOutputStream(file)
try {
@tailrec
def helper(): Unit = {
val read = in.read(b)
if (read >= 0) {
w.write(b, 0, read)
out.write(b, 0, read)
helper()
}
}
helper()
} finally w.close()
} finally out.close()
} finally in.close()
logger.foreach(_.downloadedArtifact(urlStr, success = true))
@ -92,9 +91,24 @@ case class ArtifactDownloader(root: String, cache: File, logger: Option[Artifact
EitherT(cachePolicy(locally)(remote))
}
def artifact(dependency: Dependency,
cachePolicy: CachePolicy = CachePolicy.Default): EitherT[Task, String, File] =
artifact(dependency.module, dependency.version, dependency.classifier, dependency.`type`, cachePolicy = cachePolicy)
def artifacts(dependency: Dependency,
project: Project,
cachePolicy: CachePolicy = CachePolicy.Default): Task[Seq[String \/ File]] = {
val artifacts0 =
dependency.artifacts match {
case s: Artifacts.Sufficient => s.artifacts
case p: Artifacts.WithProject => p.artifacts(project)
}
val tasks =
artifacts0 .map { artifact0 =>
// Important: using version from project, as the one from dependency can be an interval
artifact(dependency.module, project.version, artifact0, cachePolicy = cachePolicy).run
}
Task.gatherUnordered(tasks)
}
}
@ -138,23 +152,15 @@ object Remote {
case class Remote(root: String,
cache: Option[File] = None,
logger: Option[RemoteLogger] = None) extends Repository {
logger: Option[RemoteLogger] = None) extends MavenRepository {
def find(module: Module,
version: String,
cachePolicy: CachePolicy): EitherT[Task, String, Project] = {
private def get(path: Seq[String],
cachePolicy: CachePolicy): EitherT[Task, String, String] = {
val relPath =
module.organization.split('.').toSeq ++ Seq(
module.name,
version,
s"${module.name}-$version.pom"
)
def localFile = {
lazy val localFile = {
for {
cache0 <- cache.toRightDisjunction("No cache")
f = (cache0 /: relPath)(new File(_, _))
f = (cache0 /: path)(new File(_, _))
} yield f
}
@ -172,7 +178,7 @@ case class Remote(root: String,
}
def remote = {
val urlStr = root + relPath.mkString("/")
val urlStr = root + path.mkString("/")
val url = new URL(urlStr)
def log = Task(logger.foreach(_.downloading(urlStr)))
@ -196,7 +202,21 @@ case class Remote(root: String,
)
}
val task = cachePolicy.saving(locally)(remote)(save)
EitherT(cachePolicy.saving(locally)(remote)(save))
}
def findNoInterval(module: Module,
version: String,
cachePolicy: CachePolicy): EitherT[Task, String, Project] = {
val path =
module.organization.split('.').toSeq ++ Seq(
module.name,
version,
s"${module.name}-$version.pom"
)
val task = get(path, cachePolicy).run
.map(eitherStr =>
for {
str <- eitherStr
@ -213,29 +233,13 @@ case class Remote(root: String,
name: String,
cachePolicy: CachePolicy): EitherT[Task, String, Versions] = {
val relPath =
val path =
organization.split('.').toSeq ++ Seq(
name,
"maven-metadata.xml"
)
def locally = {
???
}
def remote = {
val urlStr = root + relPath.mkString("/")
val url = new URL(urlStr)
Remote.readFully(url.openStream())
}
def save(s: String) = {
// TODO
Task.now(())
}
val task = cachePolicy.saving(locally)(remote)(save)
val task = get(path, cachePolicy).run
.map(eitherStr =>
for {
str <- eitherStr

View File

@ -1,7 +1,5 @@
package coursier
import coursier.core.Resolver.ModuleVersion
import scalaz.EitherT
import scalaz.concurrent.Task

View File

@ -1,6 +1,8 @@
package coursier.test
import scala.concurrent.Future
import coursier.core.Remote
import scala.concurrent.{ExecutionContext, Future}
import scalaz.concurrent.Task
package object compatibility {
@ -11,4 +13,11 @@ package object compatibility {
def runF: Future[T] = Future.successful(underlying.run)
}
def textResource(path: String)(implicit ec: ExecutionContext): Future[String] = Future {
def is = getClass.getClassLoader
.getResource(path).openStream()
new String(Remote.readFullySync(is), "UTF-8")
}
}

View File

@ -1,205 +0,0 @@
package coursier.core
import scala.annotation.tailrec
import coursier.core.compatibility._
/** Same kind of ordering as aether-util/src/main/java/org/eclipse/aether/util/version/GenericVersion.java */
object ComparableVersion {
sealed trait Item extends Ordered[Item] {
def compare(other: Item): Int =
(this, other) match {
case (Number(a), Number(b)) => a.compare(b)
case (BigNumber(a), BigNumber(b)) => a.compare(b)
case (Number(a), BigNumber(b)) => -b.compare(a)
case (BigNumber(a), Number(b)) => a.compare(b)
case (Qualifier(_, a), Qualifier(_, b)) => a.compare(b)
case (Literal(a), Literal(b)) => a.compareToIgnoreCase(b)
case _ =>
val rel0 = compareToEmpty
val rel1 = other.compareToEmpty
if (rel0 == rel1) order.compare(other.order)
else rel0.compare(rel1)
}
def order: Int
def isEmpty: Boolean = compareToEmpty == 0
def compareToEmpty: Int = 1
}
sealed trait Numeric extends Item
case class Number(value: Int) extends Numeric {
val order = 0
override def compareToEmpty = value.compare(0)
}
case class BigNumber(value: BigInt) extends Numeric {
val order = 0
override def compareToEmpty = value.compare(0)
}
case class Qualifier(value: String, level: Int) extends Item {
val order = -2
override def compareToEmpty = level.compare(0)
}
case class Literal(value: String) extends Item {
val order = -1
override def compareToEmpty = if (value.isEmpty) 0 else 1
}
case object Min extends Item {
val order = -8
override def compareToEmpty = -1
}
case object Max extends Item {
val order = 8
}
val empty = Number(0)
val qualifiers = Seq[Qualifier](
Qualifier("alpha", -5),
Qualifier("beta", -4),
Qualifier("milestone", -3),
Qualifier("cr", -2),
Qualifier("rc", -2),
Qualifier("snapshot", -1),
Qualifier("ga", 0),
Qualifier("final", 0),
Qualifier("sp", 1)
)
val qualifiersMap = qualifiers.map(q => q.value -> q).toMap
object Tokenizer {
sealed trait Separator
case object Dot extends Separator
case object Hyphen extends Separator
case object Underscore extends Separator
case object None extends Separator
def apply(s: String): (Item, Stream[(Separator, Item)]) = {
def parseItem(s: Stream[Char]): (Item, Stream[Char]) = {
if (s.isEmpty || !s.head.letterOrDigit) (empty, s)
else if (s.head.isDigit) {
def digits(b: StringBuilder, s: Stream[Char]): (String, Stream[Char]) =
if (s.isEmpty || !s.head.isDigit) (b.result(), s)
else digits(b + s.head, s.tail)
val (digits0, rem) = digits(new StringBuilder, s)
val item =
if (digits0.length >= 10) BigNumber(BigInt(digits0))
else Number(digits0.toInt)
(item, rem)
} else {
assert(s.head.letter)
def letters(b: StringBuilder, s: Stream[Char]): (String, Stream[Char]) =
if (s.isEmpty || !s.head.letter) (b.result().toLowerCase, s)
else letters(b + s.head, s.tail)
val (letters0, rem) = letters(new StringBuilder, s)
val item =
qualifiersMap.getOrElse(letters0, Literal(letters0))
(item, rem)
}
}
def parseSeparator(s: Stream[Char]): (Separator, Stream[Char]) = {
assert(s.nonEmpty)
s.head match {
case '.' => (Dot, s.tail)
case '-' => (Hyphen, s.tail)
case '_' => (Underscore, s.tail)
case _ => (None, s)
}
}
def helper(s: Stream[Char]): Stream[(Separator, Item)] = {
if (s.isEmpty) Stream()
else {
val (sep, rem0) = parseSeparator(s)
val (item, rem) = parseItem(rem0)
(sep, item) #:: helper(rem)
}
}
val (first, rem) = parseItem(s.toStream)
(first, helper(rem))
}
}
def parse(s: String): ComparableVersion = {
val (first, tokens) = Tokenizer(s)
def isNumeric(item: Item) = item match { case _: Numeric => true; case _ => false }
def postProcess(prevIsNumeric: Option[Boolean], item: Item, tokens0: Stream[(Tokenizer.Separator, Item)]): Stream[Item] = {
val tokens = {
var _tokens = tokens0
if (isNumeric(item)) {
val nextNonDotZero = _tokens.dropWhile{case (Tokenizer.Dot, n: Numeric) => n.isEmpty; case _ => false }
if (nextNonDotZero.forall(t => t._1 == Tokenizer.Hyphen || ((t._1 == Tokenizer.Dot || t._1 == Tokenizer.None) && !isNumeric(t._2)))) { // Dot && isNumeric(t._2)
_tokens = nextNonDotZero
}
}
_tokens
}
def ifFollowedByNumberElse(ifFollowedByNumber: Item, default: Item) = {
val followedByNumber = tokens.headOption
.exists{ case (Tokenizer.None, num: Numeric) if !num.isEmpty => true; case _ => false }
if (followedByNumber) ifFollowedByNumber
else default
}
def next =
if (tokens.isEmpty) Stream()
else postProcess(Some(isNumeric(item)), tokens.head._2, tokens.tail)
item match {
case Literal("min") => Min #:: next
case Literal("max") => Max #:: next
case Literal("a") =>
ifFollowedByNumberElse(qualifiersMap("alpha"), item) #:: next
case Literal("b") =>
ifFollowedByNumberElse(qualifiersMap("beta"), item) #:: next
case Literal("m") =>
ifFollowedByNumberElse(qualifiersMap("milestone"), item) #:: next
case _ =>
item #:: next
}
}
ComparableVersion(postProcess(None, first, tokens).toList)
}
@tailrec
def listCompare(first: List[Item], second: List[Item]): Int = {
if (first.isEmpty && second.isEmpty) 0
else if (first.isEmpty) {
assert(second.nonEmpty)
-second.dropWhile(_.isEmpty).headOption.fold(0)(_.compareToEmpty)
} else if (second.isEmpty) {
assert(first.nonEmpty)
first.dropWhile(_.isEmpty).headOption.fold(0)(_.compareToEmpty)
} else {
val rel = first.head.compare(second.head)
if (rel == 0) listCompare(first.tail, second.tail)
else rel
}
}
}
case class ComparableVersion(items: List[ComparableVersion.Item]) extends Ordered[ComparableVersion] {
def compare(other: ComparableVersion) = ComparableVersion.listCompare(items, other.items)
def isEmpty = items.forall(_.isEmpty)
}

View File

@ -32,20 +32,44 @@ sealed abstract class Scope(val name: String)
case class Dependency(module: Module,
version: String,
scope: Scope,
`type`: String,
classifier: String,
artifacts: Artifacts,
exclusions: Set[(String, String)],
optional: Boolean) {
def moduleVersion = (module, version)
}
sealed trait Artifacts
object Artifacts {
/**
* May become a bit more complicated with Ivy support,
* but should still point at one single artifact.
*/
case class Artifact(`type`: String,
classifier: String)
sealed trait WithProject extends Artifacts {
def artifacts(project: Project): Seq[Artifact]
}
sealed trait Sufficient extends Artifacts {
def artifacts: Seq[Artifact]
}
case class Maven(`type`: String,
classifier: String) extends Sufficient {
def artifacts: Seq[Artifact] = Seq(Artifact(`type`, classifier))
}
}
case class Project(module: Module,
version: String,
dependencies: Seq[Dependency],
parent: Option[(Module, String)],
dependencyManagement: Seq[Dependency],
properties: Map[String, String],
profiles: Seq[Profile]) {
profiles: Seq[Profile],
versions: Option[Versions]) {
def moduleVersion = (module, version)
}
@ -66,3 +90,12 @@ case class Profile(id: String,
dependencies: Seq[Dependency],
dependencyManagement: Seq[Dependency],
properties: Map[String, String])
case class Versions(latest: String,
release: String,
available: List[String],
lastUpdated: Option[Versions.DateTime])
object Versions {
case class DateTime(year: Int, month: Int, day: Int, hour: Int, minute: Int, second: Int)
}

View File

@ -29,7 +29,7 @@ object Parse {
strTo = s0.drop(commaIdx + 1)
from <- if (strFrom.isEmpty) Some(None) else version(strFrom).map(Some(_))
to <- if (strTo.isEmpty) Some(None) else version(strTo).map(Some(_))
} yield VersionInterval(from.filterNot(_.cmp.isEmpty), to.filterNot(_.cmp.isEmpty), fromIncluded, toIncluded)
} yield VersionInterval(from.filterNot(_.isEmpty), to.filterNot(_.isEmpty), fromIncluded, toIncluded)
}
def versionConstraint(s: String): Option[VersionConstraint] = {

View File

@ -1,6 +1,6 @@
package coursier.core
import scalaz.{\/, EitherT}
import scalaz.{-\/, \/-, \/, EitherT}
import scalaz.concurrent.Task
trait Repository {
@ -36,3 +36,38 @@ object CachePolicy {
remote
}
}
trait MavenRepository extends Repository {
def find(module: Module,
version: String,
cachePolicy: CachePolicy): EitherT[Task, String, Project] = {
Parse.versionInterval(version).filter(_.isValid) match {
case None => findNoInterval(module, version, cachePolicy)
case Some(itv) =>
versions(module.organization, module.name, cachePolicy).flatMap { versions0 =>
val eitherVersion = {
val release = Version(versions0.release)
if (itv.contains(release)) \/-(versions0.release)
else {
val inInterval = versions0.available.map(Version(_)).filter(itv.contains)
if (inInterval.isEmpty) -\/(s"No version found for $version")
else \/-(inInterval.max.repr)
}
}
eitherVersion match {
case -\/(reason) => EitherT[Task, String, Project](Task.now(-\/(reason)))
case \/-(version0) => findNoInterval(module, version0, cachePolicy)
.map(_.copy(versions = Some(versions0)))
}
}
}
}
def findNoInterval(module: Module,
version: String,
cachePolicy: CachePolicy): EitherT[Task, String, Project]
}

View File

@ -70,7 +70,9 @@ object Resolver {
type DepMgmtKey = (String, String, String)
def dependencyManagementKey(dep: Dependency): DepMgmtKey =
(dep.module.organization, dep.module.name, dep.`type`)
dep.artifacts match {
case Artifacts.Maven(type0, _) => (dep.module.organization, dep.module.name, type0)
}
def dependencyManagementAdd(m: Map[DepMgmtKey, Dependency], dep: Dependency): Map[DepMgmtKey, Dependency] = {
val key = dependencyManagementKey(dep)
if (m.contains(key)) m else m + (key -> dep)
@ -119,7 +121,13 @@ object Resolver {
name = substituteProps(dep.module.name)
),
version = substituteProps(dep.version),
`type` = substituteProps(dep.`type`),
artifacts = dep.artifacts match {
case maven: Artifacts.Maven =>
maven.copy(
`type` = substituteProps(maven.`type`),
classifier = substituteProps(maven.classifier)
)
},
scope = Parse.scope(substituteProps(dep.scope.name)),
exclusions = dep.exclusions
.map{case (org, name) => (substituteProps(org), substituteProps(name))}
@ -249,49 +257,6 @@ object Resolver {
}
}
/**
* Intersection of exclusions. A module is excluded by the result if it is excluded
* by both `first` and `second`.
*/
def exclusionsIntersect(first: Set[(String, String)],
second: Set[(String, String)]): Set[(String, String)] = {
val (firstAll, firstNonAll) = first.partition{case ("*", "*") => true; case _ => false }
val (secondAll, secondNonAll) = second.partition{case ("*", "*") => true; case _ => false }
if (firstAll.nonEmpty && secondAll.nonEmpty) Set(("*", "*"))
else {
val firstOrgWildcards = firstNonAll.collect{ case ("*", name) => name }
val firstNameWildcards = firstNonAll.collect{ case (org, "*") => org }
val secondOrgWildcards = secondNonAll.collect{ case ("*", name) => name }
val secondNameWildcards = secondNonAll.collect{ case (org, "*") => org }
val orgWildcards =
(firstOrgWildcards intersect secondOrgWildcards) ++
(if (secondAll.nonEmpty) firstOrgWildcards else Set.empty) ++
(if (firstAll.nonEmpty) secondOrgWildcards else Set.empty)
val nameWildcards =
(firstNameWildcards intersect secondNameWildcards) ++
(if (secondAll.nonEmpty) firstNameWildcards else Set.empty) ++
(if (firstAll.nonEmpty) secondNameWildcards else Set.empty)
val firstRemaining = firstNonAll.filter{ case (org, name) => org != "*" && name != "*" }
val secondRemaining = secondNonAll.filter{ case (org, name) => org != "*" && name != "*" }
val remaining =
(firstRemaining intersect secondRemaining) ++
(if (secondAll.nonEmpty) firstRemaining else Set.empty) ++
(if (firstAll.nonEmpty) secondRemaining else Set.empty) ++
(if (secondOrgWildcards.nonEmpty) firstRemaining.filter(e => secondOrgWildcards(e._2)) else Set.empty) ++
(if (firstOrgWildcards.nonEmpty) secondRemaining.filter(e => firstOrgWildcards(e._2)) else Set.empty) ++
(if (secondNameWildcards.nonEmpty) firstRemaining.filter(e => secondNameWildcards(e._1)) else Set.empty) ++
(if (firstNameWildcards.nonEmpty) secondRemaining.filter(e => firstNameWildcards(e._1)) else Set.empty)
orgWildcards.map(name => ("*", name)) ++ nameWildcards.map(org => (org, "*")) ++ remaining
}
}
def withDefaultScope(dep: Dependency): Dependency =
if (dep.scope.name.isEmpty) dep.copy(scope = Scope.Compile)
else dep
@ -393,7 +358,7 @@ object Resolver {
* Transitive dependencies of the current dependencies, according to what there currently is in cache.
* No attempt is made to solve version conflicts here.
*/
def transitiveDependencies =
def transitiveDependencies: Seq[Dependency] =
for {
dep <- (dependencies -- conflicts).toList
trDep <- finalDependencies0(dep)
@ -404,11 +369,11 @@ object Resolver {
* trying to solve version conflicts. Transitive dependencies are calculated with the current cache.
*
* May contain dependencies added in previous iterations, but no more required. These are filtered below, see
* @newDependencies.
* `newDependencies`.
*
* Returns a tuple made of the conflicting dependencies, and all the dependencies.
*/
def nextDependenciesAndConflicts = {
def nextDependenciesAndConflicts: (Seq[Dependency], Seq[Dependency]) = {
merge(dependencies ++ transitiveDependencies)
}
@ -436,23 +401,23 @@ object Resolver {
missingFromCache.isEmpty && isFixPoint
}
private def key(dep: Dependency) =
(dep.module.organization, dep.module.name, dep.scope)
private def eraseVersion(dep: Dependency) = dep.copy(version = "")
/**
* Returns a map giving the dependency that brought each of the dependency of the "next" dependency set,
* along with the exclusions that the source dependency adds to it.
* Returns a map giving the dependencies that brought each of the dependency of the "next" dependency set.
*
* The versions of all the dependencies returned are erased (emptied).
*/
def reverseDependenciesAndExclusions = {
def reverseDependencies: Map[Dependency, Vector[Dependency]] = {
val (updatedConflicts, updatedDeps) = nextDependenciesAndConflicts
val trDepsSeq =
for {
dep <- updatedDeps
trDep <- finalDependencies0(dep)
} yield key(trDep) -> (key(dep), trDep.exclusions)
} yield eraseVersion(trDep) -> eraseVersion(dep)
val knownDeps = (updatedDeps ++ updatedConflicts).map(key).toSet
val knownDeps = (updatedDeps ++ updatedConflicts).map(eraseVersion).toSet
trDepsSeq
.groupBy(_._1)
@ -462,48 +427,38 @@ object Resolver {
}
/**
* Returns a map, whose keys are the dependencies from the "next" dependency set,
* filtering out those that are no more required, and whose values are the exclusions
* added to them by the dependencies that brought them here.
* Returns dependencies from the "next" dependency set, filtering out
* those that are no more required.
*
* The versions of all the dependencies returned are erased (emptied).
*/
def remainingDependenciesAndExclusions = {
val rootDependenciesExclusions = rootDependencies
.map(dep => key(dep) -> dep.exclusions)
.toMap
type D = (String, String, Scope)
def remainingDependencies: Set[Dependency] = {
val rootDependencies0 = rootDependencies.map(eraseVersion)
@tailrec
def helper[T](reverseDeps: Map[D, Vector[(D, T)]]): Map[D, Vector[(D, T)]] = {
val (toRemove, remaining) = reverseDeps.partition(kv => kv._2.isEmpty && !rootDependenciesExclusions.contains(kv._1))
def helper(reverseDeps: Map[Dependency, Vector[Dependency]]): Map[Dependency, Vector[Dependency]] = {
val (toRemove, remaining) = reverseDeps.partition(kv => kv._2.isEmpty && !rootDependencies0(kv._1))
if (toRemove.isEmpty) reverseDeps
else helper(remaining.mapValues(_.filter(x => remaining.contains(x._1) || rootDependenciesExclusions.contains(x._1))).toList.toMap)
else helper(remaining.mapValues(_.filter(x => remaining.contains(x) || rootDependencies0(x))).toList.toMap)
}
val filteredReverseDependenciesAndExclusions = helper(reverseDependenciesAndExclusions)
val filteredReverseDependencies = helper(reverseDependencies)
(rootDependenciesExclusions.keySet ++ filteredReverseDependenciesAndExclusions.keySet)
.toList
.map{case dep => dep ->
(filteredReverseDependenciesAndExclusions.get(dep).map(_.map(_._2)).getOrElse(Nil) ++ rootDependenciesExclusions.get(dep))
.reduce(exclusionsIntersect)
}
.toMap
rootDependencies0 ++ filteredReverseDependencies.keys
}
/**
* The final next dependency set, stripped of no more required ones.
*/
def newDependencies = {
val remainingDeps0 = remainingDependenciesAndExclusions
def newDependencies: Set[Dependency] = {
val remainingDependencies0 = remainingDependencies
nextDependenciesAndConflicts._2
.filter(dep => remainingDeps0.contains(key(dep)))
.map(dep => dep.copy(exclusions = remainingDeps0(key(dep))))
.filter(dep => remainingDependencies0(eraseVersion(dep)))
.toSet
}
private def nextNoMissingUnsafe(): Resolution = {
private def nextNoMissingUnsafe: Resolution = {
val (newConflicts, _) = nextDependenciesAndConflicts
copy(dependencies = newDependencies ++ newConflicts, conflicts = newConflicts.toSet)
}
@ -512,9 +467,9 @@ object Resolver {
* If no module info is missing, the next state of the resolution, which can be immediately calculated.
* Else, the current resolution itself.
*/
def nextIfNoMissing(): Resolution = {
def nextIfNoMissing: Resolution = {
val missing = missingFromCache
if (missing.isEmpty) nextNoMissingUnsafe()
if (missing.isEmpty) nextNoMissingUnsafe
else this
}
@ -523,8 +478,8 @@ object Resolver {
*/
def next(fetchModule: ModuleVersion => EitherT[Task, List[String], (Repository, Project)]): Task[Resolution] = {
val missing = missingFromCache
if (missing.isEmpty) Task.now(nextNoMissingUnsafe())
else fetch(missing.toList, fetchModule).map(_.nextIfNoMissing())
if (missing.isEmpty) Task.now(nextNoMissingUnsafe)
else fetch(missing.toList, fetchModule).map(_.nextIfNoMissing)
}
/**
@ -636,20 +591,20 @@ object Resolver {
val lookups = modules.map(dep => fetchModule(dep).run.map(dep -> _))
val gatheredLookups = Task.gatherUnordered(lookups, exceptionCancels = true)
gatheredLookups.flatMap{ lookupResults =>
val errors0 = errors ++ lookupResults.collect{case (mod, -\/(repoErrors)) => mod -> repoErrors}
val newProjects = lookupResults.collect{case (mod, \/-(proj)) => mod -> proj}
val errors0 = errors ++ lookupResults.collect{case (modVer, -\/(repoErrors)) => modVer -> repoErrors}
val newProjects = lookupResults.collect{case (modVer, \/-(proj)) => modVer -> proj}
/*
* newProjects are project definitions, fresh from the repositories. We need to add
* dependency management / inheritance-related bits to them.
*/
newProjects.foldLeft(Task.now(copy(errors = errors0))) { case (accTask, (mod, (repo, proj))) =>
newProjects.foldLeft(Task.now(copy(errors = errors0))) { case (accTask, (modVer, (repo, proj))) =>
for {
current <- accTask
updated <- current.fetch(current.dependencyManagementMissing(proj).toList, fetchModule)
proj0 = updated.withDependencyManagement(proj)
} yield updated.copy(projectsCache = updated.projectsCache + (proj0.moduleVersion -> (repo, proj0)))
} yield updated.copy(projectsCache = updated.projectsCache + (modVer -> (repo, proj0)))
}
}
}

View File

@ -1,104 +1,210 @@
package coursier.core
import scala.annotation.tailrec
import coursier.core.compatibility._
case class Versions(latest: String,
release: String,
available: List[String],
lastUpdated: Option[DateTime])
/** Used internally by Resolver */
/**
* Used internally by Resolver.
*
* Same kind of ordering as aether-util/src/main/java/org/eclipse/aether/util/version/GenericVersion.java
*/
case class Version(repr: String) extends Ordered[Version] {
lazy val cmp = ComparableVersion.parse(repr)
def compare(other: Version): Int = {
cmp.compare(other.cmp)
}
lazy val items = Version.items(repr)
def compare(other: Version) = Version.listCompare(items, other.items)
def isEmpty = items.forall(_.isEmpty)
}
case class VersionInterval(from: Option[Version],
to: Option[Version],
fromIncluded: Boolean,
toIncluded: Boolean) {
object Version {
def isValid: Boolean = {
val fromToOrder =
for {
f <- from
t <- to
cmd = f.compare(t)
} yield cmd < 0 || (cmd == 0 && fromIncluded && toIncluded)
sealed trait Item extends Ordered[Item] {
def compare(other: Item): Int =
(this, other) match {
case (Number(a), Number(b)) => a.compare(b)
case (BigNumber(a), BigNumber(b)) => a.compare(b)
case (Number(a), BigNumber(b)) => -b.compare(a)
case (BigNumber(a), Number(b)) => a.compare(b)
case (Qualifier(_, a), Qualifier(_, b)) => a.compare(b)
case (Literal(a), Literal(b)) => a.compareToIgnoreCase(b)
fromToOrder.forall(x => x) && (from.nonEmpty || !fromIncluded) && (to.nonEmpty || !toIncluded)
}
case _ =>
val rel0 = compareToEmpty
val rel1 = other.compareToEmpty
def merge(other: VersionInterval): Option[VersionInterval] = {
val (newFrom, newFromIncluded) =
(from, other.from) match {
case (Some(a), Some(b)) =>
val cmp = a.compare(b)
if (cmp < 0) (Some(b), other.fromIncluded)
else if (cmp > 0) (Some(a), fromIncluded)
else (Some(a), fromIncluded && other.fromIncluded)
case (Some(a), None) => (Some(a), fromIncluded)
case (None, Some(b)) => (Some(b), other.fromIncluded)
case (None, None) => (None, false)
if (rel0 == rel1) order.compare(other.order)
else rel0.compare(rel1)
}
val (newTo, newToIncluded) =
(to, other.to) match {
case (Some(a), Some(b)) =>
val cmp = a.compare(b)
if (cmp < 0) (Some(a), toIncluded)
else if (cmp > 0) (Some(b), other.toIncluded)
else (Some(a), toIncluded && other.toIncluded)
case (Some(a), None) => (Some(a), toIncluded)
case (None, Some(b)) => (Some(b), other.toIncluded)
case (None, None) => (None, false)
}
Some(VersionInterval(newFrom, newTo, newFromIncluded, newToIncluded))
.filter(_.isValid)
def order: Int
def isEmpty: Boolean = compareToEmpty == 0
def compareToEmpty: Int = 1
}
def constraint: VersionConstraint =
this match {
case VersionInterval.zero => VersionConstraint.None
case VersionInterval(Some(version), None, true, false) => VersionConstraint.Preferred(version)
case itv => VersionConstraint.Interval(itv)
sealed trait Numeric extends Item
case class Number(value: Int) extends Numeric {
val order = 0
override def compareToEmpty = value.compare(0)
}
case class BigNumber(value: BigInt) extends Numeric {
val order = 0
override def compareToEmpty = value.compare(0)
}
case class Qualifier(value: String, level: Int) extends Item {
val order = -2
override def compareToEmpty = level.compare(0)
}
case class Literal(value: String) extends Item {
val order = -1
override def compareToEmpty = if (value.isEmpty) 0 else 1
}
case object Min extends Item {
val order = -8
override def compareToEmpty = -1
}
case object Max extends Item {
val order = 8
}
val empty = Number(0)
val qualifiers = Seq[Qualifier](
Qualifier("alpha", -5),
Qualifier("beta", -4),
Qualifier("milestone", -3),
Qualifier("cr", -2),
Qualifier("rc", -2),
Qualifier("snapshot", -1),
Qualifier("ga", 0),
Qualifier("final", 0),
Qualifier("sp", 1)
)
val qualifiersMap = qualifiers.map(q => q.value -> q).toMap
object Tokenizer {
sealed trait Separator
case object Dot extends Separator
case object Hyphen extends Separator
case object Underscore extends Separator
case object None extends Separator
def apply(s: String): (Item, Stream[(Separator, Item)]) = {
def parseItem(s: Stream[Char]): (Item, Stream[Char]) = {
if (s.isEmpty || !s.head.letterOrDigit) (empty, s)
else if (s.head.isDigit) {
def digits(b: StringBuilder, s: Stream[Char]): (String, Stream[Char]) =
if (s.isEmpty || !s.head.isDigit) (b.result(), s)
else digits(b + s.head, s.tail)
val (digits0, rem) = digits(new StringBuilder, s)
val item =
if (digits0.length >= 10) BigNumber(BigInt(digits0))
else Number(digits0.toInt)
(item, rem)
} else {
assert(s.head.letter)
def letters(b: StringBuilder, s: Stream[Char]): (String, Stream[Char]) =
if (s.isEmpty || !s.head.letter) (b.result().toLowerCase, s)
else letters(b + s.head, s.tail)
val (letters0, rem) = letters(new StringBuilder, s)
val item =
qualifiersMap.getOrElse(letters0, Literal(letters0))
(item, rem)
}
}
def parseSeparator(s: Stream[Char]): (Separator, Stream[Char]) = {
assert(s.nonEmpty)
s.head match {
case '.' => (Dot, s.tail)
case '-' => (Hyphen, s.tail)
case '_' => (Underscore, s.tail)
case _ => (None, s)
}
}
def helper(s: Stream[Char]): Stream[(Separator, Item)] = {
if (s.isEmpty) Stream()
else {
val (sep, rem0) = parseSeparator(s)
val (item, rem) = parseItem(rem0)
(sep, item) #:: helper(rem)
}
}
val (first, rem) = parseItem(s.toStream)
(first, helper(rem))
}
}
def items(repr: String): List[Item] = {
val (first, tokens) = Tokenizer(repr)
def isNumeric(item: Item) = item match { case _: Numeric => true; case _ => false }
def postProcess(prevIsNumeric: Option[Boolean], item: Item, tokens0: Stream[(Tokenizer.Separator, Item)]): Stream[Item] = {
val tokens = {
var _tokens = tokens0
if (isNumeric(item)) {
val nextNonDotZero = _tokens.dropWhile{case (Tokenizer.Dot, n: Numeric) => n.isEmpty; case _ => false }
if (nextNonDotZero.forall(t => t._1 == Tokenizer.Hyphen || ((t._1 == Tokenizer.Dot || t._1 == Tokenizer.None) && !isNumeric(t._2)))) { // Dot && isNumeric(t._2)
_tokens = nextNonDotZero
}
}
_tokens
}
def ifFollowedByNumberElse(ifFollowedByNumber: Item, default: Item) = {
val followedByNumber = tokens.headOption
.exists{ case (Tokenizer.None, num: Numeric) if !num.isEmpty => true; case _ => false }
if (followedByNumber) ifFollowedByNumber
else default
}
def next =
if (tokens.isEmpty) Stream()
else postProcess(Some(isNumeric(item)), tokens.head._2, tokens.tail)
item match {
case Literal("min") => Min #:: next
case Literal("max") => Max #:: next
case Literal("a") =>
ifFollowedByNumberElse(qualifiersMap("alpha"), item) #:: next
case Literal("b") =>
ifFollowedByNumberElse(qualifiersMap("beta"), item) #:: next
case Literal("m") =>
ifFollowedByNumberElse(qualifiersMap("milestone"), item) #:: next
case _ =>
item #:: next
}
}
def repr: String = Seq(
if (fromIncluded) "[" else "(",
from.map(_.repr).mkString,
",",
to.map(_.repr).mkString,
if (toIncluded) "]" else ")"
).mkString
}
postProcess(None, first, tokens).toList
}
object VersionInterval {
val zero = VersionInterval(None, None, fromIncluded = false, toIncluded = false)
}
@tailrec
def listCompare(first: List[Item], second: List[Item]): Int = {
if (first.isEmpty && second.isEmpty) 0
else if (first.isEmpty) {
assert(second.nonEmpty)
-second.dropWhile(_.isEmpty).headOption.fold(0)(_.compareToEmpty)
} else if (second.isEmpty) {
assert(first.nonEmpty)
first.dropWhile(_.isEmpty).headOption.fold(0)(_.compareToEmpty)
} else {
val rel = first.head.compare(second.head)
if (rel == 0) listCompare(first.tail, second.tail)
else rel
}
}
sealed trait VersionConstraint {
def interval: VersionInterval
def repr: String
}
object VersionConstraint {
/** Currently treated as minimum... */
case class Preferred(version: Version) extends VersionConstraint {
def interval: VersionInterval = VersionInterval(Some(version), Option.empty, fromIncluded = true, toIncluded = false)
def repr: String = version.repr
}
case class Interval(interval: VersionInterval) extends VersionConstraint {
def repr: String = interval.repr
}
case object None extends VersionConstraint {
val interval = VersionInterval.zero
def repr: String = "" // Once parsed, "(,)" becomes "" because of this
}
}

View File

@ -0,0 +1,102 @@
package coursier.core
case class VersionInterval(from: Option[Version],
to: Option[Version],
fromIncluded: Boolean,
toIncluded: Boolean) {
def isValid: Boolean = {
val fromToOrder =
for {
f <- from
t <- to
cmd = f.compare(t)
} yield cmd < 0 || (cmd == 0 && fromIncluded && toIncluded)
fromToOrder.forall(x => x) && (from.nonEmpty || !fromIncluded) && (to.nonEmpty || !toIncluded)
}
def contains(version: Version): Boolean = {
val fromCond =
from.forall { from0 =>
val cmp = from0.compare(version)
cmp < 0 || cmp == 0 && fromIncluded
}
lazy val toCond =
to.forall { to0 =>
val cmp = version.compare(to0)
cmp < 0 || cmp == 0 && toIncluded
}
fromCond && toCond
}
def merge(other: VersionInterval): Option[VersionInterval] = {
val (newFrom, newFromIncluded) =
(from, other.from) match {
case (Some(a), Some(b)) =>
val cmp = a.compare(b)
if (cmp < 0) (Some(b), other.fromIncluded)
else if (cmp > 0) (Some(a), fromIncluded)
else (Some(a), fromIncluded && other.fromIncluded)
case (Some(a), None) => (Some(a), fromIncluded)
case (None, Some(b)) => (Some(b), other.fromIncluded)
case (None, None) => (None, false)
}
val (newTo, newToIncluded) =
(to, other.to) match {
case (Some(a), Some(b)) =>
val cmp = a.compare(b)
if (cmp < 0) (Some(a), toIncluded)
else if (cmp > 0) (Some(b), other.toIncluded)
else (Some(a), toIncluded && other.toIncluded)
case (Some(a), None) => (Some(a), toIncluded)
case (None, Some(b)) => (Some(b), other.toIncluded)
case (None, None) => (None, false)
}
Some(VersionInterval(newFrom, newTo, newFromIncluded, newToIncluded))
.filter(_.isValid)
}
def constraint: VersionConstraint =
this match {
case VersionInterval.zero => VersionConstraint.None
case VersionInterval(Some(version), None, true, false) => VersionConstraint.Preferred(version)
case itv => VersionConstraint.Interval(itv)
}
def repr: String = Seq(
if (fromIncluded) "[" else "(",
from.map(_.repr).mkString,
",",
to.map(_.repr).mkString,
if (toIncluded) "]" else ")"
).mkString
}
object VersionInterval {
val zero = VersionInterval(None, None, fromIncluded = false, toIncluded = false)
}
sealed trait VersionConstraint {
def interval: VersionInterval
def repr: String
}
object VersionConstraint {
/** Currently treated as minimum... */
case class Preferred(version: Version) extends VersionConstraint {
def interval: VersionInterval = VersionInterval(Some(version), Option.empty, fromIncluded = true, toIncluded = false)
def repr: String = version.repr
}
case class Interval(interval: VersionInterval) extends VersionConstraint {
def repr: String = interval.repr
}
case object None extends VersionConstraint {
val interval = VersionInterval.zero
def repr: String = "" // Once parsed, "(,)" becomes "" because of this
}
}

View File

@ -1,7 +1,5 @@
package coursier.core
import coursier.core.compatibility.DateTime
import scalaz._
object Xml {
@ -87,8 +85,7 @@ object Xml {
mod,
version0,
scopeOpt getOrElse defaultScope,
typeOpt getOrElse defaultType,
classifierOpt getOrElse defaultClassifier,
Artifacts.Maven(typeOpt getOrElse defaultType, classifierOpt getOrElse defaultClassifier),
exclusions.map(mod => (mod.organization, mod.name)).toSet,
optional
)
@ -117,17 +114,18 @@ object Xml {
def profile(node: Node): String \/ Profile = {
import Scalaz._
val id = text(node, "id", "Profile ID").getOrElse("")
val xmlActivationOpt = node.child
.find(_.label == "activation")
val (activeByDefault, activation) = xmlActivationOpt.fold((Option.empty[Boolean], Activation(Nil)))(profileActivation)
val xmlDeps = node.child
.find(_.label == "dependencies")
.map(_.child.filter(_.label == "dependency"))
.getOrElse(Seq.empty)
for {
id <- text(node, "id", "Profile ID")
xmlActivationOpt = node.child
.find(_.label == "activation")
(activeByDefault, activation) = xmlActivationOpt.fold((Option.empty[Boolean], Activation(Nil)))(profileActivation)
xmlDeps = node.child
.find(_.label == "dependencies")
.map(_.child.filter(_.label == "dependency"))
.getOrElse(Seq.empty)
deps <- xmlDeps.toList.traverseU(dependency)
xmlDepMgmts = node.child
@ -141,6 +139,7 @@ object Xml {
.find(_.label == "properties")
.map(_.child.collect{case elem if elem.isElement => elem})
.getOrElse(Seq.empty)
properties <- {
import Scalaz._
xmlProperties.toList.traverseU(property)
@ -210,7 +209,8 @@ object Xml {
parentModuleOpt.map((_, parentVersionOpt.getOrElse(""))),
depMgmts,
properties.toMap,
profiles
profiles,
None
)
}
@ -238,7 +238,7 @@ object Xml {
lastUpdatedOpt = text(xmlVersioning, "lastUpdated", "Last update date and time")
.toOption
.filter(s => s.length == 14 && s.forall(_.isDigit))
.map(s => DateTime(
.map(s => Versions.DateTime(
s.substring(0, 4).toInt,
s.substring(4, 6).toInt,
s.substring(6, 8).toInt,

View File

@ -1,263 +0,0 @@
package coursier.core.compatibility
// Cut-n-pasted from http4s 0.7.0
// Replaced Writer usages with StringBuilder
final class DateTime private (val year: Int, // the year
val month: Int, // the month of the year. January is 1.
val day: Int, // the day of the month. The first day is 1.
val hour: Int, // the hour of the day. The first hour is 0.
val minute: Int, // the minute of the hour. The first minute is 0.
val second: Int, // the second of the minute. The first second is 0.
val weekday: Int, // the day of the week. Sunday is 0.
val clicks: Long) // milliseconds since January 1, 1970, 00:00:00 GMT
extends Ordered[DateTime] with Product6[Int, Int, Int, Int, Int, Int] {
import DateTime.StringBuilderExtensions
/**
* The day of the week as a 3 letter abbreviation:
* `Sun`, `Mon`, `Tue`, `Wed`, `Thu`, `Fri` or `Sat`
*/
def weekdayStr: String = DateTime.WEEKDAYS(weekday)
/**
* The day of the month as a 3 letter abbreviation:
* `Jan`, `Feb`, `Mar`, `Apr`, `May`, `Jun`, `Jul`, `Aug`, `Sep`, `Oct`, `Nov` or `Dec`
*/
def monthStr: String = DateTime.MONTHS(month - 1)
/**
* Creates a new `DateTime` that represents the point in time the given number of ms later.
*/
def +(millis: Long): DateTime = DateTime(clicks + millis)
/**
* Creates a new `DateTime` that represents the point in time the given number of ms earlier.
*/
def -(millis: Long): DateTime = DateTime(clicks - millis)
/**
* `yyyy-mm-ddThh:mm:ss`
*/
override def toString = toIsoDateTimeString
/**
* `yyyy-mm-dd`
*/
def renderIsoDate(w: StringBuilder): w.type = {
put_##(put_##(w << year << '-', month) << '-', day)
w
}
/**
* `yyyy-mm-dd`
*/
def toIsoDateString = { val w = new StringBuilder; renderIsoDate(w).result() }
/**
* `yyyy-mm-ddThh:mm:ss`
*/
def renderIsoDateTimeString(w: StringBuilder): w.type = {
put_##(put_##(put_##(renderIsoDate(w) << 'T', hour) << ':', minute) << ':', second)
w
}
/**
* `yyyy-mm-ddThh:mm:ss`
*/
def toIsoDateTimeString = { val w = new StringBuilder; renderIsoDateTimeString(w).result() }
/**
* `yyyy-mm-dd hh:mm:ss`
*/
def renderIsoLikeDateTimeString(w: StringBuilder): w.type = {
put_##(put_##(put_##(renderIsoDate(w) << ' ', hour) << ':', minute) << ':', second)
w
}
/**
* `yyyy-mm-dd hh:mm:ss`
*/
def toIsoLikeDateTimeString = { val w = new StringBuilder; renderIsoLikeDateTimeString(w).result() }
/**
* RFC1123 date string, e.g. `Sun, 06 Nov 1994 08:49:37 GMT`
*/
def renderRfc1123DateTimeString(w: StringBuilder): w.type = {
w ++= weekdayStr
w ++= ", "
put_##(put_##(put_##(put_##(w << weekdayStr << ',' << ' ', day) << ' ' << monthStr << ' ' << year << ' ', hour) << ':', minute) << ':', second) << " GMT"
w
}
/**
* RFC1123 date string, e.g. `Sun, 06 Nov 1994 08:49:37 GMT`
*/
def toRfc1123DateTimeString = { val w = new StringBuilder; renderRfc1123DateTimeString(w).result() }
private def put_##(w: StringBuilder, i: Int): w.type = {
w << (i / 10 + '0').toChar << (i % 10 + '0').toChar
w
}
def compare(that: DateTime): Int = math.signum(clicks - that.clicks).toInt
override def hashCode() = clicks.##
override def equals(obj: Any) = obj match {
case x: DateTime x.clicks == clicks
case _ false
}
override def _1: Int = year
override def _2: Int = month
override def _3: Int = day
override def _4: Int = hour
override def _5: Int = minute
override def _6: Int = second
override def canEqual(that: Any): Boolean = that.isInstanceOf[DateTime]
}
object DateTime {
private implicit class StringBuilderExtensions(val b: StringBuilder) extends AnyVal {
def <<(s: String): b.type = b ++= s
def <<(c: Char): b.type = b += c
def <<(n: Int): b.type = b ++= n.toString
}
val WEEKDAYS = Array("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat")
val MONTHS = Array("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec")
val MinValue = DateTime(1800, 1, 1)
val MaxValue = DateTime(2199, 12, 31, 23, 59, 59)
/**
* Creates a new `DateTime` with the given properties.
* Note that this implementation discards milliseconds (i.e. rounds down to full seconds).
*/
def apply(year: Int, month: Int, day: Int, hour: Int = 0, minute: Int = 0, second: Int = 0): DateTime = {
require(1800 <= year && year <= 9999, "year must be >= 1800 and <= 9999")
require(1 <= month && month <= 12, "month must be >= 1 and <= 12")
require(1 <= day && day <= 31, "day must be >= 1 and <= 31")
require(0 <= hour && hour <= 23, "hour must be >= 0 and <= 23")
require(0 <= minute && minute <= 59, "minute_ must be >= 0 and <= 59")
require(0 <= second && second <= 59, "second must be >= 0 and <= 59")
// compute yearday from month/monthday
val m = month - 1
var d = (m % 7) * 30 + (m % 7 + 1) / 2 + day
val isLeap = ((year % 4 == 0) && !(year % 100 == 0)) || (year % 400 == 0)
if (m >= 7) d += 214
if (d >= 61) d -= 1 // skip non-existent Feb 30
if (!isLeap && (d >= 60)) d -= 1 // skip non-existent Feb 29
// convert year/yearday to days since Jan 1, 1970, 00:00:00
val y = year - 1
d += y * 365 + y / 4 - y / 100 + y / 400
val dn = d - (1969 * 365 + 492 - 19 + 4)
val c = (dn - 1) * 86400L + hour * 3600L + minute * 60L + second // seconds since Jan 1, 1970, 00:00:00
new DateTime(year, month, day, hour, minute, second, weekday = d % 7, clicks = c * 1000)
}
/**
* Creates a new `DateTime` from the number of milli seconds
* since the start of "the epoch", namely January 1, 1970, 00:00:00 GMT.
* Note that this implementation discards milliseconds (i.e. rounds down to full seconds).
*/
def apply(clicks: Long): DateTime = {
require(DateTime.MinValue.clicks <= clicks && clicks <= DateTime.MaxValue.clicks,
"DateTime value must be >= " + DateTime.MinValue + " and <= " + DateTime.MaxValue)
// based on a fast RFC1123 implementation (C) 2000 by Tim Kientzle <kientzle@acm.org>
val c = clicks - clicks % 1000
// compute day number, seconds since beginning of day
var s = c
if (s >= 0) s /= 1000 // seconds since 1 Jan 1970
else s = (s - 999) / 1000 // floor(sec/1000)
var dn = (s / 86400).toInt
s %= 86400 // positive seconds since beginning of day
if (s < 0) { s += 86400; dn -= 1 }
dn += 1969 * 365 + 492 - 19 + 4 // days since "1 Jan, year 1"
// convert days since 1 Jan, year 1 to year/yearday
var y = 400 * (dn / 146097).toInt + 1
var d = dn % 146097
if (d == 146096) { y += 399; d = 365 } // last year of 400 is long
else {
y += 100 * (d / 36524)
d %= 36524
y += 4 * (d / 1461)
d %= 1461
if (d == 1460) { y += 3; d = 365 } // last year out of 4 is long
else {
y += d / 365
d %= 365
}
}
val isLeap = ((y % 4 == 0) && !(y % 100 == 0)) || (y % 400 == 0)
// compute month/monthday from year/yearday
if (!isLeap && (d >= 59)) d += 1 // skip non-existent Feb 29
if (d >= 60) d += 1 // skip non-existent Feb 30
var mon = ((d % 214) / 61) * 2 + ((d % 214) % 61) / 31
if (d > 213) mon += 7
d = ((d % 214) % 61) % 31 + 1
// convert second to hour/min/sec
var m = (s / 60).toInt
val h = m / 60
m %= 60
s %= 60
val w = (dn + 1) % 7 // day of week, 0==Sun
new DateTime(year = y, month = mon + 1, day = d, hour = h, minute = m, second = s.toInt, weekday = w, clicks = c)
}
/**
* Creates a new `DateTime` instance for the current point in time.
* Note that this implementation discards milliseconds (i.e. rounds down to full seconds).
*/
def now: DateTime = apply(System.currentTimeMillis)
/**
* Creates a new DateTime instance from the given String,
* if it adheres to the format `yyyy-mm-ddThh:mm:ss[.SSSZ]`.
* Note that this implementation discards milliseconds (i.e. rounds down to full seconds).
*/
def fromIsoDateTimeString(string: String): Option[DateTime] = {
def c(ix: Int) = string.charAt(ix)
def isDigit(c: Char) = '0' <= c && c <= '9'
def i(ix: Int) = {
val x = c(ix)
require(isDigit(x))
x - '0'
}
def check(len: Int): Boolean =
len match {
case 19 c(4) == '-' && c(7) == '-' && c(10) == 'T' && c(13) == ':' && c(16) == ':'
case 24 check(19) && c(19) == '.' && isDigit(c(20)) && isDigit(c(21)) && isDigit(c(22)) && c(23) == 'Z'
case _ false
}
if (check(string.length)) {
try {
val year = i(0) * 1000 + i(1) * 100 + i(2) * 10 + i(3)
val month = i(5) * 10 + i(6)
val day = i(8) * 10 + i(9)
val hour = i(11) * 10 + i(12)
val min = i(14) * 10 + i(15)
val sec = i(17) * 10 + i(18)
Some(DateTime(year, month, day, hour, min, sec))
} catch { case _: IllegalArgumentException None }
} else None
}
val UnixEpoch = DateTime(0L)
def unapply(dt: DateTime): Option[(Int, Int, Int, Int, Int, Int)] =
Some((dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second))
}

View File

@ -7,12 +7,21 @@ package object coursier {
object Dependency {
def apply(module: Module,
version: String,
scope: Scope = Scope.Other(""), // Subsituted by Resolver with its own default scope (compile)
`type`: String = "jar",
classifier: String = "",
scope: Scope = Scope.Other(""), // Substituted by Resolver with its own default scope (compile)
artifacts: Artifacts = Artifacts.Maven(),
exclusions: Set[(String, String)] = Set.empty,
optional: Boolean = false): Dependency =
core.Dependency(module, version, scope, `type`, classifier, exclusions, optional)
core.Dependency(module, version, scope, artifacts, exclusions, optional)
}
type Artifacts = core.Artifacts
object Artifacts {
type Maven = core.Artifacts.Maven
object Maven {
def apply(`type`: String = "jar",
classifier: String = ""): Maven =
core.Artifacts.Maven(`type`, classifier)
}
}
type Project = core.Project
@ -23,8 +32,9 @@ package object coursier {
parent: Option[ModuleVersion] = None,
dependencyManagement: Seq[Dependency] = Seq.empty,
properties: Map[String, String] = Map.empty,
profiles: Seq[Profile] = Seq.empty): Project =
core.Project(module, version, dependencies, parent, dependencyManagement, properties, profiles)
profiles: Seq[Profile] = Seq.empty,
versions: Option[core.Versions] = None): Project =
core.Project(module, version, dependencies, parent, dependencyManagement, properties, profiles, versions)
}
type Profile = core.Profile

View File

@ -0,0 +1,10 @@
com.chuusai:shapeless_2.11:jar:2.2.0
com.github.alexarchambault:argonaut-shapeless_6.1_2.11:jar:0.2.0
com.github.julien-truffaut:monocle-core_2.11:jar:1.1.0
com.github.julien-truffaut:monocle-macro_2.11:jar:1.1.0
io.argonaut:argonaut_2.11:jar:6.1
org.scala-lang.modules:scala-parser-combinators_2.11:jar:1.0.2
org.scala-lang.modules:scala-xml_2.11:jar:1.0.2
org.scala-lang:scala-library:jar:2.11.6
org.scala-lang:scala-reflect:jar:2.11.6
org.scalaz:scalaz-core_2.11:jar:7.1.1

View File

@ -0,0 +1,10 @@
com.chuusai:shapeless_2.11:jar:2.2.0
com.github.alexarchambault:argonaut-shapeless_6.1_2.11:jar:0.2.0
com.github.julien-truffaut:monocle-core_2.11:jar:1.1.0
com.github.julien-truffaut:monocle-macro_2.11:jar:1.1.0
io.argonaut:argonaut_2.11:jar:6.1
org.scala-lang.modules:scala-parser-combinators_2.11:jar:1.0.2
org.scala-lang.modules:scala-xml_2.11:jar:1.0.2
org.scala-lang:scala-library:jar:2.11.6
org.scala-lang:scala-reflect:jar:2.11.6
org.scalaz:scalaz-core_2.11:jar:7.1.1

View File

@ -0,0 +1,128 @@
aopalliance:aopalliance:jar:1.0
asm:asm:jar:3.1
com.clearspring.analytics:stream:jar:2.7.0
com.esotericsoftware.kryo:kryo:jar:2.21
com.esotericsoftware.minlog:minlog:jar:1.2
com.esotericsoftware.reflectasm:reflectasm:jar:shaded:1.07
com.fasterxml.jackson.core:jackson-annotations:jar:2.4.4
com.fasterxml.jackson.core:jackson-core:jar:2.4.4
com.fasterxml.jackson.core:jackson-databind:jar:2.4.4
com.fasterxml.jackson.module:jackson-module-scala_2.11:jar:2.4.4
com.google.code.findbugs:jsr305:jar:2.0.1
com.google.guava:guava:jar:14.0.1
com.google.inject:guice:jar:3.0
com.google.protobuf:protobuf-java:jar:2.5.0
com.ning:compress-lzf:jar:1.0.0
com.sun.jersey.contribs:jersey-guice:jar:1.9
com.sun.jersey.jersey-test-framework:jersey-test-framework-core:jar:1.9
com.sun.jersey.jersey-test-framework:jersey-test-framework-grizzly2:jar:1.9
com.sun.jersey:jersey-client:jar:1.9
com.sun.jersey:jersey-core:jar:1.9
com.sun.jersey:jersey-grizzly2:jar:1.9
com.sun.jersey:jersey-json:jar:1.9
com.sun.jersey:jersey-server:jar:1.9
com.sun.xml.bind:jaxb-impl:jar:2.2.3-1
com.thoughtworks.paranamer:paranamer:jar:2.6
com.twitter:chill-java:jar:0.5.0
com.twitter:chill_2.11:jar:0.5.0
com.typesafe:config:jar:1.2.1
commons-beanutils:commons-beanutils-core:jar:1.8.0
commons-beanutils:commons-beanutils:jar:1.7.0
commons-cli:commons-cli:jar:1.2
commons-codec:commons-codec:jar:1.4
commons-collections:commons-collections:jar:3.2.1
commons-configuration:commons-configuration:jar:1.6
commons-digester:commons-digester:jar:1.8
commons-httpclient:commons-httpclient:jar:3.1
commons-io:commons-io:jar:2.4
commons-lang:commons-lang:jar:2.5
commons-logging:commons-logging:jar:1.1.1
commons-net:commons-net:jar:3.1
io.dropwizard.metrics:metrics-core:jar:3.1.0
io.dropwizard.metrics:metrics-graphite:jar:3.1.0
io.dropwizard.metrics:metrics-json:jar:3.1.0
io.dropwizard.metrics:metrics-jvm:jar:3.1.0
io.netty:netty-all:jar:4.0.23.Final
io.netty:netty:jar:3.8.0.Final
javax.activation:activation:jar:1.1
javax.inject:javax.inject:jar:1
javax.servlet:javax.servlet-api:jar:3.0.1
javax.xml.bind:jaxb-api:jar:2.2.2
jline:jline:jar:0.9.94
log4j:log4j:jar:1.2.17
net.java.dev.jets3t:jets3t:jar:0.7.1
net.jpountz.lz4:lz4:jar:1.2.0
net.sf.py4j:py4j:jar:0.8.2.1
org.apache.avro:avro:jar:1.7.4
org.apache.commons:commons-compress:jar:1.4.1
org.apache.commons:commons-lang3:jar:3.3.2
org.apache.commons:commons-math3:jar:3.1.1
org.apache.commons:commons-math:jar:2.1
org.apache.curator:curator-client:jar:2.4.0
org.apache.curator:curator-framework:jar:2.4.0
org.apache.curator:curator-recipes:jar:2.4.0
org.apache.hadoop:hadoop-annotations:jar:2.2.0
org.apache.hadoop:hadoop-auth:jar:2.2.0
org.apache.hadoop:hadoop-client:jar:2.2.0
org.apache.hadoop:hadoop-common:jar:2.2.0
org.apache.hadoop:hadoop-hdfs:jar:2.2.0
org.apache.hadoop:hadoop-mapreduce-client-app:jar:2.2.0
org.apache.hadoop:hadoop-mapreduce-client-common:jar:2.2.0
org.apache.hadoop:hadoop-mapreduce-client-core:jar:2.2.0
org.apache.hadoop:hadoop-mapreduce-client-jobclient:jar:2.2.0
org.apache.hadoop:hadoop-mapreduce-client-shuffle:jar:2.2.0
org.apache.hadoop:hadoop-yarn-api:jar:2.2.0
org.apache.hadoop:hadoop-yarn-client:jar:2.2.0
org.apache.hadoop:hadoop-yarn-common:jar:2.2.0
org.apache.hadoop:hadoop-yarn-server-common:jar:2.2.0
org.apache.hadoop:hadoop-yarn-server-nodemanager:jar:2.2.0
org.apache.ivy:ivy:jar:2.4.0
org.apache.mesos:mesos:jar:shaded-protobuf:0.21.0
org.apache.spark:spark-core_2.11:jar:1.3.1
org.apache.spark:spark-network-common_2.11:jar:1.3.1
org.apache.spark:spark-network-shuffle_2.11:jar:1.3.1
org.apache.zookeeper:zookeeper:jar:3.4.5
org.codehaus.jackson:jackson-core-asl:jar:1.8.8
org.codehaus.jackson:jackson-jaxrs:jar:1.8.3
org.codehaus.jackson:jackson-mapper-asl:jar:1.8.8
org.codehaus.jackson:jackson-xc:jar:1.8.3
org.codehaus.jettison:jettison:jar:1.1
org.eclipse.jetty.orbit:javax.servlet:jar:3.0.0.v201112011016
org.glassfish.external:management-api:jar:3.0.0-b012
org.glassfish.gmbal:gmbal-api-only:jar:3.0.0-b023
org.glassfish.grizzly:grizzly-framework:jar:2.1.2
org.glassfish.grizzly:grizzly-http-server:jar:2.1.2
org.glassfish.grizzly:grizzly-http-servlet:jar:2.1.2
org.glassfish.grizzly:grizzly-http:jar:2.1.2
org.glassfish.grizzly:grizzly-rcm:jar:2.1.2
org.glassfish:javax.servlet:jar:3.1
org.json4s:json4s-ast_2.11:jar:3.2.10
org.json4s:json4s-core_2.11:jar:3.2.10
org.json4s:json4s-jackson_2.11:jar:3.2.10
org.mortbay.jetty:jetty-util:jar:6.1.26
org.objenesis:objenesis:jar:1.2
org.roaringbitmap:RoaringBitmap:jar:0.4.5
org.scala-lang.modules:scala-parser-combinators_2.11:jar:1.0.1
org.scala-lang.modules:scala-xml_2.11:jar:1.0.1
org.scala-lang:scala-compiler:jar:2.11.0
org.scala-lang:scala-library:jar:2.11.2
org.scala-lang:scala-reflect:jar:2.11.2
org.scala-lang:scalap:jar:2.11.0
org.slf4j:jcl-over-slf4j:jar:1.7.10
org.slf4j:jul-to-slf4j:jar:1.7.10
org.slf4j:slf4j-api:jar:1.7.10
org.slf4j:slf4j-log4j12:jar:1.7.10
org.spark-project.akka:akka-actor_2.11:jar:2.3.4-spark
org.spark-project.akka:akka-remote_2.11:jar:2.3.4-spark
org.spark-project.akka:akka-slf4j_2.11:jar:2.3.4-spark
org.spark-project.protobuf:protobuf-java:jar:2.5.0-spark
org.spark-project.spark:unused:jar:1.0.0
org.spark-project:pyrolite:jar:2.0.1
org.tachyonproject:tachyon-client:jar:0.5.0
org.tachyonproject:tachyon:jar:0.5.0
org.tukaani:xz:jar:1.0
org.uncommons.maths:uncommons-maths:jar:1.2.2a
org.xerial.snappy:snappy-java:jar:1.1.1.6
oro:oro:jar:2.0.8
stax:stax-api:jar:1.0.1
xmlenc:xmlenc:jar:0.52

View File

@ -0,0 +1,127 @@
aopalliance:aopalliance:jar:1.0
asm:asm:jar:3.1
com.clearspring.analytics:stream:jar:2.7.0
com.esotericsoftware.kryo:kryo:jar:2.21
com.esotericsoftware.minlog:minlog:jar:1.2
com.esotericsoftware.reflectasm:reflectasm:jar:shaded:1.07
com.fasterxml.jackson.core:jackson-annotations:jar:2.4.0
com.fasterxml.jackson.core:jackson-core:jar:2.4.4
com.fasterxml.jackson.core:jackson-databind:jar:2.4.4
com.fasterxml.jackson.module:jackson-module-scala_2.11:jar:2.4.4
com.google.code.findbugs:jsr305:jar:1.3.9
com.google.guava:guava:jar:14.0.1
com.google.inject:guice:jar:3.0
com.google.protobuf:protobuf-java:jar:2.5.0
com.ning:compress-lzf:jar:1.0.0
com.sun.jersey.contribs:jersey-guice:jar:1.9
com.sun.jersey.jersey-test-framework:jersey-test-framework-core:jar:1.9
com.sun.jersey.jersey-test-framework:jersey-test-framework-grizzly2:jar:1.9
com.sun.jersey:jersey-client:jar:1.9
com.sun.jersey:jersey-core:jar:1.9
com.sun.jersey:jersey-grizzly2:jar:1.9
com.sun.jersey:jersey-json:jar:1.9
com.sun.jersey:jersey-server:jar:1.9
com.sun.xml.bind:jaxb-impl:jar:2.2.3-1
com.thoughtworks.paranamer:paranamer:jar:2.6
com.twitter:chill-java:jar:0.5.0
com.twitter:chill_2.11:jar:0.5.0
com.typesafe:config:jar:1.2.1
commons-beanutils:commons-beanutils-core:jar:1.8.0
commons-beanutils:commons-beanutils:jar:1.7.0
commons-cli:commons-cli:jar:1.2
commons-codec:commons-codec:jar:1.3
commons-collections:commons-collections:jar:3.2.1
commons-configuration:commons-configuration:jar:1.6
commons-digester:commons-digester:jar:1.8
commons-httpclient:commons-httpclient:jar:3.1
commons-io:commons-io:jar:2.1
commons-lang:commons-lang:jar:2.5
commons-logging:commons-logging:jar:1.1.1
commons-net:commons-net:jar:2.2
io.dropwizard.metrics:metrics-core:jar:3.1.0
io.dropwizard.metrics:metrics-graphite:jar:3.1.0
io.dropwizard.metrics:metrics-json:jar:3.1.0
io.dropwizard.metrics:metrics-jvm:jar:3.1.0
io.netty:netty-all:jar:4.0.23.Final
io.netty:netty:jar:3.8.0.Final
javax.activation:activation:jar:1.1
javax.inject:javax.inject:jar:1
javax.servlet:javax.servlet-api:jar:3.0.1
javax.xml.bind:jaxb-api:jar:2.2.2
jline:jline:jar:0.9.94
log4j:log4j:jar:1.2.17
net.java.dev.jets3t:jets3t:jar:0.7.1
net.jpountz.lz4:lz4:jar:1.2.0
net.sf.py4j:py4j:jar:0.8.2.1
org.apache.avro:avro:jar:1.7.4
org.apache.commons:commons-compress:jar:1.4.1
org.apache.commons:commons-lang3:jar:3.3.2
org.apache.commons:commons-math3:jar:3.1.1
org.apache.commons:commons-math:jar:2.1
org.apache.curator:curator-client:jar:2.4.0
org.apache.curator:curator-framework:jar:2.4.0
org.apache.curator:curator-recipes:jar:2.4.0
org.apache.hadoop:hadoop-annotations:jar:2.2.0
org.apache.hadoop:hadoop-auth:jar:2.2.0
org.apache.hadoop:hadoop-client:jar:2.2.0
org.apache.hadoop:hadoop-common:jar:2.2.0
org.apache.hadoop:hadoop-hdfs:jar:2.2.0
org.apache.hadoop:hadoop-mapreduce-client-app:jar:2.2.0
org.apache.hadoop:hadoop-mapreduce-client-common:jar:2.2.0
org.apache.hadoop:hadoop-mapreduce-client-core:jar:2.2.0
org.apache.hadoop:hadoop-mapreduce-client-jobclient:jar:2.2.0
org.apache.hadoop:hadoop-mapreduce-client-shuffle:jar:2.2.0
org.apache.hadoop:hadoop-yarn-api:jar:2.2.0
org.apache.hadoop:hadoop-yarn-client:jar:2.2.0
org.apache.hadoop:hadoop-yarn-common:jar:2.2.0
org.apache.hadoop:hadoop-yarn-server-common:jar:2.2.0
org.apache.ivy:ivy:jar:2.4.0
org.apache.mesos:mesos:jar:shaded-protobuf:0.21.0
org.apache.spark:spark-core_2.11:jar:1.3.1
org.apache.spark:spark-network-common_2.11:jar:1.3.1
org.apache.spark:spark-network-shuffle_2.11:jar:1.3.1
org.apache.zookeeper:zookeeper:jar:3.4.5
org.codehaus.jackson:jackson-core-asl:jar:1.8.8
org.codehaus.jackson:jackson-jaxrs:jar:1.8.3
org.codehaus.jackson:jackson-mapper-asl:jar:1.8.8
org.codehaus.jackson:jackson-xc:jar:1.8.3
org.codehaus.jettison:jettison:jar:1.1
org.eclipse.jetty.orbit:javax.servlet:jar:3.0.0.v201112011016
org.glassfish.external:management-api:jar:3.0.0-b012
org.glassfish.gmbal:gmbal-api-only:jar:3.0.0-b023
org.glassfish.grizzly:grizzly-framework:jar:2.1.2
org.glassfish.grizzly:grizzly-http-server:jar:2.1.2
org.glassfish.grizzly:grizzly-http-servlet:jar:2.1.2
org.glassfish.grizzly:grizzly-http:jar:2.1.2
org.glassfish.grizzly:grizzly-rcm:jar:2.1.2
org.glassfish:javax.servlet:jar:3.1
org.json4s:json4s-ast_2.11:jar:3.2.10
org.json4s:json4s-core_2.11:jar:3.2.10
org.json4s:json4s-jackson_2.11:jar:3.2.10
org.mortbay.jetty:jetty-util:jar:6.1.26
org.objenesis:objenesis:jar:1.2
org.roaringbitmap:RoaringBitmap:jar:0.4.5
org.scala-lang.modules:scala-parser-combinators_2.11:jar:1.0.1
org.scala-lang.modules:scala-xml_2.11:jar:1.0.1
org.scala-lang:scala-compiler:jar:2.11.0
org.scala-lang:scala-library:jar:2.11.2
org.scala-lang:scala-reflect:jar:2.11.2
org.scala-lang:scalap:jar:2.11.0
org.slf4j:jcl-over-slf4j:jar:1.7.10
org.slf4j:jul-to-slf4j:jar:1.7.10
org.slf4j:slf4j-api:jar:1.7.10
org.slf4j:slf4j-log4j12:jar:1.7.10
org.spark-project.akka:akka-actor_2.11:jar:2.3.4-spark
org.spark-project.akka:akka-remote_2.11:jar:2.3.4-spark
org.spark-project.akka:akka-slf4j_2.11:jar:2.3.4-spark
org.spark-project.protobuf:protobuf-java:jar:2.5.0-spark
org.spark-project.spark:unused:jar:1.0.0
org.spark-project:pyrolite:jar:2.0.1
org.tachyonproject:tachyon-client:jar:0.5.0
org.tachyonproject:tachyon:jar:0.5.0
org.tukaani:xz:jar:1.0
org.uncommons.maths:uncommons-maths:jar:1.2.2a
org.xerial.snappy:snappy-java:jar:1.1.1.6
oro:oro:jar:2.0.8
stax:stax-api:jar:1.0.1
xmlenc:xmlenc:jar:0.52

View File

@ -12,26 +12,41 @@ object CentralTests extends TestSuite {
repository.mavenCentral
)
def repr(dep: Dependency) = {
val (type0, classifier) = dep.artifacts match {
case maven: Artifacts.Maven => (maven.`type`, maven.classifier)
}
s"${dep.module.organization}:${dep.module.name}:$type0:${Some(classifier).filter(_.nonEmpty).map(_+":").mkString}${dep.version}"
}
def resolutionCheck(module: Module, version: String) =
async {
val expected = await(textResource(s"resolutions/${module.organization}:${module.name}:$version")).split('\n').toSeq
val dep = Dependency(module, version)
val res = await(resolve(Set(dep), fetchFrom(repositories)).runF)
val result = res.dependencies.toVector.map(repr).sorted.distinct
for (((e, r), idx) <- expected.zip(result).zipWithIndex if e != r)
println(s"Line $idx:\n expected: $e\n got:$r")
assert(result == expected)
}
val tests = TestSuite {
'logback{
async {
val dep = Dependency(Module("ch.qos.logback", "logback-classic"), "1.1.3")
val res0 =
await(resolve(Set(dep), fetchFrom(repositories))
.runF)
val res = res0.copy(
projectsCache = Map.empty, errors = Map.empty // No validating these here
)
val res = await(resolve(Set(dep), fetchFrom(repositories)).runF)
.copy(projectsCache = Map.empty, errors = Map.empty) // No validating these here
val expected = Resolution(
rootDependencies = Set(dep.withCompileScope),
dependencies = Set(
dep.withCompileScope,
Dependency(Module("ch.qos.logback", "logback-core"), "1.1.3").withCompileScope,
Dependency(Module("org.slf4j", "slf4j-api"), "1.7.7").withCompileScope
)
)
Dependency(Module("org.slf4j", "slf4j-api"), "1.7.7").withCompileScope))
assert(res == expected)
}
@ -39,26 +54,43 @@ object CentralTests extends TestSuite {
'asm{
async {
val dep = Dependency(Module("org.ow2.asm", "asm-commons"), "5.0.2")
val res0 =
await(resolve(Set(dep), fetchFrom(repositories))
.runF)
val res = res0.copy(
projectsCache = Map.empty, errors = Map.empty // No validating these here
)
val res = await(resolve(Set(dep), fetchFrom(repositories)).runF)
.copy(projectsCache = Map.empty, errors = Map.empty) // No validating these here
val expected = Resolution(
rootDependencies = Set(dep.withCompileScope),
dependencies = Set(
dep.withCompileScope,
Dependency(Module("org.ow2.asm", "asm-tree"), "5.0.2").withCompileScope,
Dependency(Module("org.ow2.asm", "asm"), "5.0.2").withCompileScope
)
)
Dependency(Module("org.ow2.asm", "asm"), "5.0.2").withCompileScope))
assert(res == expected)
}
}
'jodaVersionInterval{
async {
val dep = Dependency(Module("joda-time", "joda-time"), "[2.2,2.8]")
val res0 = await(resolve(Set(dep), fetchFrom(repositories)).runF)
val res = res0.copy(projectsCache = Map.empty, errors = Map.empty)
val expected = Resolution(
rootDependencies = Set(dep.withCompileScope),
dependencies = Set(
dep.withCompileScope))
assert(res == expected)
assert(res0.projectsCache.contains(dep.moduleVersion))
val (_, proj) = res0.projectsCache(dep.moduleVersion)
assert(proj.version == "2.8")
}
}
'spark{
resolutionCheck(Module("org.apache.spark", "spark-core_2.11"), "1.3.1")
}
'argonautShapeless{
resolutionCheck(Module("com.github.alexarchambault", "argonaut-shapeless_6.1_2.11"), "0.2.0")
}
}
}

View File

@ -2,7 +2,7 @@ package coursier
package test
import utest._
import core.Resolver.{ exclusionsAdd, exclusionsIntersect }
import core.Resolver.exclusionsAdd
object ExclusionsTests extends TestSuite {
@ -66,59 +66,6 @@ object ExclusionsTests extends TestSuite {
assert(resultb2 == eb)
}
}
'intersect{
'basicZero{
val result1l = exclusionsIntersect(e1, Set.empty)
val result1r = exclusionsIntersect(Set.empty, e1)
val result2l = exclusionsIntersect(e2, Set.empty)
val result2r = exclusionsIntersect(Set.empty, e2)
assert(result1l == Set.empty)
assert(result1r == Set.empty)
assert(result2l == Set.empty)
assert(result2r == Set.empty)
}
'basic{
val expected = e1 ++ e2
val result12 = exclusionsIntersect(e1, e2)
val result21 = exclusionsIntersect(e2, e1)
assert(result12 == Set.empty)
assert(result21 == Set.empty)
}
'nameBlob{
val result1b = exclusionsIntersect(e1, enb)
val resultb1 = exclusionsIntersect(enb, e1)
val result2b = exclusionsIntersect(e2, enb)
val resultb2 = exclusionsIntersect(enb, e2)
assert(result1b == e1)
assert(resultb1 == e1)
assert(result2b == Set.empty)
assert(resultb2 == Set.empty)
}
'orgBlob{
val result1b = exclusionsIntersect(e1, eob)
val resultb1 = exclusionsIntersect(eob, e1)
val result2b = exclusionsIntersect(e2, eob)
val resultb2 = exclusionsIntersect(eob, e2)
assert(result1b == e1)
assert(resultb1 == e1)
assert(result2b == Set.empty)
assert(resultb2 == Set.empty)
}
'blob{
val result1b = exclusionsIntersect(e1, eb)
val resultb1 = exclusionsIntersect(eb, e1)
val result2b = exclusionsIntersect(e2, eb)
val resultb2 = exclusionsIntersect(eb, e2)
assert(result1b == e1)
assert(resultb1 == e1)
assert(result2b == e2)
assert(resultb2 == e2)
}
}
}
}

View File

@ -21,7 +21,7 @@ object PomParsingTests extends TestSuite {
</dependency>
"""
val expected = \/-(Dependency(Module("comp", "lib"), "2.1", classifier = "extra"))
val expected = \/-(Dependency(Module("comp", "lib"), "2.1", artifacts = Artifacts.Maven(classifier = "extra")))
val result = Xml.dependency(xmlParse(depNode).right.get)
@ -40,6 +40,21 @@ object PomParsingTests extends TestSuite {
assert(result == expected)
}
'beFineWithProfilesWithNoId{
val profileNode = """
<profile>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
"""
val expected = \/-(Profile("", Some(true), Activation(Nil), Nil, Nil, Map.empty))
val result = Xml.profile(xmlParse(profileNode).right.get)
assert(result == expected)
}
'readProfileActivatedByDefault{
val profileNode ="""
<profile>

View File

@ -22,7 +22,7 @@ object ResolverTests extends TestSuite {
Project(Module("acme", "play-json"), "2.4.0"),
Project(Module("acme", "play"), "2.4.1",
Seq(
dependencies = Seq(
Dependency(Module("acme", "play-json"), "${playJsonVersion}"),
Dependency(Module("${project.groupId}", "${configName}"), "1.3.0")),
properties = Map(
@ -52,9 +52,8 @@ object ResolverTests extends TestSuite {
exclusions = Set(("acme", "play-json"))))),
Project(Module("se.ikea", "billy"), "18.0",
Seq(
Dependency(Module("acme", "play"), "")
),
dependencies = Seq(
Dependency(Module("acme", "play"), "")),
parent = Some(Module("se.ikea", "parent"), "18.0")),
Project(Module("org.gnome", "parent"), "7.0",
@ -62,7 +61,7 @@ object ResolverTests extends TestSuite {
Dependency(Module("org.gnu", "glib"), "13.4"))),
Project(Module("org.gnome", "panel-legacy"), "7.0",
Seq(
dependencies = Seq(
Dependency(Module("org.gnome", "desktop"), "${project.version}")),
parent = Some(Module("org.gnome", "parent"), "7.0")),
@ -71,13 +70,13 @@ object ResolverTests extends TestSuite {
Dependency(Module("gov.nsa", "crypto"), "536.89"))),
Project(Module("com.mailapp", "mail-client"), "2.1",
Seq(
dependencies = Seq(
Dependency(Module("gov.nsa", "secure-pgp"), "10.0",
exclusions = Set(("*", "${crypto.name}")))),
properties = Map("crypto.name" -> "crypto", "dummy" -> "2")),
Project(Module("com.thoughtworks.paranamer", "paranamer-parent"), "2.6",
Seq(
dependencies = Seq(
Dependency(Module("junit", "junit"), "")),
dependencyManagement = Seq(
Dependency(Module("junit", "junit"), "4.11", scope = Scope.Test))),
@ -88,44 +87,33 @@ object ResolverTests extends TestSuite {
Project(Module("com.github.dummy", "libb"), "0.3.3",
profiles = Seq(
Profile("default", activeByDefault = Some(true), dependencies = Seq(
Dependency(Module("org.escalier", "librairie-standard"), "2.11.6")
))
)),
Dependency(Module("org.escalier", "librairie-standard"), "2.11.6"))))),
Project(Module("com.github.dummy", "libb"), "0.4.2",
Seq(
Dependency(Module("org.scalaverification", "scala-verification"), "1.12.4")
),
dependencies = Seq(
Dependency(Module("org.scalaverification", "scala-verification"), "1.12.4")),
profiles = Seq(
Profile("default", activeByDefault = Some(true), dependencies = Seq(
Dependency(Module("org.escalier", "librairie-standard"), "2.11.6"),
Dependency(Module("org.scalaverification", "scala-verification"), "1.12.4", scope = Scope.Test)
))
)),
Dependency(Module("org.scalaverification", "scala-verification"), "1.12.4", scope = Scope.Test))))),
Project(Module("com.github.dummy", "libb"), "0.5.3",
properties = Map("special" -> "true"),
profiles = Seq(
Profile("default", activation = Profile.Activation(properties = Seq("special" -> None)), dependencies = Seq(
Dependency(Module("org.escalier", "librairie-standard"), "2.11.6")
))
)),
Dependency(Module("org.escalier", "librairie-standard"), "2.11.6"))))),
Project(Module("com.github.dummy", "libb"), "0.5.4",
properties = Map("special" -> "true"),
profiles = Seq(
Profile("default", activation = Profile.Activation(properties = Seq("special" -> Some("true"))), dependencies = Seq(
Dependency(Module("org.escalier", "librairie-standard"), "2.11.6")
))
)),
Dependency(Module("org.escalier", "librairie-standard"), "2.11.6"))))),
Project(Module("com.github.dummy", "libb"), "0.5.5",
properties = Map("special" -> "true"),
profiles = Seq(
Profile("default", activation = Profile.Activation(properties = Seq("special" -> Some("!false"))), dependencies = Seq(
Dependency(Module("org.escalier", "librairie-standard"), "2.11.6")
))
)),
Dependency(Module("org.escalier", "librairie-standard"), "2.11.6"))))),
Project(Module("com.github.dummy", "libb-parent"), "0.5.6",
properties = Map("special" -> "true")),
@ -135,9 +123,21 @@ object ResolverTests extends TestSuite {
properties = Map("special" -> "true"),
profiles = Seq(
Profile("default", activation = Profile.Activation(properties = Seq("special" -> Some("!false"))), dependencies = Seq(
Dependency(Module("org.escalier", "librairie-standard"), "2.11.6")
))
))
Dependency(Module("org.escalier", "librairie-standard"), "2.11.6"))))),
Project(Module("an-org", "a-name"), "1.0"),
Project(Module("an-org", "a-lib"), "1.0",
Seq(Dependency(Module("an-org", "a-name"), "1.0"))),
Project(Module("an-org", "another-lib"), "1.0",
Seq(Dependency(Module("an-org", "a-name"), "1.0"))),
// Must bring transitively an-org:a-name, as an optional dependency
Project(Module("an-org", "an-app"), "1.0",
Seq(
Dependency(Module("an-org", "a-lib"), "1.0", exclusions = Set(("an-org", "a-name"))),
Dependency(Module("an-org", "another-lib"), "1.0", optional = true)))
)
val projectsMap = projects.map(p => p.moduleVersion -> p).toMap
@ -153,8 +153,7 @@ object ResolverTests extends TestSuite {
val res = await(resolve(
Set.empty,
fetchFrom(repositories)
).runF
)
).runF)
assert(res == Resolution.empty)
}
@ -178,236 +177,215 @@ object ResolverTests extends TestSuite {
}
'single{
async {
val dep = Dependency(Module("acme", "config"), "1.3.0")
val res = await(resolve(
Set(dep),
fetchFrom(repositories)
).runF)
val dep = Dependency(Module("acme", "config"), "1.3.0")
val res = await(resolve(
Set(dep),
fetchFrom(repositories)
).runF)
val expected = Resolution(
rootDependencies = Set(dep.withCompileScope),
dependencies = Set(dep.withCompileScope),
projectsCache = Map(dep.moduleVersion -> (testRepository, projectsMap(dep.moduleVersion)))
)
val expected = Resolution(
rootDependencies = Set(dep.withCompileScope),
dependencies = Set(dep.withCompileScope),
projectsCache = Map(dep.moduleVersion -> (testRepository, projectsMap(dep.moduleVersion)))
)
assert(res == expected)
assert(res == expected)
}
}
'oneTransitiveDependency{
async {
val dep = Dependency(Module("acme", "play"), "2.4.0")
val trDep = Dependency(Module("acme", "play-json"), "2.4.0")
val res = await(resolve(
Set(dep),
fetchFrom(repositories)
).runF)
val dep = Dependency(Module("acme", "play"), "2.4.0")
val trDep = Dependency(Module("acme", "play-json"), "2.4.0")
val res = await(resolve(
Set(dep),
fetchFrom(repositories)
).runF)
val expected = Resolution(
rootDependencies = Set(dep.withCompileScope),
dependencies = Set(dep.withCompileScope, trDep.withCompileScope),
projectsCache = Map(
projectsMap(dep.moduleVersion).kv,
projectsMap(trDep.moduleVersion).kv
val expected = Resolution(
rootDependencies = Set(dep.withCompileScope),
dependencies = Set(dep.withCompileScope, trDep.withCompileScope),
projectsCache = Map(
projectsMap(dep.moduleVersion).kv,
projectsMap(trDep.moduleVersion).kv
)
)
)
assert(res == expected)
assert(res == expected)
}
}
'twoTransitiveDependencyWithProps{
async {
val dep = Dependency(Module("acme", "play"), "2.4.1")
val trDeps = Seq(
Dependency(Module("acme", "play-json"), "2.4.0"),
Dependency(Module("acme", "config"), "1.3.0")
)
val res = await(resolve(
Set(dep),
fetchFrom(repositories)
).runF)
val dep = Dependency(Module("acme", "play"), "2.4.1")
val trDeps = Seq(
Dependency(Module("acme", "play-json"), "2.4.0"),
Dependency(Module("acme", "config"), "1.3.0")
)
val res = await(resolve(
Set(dep),
fetchFrom(repositories)
).runF)
val expected = Resolution(
rootDependencies = Set(dep.withCompileScope),
dependencies = Set(dep.withCompileScope) ++ trDeps.map(_.withCompileScope),
projectsCache = Map(
projectsMap(dep.moduleVersion).kv
) ++ trDeps.map(trDep => projectsMap(trDep.moduleVersion).kv)
)
val expected = Resolution(
rootDependencies = Set(dep.withCompileScope),
dependencies = Set(dep.withCompileScope) ++ trDeps.map(_.withCompileScope),
projectsCache = Map(
projectsMap(dep.moduleVersion).kv
) ++ trDeps.map(trDep => projectsMap(trDep.moduleVersion).kv)
)
assert(res == expected)
assert(res == expected)
}
}
'exclude{
async {
val dep = Dependency(Module("acme", "play-extra-no-config"), "2.4.1")
val trDeps = Seq(
Dependency(Module("acme", "play"), "2.4.1",
exclusions = Set(("acme", "config"))),
Dependency(Module("acme", "play-json"), "2.4.0",
exclusions = Set(("acme", "config")))
)
val res = await(resolve(
Set(dep),
fetchFrom(repositories)
).runF)
val dep = Dependency(Module("acme", "play-extra-no-config"), "2.4.1")
val trDeps = Seq(
Dependency(Module("acme", "play"), "2.4.1",
exclusions = Set(("acme", "config"))),
Dependency(Module("acme", "play-json"), "2.4.0",
exclusions = Set(("acme", "config")))
)
val res = await(resolve(
Set(dep),
fetchFrom(repositories)
).runF)
val expected = Resolution(
rootDependencies = Set(dep.withCompileScope),
dependencies = Set(dep.withCompileScope) ++ trDeps.map(_.withCompileScope),
projectsCache = Map(
projectsMap(dep.moduleVersion).kv
) ++ trDeps.map(trDep => projectsMap(trDep.moduleVersion).kv)
)
val expected = Resolution(
rootDependencies = Set(dep.withCompileScope),
dependencies = Set(dep.withCompileScope) ++ trDeps.map(_.withCompileScope),
projectsCache = Map(
projectsMap(dep.moduleVersion).kv
) ++ trDeps.map(trDep => projectsMap(trDep.moduleVersion).kv)
)
assert(res == expected)
assert(res == expected)
}
}
'excludeOrgWildcard{
async {
val dep = Dependency(Module("acme", "play-extra-no-config-no"), "2.4.1")
val trDeps = Seq(
Dependency(Module("acme", "play"), "2.4.1",
exclusions = Set(("*", "config"))),
Dependency(Module("acme", "play-json"), "2.4.0",
exclusions = Set(("*", "config")))
)
val res = await(resolve(
Set(dep),
fetchFrom(repositories)
).runF)
val dep = Dependency(Module("acme", "play-extra-no-config-no"), "2.4.1")
val trDeps = Seq(
Dependency(Module("acme", "play"), "2.4.1",
exclusions = Set(("*", "config"))),
Dependency(Module("acme", "play-json"), "2.4.0",
exclusions = Set(("*", "config")))
)
val res = await(resolve(
Set(dep),
fetchFrom(repositories)
).runF)
val expected = Resolution(
rootDependencies = Set(dep.withCompileScope),
dependencies = Set(dep.withCompileScope) ++ trDeps.map(_.withCompileScope),
projectsCache = Map(
projectsMap(dep.moduleVersion).kv
) ++ trDeps.map(trDep => projectsMap(trDep.moduleVersion).kv)
)
val expected = Resolution(
rootDependencies = Set(dep.withCompileScope),
dependencies = Set(dep.withCompileScope) ++ trDeps.map(_.withCompileScope),
projectsCache = Map(
projectsMap(dep.moduleVersion).kv
) ++ trDeps.map(trDep => projectsMap(trDep.moduleVersion).kv)
)
assert(res == expected)
assert(res == expected)
}
}
'filter{
async {
val dep = Dependency(Module("hudsucker", "mail"), "10.0")
val res = await(resolve(
Set(dep),
fetchFrom(repositories),
filter = Some(_.scope == Scope.Compile)
).runF).copy(filter = None)
val dep = Dependency(Module("hudsucker", "mail"), "10.0")
val res = await(resolve(
Set(dep),
fetchFrom(repositories),
filter = Some(_.scope == Scope.Compile)
).runF).copy(filter = None)
val expected = Resolution(
rootDependencies = Set(dep.withCompileScope),
dependencies = Set(dep.withCompileScope),
projectsCache = Map(
projectsMap(dep.moduleVersion).kv
val expected = Resolution(
rootDependencies = Set(dep.withCompileScope),
dependencies = Set(dep.withCompileScope),
projectsCache = Map(
projectsMap(dep.moduleVersion).kv
)
)
)
assert(res == expected)
assert(res == expected)
}
}
'parentDepMgmt{
async {
val dep = Dependency(Module("se.ikea", "billy"), "18.0")
val trDeps = Seq(
Dependency(Module("acme", "play"), "2.4.0",
exclusions = Set(("acme", "play-json")))
)
val res = await(resolve(
Set(dep),
fetchFrom(repositories),
filter = Some(_.scope == Scope.Compile)
).runF).copy(filter = None, projectsCache = Map.empty)
val dep = Dependency(Module("se.ikea", "billy"), "18.0")
val trDeps = Seq(
Dependency(Module("acme", "play"), "2.4.0",
exclusions = Set(("acme", "play-json")))
)
val res = await(resolve(
Set(dep),
fetchFrom(repositories),
filter = Some(_.scope == Scope.Compile)
).runF).copy(filter = None, projectsCache = Map.empty)
val expected = Resolution(
rootDependencies = Set(dep.withCompileScope),
dependencies = Set(dep.withCompileScope) ++ trDeps.map(_.withCompileScope)
)
val expected = Resolution(
rootDependencies = Set(dep.withCompileScope),
dependencies = Set(dep.withCompileScope) ++ trDeps.map(_.withCompileScope)
)
assert(res == expected)
assert(res == expected)
}
}
'parentDependencies{
async {
val dep = Dependency(Module("org.gnome", "panel-legacy"), "7.0")
val trDeps = Seq(
Dependency(Module("org.gnu", "glib"), "13.4"),
Dependency(Module("org.gnome", "desktop"), "7.0"))
val res = await(resolve(
Set(dep),
fetchFrom(repositories),
filter = Some(_.scope == Scope.Compile)
).runF).copy(filter = None, projectsCache = Map.empty, errors = Map.empty)
val dep = Dependency(Module("org.gnome", "panel-legacy"), "7.0")
val trDeps = Seq(
Dependency(Module("org.gnu", "glib"), "13.4"),
Dependency(Module("org.gnome", "desktop"), "7.0"))
val res = await(resolve(
Set(dep),
fetchFrom(repositories),
filter = Some(_.scope == Scope.Compile)
).runF).copy(filter = None, projectsCache = Map.empty, errors = Map.empty)
val expected = Resolution(
rootDependencies = Set(dep.withCompileScope),
dependencies = Set(dep.withCompileScope) ++ trDeps.map(_.withCompileScope)
)
val expected = Resolution(
rootDependencies = Set(dep.withCompileScope),
dependencies = Set(dep.withCompileScope) ++ trDeps.map(_.withCompileScope)
)
assert(res == expected)
assert(res == expected)
}
}
'propertiesInExclusions{
async {
val dep = Dependency(Module("com.mailapp", "mail-client"), "2.1")
val trDeps = Seq(
Dependency(Module("gov.nsa", "secure-pgp"), "10.0", exclusions = Set(("*", "crypto"))))
val res = await(resolve(
Set(dep),
fetchFrom(repositories),
filter = Some(_.scope == Scope.Compile)
).runF).copy(filter = None, projectsCache = Map.empty, errors = Map.empty)
val dep = Dependency(Module("com.mailapp", "mail-client"), "2.1")
val trDeps = Seq(
Dependency(Module("gov.nsa", "secure-pgp"), "10.0", exclusions = Set(("*", "crypto"))))
val res = await(resolve(
Set(dep),
fetchFrom(repositories),
filter = Some(_.scope == Scope.Compile)
).runF).copy(filter = None, projectsCache = Map.empty, errors = Map.empty)
val expected = Resolution(
rootDependencies = Set(dep.withCompileScope),
dependencies = Set(dep.withCompileScope) ++ trDeps.map(_.withCompileScope)
)
val expected = Resolution(
rootDependencies = Set(dep.withCompileScope),
dependencies = Set(dep.withCompileScope) ++ trDeps.map(_.withCompileScope)
)
assert(res == expected)
assert(res == expected)
}
}
'depMgmtInParentDeps{
async {
val dep = Dependency(Module("com.thoughtworks.paranamer", "paranamer"), "2.6")
val res = await(resolve(
Set(dep),
fetchFrom(repositories),
filter = Some(_.scope == Scope.Compile)
).runF).copy(filter = None, projectsCache = Map.empty, errors = Map.empty)
val dep = Dependency(Module("com.thoughtworks.paranamer", "paranamer"), "2.6")
val res = await(resolve(
Set(dep),
fetchFrom(repositories),
filter = Some(_.scope == Scope.Compile)
).runF).copy(filter = None, projectsCache = Map.empty, errors = Map.empty)
val expected = Resolution(
rootDependencies = Set(dep.withCompileScope),
dependencies = Set(dep.withCompileScope)
)
val expected = Resolution(
rootDependencies = Set(dep.withCompileScope),
dependencies = Set(dep.withCompileScope)
)
assert(res == expected)
assert(res == expected)
}
}
'depsFromDefaultProfile{
async {
val dep = Dependency(Module("com.github.dummy", "libb"), "0.3.3")
val trDeps = Seq(
Dependency(Module("org.escalier", "librairie-standard"), "2.11.6"))
val res = await(resolve(
Set(dep),
fetchFrom(repositories),
filter = Some(_.scope == Scope.Compile)
).runF).copy(filter = None, projectsCache = Map.empty, errors = Map.empty)
val expected = Resolution(
rootDependencies = Set(dep.withCompileScope),
dependencies = Set(dep.withCompileScope) ++ trDeps.map(_.withCompileScope)
)
assert(res == expected)
}
}
'depsFromPropertyActivatedProfile{
val f =
for (version <- Seq("0.5.3", "0.5.4", "0.5.5", "0.5.6")) yield {
async {
val dep = Dependency(Module("com.github.dummy", "libb"), version)
val dep = Dependency(Module("com.github.dummy", "libb"), "0.3.3")
val trDeps = Seq(
Dependency(Module("org.escalier", "librairie-standard"), "2.11.6"))
val res = await(resolve(
@ -423,28 +401,95 @@ object ResolverTests extends TestSuite {
assert(res == expected)
}
}
}
'depsFromPropertyActivatedProfile{
val f =
for (version <- Seq("0.5.3", "0.5.4", "0.5.5", "0.5.6")) yield {
async {
val dep = Dependency(Module("com.github.dummy", "libb"), version)
val trDeps = Seq(
Dependency(Module("org.escalier", "librairie-standard"), "2.11.6"))
val res = await(resolve(
Set(dep),
fetchFrom(repositories),
filter = Some(_.scope == Scope.Compile)
).runF).copy(filter = None, projectsCache = Map.empty, errors = Map.empty)
val expected = Resolution(
rootDependencies = Set(dep.withCompileScope),
dependencies = Set(dep.withCompileScope) ++ trDeps.map(_.withCompileScope)
)
assert(res == expected)
}
}
scala.concurrent.Future.sequence(f)
}
'depsScopeOverrideFromProfile{
async {
// Like com.google.inject:guice:3.0 with org.sonatype.sisu.inject:cglib
val dep = Dependency(Module("com.github.dummy", "libb"), "0.4.2")
val trDeps = Seq(
Dependency(Module("org.escalier", "librairie-standard"), "2.11.6"))
val res = await(resolve(
Set(dep),
fetchFrom(repositories),
filter = Some(_.scope == Scope.Compile)
).runF).copy(filter = None, projectsCache = Map.empty, errors = Map.empty)
// Like com.google.inject:guice:3.0 with org.sonatype.sisu.inject:cglib
val dep = Dependency(Module("com.github.dummy", "libb"), "0.4.2")
val trDeps = Seq(
Dependency(Module("org.escalier", "librairie-standard"), "2.11.6"))
val res = await(resolve(
Set(dep),
fetchFrom(repositories),
filter = Some(_.scope == Scope.Compile)
).runF).copy(filter = None, projectsCache = Map.empty, errors = Map.empty)
val expected = Resolution(
rootDependencies = Set(dep.withCompileScope),
dependencies = Set(dep.withCompileScope) ++ trDeps.map(_.withCompileScope)
)
val expected = Resolution(
rootDependencies = Set(dep.withCompileScope),
dependencies = Set(dep.withCompileScope) ++ trDeps.map(_.withCompileScope)
)
assert(res == expected)
assert(res == expected)
}
}
'exclusionsAndOptionalShouldGoAlong{
async {
val dep = Dependency(Module("an-org", "an-app"), "1.0")
val trDeps = Seq(
Dependency(Module("an-org", "a-lib"), "1.0", exclusions = Set(("an-org", "a-name"))),
Dependency(Module("an-org", "another-lib"), "1.0", optional = true),
Dependency(Module("an-org", "a-name"), "1.0", optional = true))
val res = await(resolve(
Set(dep),
fetchFrom(repositories),
filter = Some(_.scope == Scope.Compile)
).runF).copy(filter = None, projectsCache = Map.empty, errors = Map.empty)
val expected = Resolution(
rootDependencies = Set(dep.withCompileScope),
dependencies = Set(dep.withCompileScope) ++ trDeps.map(_.withCompileScope)
)
assert(res == expected)
}
}
'exclusionsOfDependenciesFromDifferentPathsShouldNotCollide{
async {
val deps = Set(
Dependency(Module("an-org", "an-app"), "1.0"),
Dependency(Module("an-org", "a-lib"), "1.0", optional = true))
val trDeps = Seq(
Dependency(Module("an-org", "a-lib"), "1.0", exclusions = Set(("an-org", "a-name"))),
Dependency(Module("an-org", "another-lib"), "1.0", optional = true),
Dependency(Module("an-org", "a-name"), "1.0", optional = true))
val res = await(resolve(
deps,
fetchFrom(repositories),
filter = Some(_.scope == Scope.Compile)
).runF).copy(filter = None, projectsCache = Map.empty, errors = Map.empty)
val expected = Resolution(
rootDependencies = deps.map(_.withCompileScope),
dependencies = (deps ++ trDeps).map(_.withCompileScope)
)
assert(res == expected)
}
}

View File

@ -121,6 +121,46 @@ object VersionIntervalTests extends TestSuite {
}
}
'contains{
val v21 = Version("2.1")
val v22 = Version("2.2")
val v23 = Version("2.3")
val v24 = Version("2.4")
val v25 = Version("2.5")
val v26 = Version("2.6")
val v27 = Version("2.7")
val v28 = Version("2.8")
'basic{
val itv = Parse.versionInterval("[2.2,)").get
assert(!itv.contains(v21))
assert(itv.contains(v22))
assert(itv.contains(v23))
assert(itv.contains(v24))
}
'open{
val itv = Parse.versionInterval("(2.2,)").get
assert(!itv.contains(v21))
assert(!itv.contains(v22))
assert(itv.contains(v23))
assert(itv.contains(v24))
}
'segment{
val itv = Parse.versionInterval("[2.2,2.8]").get
assert(!itv.contains(v21))
assert(itv.contains(v22))
assert(itv.contains(v23))
assert(itv.contains(v24))
assert(itv.contains(v25))
assert(itv.contains(v26))
assert(itv.contains(v27))
assert(itv.contains(v28))
}
}
'parse{
'malformed{
val s1 = "[1.1]"
@ -225,77 +265,6 @@ object VersionIntervalTests extends TestSuite {
}
}
'repr{
'basic {
val s1 = "[1.1,1.3]"
val repr1 = Parse.versionInterval(s1).map(_.repr)
assert(repr1 == Some(s1))
val s2 = "(1.1,1.3]"
val repr2 = Parse.versionInterval(s2).map(_.repr)
assert(repr2 == Some(s2))
val s3 = "[1.1,1.3)"
val repr3 = Parse.versionInterval(s3).map(_.repr)
assert(repr3 == Some(s3))
val s4 = "(1.1,1.3)"
val repr4 = Parse.versionInterval(s4).map(_.repr)
assert(repr4 == Some(s4))
}
'leftEmptyVersions {
val s1 = "[,1.3]"
val repr1 = Parse.versionInterval(s1).map(_.repr)
assert(repr1 == Some(s1))
val s2 = "(,1.3]"
val repr2 = Parse.versionInterval(s2).map(_.repr)
assert(repr2 == Some(s2))
val s3 = "[,1.3)"
val repr3 = Parse.versionInterval(s3).map(_.repr)
assert(repr3 == Some(s3))
val s4 = "(,1.3)"
val repr4 = Parse.versionInterval(s4).map(_.repr)
assert(repr4 == Some(s4))
}
'rightEmptyVersions {
val s1 = "[1.3,]"
val repr1 = Parse.versionInterval(s1).map(_.repr)
assert(repr1 == Some(s1))
val s2 = "(1.3,]"
val repr2 = Parse.versionInterval(s2).map(_.repr)
assert(repr2 == Some(s2))
val s3 = "[1.3,)"
val repr3 = Parse.versionInterval(s3).map(_.repr)
assert(repr3 == Some(s3))
val s4 = "(1.3,)"
val repr4 = Parse.versionInterval(s4).map(_.repr)
assert(repr4 == Some(s4))
}
'bothEmptyVersions {
val s1 = "[,]"
val repr1 = Parse.versionInterval(s1).map(_.repr)
assert(repr1 == Some(s1))
val s2 = "(,]"
val repr2 = Parse.versionInterval(s2).map(_.repr)
assert(repr2 == Some(s2))
val s3 = "[,)"
val repr3 = Parse.versionInterval(s3).map(_.repr)
assert(repr3 == Some(s3))
val s4 = "(,]"
val repr4 = Parse.versionInterval(s4).map(_.repr)
assert(repr4 == Some(s4))
}
}
'constraint{
'none{
val s1 = "(,)"

View File

@ -1,14 +1,12 @@
package coursier
package test
import java.util.Locale
import utest._
object ComparableVersionTests extends TestSuite {
import core.ComparableVersion.parse
object VersionTests extends TestSuite {
import core.Version
def compare(first: String, second: String) = parse(first).compare(parse(second))
def compare(first: String, second: String) = Version(first).compare(Version(second))
def increasing(versions: String*): Boolean =
versions.iterator.sliding(2).withPartial(false).forall{case Seq(a, b) => compare(a, b) < 0 }
@ -16,18 +14,31 @@ object ComparableVersionTests extends TestSuite {
val tests = TestSuite {
'stackOverflow{
val s = "." * 100000
val v = parse(s)
val v = Version(s)
assert(v.isEmpty)
}
'empty{
val v0 = parse("0")
val v = parse("")
val v0 = Version("0")
val v = Version("")
assert(v0.isEmpty)
assert(v.isEmpty)
}
'max{
val v21 = Version("2.1")
val v22 = Version("2.2")
val v23 = Version("2.3")
val v24 = Version("2.4")
val v241 = Version("2.4.1")
val l = Seq(v21, v22, v23, v24, v241)
val max = l.max
assert(max == v241)
}
'numericOrdering{
assert(compare("1.2", "1.10") < 0)
}
@ -328,6 +339,7 @@ object ComparableVersionTests extends TestSuite {
// 'CaseInsensitiveOrderingOfQualifiersIsLocaleIndependent
// {
// import java.util.Locale
// val orig = Locale.getDefault
// try {
// for ( locale <- Seq(Locale.ENGLISH, new Locale( "tr" )) ) {

View File

@ -8,6 +8,9 @@ import sbtrelease.ReleasePlugin.ReleaseKeys.{ publishArtifactsAction, versionBum
import sbtrelease.Version.Bump
import com.typesafe.sbt.pgp.PgpKeys
import xerial.sbt.Pack._
object CoursierBuild extends Build {
lazy val publishingSettings = Seq[Setting[_]](
@ -53,7 +56,7 @@ object CoursierBuild extends Build {
) ++ releaseSettings
lazy val commonSettings = Seq[Setting[_]](
organization := "eu.frowning-lambda",
organization := "com.github.alexarchambault",
version := "0.1.0-SNAPSHOT",
scalaVersion := "2.11.6",
crossScalaVersions := Seq("2.10.5", "2.11.6"),
@ -65,6 +68,8 @@ object CoursierBuild extends Build {
libraryDependencies += "org.scala-lang.modules" %% "scala-async" % "0.9.1" % "provided",
unmanagedSourceDirectories in Compile += (baseDirectory in LocalRootProject).value / "core" / "src" / "main" / "scala",
unmanagedSourceDirectories in Test += (baseDirectory in LocalRootProject).value / "core" / "src" / "test" / "scala",
unmanagedResourceDirectories in Compile += (baseDirectory in LocalRootProject).value / "core" / "src" / "main" / "resources",
unmanagedResourceDirectories in Test += (baseDirectory in LocalRootProject).value / "core" / "src" / "test" / "resources",
testFrameworks += new TestFramework("utest.runner.Framework")
)
@ -98,8 +103,14 @@ object CoursierBuild extends Build {
lazy val cli = Project(id = "cli", base = file("cli"))
.dependsOn(coreJvm)
.settings(commonSettings ++ xerial.sbt.Pack.packAutoSettings: _*)
.settings(commonSettings ++ packAutoSettings ++ publishPackTxzArchive ++ publishPackZipArchive: _*)
.settings(
packArchivePrefix := s"coursier-cli_${scalaBinaryVersion.value}",
packArchiveTxzArtifact := Artifact("coursier-cli", "arch", "tar.xz"),
packArchiveZipArtifact := Artifact("coursier-cli", "arch", "zip")
)
.settings(
name := "coursier-cli",
libraryDependencies ++= Seq(
"com.github.alexarchambault" %% "case-app" % "0.2.2",
"ch.qos.logback" % "logback-classic" % "1.1.3"

View File

@ -21,7 +21,7 @@ cp -R "$DIR/classes/css" staging
for i in staging/*.html; do
mv "$i" "$i.0"
grep -v "src=\"\.\.\/web-" < "$i.0" > "$i"
sed "s/src=\"\.\.\/web-/src=\"web-/g" < "$i.0" > "$i"
rm -f "$i.0"
done

View File

@ -6,8 +6,8 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- FIXME Get from WebJars -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">
<!-- FIXME Get from WebJar -->
<link rel="stylesheet" href="css/bootstrap-treeview.css">
<style>
@ -46,16 +46,8 @@
<div class="collapse navbar-collapse" id="mainNavBar">
<ul class="nav navbar-nav">
<!-- class="active" -->
<li><a href="#demo" data-toggle="tab">Demo</a></li>
<li><a href="https://github.com/alexarchambault/coursier/blob/master/USAGE.md">Usage</a></li>
<!-- <li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Usage <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#usageCli" data-toggle="tab">Command-line</a></li>
<li><a href="#usageApi" data-toggle="tab">API</a></li>
</ul>
</li> -->
</ul>
<ul class="nav navbar-nav navbar-right">
@ -74,13 +66,10 @@
<p>Pure Scala Artifact Fetching</p>
<p><a href="https://github.com/alexarchambault/coursier">Project Page</a></p>
</div>
</div>
<div class="tab-pane fade" id="demo">
<div id="demoContent"></div>
</div>
<div class="tab-pane fade" id="usageCli">
@ -113,15 +102,12 @@
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<!-- during dev -->
<script type="text/javascript" src="../web-jsdeps.js"></script>
<script type="text/javascript" src="../web-fastopt.js"></script>
<!-- github pages -->
<script type="text/javascript" src="web-jsdeps.js"></script>
<script type="text/javascript" src="web-fastopt.js"></script>
<!-- Paths changed by push-gh-pages.sh before pushing to gh-pages -->
<script src="../web-jsdeps.js"></script>
<script src="../web-fastopt.js"></script>
<script type="text/javascript" src="https://cdn.rawgit.com/strathausen/dracula/26010eb3b0df037cf507886897e20c02c4ec041b/lib/dracula_graph.js"></script>
<script type="text/javascript" src="https://cdn.rawgit.com/strathausen/dracula/26010eb3b0df037cf507886897e20c02c4ec041b/lib/dracula_graffle.js"></script>
<script src="https://cdn.rawgit.com/strathausen/dracula/26010eb3b0df037cf507886897e20c02c4ec041b/lib/dracula_graph.js"></script>
<script src="https://cdn.rawgit.com/strathausen/dracula/26010eb3b0df037cf507886897e20c02c4ec041b/lib/dracula_graffle.js"></script>
<script>
// From http://www.bootply.com/VQqzOawoYc

View File

@ -40,11 +40,11 @@ class Backend($: BackendScope[Unit, State]) {
}
for {
((org, name, scope), par) <- resolution.reverseDependenciesAndExclusions.toList
from = s"$org:$name:${scope.name}"
(dep, parents) <- resolution.reverseDependencies.toList
from = s"${dep.module.organization}:${dep.module.name}:${dep.scope.name}"
_ = addNode(from)
((parOrg, parName, parScope), _) <- par
to = s"$parOrg:$parName:${parScope.name}"
parDep <- parents
to = s"${parDep.module.organization}:${parDep.module.name}:${parDep.scope.name}"
_ = addNode(to)
} {
graph.addEdge(from, to)
@ -203,8 +203,12 @@ object App {
def infoLabel(label: String) =
<.span(^.`class` := "label label-info", label)
def errorLabel(label: String, desc: String) =
<.button(^.`type` := "button", ^.`class` := "btn btn-xs btn-danger",
def errorPopOver(label: String, desc: String) =
popOver("danger", label, desc)
def infoPopOver(label: String, desc: String) =
popOver("info", label, desc)
def popOver(`type`: String, label: String, desc: String) =
<.button(^.`type` := "button", ^.`class` := s"btn btn-xs btn-${`type`}",
Attr("data-trigger") := "focus",
Attr("data-toggle") := "popover", Attr("data-placement") := "bottom",
Attr("data-content") := desc,
@ -213,28 +217,34 @@ object App {
label
)
def depItem(dep: Dependency) =
def depItem(dep: Dependency, finalVersionOpt: Option[String]) = {
val (type0, classifier) = dep.artifacts match {
case maven: Artifacts.Maven => (maven.`type`, maven.classifier)
}
<.tr(
^.`class` := (if (res.errors.contains(dep.moduleVersion)) "danger" else ""),
<.td(dep.module.organization),
<.td(dep.module.name),
<.td(dep.version),
<.td(finalVersionOpt.fold(dep.version)(finalVersion => s"$finalVersion (for ${dep.version})")),
<.td(Seq[Seq[TagMod]](
if (dep.scope == Scope.Compile) Seq() else Seq(infoLabel(dep.scope.name)),
if (dep.`type`.isEmpty || dep.`type` == "jar") Seq() else Seq(infoLabel(dep.`type`)),
if (dep.classifier.isEmpty) Seq() else Seq(infoLabel(dep.classifier)),
if (type0.isEmpty || type0 == "jar") Seq() else Seq(infoLabel(type0)),
if (classifier.isEmpty) Seq() else Seq(infoLabel(classifier)),
Some(dep.exclusions).filter(_.nonEmpty).map(excls => infoPopOver("Exclusions", excls.toList.sorted.map{case (org, name) => s"$org:$name"}.mkString("; "))).toSeq,
if (dep.optional) Seq(infoLabel("optional")) else Seq(),
res.errors.get(dep.moduleVersion).map(errs => errorLabel("Error", errs.mkString("; "))).toSeq
res.errors.get(dep.moduleVersion).map(errs => errorPopOver("Error", errs.mkString("; "))).toSeq
)),
<.td(Seq[Seq[TagMod]](
res.projectsCache.get(dep.moduleVersion) match {
case Some((repo: Remote, _)) =>
// FIXME Maven specific, generalize if/when adding support for Ivy
val version0 = finalVersionOpt getOrElse dep.version
val relPath =
dep.module.organization.split('.').toSeq ++ Seq(
dep.module.name,
dep.version,
s"${dep.module.name}-${dep.version}"
version0,
s"${dep.module.name}-$version0"
)
Seq(
@ -250,6 +260,7 @@ object App {
}
))
)
}
val sortedDeps = res.dependencies.toList
.sortBy(dep => coursier.core.Module.unapply(dep.module).get)
@ -265,7 +276,7 @@ object App {
)
),
<.tbody(
sortedDeps.map(depItem)
sortedDeps.map(dep => depItem(dep, res.projectsCache.get(dep.moduleVersion).map(_._2.version).filter(_ != dep.version)))
)
)
}