mirror of https://github.com/sbt/sbt.git
Better handling of version intervals / hints reconciliation
Fixes https://github.com/alexarchambault/coursier/issues/303
This commit is contained in:
parent
97bdd1f77d
commit
eb4e73fa54
|
|
@ -148,6 +148,14 @@ lazy val core = crossProject
|
|||
|
||||
Seq(
|
||||
// Since 1.0.0-M13
|
||||
// reworked VersionConstraint
|
||||
ProblemFilters.exclude[MissingClassProblem]("coursier.core.VersionConstraint$Interval"),
|
||||
ProblemFilters.exclude[MissingClassProblem]("coursier.core.VersionConstraint$Preferred"),
|
||||
ProblemFilters.exclude[MissingClassProblem]("coursier.core.VersionConstraint$Preferred$"),
|
||||
ProblemFilters.exclude[MissingClassProblem]("coursier.core.VersionConstraint$Interval$"),
|
||||
ProblemFilters.exclude[FinalClassProblem]("coursier.core.VersionConstraint"),
|
||||
ProblemFilters.exclude[IncompatibleResultTypeProblem]("coursier.core.VersionConstraint.repr"),
|
||||
ProblemFilters.exclude[IncompatibleMethTypeProblem]("coursier.core.VersionConstraint.this"),
|
||||
// Extra `actualVersion` field in `Project`
|
||||
ProblemFilters.exclude[MissingTypesProblem]("coursier.core.Project$"),
|
||||
ProblemFilters.exclude[MissingMethodProblem]("coursier.core.Project.apply"),
|
||||
|
|
|
|||
|
|
@ -43,12 +43,12 @@ object Parse {
|
|||
}
|
||||
|
||||
def versionConstraint(s: String): Option[VersionConstraint] = {
|
||||
def noConstraint = if (s.isEmpty) Some(VersionConstraint.None) else None
|
||||
def noConstraint = if (s.isEmpty) Some(VersionConstraint.all) else None
|
||||
|
||||
noConstraint
|
||||
.orElse(ivyLatestSubRevisionInterval(s).map(VersionConstraint.Interval))
|
||||
.orElse(version(s).map(VersionConstraint.Preferred))
|
||||
.orElse(versionInterval(s).map(VersionConstraint.Interval))
|
||||
.orElse(ivyLatestSubRevisionInterval(s).map(VersionConstraint.interval))
|
||||
.orElse(version(s).map(VersionConstraint.preferred))
|
||||
.orElse(versionInterval(s).map(VersionConstraint.interval))
|
||||
}
|
||||
|
||||
val fallbackConfigRegex = {
|
||||
|
|
|
|||
|
|
@ -140,25 +140,26 @@ object Resolution {
|
|||
* Returns `None` in case of conflict.
|
||||
*/
|
||||
def mergeVersions(versions: Seq[String]): Option[String] = {
|
||||
val (nonParsedConstraints, parsedConstraints) =
|
||||
versions
|
||||
.map(v => v -> Parse.versionConstraint(v))
|
||||
.partition(_._2.isEmpty)
|
||||
|
||||
val parseResults = versions.map(v => v -> Parse.versionConstraint(v))
|
||||
|
||||
val nonParsedConstraints = parseResults.collect {
|
||||
case (repr, None) => repr
|
||||
}
|
||||
|
||||
// FIXME Report this in return type, not this way
|
||||
if (nonParsedConstraints.nonEmpty)
|
||||
Console.err.println(
|
||||
s"Ignoring unparsed versions: ${nonParsedConstraints.map(_._1)}"
|
||||
s"Ignoring unparsed versions: $nonParsedConstraints"
|
||||
)
|
||||
|
||||
val intervalOpt =
|
||||
(Option(VersionInterval.zero) /: parsedConstraints) {
|
||||
case (acc, (_, someCstr)) =>
|
||||
acc.flatMap(_.merge(someCstr.get.interval))
|
||||
}
|
||||
val parsedConstraints = parseResults.collect {
|
||||
case (_, Some(c)) => c
|
||||
}
|
||||
|
||||
intervalOpt
|
||||
.map(_.constraint.repr)
|
||||
VersionConstraint
|
||||
.merge(parsedConstraints: _*)
|
||||
.flatMap(_.repr)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
package coursier.core
|
||||
|
||||
import scalaz.{ -\/, \/, \/- }
|
||||
import scalaz.Scalaz.ToEitherOps
|
||||
|
||||
case class VersionInterval(from: Option[Version],
|
||||
to: Option[Version],
|
||||
fromIncluded: Boolean,
|
||||
|
|
@ -64,9 +67,9 @@ case class VersionInterval(from: Option[Version],
|
|||
|
||||
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)
|
||||
case VersionInterval.zero => VersionConstraint.all
|
||||
case VersionInterval(Some(version), None, true, false) => VersionConstraint.preferred(version)
|
||||
case itv => VersionConstraint.interval(itv)
|
||||
}
|
||||
|
||||
def repr: String = Seq(
|
||||
|
|
@ -82,23 +85,54 @@ object VersionInterval {
|
|||
val zero = VersionInterval(None, None, fromIncluded = false, toIncluded = false)
|
||||
}
|
||||
|
||||
sealed abstract class VersionConstraint(
|
||||
val interval: VersionInterval,
|
||||
val repr: String
|
||||
)
|
||||
final case class VersionConstraint(
|
||||
interval: VersionInterval,
|
||||
preferred: Seq[Version]
|
||||
) {
|
||||
def blend: Option[VersionInterval \/ Version] =
|
||||
if (interval.isValid) {
|
||||
val preferredInInterval = preferred.filter(interval.contains)
|
||||
|
||||
if (preferredInInterval.isEmpty)
|
||||
Some(interval.left)
|
||||
else
|
||||
Some(preferredInInterval.max.right)
|
||||
} else
|
||||
None
|
||||
|
||||
def repr: Option[String] =
|
||||
blend.map {
|
||||
case -\/(itv) =>
|
||||
if (itv == VersionInterval.zero)
|
||||
""
|
||||
else
|
||||
itv.repr
|
||||
case \/-(v) => v.repr
|
||||
}
|
||||
}
|
||||
|
||||
object VersionConstraint {
|
||||
/** Currently treated as minimum... */
|
||||
final case class Preferred(version: Version) extends VersionConstraint(
|
||||
VersionInterval(Some(version), Option.empty, fromIncluded = true, toIncluded = false),
|
||||
version.repr
|
||||
)
|
||||
final case class Interval(interval0: VersionInterval) extends VersionConstraint(
|
||||
interval0,
|
||||
interval0.repr
|
||||
)
|
||||
case object None extends VersionConstraint(
|
||||
VersionInterval.zero,
|
||||
"" // Once parsed, "(,)" becomes "" because of this
|
||||
)
|
||||
|
||||
def preferred(version: Version): VersionConstraint =
|
||||
VersionConstraint(VersionInterval.zero, Seq(version))
|
||||
def interval(interval: VersionInterval): VersionConstraint =
|
||||
VersionConstraint(interval, Nil)
|
||||
|
||||
val all = VersionConstraint(VersionInterval.zero, Nil)
|
||||
|
||||
def merge(constraints: VersionConstraint*): Option[VersionConstraint] = {
|
||||
|
||||
val intervals = constraints.map(_.interval)
|
||||
|
||||
val intervalOpt =
|
||||
(Option(VersionInterval.zero) /: intervals) {
|
||||
case (acc, itv) =>
|
||||
acc.flatMap(_.merge(itv))
|
||||
}
|
||||
|
||||
for (interval <- intervalOpt) yield {
|
||||
val preferreds = constraints.flatMap(_.preferred).distinct
|
||||
VersionConstraint(interval, preferreds)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
org.webjars.bower:jquery:3.1.0:compile
|
||||
org.webjars.bower:jquery-mousewheel:3.1.13:compile
|
||||
org.webjars.bower:malihu-custom-scrollbar-plugin:3.1.5:compile
|
||||
|
|
@ -237,6 +237,15 @@ object CentralTests extends TestSuite {
|
|||
)
|
||||
}
|
||||
|
||||
'versionInterval - {
|
||||
// Warning: needs to be updated when new versions of org.webjars.bower:jquery and
|
||||
// org.webjars.bower:jquery-mousewheel are published :-|
|
||||
resolutionCheck(
|
||||
Module("org.webjars.bower", "malihu-custom-scrollbar-plugin"),
|
||||
"3.1.5"
|
||||
)
|
||||
}
|
||||
|
||||
'latestRevision - {
|
||||
* - resolutionCheck(
|
||||
Module("com.chuusai", "shapeless_2.11"),
|
||||
|
|
|
|||
|
|
@ -10,45 +10,30 @@ object VersionConstraintTests extends TestSuite {
|
|||
'parse{
|
||||
'empty{
|
||||
val c0 = Parse.versionConstraint("")
|
||||
assert(c0 == Some(VersionConstraint.None))
|
||||
assert(c0 == Some(VersionConstraint.all))
|
||||
}
|
||||
'basicVersion{
|
||||
val c0 = Parse.versionConstraint("1.2")
|
||||
assert(c0 == Some(VersionConstraint.Preferred(Version("1.2"))))
|
||||
assert(c0 == Some(VersionConstraint.preferred(Version("1.2"))))
|
||||
}
|
||||
'basicVersionInterval{
|
||||
val c0 = Parse.versionConstraint("(,1.2]")
|
||||
assert(c0 == Some(VersionConstraint.Interval(VersionInterval(None, Some(Version("1.2")), false, true))))
|
||||
assert(c0 == Some(VersionConstraint.interval(VersionInterval(None, Some(Version("1.2")), false, true))))
|
||||
}
|
||||
}
|
||||
|
||||
'repr{
|
||||
'empty{
|
||||
val s0 = VersionConstraint.None.repr
|
||||
assert(s0 == "")
|
||||
val s0 = VersionConstraint.all.repr
|
||||
assert(s0 == Some(""))
|
||||
}
|
||||
'preferred{
|
||||
val s0 = VersionConstraint.Preferred(Version("2.1")).repr
|
||||
assert(s0 == "2.1")
|
||||
val s0 = VersionConstraint.preferred(Version("2.1")).repr
|
||||
assert(s0 == Some("2.1"))
|
||||
}
|
||||
'interval{
|
||||
val s0 = VersionConstraint.Interval(VersionInterval(None, Some(Version("2.1")), false, true)).repr
|
||||
assert(s0 == "(,2.1]")
|
||||
}
|
||||
}
|
||||
|
||||
'interval{
|
||||
'empty{
|
||||
val s0 = VersionConstraint.None.interval
|
||||
assert(s0 == VersionInterval.zero)
|
||||
}
|
||||
'preferred{
|
||||
val s0 = VersionConstraint.Preferred(Version("2.1")).interval
|
||||
assert(s0 == VersionInterval(Some(Version("2.1")), None, true, false))
|
||||
}
|
||||
'interval{
|
||||
val s0 = VersionConstraint.Interval(VersionInterval(None, Some(Version("2.1")), false, true)).interval
|
||||
assert(s0 == VersionInterval(None, Some(Version("2.1")), false, true))
|
||||
val s0 = VersionConstraint.interval(VersionInterval(None, Some(Version("2.1")), false, true)).repr
|
||||
assert(s0 == Some("(,2.1]"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -269,17 +269,17 @@ object VersionIntervalTests extends TestSuite {
|
|||
'none{
|
||||
val s1 = "(,)"
|
||||
val c1 = Parse.versionInterval(s1).map(_.constraint)
|
||||
assert(c1 == Some(VersionConstraint.None))
|
||||
assert(c1 == Some(VersionConstraint.all))
|
||||
}
|
||||
'preferred{
|
||||
val s1 = "[1.3,)"
|
||||
val c1 = Parse.versionInterval(s1).map(_.constraint)
|
||||
assert(c1 == Some(VersionConstraint.Preferred(Parse.version("1.3").get)))
|
||||
assert(c1 == Some(VersionConstraint.preferred(Parse.version("1.3").get)))
|
||||
}
|
||||
'interval{
|
||||
val s1 = "[1.3,2.4)"
|
||||
val c1 = Parse.versionInterval(s1).map(_.constraint)
|
||||
assert(c1 == Some(VersionConstraint.Interval(VersionInterval(Parse.version("1.3"), Parse.version("2.4"), true, false))))
|
||||
assert(c1 == Some(VersionConstraint.interval(VersionInterval(Parse.version("1.3"), Parse.version("2.4"), true, false))))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue