Add support for Ivy latest revision syntax

Like 2.2.+ for [2.2.0,2.3.0)

Fixes https://github.com/alexarchambault/coursier/issues/104
This commit is contained in:
Alexandre Archambault 2016-01-23 15:42:08 +01:00
parent 061dbe2f91
commit 7330494873
8 changed files with 65 additions and 2 deletions

View File

@ -10,6 +10,21 @@ object Parse {
else Some(Version(s))
}
def ivyLatestSubRevisionInterval(s: String): Option[VersionInterval] =
if (s.endsWith(".+")) {
for {
from <- version(s.stripSuffix(".+"))
if from.rawItems.nonEmpty
last <- Some(from.rawItems.last).collect { case n: Version.Numeric => n }
// a bit loose, but should do the job
if from.repr.endsWith(last.repr)
to <- version(from.repr.stripSuffix(last.repr) + last.next.repr)
// the contrary would mean something went wrong in the loose substitution above
if from.rawItems.init == to.rawItems.init
} yield VersionInterval(Some(from), Some(to), fromIncluded = true, toIncluded = false)
} else
None
def versionInterval(s: String): Option[VersionInterval] = {
for {
fromIncluded <- if (s.startsWith("[")) Some(true) else if (s.startsWith("(")) Some(false) else None
@ -28,6 +43,7 @@ object Parse {
def noConstraint = if (s.isEmpty) Some(VersionConstraint.None) else None
noConstraint
.orElse(ivyLatestSubRevisionInterval(s).map(VersionConstraint.Interval))
.orElse(version(s).map(VersionConstraint.Preferred))
.orElse(versionInterval(s).map(VersionConstraint.Interval))
}

View File

@ -10,6 +10,10 @@ import coursier.core.compatibility._
*/
case class Version(repr: String) extends Ordered[Version] {
lazy val items = Version.items(repr)
lazy val rawItems: Seq[Version.Item] = {
val (first, tokens) = Version.Tokenizer(repr)
first +: tokens.toVector.map { case (_, item) => item }
}
def compare(other: Version) = Version.listCompare(items, other.items)
def isEmpty = items.forall(_.isEmpty)
}
@ -39,13 +43,20 @@ object Version {
def compareToEmpty: Int = 1
}
sealed trait Numeric extends Item
sealed trait Numeric extends Item {
def repr: String
def next: Numeric
}
case class Number(value: Int) extends Numeric {
val order = 0
def next: Number = Number(value + 1)
def repr: String = value.toString
override def compareToEmpty = value.compare(0)
}
case class BigNumber(value: BigInt) extends Numeric {
val order = 0
def next: BigNumber = BigNumber(value + 1)
def repr: String = value.toString
override def compareToEmpty = value.compare(0)
}
case class Qualifier(value: String, level: Int) extends Item {

View File

@ -261,6 +261,7 @@ case class MavenRepository(
): EitherT[F, String, (Artifact.Source, Project)] = {
Parse.versionInterval(version)
.orElse(Parse.ivyLatestSubRevisionInterval(version))
.filter(_.isValid) match {
case None =>
findNoInterval(module, version, fetch).map((source, _))

View File

@ -0,0 +1,2 @@
com.chuusai:shapeless_2.11:jar:2.2.5
org.scala-lang:scala-library:jar:2.11.7

View File

@ -0,0 +1,2 @@
com.chuusai:shapeless_2.11:jar:2.2.5
org.scala-lang:scala-library:jar:2.11.7

View File

@ -0,0 +1 @@
com.googlecode.libphonenumber:libphonenumber:jar:7.0.11

View File

@ -0,0 +1 @@
com.googlecode.libphonenumber:libphonenumber:jar:7.0.11

View File

@ -61,7 +61,15 @@ object CentralTests extends TestSuite {
val result = res
.dependencies
.toVector
.map(repr)
.map { dep =>
val projOpt = res.projectCache
.get(dep.moduleVersion)
.map { case (_, proj) => proj }
val dep0 = dep.copy(
version = projOpt.fold(dep.version)(_.version)
)
repr(dep0)
}
.sorted
.distinct
@ -149,6 +157,27 @@ object CentralTests extends TestSuite {
"1.1.2"
)
}
'latestRevision - {
resolutionCheck(
Module("com.chuusai", "shapeless_2.11"),
"[2.2.0,2.3.0)"
)
resolutionCheck(
Module("com.chuusai", "shapeless_2.11"),
"2.2.+"
)
resolutionCheck(
Module("com.googlecode.libphonenumber", "libphonenumber"),
"[7.0,7.1)"
)
resolutionCheck(
Module("com.googlecode.libphonenumber", "libphonenumber"),
"7.0.+"
)
}
}
}