Merge pull request #1703 from sbt/wip/merge-0.13.7

Wip/merge 0.13.7
This commit is contained in:
eugene yokota 2014-10-29 21:36:36 -04:00
commit d6bb793855
1 changed files with 30 additions and 11 deletions

View File

@ -216,6 +216,7 @@ private[sbt] trait CachedResolutionResolveEngine extends ResolveEngine {
private[sbt] def cachedResolutionResolveCache: CachedResolutionResolveCache
private[sbt] def projectResolver: Option[ProjectResolver]
private[sbt] def makeInstance: Ivy
private[sbt] val ignoreTransitiveForce: Boolean = true
/**
* This returns sbt's UpdateReport structure.
@ -329,6 +330,17 @@ private[sbt] trait CachedResolutionResolveEngine extends ResolveEngine {
survivor ++ evicted ++ (merged filter { m => m.evicted || m.problem.isDefined })
}
}
/**
* resolves dependency resolution conflicts in which multiple candidates are found for organization+name combos.
* The main input is conflicts, which is a Vector of ModuleReport, which contains full info on the modulerevision, including its callers.
* Conflict resolution could be expensive, so this is first cached to `cachedResolutionResolveCache` if the conflict is between 2 modules.
* Otherwise, the default "latest" resolution takes the following precedence:
* 1. overrides passed in to `os`.
* 2. diretly forced dependency within the artificial module.
* 3. latest revision.
* Note transitively forced dependencies are not respected. This seems to be the case for stock Ivy's behavior as well,
* which may be because Ivy makes all Maven dependencies as forced="true".
*/
def resolveConflict(rootModuleConf: String, conflicts: Vector[ModuleReport], os: Vector[IvyOverride], log: Logger): (Vector[ModuleReport], Vector[ModuleReport]) =
{
import org.apache.ivy.plugins.conflict.{ NoConflictManager, StrictConflictManager, LatestConflictManager }
@ -339,19 +351,26 @@ private[sbt] trait CachedResolutionResolveEngine extends ResolveEngine {
def useLatest(lcm: LatestConflictManager): (Vector[ModuleReport], Vector[ModuleReport], String) =
(conflicts find { m =>
m.callers.exists { _.isDirectlyForceDependency }
} orElse (conflicts find { m =>
m.callers.exists { _.isForceDependency }
})) match {
}) match {
case Some(m) =>
log.debug(s"- forced dependency: $m ${m.callers}")
(Vector(m), conflicts filterNot { _ == m } map { _.copy(evicted = true, evictedReason = Some(lcm.toString)) }, lcm.toString)
log.debug(s"- directly forced dependency: $m ${m.callers}")
(Vector(m), conflicts filterNot { _ == m } map { _.copy(evicted = true, evictedReason = Some("direct-force")) }, "direct-force")
case None =>
val strategy = lcm.getStrategy
val infos = conflicts map { ModuleReportArtifactInfo(_) }
Option(strategy.findLatest(infos.toArray, None.orNull)) match {
case Some(ModuleReportArtifactInfo(m)) =>
(Vector(m), conflicts filterNot { _ == m } map { _.copy(evicted = true, evictedReason = Some(lcm.toString)) }, lcm.toString)
case _ => (conflicts, Vector(), lcm.toString)
(conflicts find { m =>
m.callers.exists { _.isForceDependency }
}) match {
// Ivy translates pom.xml dependencies to forced="true", so transitive force is broken.
case Some(m) if !ignoreTransitiveForce =>
log.debug(s"- transitively forced dependency: $m ${m.callers}")
(Vector(m), conflicts filterNot { _ == m } map { _.copy(evicted = true, evictedReason = Some("transitive-force")) }, "transitive-force")
case _ =>
val strategy = lcm.getStrategy
val infos = conflicts map { ModuleReportArtifactInfo(_) }
Option(strategy.findLatest(infos.toArray, None.orNull)) match {
case Some(ModuleReportArtifactInfo(m)) =>
(Vector(m), conflicts filterNot { _ == m } map { _.copy(evicted = true, evictedReason = Some(lcm.toString)) }, lcm.toString)
case _ => (conflicts, Vector(), lcm.toString)
}
}
}
def doResolveConflict: (Vector[ModuleReport], Vector[ModuleReport], String) =