diff --git a/ivy/src/main/scala/sbt/Ivy.scala b/ivy/src/main/scala/sbt/Ivy.scala index 4bf6ffad6..c0e7d508a 100644 --- a/ivy/src/main/scala/sbt/Ivy.scala +++ b/ivy/src/main/scala/sbt/Ivy.scala @@ -4,7 +4,7 @@ package sbt import Resolver.PluginPattern -import ivyint.{ CachedResolutionResolveEngine, CachedResolutionResolveCache } +import ivyint.{ CachedResolutionResolveEngine, CachedResolutionResolveCache, SbtDefaultDependencyDescriptor } import java.io.File import java.net.URI @@ -570,7 +570,9 @@ private[sbt] object IvySbt { /** Transforms an sbt ModuleID into an Ivy DefaultDependencyDescriptor.*/ def convertDependency(moduleID: DefaultModuleDescriptor, dependency: ModuleID, parser: CustomXmlParser.CustomParser): DefaultDependencyDescriptor = { - val dependencyDescriptor = new DefaultDependencyDescriptor(moduleID, toID(dependency), dependency.isForce, dependency.isChanging, dependency.isTransitive) + val dependencyDescriptor = new DefaultDependencyDescriptor(moduleID, toID(dependency), dependency.isForce, dependency.isChanging, dependency.isTransitive) with SbtDefaultDependencyDescriptor { + def dependencyModuleId = dependency + } dependency.configurations match { case None => // The configuration for this dependency was not explicitly specified, so use the default parser.parseDepsConfs(parser.getDefaultConf, dependencyDescriptor) diff --git a/ivy/src/main/scala/sbt/IvyRetrieve.scala b/ivy/src/main/scala/sbt/IvyRetrieve.scala index 1e74f3955..f453efb1f 100644 --- a/ivy/src/main/scala/sbt/IvyRetrieve.scala +++ b/ivy/src/main/scala/sbt/IvyRetrieve.scala @@ -13,6 +13,7 @@ import module.id.{ ModuleRevisionId, ModuleId => IvyModuleId } import report.{ ArtifactDownloadReport, ConfigurationResolveReport, ResolveReport } import resolve.{ IvyNode, IvyNodeCallers } import IvyNodeCallers.{ Caller => IvyCaller } +import ivyint.SbtDefaultDependencyDescriptor object IvyRetrieve { def reports(report: ResolveReport): Seq[ConfigurationResolveReport] = @@ -77,11 +78,14 @@ object IvyRetrieve { case x if nonEmptyString(x).isDefined => x } val ddOpt = Option(caller.getDependencyDescriptor) - val (extraAttributes, isForce, isChanging, isTransitive) = ddOpt match { - case Some(dd) => (toExtraAttributes(dd.getExtraAttributes), dd.isForce, dd.isChanging, dd.isTransitive) - case None => (Map.empty[String, String], false, false, true) + val (extraAttributes, isForce, isChanging, isTransitive, isDirectlyForce) = ddOpt match { + case Some(dd: SbtDefaultDependencyDescriptor) => + val mod = dd.dependencyModuleId + (toExtraAttributes(dd.getExtraAttributes), mod.isForce, mod.isChanging, mod.isTransitive, mod.isForce) + case Some(dd) => (toExtraAttributes(dd.getExtraAttributes), dd.isForce, dd.isChanging, dd.isTransitive, false) + case None => (Map.empty[String, String], false, false, true, false) } - new Caller(m, callerConfigurations, extraAttributes, isForce, isChanging, isTransitive) + new Caller(m, callerConfigurations, extraAttributes, isForce, isChanging, isTransitive, isDirectlyForce) } val revId = dep.getResolvedId val moduleId = toModuleID(revId) diff --git a/ivy/src/main/scala/sbt/UpdateReport.scala b/ivy/src/main/scala/sbt/UpdateReport.scala index 443c84ed3..696fa4d20 100644 --- a/ivy/src/main/scala/sbt/UpdateReport.scala +++ b/ivy/src/main/scala/sbt/UpdateReport.scala @@ -190,7 +190,8 @@ final class Caller( val callerExtraAttributes: Map[String, String], val isForceDependency: Boolean, val isChangingDependency: Boolean, - val isTransitiveDependency: Boolean) { + val isTransitiveDependency: Boolean, + val isDirectlyForceDependency: Boolean) { override def toString: String = s"$caller" } diff --git a/ivy/src/main/scala/sbt/ivyint/CachedResolutionResolveEngine.scala b/ivy/src/main/scala/sbt/ivyint/CachedResolutionResolveEngine.scala index 3ee26964e..850f1b61d 100644 --- a/ivy/src/main/scala/sbt/ivyint/CachedResolutionResolveEngine.scala +++ b/ivy/src/main/scala/sbt/ivyint/CachedResolutionResolveEngine.scala @@ -36,6 +36,9 @@ private[sbt] class CachedResolutionResolveCache() { val mds = if (mrid0.getOrganisation == sbtOrgTemp) Vector(md0) else buildArtificialModuleDescriptors(md0, prOpt) map { _._1 } + + updateReportCache.remove(md0.getModuleRevisionId) + directDependencyCache.remove(md0.getModuleRevisionId) mds foreach { md => updateReportCache.remove(md.getModuleRevisionId) directDependencyCache.remove(md.getModuleRevisionId) @@ -186,6 +189,7 @@ private[sbt] trait CachedResolutionResolveEngine extends ResolveEngine { val miniGraphPath = depDir / "module" val cachedDescriptor = getSettings.getResolutionCacheManager.getResolvedIvyFileInCache(md0.getModuleRevisionId) val cache = cachedResolutionResolveCache + cache.directDependencyCache.remove(md0.getModuleRevisionId) val mds = cache.buildArtificialModuleDescriptors(md0, projectResolver) def doWork(md: ModuleDescriptor): Either[ResolveException, UpdateReport] = { @@ -292,10 +296,13 @@ private[sbt] trait CachedResolutionResolveEngine extends ResolveEngine { val name = head.module.name log.debug(s"- conflict in $rootModuleConf:$organization:$name " + (conflicts map { _.module }).mkString("(", ", ", ")")) def useLatest(lcm: LatestConflictManager): (Vector[ModuleReport], Vector[ModuleReport], String) = - conflicts find { m => + (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") (Vector(m), conflicts filterNot { _ == m } map { _.copy(evicted = true, evictedReason = Some(lcm.toString)) }, lcm.toString) case None => val strategy = lcm.getStrategy diff --git a/ivy/src/main/scala/sbt/ivyint/SbtDefaultDependencyDescriptor.scala b/ivy/src/main/scala/sbt/ivyint/SbtDefaultDependencyDescriptor.scala new file mode 100644 index 000000000..0a3338fac --- /dev/null +++ b/ivy/src/main/scala/sbt/ivyint/SbtDefaultDependencyDescriptor.scala @@ -0,0 +1,9 @@ +package sbt +package ivyint + +import org.apache.ivy.core +import core.module.descriptor.DefaultDependencyDescriptor + +trait SbtDefaultDependencyDescriptor { self: DefaultDependencyDescriptor => + def dependencyModuleId: ModuleID +}