mirror of https://github.com/sbt/sbt.git
Allow to force some module versions during resolution
What SBT calls "dependency overrides"
This commit is contained in:
parent
f1cf78b543
commit
98acae19bc
|
|
@ -163,25 +163,34 @@ object Resolution {
|
||||||
* Returns the conflicted dependencies, and the merged others.
|
* Returns the conflicted dependencies, and the merged others.
|
||||||
*/
|
*/
|
||||||
def merge(
|
def merge(
|
||||||
dependencies: TraversableOnce[Dependency]
|
dependencies: TraversableOnce[Dependency],
|
||||||
|
forceVersions: Map[Module, String]
|
||||||
): (Seq[Dependency], Seq[Dependency]) = {
|
): (Seq[Dependency], Seq[Dependency]) = {
|
||||||
|
|
||||||
val mergedByModVer = dependencies
|
val mergedByModVer = dependencies
|
||||||
.toList
|
.toList
|
||||||
.groupBy(dep => dep.module)
|
.groupBy(dep => dep.module)
|
||||||
.mapValues { deps =>
|
.map { case (module, deps) =>
|
||||||
if (deps.lengthCompare(1) == 0) \/-(deps)
|
module -> {
|
||||||
else {
|
forceVersions.get(module) match {
|
||||||
val versions = deps
|
|
||||||
.map(_.version)
|
|
||||||
.distinct
|
|
||||||
val versionOpt = mergeVersions(versions)
|
|
||||||
|
|
||||||
versionOpt match {
|
|
||||||
case Some(version) =>
|
|
||||||
\/-(deps.map(dep => dep.copy(version = version)))
|
|
||||||
case None =>
|
case None =>
|
||||||
-\/(deps)
|
if (deps.lengthCompare(1) == 0) \/-(deps)
|
||||||
|
else {
|
||||||
|
val versions = deps
|
||||||
|
.map(_.version)
|
||||||
|
.distinct
|
||||||
|
val versionOpt = mergeVersions(versions)
|
||||||
|
|
||||||
|
versionOpt match {
|
||||||
|
case Some(version) =>
|
||||||
|
\/-(deps.map(dep => dep.copy(version = version)))
|
||||||
|
case None =>
|
||||||
|
-\/(deps)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case Some(forcedVersion) =>
|
||||||
|
\/-(deps.map(dep => dep.copy(version = forcedVersion)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -380,6 +389,7 @@ object Resolution {
|
||||||
case class Resolution(
|
case class Resolution(
|
||||||
rootDependencies: Set[Dependency],
|
rootDependencies: Set[Dependency],
|
||||||
dependencies: Set[Dependency],
|
dependencies: Set[Dependency],
|
||||||
|
forceVersions: Map[Module, String],
|
||||||
conflicts: Set[Dependency],
|
conflicts: Set[Dependency],
|
||||||
projectCache: Map[Resolution.ModuleVersion, (Artifact.Source, Project)],
|
projectCache: Map[Resolution.ModuleVersion, (Artifact.Source, Project)],
|
||||||
errorCache: Map[Resolution.ModuleVersion, Seq[String]],
|
errorCache: Map[Resolution.ModuleVersion, Seq[String]],
|
||||||
|
|
@ -426,9 +436,10 @@ case class Resolution(
|
||||||
* the dependencies.
|
* the dependencies.
|
||||||
*/
|
*/
|
||||||
def nextDependenciesAndConflicts: (Seq[Dependency], Seq[Dependency]) =
|
def nextDependenciesAndConflicts: (Seq[Dependency], Seq[Dependency]) =
|
||||||
|
// TODO Provide the modules whose version was forced by dependency overrides too
|
||||||
merge(
|
merge(
|
||||||
rootDependencies.map(withDefaultScope) ++ dependencies ++
|
rootDependencies.map(withDefaultScope) ++ dependencies ++ transitiveDependencies,
|
||||||
transitiveDependencies
|
forceVersions
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,7 @@ package object coursier {
|
||||||
def apply(
|
def apply(
|
||||||
rootDependencies: Set[Dependency] = Set.empty,
|
rootDependencies: Set[Dependency] = Set.empty,
|
||||||
dependencies: Set[Dependency] = Set.empty,
|
dependencies: Set[Dependency] = Set.empty,
|
||||||
|
forceVersions: Map[Module, String] = Map.empty,
|
||||||
conflicts: Set[Dependency] = Set.empty,
|
conflicts: Set[Dependency] = Set.empty,
|
||||||
projectCache: Map[ModuleVersion, (Artifact.Source, Project)] = Map.empty,
|
projectCache: Map[ModuleVersion, (Artifact.Source, Project)] = Map.empty,
|
||||||
errorCache: Map[ModuleVersion, Seq[String]] = Map.empty,
|
errorCache: Map[ModuleVersion, Seq[String]] = Map.empty,
|
||||||
|
|
@ -72,6 +73,7 @@ package object coursier {
|
||||||
core.Resolution(
|
core.Resolution(
|
||||||
rootDependencies,
|
rootDependencies,
|
||||||
dependencies,
|
dependencies,
|
||||||
|
forceVersions,
|
||||||
conflicts,
|
conflicts,
|
||||||
projectCache,
|
projectCache,
|
||||||
errorCache,
|
errorCache,
|
||||||
|
|
|
||||||
|
|
@ -9,12 +9,15 @@ import coursier.test.compatibility._
|
||||||
|
|
||||||
object ResolutionTests extends TestSuite {
|
object ResolutionTests extends TestSuite {
|
||||||
|
|
||||||
def resolve0(deps: Set[Dependency], filter: Option[Dependency => Boolean] = None) = {
|
def resolve0(
|
||||||
Resolution(deps, filter = filter)
|
deps: Set[Dependency],
|
||||||
|
filter: Option[Dependency => Boolean] = None,
|
||||||
|
forceVersions: Map[Module, String] = Map.empty
|
||||||
|
) =
|
||||||
|
Resolution(deps, filter = filter, forceVersions = forceVersions)
|
||||||
.process
|
.process
|
||||||
.run(Fetch.default(repositories))
|
.run(Fetch.default(repositories))
|
||||||
.runF
|
.runF
|
||||||
}
|
|
||||||
|
|
||||||
implicit class ProjectOps(val p: Project) extends AnyVal {
|
implicit class ProjectOps(val p: Project) extends AnyVal {
|
||||||
def kv: (ModuleVersion, (Artifact.Source, Project)) = p.moduleVersion -> (testRepository.source, p)
|
def kv: (ModuleVersion, (Artifact.Source, Project)) = p.moduleVersion -> (testRepository.source, p)
|
||||||
|
|
@ -134,9 +137,16 @@ object ResolutionTests extends TestSuite {
|
||||||
|
|
||||||
Project(Module("an-org", "a-name"), "1.0"),
|
Project(Module("an-org", "a-name"), "1.0"),
|
||||||
|
|
||||||
|
Project(Module("an-org", "a-name"), "1.2"),
|
||||||
|
|
||||||
Project(Module("an-org", "a-lib"), "1.0",
|
Project(Module("an-org", "a-lib"), "1.0",
|
||||||
Seq(Dependency(Module("an-org", "a-name"), "1.0"))),
|
Seq(Dependency(Module("an-org", "a-name"), "1.0"))),
|
||||||
|
|
||||||
|
Project(Module("an-org", "a-lib"), "1.1"),
|
||||||
|
|
||||||
|
Project(Module("an-org", "a-lib"), "1.2",
|
||||||
|
Seq(Dependency(Module("an-org", "a-name"), "1.2"))),
|
||||||
|
|
||||||
Project(Module("an-org", "another-lib"), "1.0",
|
Project(Module("an-org", "another-lib"), "1.0",
|
||||||
Seq(Dependency(Module("an-org", "a-name"), "1.0"))),
|
Seq(Dependency(Module("an-org", "a-name"), "1.0"))),
|
||||||
|
|
||||||
|
|
@ -144,7 +154,15 @@ object ResolutionTests extends TestSuite {
|
||||||
Project(Module("an-org", "an-app"), "1.0",
|
Project(Module("an-org", "an-app"), "1.0",
|
||||||
Seq(
|
Seq(
|
||||||
Dependency(Module("an-org", "a-lib"), "1.0", exclusions = Set(("an-org", "a-name"))),
|
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", "another-lib"), "1.0", optional = true))),
|
||||||
|
|
||||||
|
Project(Module("an-org", "an-app"), "1.1",
|
||||||
|
Seq(
|
||||||
|
Dependency(Module("an-org", "a-lib"), "1.1"))),
|
||||||
|
|
||||||
|
Project(Module("an-org", "an-app"), "1.2",
|
||||||
|
Seq(
|
||||||
|
Dependency(Module("an-org", "a-lib"), "1.2")))
|
||||||
)
|
)
|
||||||
|
|
||||||
val projectsMap = projects.map(p => p.moduleVersion -> p).toMap
|
val projectsMap = projects.map(p => p.moduleVersion -> p).toMap
|
||||||
|
|
@ -483,6 +501,86 @@ object ResolutionTests extends TestSuite {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
'dependencyOverrides - {
|
||||||
|
* - {
|
||||||
|
async {
|
||||||
|
val deps = Set(
|
||||||
|
Dependency(Module("an-org", "a-name"), "1.1"))
|
||||||
|
val depOverrides = Map(
|
||||||
|
Module("an-org", "a-name") -> "1.0")
|
||||||
|
|
||||||
|
val res = await(resolve0(
|
||||||
|
deps,
|
||||||
|
forceVersions = depOverrides,
|
||||||
|
filter = Some(_.scope == Scope.Compile)
|
||||||
|
)).copy(filter = None, projectCache = Map.empty, errorCache = Map.empty)
|
||||||
|
|
||||||
|
val expected = Resolution(
|
||||||
|
rootDependencies = deps,
|
||||||
|
dependencies = Set(
|
||||||
|
Dependency(Module("an-org", "a-name"), "1.0")
|
||||||
|
).map(_.withCompileScope),
|
||||||
|
forceVersions = depOverrides
|
||||||
|
)
|
||||||
|
|
||||||
|
assert(res == expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
* - {
|
||||||
|
async {
|
||||||
|
val deps = Set(
|
||||||
|
Dependency(Module("an-org", "an-app"), "1.1"))
|
||||||
|
val depOverrides = Map(
|
||||||
|
Module("an-org", "a-lib") -> "1.0")
|
||||||
|
|
||||||
|
val res = await(resolve0(
|
||||||
|
deps,
|
||||||
|
forceVersions = depOverrides,
|
||||||
|
filter = Some(_.scope == Scope.Compile)
|
||||||
|
)).copy(filter = None, projectCache = Map.empty, errorCache = Map.empty)
|
||||||
|
|
||||||
|
val expected = Resolution(
|
||||||
|
rootDependencies = deps,
|
||||||
|
dependencies = Set(
|
||||||
|
Dependency(Module("an-org", "an-app"), "1.1"),
|
||||||
|
Dependency(Module("an-org", "a-lib"), "1.0"),
|
||||||
|
Dependency(Module("an-org", "a-name"), "1.0")
|
||||||
|
).map(_.withCompileScope),
|
||||||
|
forceVersions = depOverrides
|
||||||
|
)
|
||||||
|
|
||||||
|
assert(res == expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
* - {
|
||||||
|
async {
|
||||||
|
val deps = Set(
|
||||||
|
Dependency(Module("an-org", "an-app"), "1.2"))
|
||||||
|
val depOverrides = Map(
|
||||||
|
Module("an-org", "a-lib") -> "1.1")
|
||||||
|
|
||||||
|
val res = await(resolve0(
|
||||||
|
deps,
|
||||||
|
forceVersions = depOverrides,
|
||||||
|
filter = Some(_.scope == Scope.Compile)
|
||||||
|
)).copy(filter = None, projectCache = Map.empty, errorCache = Map.empty)
|
||||||
|
|
||||||
|
val expected = Resolution(
|
||||||
|
rootDependencies = deps,
|
||||||
|
dependencies = Set(
|
||||||
|
Dependency(Module("an-org", "an-app"), "1.2"),
|
||||||
|
Dependency(Module("an-org", "a-lib"), "1.1")
|
||||||
|
).map(_.withCompileScope),
|
||||||
|
forceVersions = depOverrides
|
||||||
|
)
|
||||||
|
|
||||||
|
assert(res == expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
'parts{
|
'parts{
|
||||||
'propertySubstitution{
|
'propertySubstitution{
|
||||||
val res =
|
val res =
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue