From b1d39404a1ce88e9435a10da36725c2d7d429fd9 Mon Sep 17 00:00:00 2001 From: Mark Harrah Date: Wed, 16 Mar 2011 20:10:41 -0400 Subject: [PATCH] make default conflict manager ignore force see comment on IvySbt.latestNoForce --- ivy/Ivy.scala | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/ivy/Ivy.scala b/ivy/Ivy.scala index a2d03f269..1a25cb1d1 100644 --- a/ivy/Ivy.scala +++ b/ivy/Ivy.scala @@ -7,6 +7,7 @@ import Artifact.{defaultExtension, defaultType} import java.io.File import java.util.concurrent.Callable +import java.util.{Collection, Collections} import org.apache.ivy.{core, plugins, util, Ivy} import core.IvyPatternHelper @@ -14,7 +15,10 @@ import core.cache.{CacheMetadataOptions, DefaultRepositoryCacheManager} import core.module.descriptor.{DefaultArtifact, DefaultDependencyArtifactDescriptor, MDArtifact} import core.module.descriptor.{DefaultDependencyDescriptor, DefaultModuleDescriptor, DependencyDescriptor, ModuleDescriptor} import core.module.id.{ArtifactId,ModuleId, ModuleRevisionId} +import core.resolve.IvyNode import core.settings.IvySettings +import plugins.conflict.{ConflictManager, LatestConflictManager} +import plugins.latest.LatestRevisionStrategy import plugins.matcher.PatternMatcher import plugins.parser.m2.PomModuleDescriptorParser import plugins.resolver.ChainResolver @@ -44,7 +48,7 @@ final class IvySbt(val configuration: IvyConfiguration) // Ivy is not thread-safe nor can the cache be used concurrently. // If provided a GlobalLock, we can use that to ensure safe access to the cache. // Otherwise, we can at least synchronize within the JVM. - // For thread-safety In particular, Ivy uses a static DocumentBuilder, which is not thread-safe. + // For thread-safety in particular, Ivy uses a static DocumentBuilder, which is not thread-safe. configuration.lock match { case Some(lock) => lock(ivyLockFile, new Callable[T] { def call = action() }) @@ -55,6 +59,7 @@ final class IvySbt(val configuration: IvyConfiguration) { val is = new IvySettings is.setBaseDir(baseDirectory) + is.setDefaultConflictManager(IvySbt.latestNoForce(is)) configuration match { case e: ExternalIvyConfiguration => is.load(e.file) @@ -392,4 +397,36 @@ private object IvySbt case Some(confs) => confs.map(_.name).toList.toArray case None => module.getPublicConfigurationsNames } + + // same as Ivy's builtin latest-revision manager except that it ignores the force setting, + // which seems to be added to dependencies read from poms (perhaps only in certain circumstances) + // causing revisions of indirect dependencies other than latest to be selected + def latestNoForce(settings: IvySettings): ConflictManager = + { + import collection.JavaConversions._ + + new LatestConflictManager("latest-revision-no-force", new LatestRevisionStrategy) + { + setSettings(settings) + + override def resolveConflicts(parent: IvyNode, conflicts: Collection[_]): Collection[_] = + if(conflicts.size < 2) + conflicts + else + resolveMultiple(parent, conflicts.asInstanceOf[Collection[IvyNode]]).asInstanceOf[Collection[_]] + + def resolveMultiple(parent: IvyNode, conflicts: Collection[IvyNode]): Collection[IvyNode] = + { + val matcher = settings.getVersionMatcher + val dynamic = conflicts.exists { node => matcher.isDynamic(node.getResolvedId) } + if(dynamic) null else { + try { + val l = getStrategy.findLatest(toArtifactInfo(conflicts), null).asInstanceOf[{def getNode(): IvyNode}] + if(l eq null) conflicts else Collections.singleton(l.getNode) + } + catch { case e: LatestConflictManager.NoConflictResolvedYetException => null } + } + } + } + } }