From bad1e9d487a30b3f66818c9e2e63d362744fdfc8 Mon Sep 17 00:00:00 2001 From: Josh Suereth Date: Tue, 21 Jul 2015 21:51:13 -0400 Subject: [PATCH 1/3] Add handling for transitive exclude rules in pom.xml files. Fixes #2109 * Add maven resolver tests back to travisCI * Disable ivy.xml translation test from maven-repository-resolver config, due to incorrect assumptions. --- .travis.yml | 4 ++-- .../maven-plugin-transitive-excludes.markdown | 10 ++++++++ .../mavenint/MavenRepositoryResolver.scala | 23 ++++++++++++++----- .../pom-parent-pom/build.sbt | 7 +++++- 4 files changed, 35 insertions(+), 9 deletions(-) create mode 100644 notes/0.13.10/maven-plugin-transitive-excludes.markdown diff --git a/.travis.yml b/.travis.yml index 3911a9cf5..6885ec812 100644 --- a/.travis.yml +++ b/.travis.yml @@ -34,8 +34,8 @@ env: - SCRIPTED_TEST="scripted tests/*" - SCRIPTED_TEST="scripted project-load/*" - SCRIPTED_TEST="checkBuildScala211" - # - SCRIPTED_TEST="mavenResolverPluginTest:scripted dependency-management/*1of2 project/transitive-plugins" - # - SCRIPTED_TEST="mavenResolverPluginTest:scripted dependency-management/*2of2" + - SCRIPTED_TEST="mavenResolverPluginTest:scripted dependency-management/*1of2 project/transitive-plugins" + - SCRIPTED_TEST="mavenResolverPluginTest:scripted dependency-management/*2of2" notifications: email: diff --git a/notes/0.13.10/maven-plugin-transitive-excludes.markdown b/notes/0.13.10/maven-plugin-transitive-excludes.markdown new file mode 100644 index 000000000..1b45a24b0 --- /dev/null +++ b/notes/0.13.10/maven-plugin-transitive-excludes.markdown @@ -0,0 +1,10 @@ +[@jsuereth]: http://github.com/jsuereth +[2109]: https://github.com/sbt/sbt/issues/2109 + +### Fixes with compatibility implications + +### Improvements + +### Bug fixes + +- Expand transitive dependency exclusions when using sbt-maven-resolver-plugin [#2109][2109] by [@jsuereth][@jsuereth] diff --git a/sbt-maven-resolver/src/main/scala/sbt/mavenint/MavenRepositoryResolver.scala b/sbt-maven-resolver/src/main/scala/sbt/mavenint/MavenRepositoryResolver.scala index 7e105957c..e550b9c0a 100644 --- a/sbt-maven-resolver/src/main/scala/sbt/mavenint/MavenRepositoryResolver.scala +++ b/sbt-maven-resolver/src/main/scala/sbt/mavenint/MavenRepositoryResolver.scala @@ -6,11 +6,11 @@ import java.util.Date import org.apache.ivy.core.IvyContext import org.apache.ivy.core.cache.{ ArtifactOrigin, ModuleDescriptorWriter } import org.apache.ivy.core.module.descriptor._ -import org.apache.ivy.core.module.id.{ ModuleId, ModuleRevisionId } +import org.apache.ivy.core.module.id.{ ArtifactId, ModuleId, ModuleRevisionId } import org.apache.ivy.core.report.{ ArtifactDownloadReport, DownloadReport, DownloadStatus, MetadataArtifactDownloadReport } import org.apache.ivy.core.resolve.{ DownloadOptions, ResolveData, ResolvedModuleRevision } import org.apache.ivy.core.settings.IvySettings -import org.apache.ivy.plugins.matcher.ExactPatternMatcher +import org.apache.ivy.plugins.matcher.{ PatternMatcher, ExactPatternMatcher } import org.apache.ivy.plugins.parser.m2.{ PomModuleDescriptorBuilder, ReplaceMavenConfigurationMappings } import org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorWriter import org.apache.ivy.plugins.resolver.AbstractResolver @@ -172,7 +172,6 @@ abstract class MavenRepositoryResolver(settings: IvySettings) extends AbstractRe addDependenciesFromAether(result, md) // Here we use pom.xml Dependency management section to create Ivy dependency mediators. addManagedDependenciesFromAether(result, md) - // TODO - Add excludes? // Here we rip out license info. addLicenseInfo(md, result.getProperties) @@ -319,8 +318,9 @@ abstract class MavenRepositoryResolver(settings: IvySettings) extends AbstractRe } /** Adds the dependency mediators required based on the managed dependency instances from this pom. */ - def addManagedDependenciesFromAether(result: AetherDescriptorResult, md: DefaultModuleDescriptor) { + def addManagedDependenciesFromAether(result: AetherDescriptorResult, md: DefaultModuleDescriptor): Unit = { for (d <- result.getManagedDependencies.asScala) { + // TODO - Figure out what to do about exclusions on managed dependencies. md.addDependencyDescriptorMediator( ModuleId.newInstance(d.getArtifact.getGroupId, d.getArtifact.getArtifactId), ExactPatternMatcher.INSTANCE, @@ -334,7 +334,7 @@ abstract class MavenRepositoryResolver(settings: IvySettings) extends AbstractRe } /** Adds the list of dependencies this artifact has on other artifacts. */ - def addDependenciesFromAether(result: AetherDescriptorResult, md: DefaultModuleDescriptor) { + def addDependenciesFromAether(result: AetherDescriptorResult, md: DefaultModuleDescriptor): Unit = { // First we construct a map of any extra attributes we must append to dependencies. // This is necessary for transitive maven-based sbt plugin dependencies, where we need to // attach the sbtVersion/scalaVersion to the dependency id otherwise we'll fail to resolve the @@ -366,7 +366,6 @@ abstract class MavenRepositoryResolver(settings: IvySettings) extends AbstractRe // TODO - Configuration mappings (are we grabbing scope correctly, or should the default not always be compile?) val scope = Option(d.getScope).filterNot(_.isEmpty).getOrElse("compile") val mapping = ReplaceMavenConfigurationMappings.addMappings(dd, scope, d.isOptional) - // TODO - include rules and exclude rules. Message.debug(s"Adding maven transitive dependency ${md.getModuleRevisionId} -> ${dd}") // TODO - Unify this borrowed Java code into something a bit friendlier. // Now we add the artifact.... @@ -390,6 +389,18 @@ abstract class MavenRepositoryResolver(settings: IvySettings) extends AbstractRe // TOOD - We may need to fix the configuration mappings here. dd.addDependencyArtifact(optionalizedScope, depArtifact) } + // Include rules and exclude rules. + for (e <- d.getExclusions.asScala) { + val excludedModule = new ModuleId(e.getGroupId, e.getArtifactId) + for (conf <- dd.getModuleConfigurations) { + // TODO - Do we need extra attributes for this? + dd.addExcludeRule(conf, new DefaultExcludeRule(new ArtifactId( + excludedModule, PatternMatcher.ANY_EXPRESSION, + PatternMatcher.ANY_EXPRESSION, + PatternMatcher.ANY_EXPRESSION), + ExactPatternMatcher.INSTANCE, null)) + } + } md.addDependency(dd) } } diff --git a/sbt/src/sbt-test/dependency-management/pom-parent-pom/build.sbt b/sbt/src/sbt-test/dependency-management/pom-parent-pom/build.sbt index 82e17b0ab..d0fb533bb 100644 --- a/sbt/src/sbt-test/dependency-management/pom-parent-pom/build.sbt +++ b/sbt/src/sbt-test/dependency-management/pom-parent-pom/build.sbt @@ -25,6 +25,8 @@ cleanExampleCache := { val checkIvyXml = taskKey[Unit]("Checks the ivy.xml transform was correct") + + checkIvyXml := { ivySbt.value.withIvy(streams.value.log) { ivy => val cacheDir = ivy.getSettings.getDefaultRepositoryCacheBasedir @@ -34,6 +36,9 @@ checkIvyXml := { //cacheDir / "com.example" / "example-child" / "ivy-1.0-SNAPSHOT.xml" val lines = IO.read(xmlFile) if(lines.isEmpty) sys.error(s"Unable to read $xmlFile, could not resolve geronimo...") - assert(lines contains "xmlns:e", s"Failed to appropriately modify ivy.xml file for sbt extra attributes!\n$lines") + // Note: We do not do this if the maven plguin is enabled, because there is no rewrite of ivy.xml, extra attribtues + // are handled in a different mechanism. This is a hacky mechanism to detect that. + val isMavenResolver = updateOptions.value.resolverConverter != PartialFunction.empty + if(!isMavenResolver) assert(lines contains "xmlns:e", s"Failed to appropriately modify ivy.xml file for sbt extra attributes!\n$lines") } } From 3613cc8c39268272d3bad01aab3de40b7065e0d4 Mon Sep 17 00:00:00 2001 From: Josh Suereth Date: Thu, 23 Jul 2015 15:59:35 -0400 Subject: [PATCH 2/3] Add failing transitive exlcude test. --- .../transitive-excludes/build.sbt | 28 +++++++++++++++++++ .../exclude/test/app/1.0.0/app-1.0.0.jar | 0 .../exclude/test/app/1.0.0/app-1.0.0.pom | 17 +++++++++++ .../test/bottom/1.0.0/bottom-1.0.0.jar | 0 .../test/bottom/1.0.0/bottom-1.0.0.pom | 12 ++++++++ .../test/middle/1.0.0/middle-1.0.0.jar | 0 .../test/middle/1.0.0/middle-1.0.0.pom | 17 +++++++++++ .../exclude/test/top/1.0.0/top-1.0.0.jar | 0 .../exclude/test/top/1.0.0/top-1.0.0.pom | 23 +++++++++++++++ .../transitive-excludes/test | 1 + 10 files changed, 98 insertions(+) create mode 100644 sbt/src/sbt-test/dependency-management/transitive-excludes/build.sbt create mode 100644 sbt/src/sbt-test/dependency-management/transitive-excludes/repository/exclude/test/app/1.0.0/app-1.0.0.jar create mode 100644 sbt/src/sbt-test/dependency-management/transitive-excludes/repository/exclude/test/app/1.0.0/app-1.0.0.pom create mode 100644 sbt/src/sbt-test/dependency-management/transitive-excludes/repository/exclude/test/bottom/1.0.0/bottom-1.0.0.jar create mode 100644 sbt/src/sbt-test/dependency-management/transitive-excludes/repository/exclude/test/bottom/1.0.0/bottom-1.0.0.pom create mode 100644 sbt/src/sbt-test/dependency-management/transitive-excludes/repository/exclude/test/middle/1.0.0/middle-1.0.0.jar create mode 100644 sbt/src/sbt-test/dependency-management/transitive-excludes/repository/exclude/test/middle/1.0.0/middle-1.0.0.pom create mode 100644 sbt/src/sbt-test/dependency-management/transitive-excludes/repository/exclude/test/top/1.0.0/top-1.0.0.jar create mode 100644 sbt/src/sbt-test/dependency-management/transitive-excludes/repository/exclude/test/top/1.0.0/top-1.0.0.pom create mode 100644 sbt/src/sbt-test/dependency-management/transitive-excludes/test diff --git a/sbt/src/sbt-test/dependency-management/transitive-excludes/build.sbt b/sbt/src/sbt-test/dependency-management/transitive-excludes/build.sbt new file mode 100644 index 000000000..5a04d1401 --- /dev/null +++ b/sbt/src/sbt-test/dependency-management/transitive-excludes/build.sbt @@ -0,0 +1,28 @@ + + +resolvers += { + val f = baseDirectory.value / "repository" + "local-test-repo" at f.getCanonicalFile.toURI.toASCIIString +} +libraryDependencies += "exclude.test" % "app" % "1.0.0" + +val checkDependencies = taskKey[Unit]("Checks that dependcies are correct.") + +checkDependencies := { + val hasBadJar = (fullClasspath in Compile).value.exists { jar => jar.data.getName contains "bottom-1.0.0.jar"} + val errorJarString = (fullClasspath in Compile).value.map(_.data.getName).mkString(" * ", "\n * ", "") + assert(!hasBadJar, s"Failed to exclude transitive excluded dependency on classpath!\nFound:\n$errorJarString") + val modules = + (for { + c <- update.value.configurations + m <- c.modules + if !m.evicted + } yield m.module).distinct + val hasBadDep = + modules exists { m => + (m.organization == "exclude.test") && (m.name == "bottom") + } + val errModuleString = modules.mkString("\n * ", "\n * ", "") + assert(!hasBadDep, s"Failed to exclude transitive excluded dependency!\nFound:\n$errModuleString") + +} \ No newline at end of file diff --git a/sbt/src/sbt-test/dependency-management/transitive-excludes/repository/exclude/test/app/1.0.0/app-1.0.0.jar b/sbt/src/sbt-test/dependency-management/transitive-excludes/repository/exclude/test/app/1.0.0/app-1.0.0.jar new file mode 100644 index 000000000..e69de29bb diff --git a/sbt/src/sbt-test/dependency-management/transitive-excludes/repository/exclude/test/app/1.0.0/app-1.0.0.pom b/sbt/src/sbt-test/dependency-management/transitive-excludes/repository/exclude/test/app/1.0.0/app-1.0.0.pom new file mode 100644 index 000000000..ba115f816 --- /dev/null +++ b/sbt/src/sbt-test/dependency-management/transitive-excludes/repository/exclude/test/app/1.0.0/app-1.0.0.pom @@ -0,0 +1,17 @@ + + 4.0.0 + exclude.test + app + jar + 1.0.0 + app + http://maven.apache.org + + + exclude.test + top + 1.0.0 + + + \ No newline at end of file diff --git a/sbt/src/sbt-test/dependency-management/transitive-excludes/repository/exclude/test/bottom/1.0.0/bottom-1.0.0.jar b/sbt/src/sbt-test/dependency-management/transitive-excludes/repository/exclude/test/bottom/1.0.0/bottom-1.0.0.jar new file mode 100644 index 000000000..e69de29bb diff --git a/sbt/src/sbt-test/dependency-management/transitive-excludes/repository/exclude/test/bottom/1.0.0/bottom-1.0.0.pom b/sbt/src/sbt-test/dependency-management/transitive-excludes/repository/exclude/test/bottom/1.0.0/bottom-1.0.0.pom new file mode 100644 index 000000000..757ce6d6a --- /dev/null +++ b/sbt/src/sbt-test/dependency-management/transitive-excludes/repository/exclude/test/bottom/1.0.0/bottom-1.0.0.pom @@ -0,0 +1,12 @@ + + 4.0.0 + exclude.test + bottom + jar + 1.0.0 + bottom + http://maven.apache.org + + + \ No newline at end of file diff --git a/sbt/src/sbt-test/dependency-management/transitive-excludes/repository/exclude/test/middle/1.0.0/middle-1.0.0.jar b/sbt/src/sbt-test/dependency-management/transitive-excludes/repository/exclude/test/middle/1.0.0/middle-1.0.0.jar new file mode 100644 index 000000000..e69de29bb diff --git a/sbt/src/sbt-test/dependency-management/transitive-excludes/repository/exclude/test/middle/1.0.0/middle-1.0.0.pom b/sbt/src/sbt-test/dependency-management/transitive-excludes/repository/exclude/test/middle/1.0.0/middle-1.0.0.pom new file mode 100644 index 000000000..fe6e0c993 --- /dev/null +++ b/sbt/src/sbt-test/dependency-management/transitive-excludes/repository/exclude/test/middle/1.0.0/middle-1.0.0.pom @@ -0,0 +1,17 @@ + + 4.0.0 + exclude.test + middle + jar + 1.0.0 + middle + http://maven.apache.org + + + exclude.test + bottom + 1.0.0 + + + \ No newline at end of file diff --git a/sbt/src/sbt-test/dependency-management/transitive-excludes/repository/exclude/test/top/1.0.0/top-1.0.0.jar b/sbt/src/sbt-test/dependency-management/transitive-excludes/repository/exclude/test/top/1.0.0/top-1.0.0.jar new file mode 100644 index 000000000..e69de29bb diff --git a/sbt/src/sbt-test/dependency-management/transitive-excludes/repository/exclude/test/top/1.0.0/top-1.0.0.pom b/sbt/src/sbt-test/dependency-management/transitive-excludes/repository/exclude/test/top/1.0.0/top-1.0.0.pom new file mode 100644 index 000000000..912f10b7a --- /dev/null +++ b/sbt/src/sbt-test/dependency-management/transitive-excludes/repository/exclude/test/top/1.0.0/top-1.0.0.pom @@ -0,0 +1,23 @@ + + 4.0.0 + exclude.test + top + jar + 1.0.0 + top + http://maven.apache.org + + + exclude.test + middle + 1.0.0 + + + exclude.test + middle + + + + + \ No newline at end of file diff --git a/sbt/src/sbt-test/dependency-management/transitive-excludes/test b/sbt/src/sbt-test/dependency-management/transitive-excludes/test new file mode 100644 index 000000000..c579cedc3 --- /dev/null +++ b/sbt/src/sbt-test/dependency-management/transitive-excludes/test @@ -0,0 +1 @@ +> checkDependencies \ No newline at end of file From 6f2c4a8d10ed510fc7d7d3a880dac0cc7df2bd0c Mon Sep 17 00:00:00 2001 From: Josh Suereth Date: Fri, 24 Jul 2015 09:51:46 -0400 Subject: [PATCH 3/3] Fix test setup to be accurate. --- .../dependency-management/transitive-excludes/build.sbt | 7 +++++++ .../repository/exclude/test/app/1.0.0/app-1.0.0.pom | 6 ++++++ .../repository/exclude/test/top/1.0.0/top-1.0.0.pom | 6 ------ 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/sbt/src/sbt-test/dependency-management/transitive-excludes/build.sbt b/sbt/src/sbt-test/dependency-management/transitive-excludes/build.sbt index 5a04d1401..2776e4448 100644 --- a/sbt/src/sbt-test/dependency-management/transitive-excludes/build.sbt +++ b/sbt/src/sbt-test/dependency-management/transitive-excludes/build.sbt @@ -11,6 +11,8 @@ val checkDependencies = taskKey[Unit]("Checks that dependcies are correct.") checkDependencies := { val hasBadJar = (fullClasspath in Compile).value.exists { jar => jar.data.getName contains "bottom-1.0.0.jar"} val errorJarString = (fullClasspath in Compile).value.map(_.data.getName).mkString(" * ", "\n * ", "") + val hasBadMiddleJar = (fullClasspath in Compile).value.exists { jar => jar.data.getName contains "middle-1.0.0.jar"} + assert(!hasBadMiddleJar, s"Failed to exclude excluded dependency on classpath!\nFound:\n$errorJarString") assert(!hasBadJar, s"Failed to exclude transitive excluded dependency on classpath!\nFound:\n$errorJarString") val modules = (for { @@ -22,7 +24,12 @@ checkDependencies := { modules exists { m => (m.organization == "exclude.test") && (m.name == "bottom") } + val hasBadMiddleDep = + modules exists { m => + (m.organization == "exclude.test") && (m.name == "middle") + } val errModuleString = modules.mkString("\n * ", "\n * ", "") + assert(!hasBadMiddleDep, s"Failed to exclude transitive excluded dependency!\nFound:\n$errModuleString") assert(!hasBadDep, s"Failed to exclude transitive excluded dependency!\nFound:\n$errModuleString") } \ No newline at end of file diff --git a/sbt/src/sbt-test/dependency-management/transitive-excludes/repository/exclude/test/app/1.0.0/app-1.0.0.pom b/sbt/src/sbt-test/dependency-management/transitive-excludes/repository/exclude/test/app/1.0.0/app-1.0.0.pom index ba115f816..801b7ddf3 100644 --- a/sbt/src/sbt-test/dependency-management/transitive-excludes/repository/exclude/test/app/1.0.0/app-1.0.0.pom +++ b/sbt/src/sbt-test/dependency-management/transitive-excludes/repository/exclude/test/app/1.0.0/app-1.0.0.pom @@ -12,6 +12,12 @@ exclude.test top 1.0.0 + + + exclude.test + middle + + \ No newline at end of file diff --git a/sbt/src/sbt-test/dependency-management/transitive-excludes/repository/exclude/test/top/1.0.0/top-1.0.0.pom b/sbt/src/sbt-test/dependency-management/transitive-excludes/repository/exclude/test/top/1.0.0/top-1.0.0.pom index 912f10b7a..2cad5b396 100644 --- a/sbt/src/sbt-test/dependency-management/transitive-excludes/repository/exclude/test/top/1.0.0/top-1.0.0.pom +++ b/sbt/src/sbt-test/dependency-management/transitive-excludes/repository/exclude/test/top/1.0.0/top-1.0.0.pom @@ -12,12 +12,6 @@ exclude.test middle 1.0.0 - - - exclude.test - middle - - \ No newline at end of file