mirror of https://github.com/sbt/sbt.git
Changes in Resolution API
This commit is contained in:
parent
510dd7b2d4
commit
27c8cc9929
|
|
@ -13,7 +13,7 @@ import scalaz.{-\/, \/-}
|
|||
case class Coursier(scope: List[String],
|
||||
keepOptional: Boolean,
|
||||
fetch: Boolean,
|
||||
@ExtraName("N") maxIterations: Int) extends App {
|
||||
@ExtraName("N") maxIterations: Int = 100) extends App {
|
||||
|
||||
val scopes0 =
|
||||
if (scope.isEmpty) List(Scope.Compile, Scope.Runtime)
|
||||
|
|
@ -85,12 +85,12 @@ case class Coursier(scope: List[String],
|
|||
Dependency(mod, ver, scope = Scope.Runtime)
|
||||
}
|
||||
|
||||
val res = resolve(
|
||||
val startRes = Resolution(
|
||||
deps.toSet,
|
||||
fetchFrom(repositories),
|
||||
maxIterations = Some(maxIterations).filter(_ > 0),
|
||||
filter = Some(dep => (keepOptional || !dep.optional) && scopes(dep.scope))
|
||||
).run
|
||||
)
|
||||
|
||||
val res = startRes.last(fetchFrom(repositories), maxIterations).run
|
||||
|
||||
if (!res.isDone) {
|
||||
Console.err.println(s"Maximum number of iteration reached!")
|
||||
|
|
@ -107,7 +107,7 @@ case class Coursier(scope: List[String],
|
|||
s"${dep.module.organization}:${dep.module.name}:${dep.artifact.`type`}:${Some(dep.artifact.classifier).filter(_.nonEmpty).map(_+":").mkString}$version$extra"
|
||||
}
|
||||
|
||||
val trDeps = res.dependencies.toList.sortBy(repr)
|
||||
val trDeps = res.minDependencies.toList.sortBy(repr)
|
||||
|
||||
println("\n" + trDeps.map(repr).distinct.mkString("\n"))
|
||||
|
||||
|
|
@ -129,7 +129,7 @@ case class Coursier(scope: List[String],
|
|||
|
||||
val cachePolicy: CachePolicy = CachePolicy.Default
|
||||
|
||||
val m = res.dependencies.groupBy(dep => res.projectsCache.get(dep.moduleVersion).map(_._1))
|
||||
val m = res.minDependencies.groupBy(dep => res.projectsCache.get(dep.moduleVersion).map(_._1))
|
||||
val (notFound, remaining0) = m.partition(_._1.isEmpty)
|
||||
if (notFound.nonEmpty) {
|
||||
val notFound0 = notFound.values.flatten.toList.map(repr).sorted
|
||||
|
|
|
|||
|
|
@ -312,52 +312,19 @@ object Resolution {
|
|||
def defaultFilter(dep: Dependency): Boolean =
|
||||
!dep.optional && dep.scope == Scope.Compile
|
||||
|
||||
/**
|
||||
* Get all the transitive dependencies of `dependencies`, solving any dependency version mismatch.
|
||||
*
|
||||
* Iteratively fetches the missing info of the current dependencies / add newly discovered dependencies
|
||||
* to the current ones. The maximum number of such iterations can be bounded with `maxIterations`.
|
||||
*
|
||||
* ...
|
||||
*
|
||||
*/
|
||||
def resolve(dependencies: Set[Dependency],
|
||||
fetch: ModuleVersion => EitherT[Task, List[String], (Repository, Project)],
|
||||
maxIterations: Option[Int],
|
||||
filter: Option[Dependency => Boolean],
|
||||
profileActivation: Option[(String, Activation, Map[String, String]) => Boolean]): Task[Resolution] = {
|
||||
|
||||
val dependencies0 = dependencies.map(withDefaultScope)
|
||||
|
||||
val startResolution = Resolution(
|
||||
dependencies0, Set.empty, Set.empty,
|
||||
Map.empty, Map.empty,
|
||||
filter,
|
||||
profileActivation
|
||||
)
|
||||
|
||||
def helper(resolution: Resolution, remainingIter: Option[Int]): Task[(Resolution, Option[Int])] = {
|
||||
if (resolution.isDone || remainingIter.exists(_ <= 0))
|
||||
Task.now((resolution, remainingIter))
|
||||
else
|
||||
resolution.next(fetch).flatMap(helper(_, remainingIter.map(_ - 1)))
|
||||
}
|
||||
|
||||
helper(startResolution, maxIterations).map(_._1)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* State of a dependency resolution.
|
||||
*
|
||||
* Done if method `isDone` returns `true`.
|
||||
*
|
||||
* @param dependencies: current set of dependencies
|
||||
* @param conflicts: conflicting dependencies
|
||||
* @param projectsCache: cache of known projects
|
||||
* @param errors: keeps track of the modules whose project definition could not be found
|
||||
*/
|
||||
/**
|
||||
* State of a dependency resolution.
|
||||
*
|
||||
* Done if method `isDone` returns `true`.
|
||||
*
|
||||
* @param dependencies: current set of dependencies
|
||||
* @param conflicts: conflicting dependencies
|
||||
* @param projectsCache: cache of known projects
|
||||
* @param errors: keeps track of the modules whose project definition could not be found
|
||||
*/
|
||||
case class Resolution(rootDependencies: Set[Dependency],
|
||||
dependencies: Set[Dependency],
|
||||
conflicts: Set[Dependency],
|
||||
|
|
@ -382,10 +349,9 @@ case class Resolution(rootDependencies: Set[Dependency],
|
|||
* No attempt is made to solve version conflicts here.
|
||||
*/
|
||||
def transitiveDependencies: Seq[Dependency] =
|
||||
for {
|
||||
dep <- (dependencies -- conflicts).toList
|
||||
trDep <- finalDependencies0(dep)
|
||||
} yield trDep
|
||||
(dependencies -- conflicts)
|
||||
.toList
|
||||
.flatMap(finalDependencies0)
|
||||
|
||||
/**
|
||||
* The "next" dependency set, made of the current dependencies and their transitive dependencies,
|
||||
|
|
@ -397,7 +363,7 @@ case class Resolution(rootDependencies: Set[Dependency],
|
|||
* Returns a tuple made of the conflicting dependencies, and all the dependencies.
|
||||
*/
|
||||
def nextDependenciesAndConflicts: (Seq[Dependency], Seq[Dependency]) = {
|
||||
merge(rootDependencies ++ dependencies ++ transitiveDependencies)
|
||||
merge(rootDependencies.map(withDefaultScope) ++ dependencies ++ transitiveDependencies)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -456,7 +422,7 @@ case class Resolution(rootDependencies: Set[Dependency],
|
|||
* The versions of all the dependencies returned are erased (emptied).
|
||||
*/
|
||||
def remainingDependencies: Set[Dependency] = {
|
||||
val rootDependencies0 = rootDependencies.map(eraseVersion)
|
||||
val rootDependencies0 = rootDependencies.map(withDefaultScope).map(eraseVersion)
|
||||
|
||||
@tailrec
|
||||
def helper(reverseDeps: Map[Dependency, Vector[Dependency]]): Map[Dependency, Vector[Dependency]] = {
|
||||
|
|
@ -632,4 +598,14 @@ case class Resolution(rootDependencies: Set[Dependency],
|
|||
}
|
||||
}
|
||||
|
||||
def last(fetchModule: ModuleVersion => EitherT[Task, List[String], (Repository, Project)], maxIterations: Int = -1): Task[Resolution] = {
|
||||
if (maxIterations == 0 || isDone) Task.now(this)
|
||||
else {
|
||||
next(fetchModule)
|
||||
.flatMap(_.last(fetchModule, if (maxIterations > 0) maxIterations - 1 else maxIterations))
|
||||
}
|
||||
}
|
||||
|
||||
def minDependencies: Set[Dependency] =
|
||||
Orders.minDependencies(dependencies)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,6 +88,14 @@ package object coursier {
|
|||
maxIterations: Option[Int] = Some(200),
|
||||
filter: Option[Dependency => Boolean] = None,
|
||||
profileActivation: Option[(String, Profile.Activation, Map[String, String]) => Boolean] = None): Task[Resolution] = {
|
||||
core.Resolution.resolve(dependencies, fetch, maxIterations, filter, profileActivation)
|
||||
|
||||
val startResolution = Resolution(
|
||||
dependencies, Set.empty, Set.empty,
|
||||
Map.empty, Map.empty,
|
||||
filter,
|
||||
profileActivation
|
||||
)
|
||||
|
||||
startResolution.last(fetch, maxIterations.getOrElse(-1))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ object CentralTests extends TestSuite {
|
|||
.copy(projectsCache = Map.empty, errors = Map.empty) // No validating these here
|
||||
|
||||
val expected = Resolution(
|
||||
rootDependencies = Set(dep.withCompileScope),
|
||||
rootDependencies = Set(dep),
|
||||
dependencies = Set(
|
||||
dep.withCompileScope,
|
||||
Dependency(Module("ch.qos.logback", "logback-core"), "1.1.3").withCompileScope,
|
||||
|
|
@ -54,7 +54,7 @@ object CentralTests extends TestSuite {
|
|||
.copy(projectsCache = Map.empty, errors = Map.empty) // No validating these here
|
||||
|
||||
val expected = Resolution(
|
||||
rootDependencies = Set(dep.withCompileScope),
|
||||
rootDependencies = Set(dep),
|
||||
dependencies = Set(
|
||||
dep.withCompileScope,
|
||||
Dependency(Module("org.ow2.asm", "asm-tree"), "5.0.2").withCompileScope,
|
||||
|
|
@ -70,7 +70,7 @@ object CentralTests extends TestSuite {
|
|||
val res = res0.copy(projectsCache = Map.empty, errors = Map.empty)
|
||||
|
||||
val expected = Resolution(
|
||||
rootDependencies = Set(dep.withCompileScope),
|
||||
rootDependencies = Set(dep),
|
||||
dependencies = Set(
|
||||
dep.withCompileScope))
|
||||
|
||||
|
|
|
|||
|
|
@ -166,7 +166,7 @@ object ResolutionTests extends TestSuite {
|
|||
).runF)
|
||||
|
||||
val expected = Resolution(
|
||||
rootDependencies = Set(dep.withCompileScope),
|
||||
rootDependencies = Set(dep),
|
||||
dependencies = Set(dep.withCompileScope),
|
||||
errors = Map(dep.moduleVersion -> Seq("Not found"))
|
||||
)
|
||||
|
|
@ -183,7 +183,7 @@ object ResolutionTests extends TestSuite {
|
|||
).runF)
|
||||
|
||||
val expected = Resolution(
|
||||
rootDependencies = Set(dep.withCompileScope),
|
||||
rootDependencies = Set(dep),
|
||||
dependencies = Set(dep.withCompileScope),
|
||||
projectsCache = Map(dep.moduleVersion -> (testRepository, projectsMap(dep.moduleVersion)))
|
||||
)
|
||||
|
|
@ -201,7 +201,7 @@ object ResolutionTests extends TestSuite {
|
|||
).runF)
|
||||
|
||||
val expected = Resolution(
|
||||
rootDependencies = Set(dep.withCompileScope),
|
||||
rootDependencies = Set(dep),
|
||||
dependencies = Set(dep.withCompileScope, trDep.withCompileScope),
|
||||
projectsCache = Map(
|
||||
projectsMap(dep.moduleVersion).kv,
|
||||
|
|
@ -225,7 +225,7 @@ object ResolutionTests extends TestSuite {
|
|||
).runF)
|
||||
|
||||
val expected = Resolution(
|
||||
rootDependencies = Set(dep.withCompileScope),
|
||||
rootDependencies = Set(dep),
|
||||
dependencies = Set(dep.withCompileScope) ++ trDeps.map(_.withCompileScope),
|
||||
projectsCache = Map(
|
||||
projectsMap(dep.moduleVersion).kv
|
||||
|
|
@ -250,7 +250,7 @@ object ResolutionTests extends TestSuite {
|
|||
).runF)
|
||||
|
||||
val expected = Resolution(
|
||||
rootDependencies = Set(dep.withCompileScope),
|
||||
rootDependencies = Set(dep),
|
||||
dependencies = Set(dep.withCompileScope) ++ trDeps.map(_.withCompileScope),
|
||||
projectsCache = Map(
|
||||
projectsMap(dep.moduleVersion).kv
|
||||
|
|
@ -275,7 +275,7 @@ object ResolutionTests extends TestSuite {
|
|||
).runF)
|
||||
|
||||
val expected = Resolution(
|
||||
rootDependencies = Set(dep.withCompileScope),
|
||||
rootDependencies = Set(dep),
|
||||
dependencies = Set(dep.withCompileScope) ++ trDeps.map(_.withCompileScope),
|
||||
projectsCache = Map(
|
||||
projectsMap(dep.moduleVersion).kv
|
||||
|
|
@ -295,7 +295,7 @@ object ResolutionTests extends TestSuite {
|
|||
).runF).copy(filter = None)
|
||||
|
||||
val expected = Resolution(
|
||||
rootDependencies = Set(dep.withCompileScope),
|
||||
rootDependencies = Set(dep),
|
||||
dependencies = Set(dep.withCompileScope),
|
||||
projectsCache = Map(
|
||||
projectsMap(dep.moduleVersion).kv
|
||||
|
|
@ -319,7 +319,7 @@ object ResolutionTests extends TestSuite {
|
|||
).runF).copy(filter = None, projectsCache = Map.empty)
|
||||
|
||||
val expected = Resolution(
|
||||
rootDependencies = Set(dep.withCompileScope),
|
||||
rootDependencies = Set(dep),
|
||||
dependencies = Set(dep.withCompileScope) ++ trDeps.map(_.withCompileScope)
|
||||
)
|
||||
|
||||
|
|
@ -339,7 +339,7 @@ object ResolutionTests extends TestSuite {
|
|||
).runF).copy(filter = None, projectsCache = Map.empty, errors = Map.empty)
|
||||
|
||||
val expected = Resolution(
|
||||
rootDependencies = Set(dep.withCompileScope),
|
||||
rootDependencies = Set(dep),
|
||||
dependencies = Set(dep.withCompileScope) ++ trDeps.map(_.withCompileScope)
|
||||
)
|
||||
|
||||
|
|
@ -358,7 +358,7 @@ object ResolutionTests extends TestSuite {
|
|||
).runF).copy(filter = None, projectsCache = Map.empty, errors = Map.empty)
|
||||
|
||||
val expected = Resolution(
|
||||
rootDependencies = Set(dep.withCompileScope),
|
||||
rootDependencies = Set(dep),
|
||||
dependencies = Set(dep.withCompileScope) ++ trDeps.map(_.withCompileScope)
|
||||
)
|
||||
|
||||
|
|
@ -375,7 +375,7 @@ object ResolutionTests extends TestSuite {
|
|||
).runF).copy(filter = None, projectsCache = Map.empty, errors = Map.empty)
|
||||
|
||||
val expected = Resolution(
|
||||
rootDependencies = Set(dep.withCompileScope),
|
||||
rootDependencies = Set(dep),
|
||||
dependencies = Set(dep.withCompileScope)
|
||||
)
|
||||
|
||||
|
|
@ -394,7 +394,7 @@ object ResolutionTests extends TestSuite {
|
|||
).runF).copy(filter = None, projectsCache = Map.empty, errors = Map.empty)
|
||||
|
||||
val expected = Resolution(
|
||||
rootDependencies = Set(dep.withCompileScope),
|
||||
rootDependencies = Set(dep),
|
||||
dependencies = Set(dep.withCompileScope) ++ trDeps.map(_.withCompileScope)
|
||||
)
|
||||
|
||||
|
|
@ -415,7 +415,7 @@ object ResolutionTests extends TestSuite {
|
|||
).runF).copy(filter = None, projectsCache = Map.empty, errors = Map.empty)
|
||||
|
||||
val expected = Resolution(
|
||||
rootDependencies = Set(dep.withCompileScope),
|
||||
rootDependencies = Set(dep),
|
||||
dependencies = Set(dep.withCompileScope) ++ trDeps.map(_.withCompileScope)
|
||||
)
|
||||
|
||||
|
|
@ -438,7 +438,7 @@ object ResolutionTests extends TestSuite {
|
|||
).runF).copy(filter = None, projectsCache = Map.empty, errors = Map.empty)
|
||||
|
||||
val expected = Resolution(
|
||||
rootDependencies = Set(dep.withCompileScope),
|
||||
rootDependencies = Set(dep),
|
||||
dependencies = Set(dep.withCompileScope) ++ trDeps.map(_.withCompileScope)
|
||||
)
|
||||
|
||||
|
|
@ -460,7 +460,7 @@ object ResolutionTests extends TestSuite {
|
|||
).runF).copy(filter = None, projectsCache = Map.empty, errors = Map.empty)
|
||||
|
||||
val expected = Resolution(
|
||||
rootDependencies = Set(dep.withCompileScope),
|
||||
rootDependencies = Set(dep),
|
||||
dependencies = Set(dep.withCompileScope) ++ trDeps.map(_.withCompileScope)
|
||||
)
|
||||
|
||||
|
|
@ -484,7 +484,7 @@ object ResolutionTests extends TestSuite {
|
|||
).runF).copy(filter = None, projectsCache = Map.empty, errors = Map.empty)
|
||||
|
||||
val expected = Resolution(
|
||||
rootDependencies = deps.map(_.withCompileScope),
|
||||
rootDependencies = deps,
|
||||
dependencies = (deps ++ trDeps).map(_.withCompileScope)
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,26 @@
|
|||
package coursier
|
||||
|
||||
import scalaz.EitherT
|
||||
import scalaz.concurrent.Task
|
||||
|
||||
package object test {
|
||||
|
||||
implicit class DependencyOps(val underlying: Dependency) extends AnyVal {
|
||||
def withCompileScope: Dependency = underlying.copy(scope = Scope.Compile)
|
||||
}
|
||||
|
||||
def resolve(dependencies: Set[Dependency],
|
||||
fetch: ModuleVersion => EitherT[Task, List[String], (Repository, Project)],
|
||||
maxIterations: Option[Int] = Some(200),
|
||||
filter: Option[Dependency => Boolean] = None,
|
||||
profileActivation: Option[(String, Profile.Activation, Map[String, String]) => Boolean] = None): Task[Resolution] = {
|
||||
|
||||
val startResolution = Resolution(
|
||||
dependencies,
|
||||
filter = filter,
|
||||
profileActivation = profileActivation
|
||||
)
|
||||
|
||||
startResolution.last(fetch, maxIterations.getOrElse(-1))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package coursier
|
||||
package web
|
||||
|
||||
import coursier.core.{Resolver, Logger, Remote}
|
||||
import coursier.core.{Logger, Remote}
|
||||
import japgolly.scalajs.react.vdom.{TagMod, Attr}
|
||||
import japgolly.scalajs.react.vdom.Attrs.dangerouslySetInnerHtml
|
||||
import japgolly.scalajs.react.{ReactEventI, ReactComponentB, BackendScope}
|
||||
|
|
@ -71,13 +71,15 @@ class Backend($: BackendScope[Unit, State]) {
|
|||
|
||||
def updateTree(resolution: Resolution, target: String, reverse: Boolean) = {
|
||||
def depsOf(dep: Dependency) =
|
||||
resolution.projectsCache.get(dep.moduleVersion).toSeq.flatMap(t => Resolver.finalDependencies(dep, t._2).filter(resolution.filter getOrElse Resolver.defaultFilter))
|
||||
resolution.projectsCache.get(dep.moduleVersion).toSeq.flatMap(t => core.Resolution.finalDependencies(dep, t._2).filter(resolution.filter getOrElse core.Resolution.defaultFilter))
|
||||
|
||||
val minDependencies = resolution.minDependencies
|
||||
|
||||
lazy val reverseDeps = {
|
||||
var m = Map.empty[Module, Seq[Dependency]]
|
||||
|
||||
for {
|
||||
dep <- resolution.dependencies
|
||||
dep <- minDependencies
|
||||
trDep <- depsOf(dep)
|
||||
} {
|
||||
m += trDep.module -> (m.getOrElse(trDep.module, Nil) :+ dep)
|
||||
|
|
@ -95,8 +97,8 @@ class Backend($: BackendScope[Unit, State]) {
|
|||
else Seq("nodes" -> js.Array(deps.map(tree): _*))
|
||||
}: _*)
|
||||
|
||||
println(resolution.dependencies.toList.map(tree).map(js.JSON.stringify(_)))
|
||||
g.$(target).treeview(js.Dictionary("data" -> js.Array(resolution.dependencies.toList.map(tree): _*)))
|
||||
println(minDependencies.toList.map(tree).map(js.JSON.stringify(_)))
|
||||
g.$(target).treeview(js.Dictionary("data" -> js.Array(minDependencies.toList.map(tree): _*)))
|
||||
}
|
||||
|
||||
def resolve(action: => Unit = ()) = {
|
||||
|
|
@ -119,11 +121,14 @@ class Backend($: BackendScope[Unit, State]) {
|
|||
}
|
||||
|
||||
val s = $.state
|
||||
def task = coursier.resolve(
|
||||
s.modules.toSet,
|
||||
fetchFrom(s.repositories.map(_.copy(logger = Some(logger)))),
|
||||
filter = Some(dep => (s.options.followOptional || !dep.optional) && (s.options.keepTest || dep.scope != Scope.Test))
|
||||
)
|
||||
def task = {
|
||||
val res = coursier.Resolution(
|
||||
s.modules.toSet,
|
||||
filter = Some(dep => (s.options.followOptional || !dep.optional) && (s.options.keepTest || dep.scope != Scope.Test))
|
||||
)
|
||||
|
||||
res.last(fetchFrom(s.repositories.map(_.copy(logger = Some(logger)))), 100)
|
||||
}
|
||||
|
||||
// For reasons that are unclear to me, not delaying this when using the runNow execution context
|
||||
// somehow discards the $.modState above. (Not a major problem as queue is used by default.)
|
||||
|
|
@ -258,7 +263,7 @@ object App {
|
|||
)
|
||||
}
|
||||
|
||||
val sortedDeps = res.dependencies.toList
|
||||
val sortedDeps = res.minDependencies.toList
|
||||
.sortBy(dep => coursier.core.Module.unapply(dep.module).get)
|
||||
|
||||
<.table(^.`class` := "table",
|
||||
|
|
|
|||
Loading…
Reference in New Issue