@@ -6,33 +6,31 @@ package coursier.version
66 * To be used mainly during resolution.
77 */
88sealed abstract class ConstraintReconciliation extends Product with Serializable {
9- def reconcile (versions : Seq [String ]): Option [String ]
9+ def reconcile (versions : Seq [VersionConstraint ]): Option [VersionConstraint ]
1010}
1111
1212object ConstraintReconciliation {
1313
14- private final val LatestIntegration = " latest.integration"
15- private final val LatestRelease = " latest.release"
16- private final val LatestStable = " latest.stable"
14+ private final val LatestIntegration = VersionConstraint ( " latest.integration" )
15+ private final val LatestRelease = VersionConstraint ( " latest.release" )
16+ private final val LatestStable = VersionConstraint ( " latest.stable" )
1717
18- private def splitStandard (versions : Seq [String ]): (Seq [String ], Seq [String ]) =
18+ private def splitStandard (versions : Seq [VersionConstraint ]): (Seq [VersionConstraint ], Seq [VersionConstraint ]) =
1919 versions.distinct.partition {
2020 case LatestIntegration => false
2121 case LatestRelease => false
2222 case LatestStable => false
2323 case _ => true
2424 }
2525
26- private def retainLatestOpt (latests : Seq [String ]): Option [String ] =
26+ private def retainLatestOpt (latests : Seq [VersionConstraint ]): Option [VersionConstraint ] =
2727 if (latests.isEmpty) None
2828 else if (latests.lengthCompare(1 ) == 0 ) latests.headOption
2929 else {
3030 val set = latests.toSet
3131 val retained =
32- if (set(LatestIntegration ))
33- LatestIntegration
34- else if (set(LatestRelease ))
35- LatestRelease
32+ if (set(LatestIntegration )) LatestIntegration
33+ else if (set(LatestRelease )) LatestRelease
3634 else {
3735 // at least two distinct latest.* means we shouldn't even reach this else block anyway
3836 assert(set(LatestStable ))
@@ -48,7 +46,7 @@ object ConstraintReconciliation {
4846 * Fails when passed version intervals that don't overlap.
4947 */
5048 case object Default extends ConstraintReconciliation {
51- def reconcile (versions : Seq [String ]): Option [String ] =
49+ def reconcile (versions : Seq [VersionConstraint ]): Option [VersionConstraint ] =
5250 if (versions.isEmpty)
5351 None
5452 else if (versions.lengthCompare(1 ) == 0 )
@@ -58,28 +56,23 @@ object ConstraintReconciliation {
5856 val retainedStandard =
5957 if (standard.isEmpty) None
6058 else if (standard.lengthCompare(1 ) == 0 ) standard.headOption
61- else {
62- val parsedConstraints = standard.map(VersionParse .versionConstraint)
63- VersionConstraint .merge(parsedConstraints : _* )
64- .flatMap(_.repr)
65- }
59+ else
60+ VersionConstraint .merge(standard : _* )
61+ .map(_.uniquePreferred.removeUnusedPreferred)
6662 val retainedLatestOpt = retainLatestOpt(latests)
6763
68- if (standard.isEmpty)
69- retainedLatestOpt
70- else if (latests.isEmpty)
71- retainedStandard
64+ if (standard.isEmpty) retainedLatestOpt
65+ else if (latests.isEmpty) retainedStandard
7266 else {
73- val parsedIntervals = standard.map( VersionParse .versionConstraint)
67+ val parsedIntervals = standard
7468 .filter(_.preferred.isEmpty) // only keep intervals
7569 .filter(_.interval != VersionInterval .zero) // not interval matching any version
7670
7771 if (parsedIntervals.isEmpty)
7872 retainedLatestOpt
7973 else
8074 VersionConstraint .merge(parsedIntervals : _* )
81- .flatMap(_.repr)
82- .map(itv => (itv +: retainedLatestOpt.toSeq).mkString(" &" ))
75+ .map(_.uniquePreferred.removeUnusedPreferred) // FIXME Add retainedLatestOpt too
8376 }
8477 }
8578 }
@@ -90,7 +83,7 @@ object ConstraintReconciliation {
9083 * When passed version intervals that don't overlap, the lowest intervals are discarded until the remaining intervals do overlap.
9184 */
9285 case object Relaxed extends ConstraintReconciliation {
93- def reconcile (versions : Seq [String ]): Option [String ] =
86+ def reconcile (versions : Seq [VersionConstraint ]): Option [VersionConstraint ] =
9487 if (versions.isEmpty)
9588 None
9689 else if (versions.lengthCompare(1 ) == 0 )
@@ -101,16 +94,15 @@ object ConstraintReconciliation {
10194 if (standard.isEmpty) None
10295 else if (standard.lengthCompare(1 ) == 0 ) standard.headOption
10396 else {
104- val parsedConstraints = standard.map(VersionParse .versionConstraint)
105- VersionConstraint .merge(parsedConstraints : _* )
106- .getOrElse(VersionConstraint .relaxedMerge(parsedConstraints : _* ))
107- .repr
97+ val repr = VersionConstraint .merge(standard : _* )
98+ .getOrElse(VersionConstraint .relaxedMerge(standard : _* ))
99+ .uniquePreferred
100+ .removeUnusedPreferred
101+ Some (repr)
108102 }
109103 val retainedLatestOpt = retainLatestOpt(latests)
110- if (latests.isEmpty)
111- retainedStandard
112- else
113- retainedLatestOpt
104+ if (latests.isEmpty) retainedStandard
105+ else retainedLatestOpt
114106 }
115107 }
116108
@@ -129,4 +121,36 @@ object ConstraintReconciliation {
129121 case _ => Default
130122 }
131123
124+ /** Strict version reconciliation.
125+ *
126+ * This particular instance behaves the same as [[Default ]] when used by
127+ * [[coursier.core.Resolution ]]. Actual strict conflict manager is handled by
128+ * `coursier.params.rule.Strict`, which is set up by `coursier.Resolve` when a strict
129+ * reconciliation is added to it.
130+ */
131+ case object Strict extends ConstraintReconciliation {
132+ def reconcile (versions : Seq [VersionConstraint ]): Option [VersionConstraint ] =
133+ Default .reconcile(versions)
134+ }
135+
136+ /** Semantic versioning version reconciliation.
137+ *
138+ * This particular instance behaves the same as [[Default ]] when used by
139+ * [[coursier.core.Resolution ]]. Actual semantic versioning checks are handled by
140+ * `coursier.params.rule.Strict` with field `semVer = true`, which is set up by
141+ * `coursier.Resolve` when a SemVer reconciliation is added to it.
142+ */
143+ case object SemVer extends ConstraintReconciliation {
144+ def reconcile (versions : Seq [VersionConstraint ]): Option [VersionConstraint ] =
145+ Default .reconcile(versions)
146+ }
147+
148+ def apply (input : String ): Option [ConstraintReconciliation ] =
149+ input match {
150+ case " default" => Some (Default )
151+ case " relaxed" => Some (Relaxed )
152+ case " strict" => Some (Strict )
153+ case " semver" => Some (SemVer )
154+ case _ => None
155+ }
132156}
0 commit comments