diff --git a/ivy/src/main/scala/sbt/MakePom.scala b/ivy/src/main/scala/sbt/MakePom.scala index 16bd6002a..1dfa5d1fe 100644 --- a/ivy/src/main/scala/sbt/MakePom.scala +++ b/ivy/src/main/scala/sbt/MakePom.scala @@ -104,7 +104,7 @@ class MakePom(val log: Logger) { { val deps = depsInConfs(module, configurations) makeProperties(module, deps) ++ - makeDependencies(deps, includeTypes) + makeDependencies(deps, includeTypes, module.getAllExcludeRules) } { makeRepositories(ivy.getSettings, allRepositories, filterRepositories) } ) @@ -220,37 +220,49 @@ class MakePom(val log: Logger) { } val IgnoreTypes: Set[String] = Set(Artifact.SourceType, Artifact.DocType, Artifact.PomType) + @deprecated("Use `makeDependencies` variant which takes excludes", "0.13.9") def makeDependencies(dependencies: Seq[DependencyDescriptor], includeTypes: Set[String]): NodeSeq = + makeDependencies(dependencies, includeTypes, Nil) + + def makeDependencies(dependencies: Seq[DependencyDescriptor], includeTypes: Set[String], excludes: Seq[ExcludeRule]): NodeSeq = if (dependencies.isEmpty) NodeSeq.Empty else - { dependencies.map(makeDependency(_, includeTypes)) } + { dependencies.map(makeDependency(_, includeTypes, excludes)) } + @deprecated("Use `makeDependency` variant which takes excludes", "0.13.9") def makeDependency(dependency: DependencyDescriptor, includeTypes: Set[String]): NodeSeq = + makeDependency(dependency, includeTypes, Nil) + + def makeDependency(dependency: DependencyDescriptor, includeTypes: Set[String], excludes: Seq[ExcludeRule]): NodeSeq = { val artifacts = dependency.getAllDependencyArtifacts val includeArtifacts = artifacts.filter(d => includeTypes(d.getType)) if (artifacts.isEmpty) { val configs = dependency.getModuleConfigurations - if (configs.filterNot(Set("sources","docs")).nonEmpty) { + if (configs.filterNot(Set("sources", "docs")).nonEmpty) { val (scope, optional) = getScopeAndOptional(dependency.getModuleConfigurations) - makeDependencyElem(dependency, scope, optional, None, None) + makeDependencyElem(dependency, scope, optional, None, None, excludes) } else NodeSeq.Empty } else if (includeArtifacts.isEmpty) NodeSeq.Empty else - NodeSeq.fromSeq(artifacts.flatMap(a => makeDependencyElem(dependency, a))) + NodeSeq.fromSeq(artifacts.flatMap(a => makeDependencyElem(dependency, a, excludes))) } + @deprecated("Use `makeDependencyElem` variant which takes excludes", "0.13.9") def makeDependencyElem(dependency: DependencyDescriptor, artifact: DependencyArtifactDescriptor): Option[Elem] = + makeDependencyElem(dependency, artifact, Nil) + + def makeDependencyElem(dependency: DependencyDescriptor, artifact: DependencyArtifactDescriptor, excludes: Seq[ExcludeRule]): Option[Elem] = { val configs = artifact.getConfigurations.toList match { case Nil | "*" :: Nil => dependency.getModuleConfigurations case x => x.toArray } - if (configs.filterNot(Set("sources","docs")).nonEmpty) { + if (configs.filterNot(Set("sources", "docs")).nonEmpty) { val (scope, optional) = getScopeAndOptional(configs) val classifier = artifactClassifier(artifact) val baseType = artifactType(artifact) @@ -258,10 +270,15 @@ class MakePom(val log: Logger) { case (Some(c), Some(tpe)) if Artifact.classifierType(c) == tpe => None case _ => baseType } - Some(makeDependencyElem(dependency, scope, optional, classifier, tpe)) + Some(makeDependencyElem(dependency, scope, optional, classifier, tpe, excludes)) } else None } + + @deprecated("Use `makeDependencyElem` variant which takes excludes", "0.13.9") def makeDependencyElem(dependency: DependencyDescriptor, scope: Option[String], optional: Boolean, classifier: Option[String], tpe: Option[String]): Elem = + makeDependencyElem(dependency, scope, optional, classifier, tpe, Nil) + + def makeDependencyElem(dependency: DependencyDescriptor, scope: Option[String], optional: Boolean, classifier: Option[String], tpe: Option[String], excludes: Seq[ExcludeRule]): Elem = { val mrid = dependency.getDependencyRevisionId @@ -272,7 +289,7 @@ class MakePom(val log: Logger) { { optionalElem(optional) } { classifierElem(classifier) } { typeElem(tpe) } - { exclusions(dependency) } + { exclusions(dependency, excludes) } } @@ -322,9 +339,12 @@ class MakePom(val log: Logger) { (scope, opt.nonEmpty) } - def exclusions(dependency: DependencyDescriptor): NodeSeq = + @deprecated("Use `exclusions` variant which takes excludes", "0.13.9") + def exclusions(dependency: DependencyDescriptor): NodeSeq = exclusions(dependency, Nil) + + def exclusions(dependency: DependencyDescriptor, excludes: Seq[ExcludeRule]): NodeSeq = { - val excl = dependency.getExcludeRules(dependency.getModuleConfigurations) + val excl = dependency.getExcludeRules(dependency.getModuleConfigurations) ++ excludes val (warns, excls) = IvyUtil.separate(excl.map(makeExclusion)) if (warns.nonEmpty) log.warn(warns.mkString(IO.Newline)) if (excls.nonEmpty) { excls } diff --git a/notes/0.13.9/project-level-exclusions-in-the-pom.markdown b/notes/0.13.9/project-level-exclusions-in-the-pom.markdown new file mode 100644 index 000000000..f534d989e --- /dev/null +++ b/notes/0.13.9/project-level-exclusions-in-the-pom.markdown @@ -0,0 +1,12 @@ + + [@dwijnand]: http://github.com/dwijnand + [#1877]: https://github.com/sbt/sbt/issues/1877 + [#2035]: https://github.com/sbt/sbt/pull/2035 + +### Fixes with compatibility implications + +### Improvements + +### Bug fixes + +- Add dependency-level exclusions in the POM for project-level exclusions. [#1877][]/[#2035][] by [@dwijnand][] diff --git a/sbt/src/sbt-test/dependency-management/exclude-dependencies/build.sbt b/sbt/src/sbt-test/dependency-management/exclude-dependencies/build.sbt index 16bc85772..5390886f3 100644 --- a/sbt/src/sbt-test/dependency-management/exclude-dependencies/build.sbt +++ b/sbt/src/sbt-test/dependency-management/exclude-dependencies/build.sbt @@ -1,3 +1,6 @@ +import scala.xml.{ Node, _ } +import scala.xml.Utility.trim + lazy val check = taskKey[Unit]("check") val dispatch = "net.databinder.dispatch" %% "dispatch-core" % "0.11.2" @@ -31,5 +34,30 @@ lazy val root = (project in file(".")). if (bcp exists { _.data.getName contains "dispatch-core_2.11-0.11.1.jar" }) { sys.error("dispatch-core_2.11-0.11.1.jar found when it should NOT be included: " + bcp.toString) } + + val bPomXml = makePomXml(streams.value.log, (makePomConfiguration in b).value, (ivyModule in b).value) + + val repatchTwitterXml = bPomXml \ "dependencies" \ "dependency" find { d => + (d \ "groupId").text == "com.eed3si9n" && (d \ "artifactId").text == "repatch-twitter-core_2.11" + } getOrElse (sys error s"Missing repatch-twitter-core dependency: $bPomXml") + + val excludeDispatchCoreXml = + + net.databinder.dispatch + dispatch-core_2.11 + + + if (trim((repatchTwitterXml \ "exclusions" \ "exclusion").head) != trim(excludeDispatchCoreXml)) + sys error s"Missing dispatch-core exclusion: $repatchTwitterXml" + + () } - ) \ No newline at end of file + ) + +def makePomXml(log: Logger, makePomConfig: MakePomConfiguration, ivyModule: IvySbt#Module): Node = { + ivyModule.withModule[Node](log) { (ivy, md, default) => + import makePomConfig._ + new MakePom(log).toPom( + ivy, md, moduleInfo, configurations, includeTypes, extra, filterRepositories, allRepositories) + } +}