mirror of https://github.com/sbt/sbt.git
Keep calculated dependencies accross resolutions
This commit is contained in:
parent
c9566fbf5d
commit
829c397ca8
|
|
@ -1,9 +1,10 @@
|
||||||
package coursier.core
|
package coursier.core
|
||||||
|
|
||||||
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
import java.util.regex.Pattern.quote
|
import java.util.regex.Pattern.quote
|
||||||
|
|
||||||
import scala.annotation.tailrec
|
import scala.annotation.tailrec
|
||||||
import scala.collection.mutable
|
import scala.collection.JavaConverters._
|
||||||
import scalaz.{ \/-, -\/ }
|
import scalaz.{ \/-, -\/ }
|
||||||
|
|
||||||
object Resolution {
|
object Resolution {
|
||||||
|
|
@ -431,28 +432,53 @@ final case class Resolution(
|
||||||
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]],
|
||||||
|
finalDependenciesCache: Map[Dependency, Seq[Dependency]],
|
||||||
filter: Option[Dependency => Boolean],
|
filter: Option[Dependency => Boolean],
|
||||||
profileActivation: Option[(String, Activation, Map[String, String]) => Boolean]
|
profileActivation: Option[(String, Activation, Map[String, String]) => Boolean]
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
def copyWithCache(
|
||||||
|
rootDependencies: Set[Dependency] = rootDependencies,
|
||||||
|
dependencies: Set[Dependency] = dependencies,
|
||||||
|
forceVersions: Map[Module, String] = forceVersions,
|
||||||
|
conflicts: Set[Dependency] = conflicts,
|
||||||
|
projectCache: Map[Resolution.ModuleVersion, (Artifact.Source, Project)] = projectCache,
|
||||||
|
errorCache: Map[Resolution.ModuleVersion, Seq[String]] = errorCache,
|
||||||
|
filter: Option[Dependency => Boolean] = filter,
|
||||||
|
profileActivation: Option[(String, Activation, Map[String, String]) => Boolean] = profileActivation
|
||||||
|
): Resolution =
|
||||||
|
copy(
|
||||||
|
rootDependencies,
|
||||||
|
dependencies,
|
||||||
|
forceVersions,
|
||||||
|
conflicts,
|
||||||
|
projectCache,
|
||||||
|
errorCache,
|
||||||
|
finalDependenciesCache ++ finalDependenciesCache0.asScala,
|
||||||
|
filter,
|
||||||
|
profileActivation
|
||||||
|
)
|
||||||
|
|
||||||
import Resolution._
|
import Resolution._
|
||||||
|
|
||||||
private val finalDependenciesCache =
|
private[core] val finalDependenciesCache0 = new ConcurrentHashMap[Dependency, Seq[Dependency]]
|
||||||
new mutable.HashMap[Dependency, Seq[Dependency]]()
|
|
||||||
private def finalDependencies0(dep: Dependency) =
|
private def finalDependencies0(dep: Dependency): Seq[Dependency] =
|
||||||
finalDependenciesCache.synchronized {
|
if (dep.transitive) {
|
||||||
finalDependenciesCache.getOrElseUpdate(dep, {
|
val deps = finalDependenciesCache.getOrElse(dep, finalDependenciesCache0.get(dep))
|
||||||
if (dep.transitive)
|
|
||||||
projectCache.get(dep.moduleVersion) match {
|
if (deps == null)
|
||||||
case Some((_, proj)) =>
|
projectCache.get(dep.moduleVersion) match {
|
||||||
finalDependencies(dep, proj)
|
case Some((_, proj)) =>
|
||||||
.filter(filter getOrElse defaultFilter)
|
val res = finalDependencies(dep, proj).filter(filter getOrElse defaultFilter)
|
||||||
case None => Nil
|
finalDependenciesCache0.put(dep, res)
|
||||||
}
|
res
|
||||||
else
|
case None => Nil
|
||||||
Nil
|
}
|
||||||
})
|
else
|
||||||
}
|
deps
|
||||||
|
} else
|
||||||
|
Nil
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transitive dependencies of the current dependencies, according to
|
* Transitive dependencies of the current dependencies, according to
|
||||||
|
|
@ -592,7 +618,7 @@ final case class Resolution(
|
||||||
private def nextNoMissingUnsafe: Resolution = {
|
private def nextNoMissingUnsafe: Resolution = {
|
||||||
val (newConflicts, _, _) = nextDependenciesAndConflicts
|
val (newConflicts, _, _) = nextDependenciesAndConflicts
|
||||||
|
|
||||||
copy(
|
copyWithCache(
|
||||||
dependencies = newDependencies ++ newConflicts,
|
dependencies = newDependencies ++ newConflicts,
|
||||||
conflicts = newConflicts.toSet
|
conflicts = newConflicts.toSet
|
||||||
)
|
)
|
||||||
|
|
@ -856,7 +882,7 @@ final case class Resolution(
|
||||||
newDeps
|
newDeps
|
||||||
}
|
}
|
||||||
|
|
||||||
copy(
|
copyWithCache(
|
||||||
rootDependencies = dependencies,
|
rootDependencies = dependencies,
|
||||||
dependencies = helper(dependencies.map(updateVersion))
|
dependencies = helper(dependencies.map(updateVersion))
|
||||||
// don't know if something should be done about conflicts
|
// don't know if something should be done about conflicts
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,7 @@ final case class Missing(
|
||||||
def cont0(res: Resolution) = {
|
def cont0(res: Resolution) = {
|
||||||
val res0 =
|
val res0 =
|
||||||
successes.foldLeft(res){case (acc, (modVer, (source, proj))) =>
|
successes.foldLeft(res){case (acc, (modVer, (source, proj))) =>
|
||||||
acc.copy(projectCache = acc.projectCache + (
|
acc.copyWithCache(projectCache = acc.projectCache + (
|
||||||
modVer -> (source, acc.withDependencyManagement(proj))
|
modVer -> (source, acc.withDependencyManagement(proj))
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
@ -83,7 +83,7 @@ final case class Missing(
|
||||||
}
|
}
|
||||||
|
|
||||||
val current0 = current
|
val current0 = current
|
||||||
.copy(errorCache = current.errorCache ++ errors)
|
.copyWithCache(errorCache = current.errorCache ++ errors)
|
||||||
|
|
||||||
if (depMgmtMissing.isEmpty)
|
if (depMgmtMissing.isEmpty)
|
||||||
cont0(current0)
|
cont0(current0)
|
||||||
|
|
|
||||||
|
|
@ -70,6 +70,7 @@ package object coursier {
|
||||||
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,
|
||||||
|
finalDependencies: Map[Dependency, Seq[Dependency]] = Map.empty,
|
||||||
filter: Option[Dependency => Boolean] = None,
|
filter: Option[Dependency => Boolean] = None,
|
||||||
profileActivation: Option[(String, core.Activation, Map[String, String]) => Boolean] = None
|
profileActivation: Option[(String, core.Activation, Map[String, String]) => Boolean] = None
|
||||||
): Resolution =
|
): Resolution =
|
||||||
|
|
@ -80,6 +81,7 @@ package object coursier {
|
||||||
conflicts,
|
conflicts,
|
||||||
projectCache,
|
projectCache,
|
||||||
errorCache,
|
errorCache,
|
||||||
|
finalDependencies,
|
||||||
filter,
|
filter,
|
||||||
profileActivation
|
profileActivation
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -90,8 +90,7 @@ object CentralTests extends TestSuite {
|
||||||
'logback{
|
'logback{
|
||||||
async {
|
async {
|
||||||
val dep = Dependency(Module("ch.qos.logback", "logback-classic"), "1.1.3")
|
val dep = Dependency(Module("ch.qos.logback", "logback-classic"), "1.1.3")
|
||||||
val res = await(resolve(Set(dep)))
|
val res = await(resolve(Set(dep))).clearCaches
|
||||||
.copy(projectCache = Map.empty, errorCache = Map.empty) // No validating these here
|
|
||||||
|
|
||||||
val expected = Resolution(
|
val expected = Resolution(
|
||||||
rootDependencies = Set(dep),
|
rootDependencies = Set(dep),
|
||||||
|
|
@ -106,8 +105,7 @@ object CentralTests extends TestSuite {
|
||||||
'asm{
|
'asm{
|
||||||
async {
|
async {
|
||||||
val dep = Dependency(Module("org.ow2.asm", "asm-commons"), "5.0.2")
|
val dep = Dependency(Module("org.ow2.asm", "asm-commons"), "5.0.2")
|
||||||
val res = await(resolve(Set(dep)))
|
val res = await(resolve(Set(dep))).clearCaches
|
||||||
.copy(projectCache = Map.empty, errorCache = Map.empty) // No validating these here
|
|
||||||
|
|
||||||
val expected = Resolution(
|
val expected = Resolution(
|
||||||
rootDependencies = Set(dep),
|
rootDependencies = Set(dep),
|
||||||
|
|
@ -123,7 +121,7 @@ object CentralTests extends TestSuite {
|
||||||
async {
|
async {
|
||||||
val dep = Dependency(Module("joda-time", "joda-time"), "[2.2,2.8]")
|
val dep = Dependency(Module("joda-time", "joda-time"), "[2.2,2.8]")
|
||||||
val res0 = await(resolve(Set(dep)))
|
val res0 = await(resolve(Set(dep)))
|
||||||
val res = res0.copy(projectCache = Map.empty, errorCache = Map.empty)
|
val res = res0.clearCaches
|
||||||
|
|
||||||
val expected = Resolution(
|
val expected = Resolution(
|
||||||
rootDependencies = Set(dep),
|
rootDependencies = Set(dep),
|
||||||
|
|
|
||||||
|
|
@ -203,7 +203,7 @@ object ResolutionTests extends TestSuite {
|
||||||
val dep = Dependency(Module("acme", "config"), "1.3.0")
|
val dep = Dependency(Module("acme", "config"), "1.3.0")
|
||||||
val res = await(resolve0(
|
val res = await(resolve0(
|
||||||
Set(dep)
|
Set(dep)
|
||||||
))
|
)).clearFinalDependenciesCache
|
||||||
|
|
||||||
val expected = Resolution(
|
val expected = Resolution(
|
||||||
rootDependencies = Set(dep),
|
rootDependencies = Set(dep),
|
||||||
|
|
@ -220,7 +220,7 @@ object ResolutionTests extends TestSuite {
|
||||||
val trDep = Dependency(Module("acme", "play-json"), "2.4.0")
|
val trDep = Dependency(Module("acme", "play-json"), "2.4.0")
|
||||||
val res = await(resolve0(
|
val res = await(resolve0(
|
||||||
Set(dep)
|
Set(dep)
|
||||||
))
|
)).clearFinalDependenciesCache
|
||||||
|
|
||||||
val expected = Resolution(
|
val expected = Resolution(
|
||||||
rootDependencies = Set(dep),
|
rootDependencies = Set(dep),
|
||||||
|
|
@ -243,7 +243,7 @@ object ResolutionTests extends TestSuite {
|
||||||
)
|
)
|
||||||
val res = await(resolve0(
|
val res = await(resolve0(
|
||||||
Set(dep)
|
Set(dep)
|
||||||
)).copy(filter = None, projectCache = Map.empty)
|
)).clearCaches
|
||||||
|
|
||||||
val expected = Resolution(
|
val expected = Resolution(
|
||||||
rootDependencies = Set(dep),
|
rootDependencies = Set(dep),
|
||||||
|
|
@ -264,7 +264,7 @@ object ResolutionTests extends TestSuite {
|
||||||
)
|
)
|
||||||
val res = await(resolve0(
|
val res = await(resolve0(
|
||||||
Set(dep)
|
Set(dep)
|
||||||
)).copy(filter = None, projectCache = Map.empty)
|
)).clearCaches
|
||||||
|
|
||||||
val expected = Resolution(
|
val expected = Resolution(
|
||||||
rootDependencies = Set(dep),
|
rootDependencies = Set(dep),
|
||||||
|
|
@ -285,7 +285,7 @@ object ResolutionTests extends TestSuite {
|
||||||
)
|
)
|
||||||
val res = await(resolve0(
|
val res = await(resolve0(
|
||||||
Set(dep)
|
Set(dep)
|
||||||
)).copy(filter = None, projectCache = Map.empty)
|
)).clearCaches
|
||||||
|
|
||||||
val expected = Resolution(
|
val expected = Resolution(
|
||||||
rootDependencies = Set(dep),
|
rootDependencies = Set(dep),
|
||||||
|
|
@ -300,7 +300,7 @@ object ResolutionTests extends TestSuite {
|
||||||
val dep = Dependency(Module("hudsucker", "mail"), "10.0")
|
val dep = Dependency(Module("hudsucker", "mail"), "10.0")
|
||||||
val res = await(resolve0(
|
val res = await(resolve0(
|
||||||
Set(dep)
|
Set(dep)
|
||||||
)).copy(filter = None, projectCache = Map.empty)
|
)).clearCaches
|
||||||
|
|
||||||
val expected = Resolution(
|
val expected = Resolution(
|
||||||
rootDependencies = Set(dep),
|
rootDependencies = Set(dep),
|
||||||
|
|
@ -319,7 +319,7 @@ object ResolutionTests extends TestSuite {
|
||||||
)
|
)
|
||||||
val res = await(resolve0(
|
val res = await(resolve0(
|
||||||
Set(dep)
|
Set(dep)
|
||||||
)).copy(filter = None, projectCache = Map.empty)
|
)).clearCaches
|
||||||
|
|
||||||
val expected = Resolution(
|
val expected = Resolution(
|
||||||
rootDependencies = Set(dep),
|
rootDependencies = Set(dep),
|
||||||
|
|
@ -337,7 +337,7 @@ object ResolutionTests extends TestSuite {
|
||||||
Dependency(Module("org.gnome", "desktop"), "7.0"))
|
Dependency(Module("org.gnome", "desktop"), "7.0"))
|
||||||
val res = await(resolve0(
|
val res = await(resolve0(
|
||||||
Set(dep)
|
Set(dep)
|
||||||
)).copy(filter = None, projectCache = Map.empty, errorCache = Map.empty)
|
)).clearCaches
|
||||||
|
|
||||||
val expected = Resolution(
|
val expected = Resolution(
|
||||||
rootDependencies = Set(dep),
|
rootDependencies = Set(dep),
|
||||||
|
|
@ -354,7 +354,7 @@ object ResolutionTests extends TestSuite {
|
||||||
Dependency(Module("gov.nsa", "secure-pgp"), "10.0", exclusions = Set(("*", "crypto"))))
|
Dependency(Module("gov.nsa", "secure-pgp"), "10.0", exclusions = Set(("*", "crypto"))))
|
||||||
val res = await(resolve0(
|
val res = await(resolve0(
|
||||||
Set(dep)
|
Set(dep)
|
||||||
)).copy(filter = None, projectCache = Map.empty, errorCache = Map.empty)
|
)).clearCaches
|
||||||
|
|
||||||
val expected = Resolution(
|
val expected = Resolution(
|
||||||
rootDependencies = Set(dep),
|
rootDependencies = Set(dep),
|
||||||
|
|
@ -369,7 +369,7 @@ object ResolutionTests extends TestSuite {
|
||||||
val dep = Dependency(Module("com.thoughtworks.paranamer", "paranamer"), "2.6")
|
val dep = Dependency(Module("com.thoughtworks.paranamer", "paranamer"), "2.6")
|
||||||
val res = await(resolve0(
|
val res = await(resolve0(
|
||||||
Set(dep)
|
Set(dep)
|
||||||
)).copy(filter = None, projectCache = Map.empty, errorCache = Map.empty)
|
)).clearCaches
|
||||||
|
|
||||||
val expected = Resolution(
|
val expected = Resolution(
|
||||||
rootDependencies = Set(dep),
|
rootDependencies = Set(dep),
|
||||||
|
|
@ -386,7 +386,7 @@ object ResolutionTests extends TestSuite {
|
||||||
Dependency(Module("org.escalier", "librairie-standard"), "2.11.6"))
|
Dependency(Module("org.escalier", "librairie-standard"), "2.11.6"))
|
||||||
val res = await(resolve0(
|
val res = await(resolve0(
|
||||||
Set(dep)
|
Set(dep)
|
||||||
)).copy(filter = None, projectCache = Map.empty, errorCache = Map.empty)
|
)).clearCaches
|
||||||
|
|
||||||
val expected = Resolution(
|
val expected = Resolution(
|
||||||
rootDependencies = Set(dep),
|
rootDependencies = Set(dep),
|
||||||
|
|
@ -405,7 +405,7 @@ object ResolutionTests extends TestSuite {
|
||||||
Dependency(Module("org.escalier", "librairie-standard"), "2.11.6"))
|
Dependency(Module("org.escalier", "librairie-standard"), "2.11.6"))
|
||||||
val res = await(resolve0(
|
val res = await(resolve0(
|
||||||
Set(dep)
|
Set(dep)
|
||||||
)).copy(filter = None, projectCache = Map.empty, errorCache = Map.empty)
|
)).clearCaches
|
||||||
|
|
||||||
val expected = Resolution(
|
val expected = Resolution(
|
||||||
rootDependencies = Set(dep),
|
rootDependencies = Set(dep),
|
||||||
|
|
@ -426,7 +426,7 @@ object ResolutionTests extends TestSuite {
|
||||||
Dependency(Module("org.escalier", "librairie-standard"), "2.11.6"))
|
Dependency(Module("org.escalier", "librairie-standard"), "2.11.6"))
|
||||||
val res = await(resolve0(
|
val res = await(resolve0(
|
||||||
Set(dep)
|
Set(dep)
|
||||||
)).copy(filter = None, projectCache = Map.empty, errorCache = Map.empty)
|
)).clearCaches
|
||||||
|
|
||||||
val expected = Resolution(
|
val expected = Resolution(
|
||||||
rootDependencies = Set(dep),
|
rootDependencies = Set(dep),
|
||||||
|
|
@ -447,7 +447,7 @@ object ResolutionTests extends TestSuite {
|
||||||
val res = await(resolve0(
|
val res = await(resolve0(
|
||||||
Set(dep),
|
Set(dep),
|
||||||
filter = Some(_ => true)
|
filter = Some(_ => true)
|
||||||
)).copy(filter = None, projectCache = Map.empty, errorCache = Map.empty)
|
)).clearCaches.clearFilter
|
||||||
|
|
||||||
val expected = Resolution(
|
val expected = Resolution(
|
||||||
rootDependencies = Set(dep),
|
rootDependencies = Set(dep),
|
||||||
|
|
@ -470,7 +470,7 @@ object ResolutionTests extends TestSuite {
|
||||||
val res = await(resolve0(
|
val res = await(resolve0(
|
||||||
deps,
|
deps,
|
||||||
filter = Some(_ => true)
|
filter = Some(_ => true)
|
||||||
)).copy(filter = None, projectCache = Map.empty, errorCache = Map.empty)
|
)).clearCaches.clearFilter
|
||||||
|
|
||||||
val expected = Resolution(
|
val expected = Resolution(
|
||||||
rootDependencies = deps,
|
rootDependencies = deps,
|
||||||
|
|
@ -492,7 +492,7 @@ object ResolutionTests extends TestSuite {
|
||||||
val res = await(resolve0(
|
val res = await(resolve0(
|
||||||
deps,
|
deps,
|
||||||
forceVersions = depOverrides
|
forceVersions = depOverrides
|
||||||
)).copy(filter = None, projectCache = Map.empty, errorCache = Map.empty)
|
)).clearCaches
|
||||||
|
|
||||||
val expected = Resolution(
|
val expected = Resolution(
|
||||||
rootDependencies = deps,
|
rootDependencies = deps,
|
||||||
|
|
@ -516,7 +516,7 @@ object ResolutionTests extends TestSuite {
|
||||||
val res = await(resolve0(
|
val res = await(resolve0(
|
||||||
deps,
|
deps,
|
||||||
forceVersions = depOverrides
|
forceVersions = depOverrides
|
||||||
)).copy(filter = None, projectCache = Map.empty, errorCache = Map.empty)
|
)).clearCaches
|
||||||
|
|
||||||
val expected = Resolution(
|
val expected = Resolution(
|
||||||
rootDependencies = deps,
|
rootDependencies = deps,
|
||||||
|
|
@ -542,7 +542,7 @@ object ResolutionTests extends TestSuite {
|
||||||
val res = await(resolve0(
|
val res = await(resolve0(
|
||||||
deps,
|
deps,
|
||||||
forceVersions = depOverrides
|
forceVersions = depOverrides
|
||||||
)).copy(filter = None, projectCache = Map.empty, errorCache = Map.empty)
|
)).clearCaches
|
||||||
|
|
||||||
val expected = Resolution(
|
val expected = Resolution(
|
||||||
rootDependencies = deps,
|
rootDependencies = deps,
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,24 @@ package object test {
|
||||||
def withCompileScope: Dependency = underlying.copy(configuration = "compile")
|
def withCompileScope: Dependency = underlying.copy(configuration = "compile")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
implicit class ResolutionOps(val underlying: Resolution) extends AnyVal {
|
||||||
|
|
||||||
|
// The content of these fields is typically not validated in the tests.
|
||||||
|
// It can be cleared with these method to it easier to compare `underlying`
|
||||||
|
// to an expected value.
|
||||||
|
|
||||||
|
def clearFinalDependenciesCache: Resolution =
|
||||||
|
underlying.copy(finalDependenciesCache = Map.empty)
|
||||||
|
def clearCaches: Resolution =
|
||||||
|
underlying.copy(
|
||||||
|
projectCache = Map.empty,
|
||||||
|
errorCache = Map.empty,
|
||||||
|
finalDependenciesCache = Map.empty
|
||||||
|
)
|
||||||
|
def clearFilter: Resolution =
|
||||||
|
underlying.copy(filter = None)
|
||||||
|
}
|
||||||
|
|
||||||
object Profile {
|
object Profile {
|
||||||
type Activation = core.Activation
|
type Activation = core.Activation
|
||||||
object Activation {
|
object Activation {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue