From 80db26bc20e7f2a2619115a1d9e61e92c2c8f179 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Sun, 14 Dec 2014 07:52:05 -0500 Subject: [PATCH] Fixes #1634. Adds inconsistent duplicate warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #1634 is about a library getting wiped out of deps graph when it’s included twice in ascending order of version. I’d say that’s a logically inconsistent state, and we should just issue warning instead of trying to fix it. --- ivy/src/main/scala/sbt/Ivy.scala | 23 +++++++++++++++ ivy/src/main/scala/sbt/IvyActions.scala | 4 +++ .../scala/InconsistentDuplicateSpec.scala | 28 +++++++++++++++++++ 3 files changed, 55 insertions(+) create mode 100644 ivy/src/test/scala/InconsistentDuplicateSpec.scala diff --git a/ivy/src/main/scala/sbt/Ivy.scala b/ivy/src/main/scala/sbt/Ivy.scala index 64afd5a40..32f2f6440 100644 --- a/ivy/src/main/scala/sbt/Ivy.scala +++ b/ivy/src/main/scala/sbt/Ivy.scala @@ -527,6 +527,29 @@ private[sbt] object IvySbt { parser } + def inconsistentDuplicateWarning(moduleID: DefaultModuleDescriptor): List[String] = + { + import IvyRetrieve.toModuleID + val dds = moduleID.getDependencies + inconsistentDuplicateWarning(dds map { dd => toModuleID(dd.getDependencyRevisionId) }) + } + + def inconsistentDuplicateWarning(dependencies: Seq[ModuleID]): List[String] = + { + val warningHeader = "Multiple dependencies with the same organization/name but different versions. To avoid conflict, pick one version:" + val out: mutable.ListBuffer[String] = mutable.ListBuffer() + (dependencies groupBy { dep => (dep.organization, dep.name) }) foreach { + case (k, vs) if vs.size > 1 => + val v0 = vs.head + (vs find { _.revision != v0.revision }) foreach { v => + out += s" * ${v0.organization}:${v0.name}:(" + (vs map { _.revision }).mkString(", ") + ")" + } + case _ => () + } + if (out.isEmpty) Nil + else warningHeader :: out.toList + } + /** This method is used to add inline dependencies to the provided module. */ def addDependencies(moduleID: DefaultModuleDescriptor, dependencies: Seq[ModuleID], parser: CustomXmlParser.CustomParser) { val converted = dependencies map { dependency => convertDependency(moduleID, dependency, parser) } diff --git a/ivy/src/main/scala/sbt/IvyActions.scala b/ivy/src/main/scala/sbt/IvyActions.scala index 31c104081..dcf393517 100644 --- a/ivy/src/main/scala/sbt/IvyActions.scala +++ b/ivy/src/main/scala/sbt/IvyActions.scala @@ -166,6 +166,8 @@ object IvyActions { case (ivy, md, default) if module.owner.configuration.updateOptions.cachedResolution && depDir.isDefined => ivy.getResolveEngine match { case x: CachedResolutionResolveEngine => + val iw = IvySbt.inconsistentDuplicateWarning(md) + iw foreach { log.warn(_) } val resolveOptions = new ResolveOptions val resolveId = ResolveOptions.getDefaultResolveId(md) resolveOptions.setResolveId(resolveId) @@ -181,6 +183,8 @@ object IvyActions { } } case (ivy, md, default) => + val iw = IvySbt.inconsistentDuplicateWarning(md) + iw foreach { log.warn(_) } val (report, err) = resolve(configuration.logging)(ivy, md, default) err match { case Some(x) if !configuration.missingOk => diff --git a/ivy/src/test/scala/InconsistentDuplicateSpec.scala b/ivy/src/test/scala/InconsistentDuplicateSpec.scala new file mode 100644 index 000000000..b9f4a05ef --- /dev/null +++ b/ivy/src/test/scala/InconsistentDuplicateSpec.scala @@ -0,0 +1,28 @@ +package sbt + +import org.specs2._ + +class InconsistentDuplicateSpec extends Specification { + def is = s2""" + + This is a specification to check the inconsistent duplicate warnings + + Duplicate with different version should + be warned $warn1 + + Duplicate with same version should + not be warned $nodupe1 + """ + + def akkaActor214 = ModuleID("com.typesafe.akka", "akka-actor", "2.1.4", Some("compile")) cross CrossVersion.binary + def akkaActor230 = ModuleID("com.typesafe.akka", "akka-actor", "2.3.0", Some("compile")) cross CrossVersion.binary + def akkaActor230Test = ModuleID("com.typesafe.akka", "akka-actor", "2.3.0", Some("test")) cross CrossVersion.binary + + def warn1 = + IvySbt.inconsistentDuplicateWarning(Seq(akkaActor214, akkaActor230)) must_== + List("Multiple dependencies with the same organization/name but different versions. To avoid conflict, pick one version:", + " * com.typesafe.akka:akka-actor:(2.1.4, 2.3.0)") + + def nodupe1 = + IvySbt.inconsistentDuplicateWarning(Seq(akkaActor230Test, akkaActor230)) must_== Nil +}