diff --git a/cache/src/main/scala/coursier/Cache.scala b/cache/src/main/scala/coursier/Cache.scala index 6cc16b6af..af10e8168 100644 --- a/cache/src/main/scala/coursier/Cache.scala +++ b/cache/src/main/scala/coursier/Cache.scala @@ -487,7 +487,8 @@ object Cache { lazy val ivy2Local = IvyRepository( ivy2HomeUri + "local/" + "[organisation]/[module]/(scala_[scalaVersion]/)(sbt_[sbtVersion]/)[revision]/[type]s/" + - "[artifact](-[classifier]).[ext]" + "[artifact](-[classifier]).[ext]", + dropInfoAttributes = true ) lazy val ivy2Cache = IvyRepository( diff --git a/cli/src/main/scala-2.11/coursier/cli/Coursier.scala b/cli/src/main/scala-2.11/coursier/cli/Coursier.scala index 8f0d95eb8..64db345eb 100644 --- a/cli/src/main/scala-2.11/coursier/cli/Coursier.scala +++ b/cli/src/main/scala-2.11/coursier/cli/Coursier.scala @@ -37,6 +37,8 @@ case class CommonOptions( noDefault: Boolean = false, @Help("Modify names in Maven repository paths for SBT plugins") sbtPluginHack: Boolean = false, + @Help("Drop module attributes starting with 'info.' - these are sometimes used by projects built with SBT") + dropInfoAttr: Boolean = false, @Help("Force module version") @Value("organization:name:forcedVersion") @Short("V") diff --git a/cli/src/main/scala-2.11/coursier/cli/Helper.scala b/cli/src/main/scala-2.11/coursier/cli/Helper.scala index f39dcc2db..e68fec54f 100644 --- a/cli/src/main/scala-2.11/coursier/cli/Helper.scala +++ b/cli/src/main/scala-2.11/coursier/cli/Helper.scala @@ -90,14 +90,22 @@ class Helper( ) val repositoriesValidation = CacheParse.repositories(common.repository).map { repos0 => - val repos = (if (common.noDefault) Nil else defaultRepositories) ++ repos0 + + var repos = (if (common.noDefault) Nil else defaultRepositories) ++ repos0 + if (common.sbtPluginHack) - repos.map { + repos = repos.map { case m: MavenRepository => m.copy(sbtAttrStub = true) case other => other } - else - repos + + if (common.dropInfoAttr) + repos = repos.map { + case m: IvyRepository => m.copy(dropInfoAttributes = true) + case other => other + } + + repos } val repositories = repositoriesValidation match { diff --git a/core/shared/src/main/scala/coursier/ivy/IvyRepository.scala b/core/shared/src/main/scala/coursier/ivy/IvyRepository.scala index 15cbfa30e..433a0674f 100644 --- a/core/shared/src/main/scala/coursier/ivy/IvyRepository.scala +++ b/core/shared/src/main/scala/coursier/ivy/IvyRepository.scala @@ -156,7 +156,19 @@ case class IvyRepository( attributes = proj0.module.attributes.filter { case (k, _) => !k.startsWith("info.") } - ) + ), + dependencies = proj0.dependencies.map { + case (config, dep0) => + val dep = dep0.copy( + module = dep0.module.copy( + attributes = dep0.module.attributes.filter { + case (k, _) => !k.startsWith("info.") + } + ) + ) + + config -> dep + } ) else proj0 diff --git a/plugin/src/main/scala-2.10/coursier/FromSbt.scala b/plugin/src/main/scala-2.10/coursier/FromSbt.scala index 65a139b9c..76c51f4cc 100644 --- a/plugin/src/main/scala-2.10/coursier/FromSbt.scala +++ b/plugin/src/main/scala-2.10/coursier/FromSbt.scala @@ -121,7 +121,8 @@ object FromSbt { "file://" + patterns.artifactPatterns.head, metadataPatternOpt = Some("file://" + patterns.ivyPatterns.head), changing = Some(true), - properties = ivyProperties + properties = ivyProperties, + dropInfoAttributes = true )) case sbt.URLRepository(_, patterns) @@ -132,7 +133,8 @@ object FromSbt { patterns.artifactPatterns.head, metadataPatternOpt = Some(patterns.ivyPatterns.head), changing = None, - properties = ivyProperties + properties = ivyProperties, + dropInfoAttributes = true )) case other => diff --git a/tests/jvm/src/test/scala/coursier/test/IvyTests.scala b/tests/jvm/src/test/scala/coursier/test/IvyTests.scala new file mode 100644 index 000000000..03d54bd14 --- /dev/null +++ b/tests/jvm/src/test/scala/coursier/test/IvyTests.scala @@ -0,0 +1,31 @@ +package coursier.test + +import coursier.Module +import coursier.ivy.IvyRepository + +import utest._ + +object IvyTests extends TestSuite { + + // only tested on the JVM for lack of support of XML attributes in our XML wrappers + + val tests = TestSuite { + 'dropInfoAttributes - { + CentralTests.resolutionCheck( + module = Module( + "org.scala-js", "sbt-scalajs", Map("sbtVersion" -> "0.13", "scalaVersion" -> "2.10") + ), + version = "0.6.6", + extraRepo = Some( + IvyRepository( + "https://repo.scala-sbt.org/scalasbt/sbt-plugin-releases/" + + "[organisation]/[module]/(scala_[scalaVersion]/)(sbt_[sbtVersion]/)" + + "[revision]/[type]s/[artifact](-[classifier]).[ext]", + dropInfoAttributes = true + ) + ) + ) + } + } + +} diff --git a/tests/jvm/src/test/scala/coursier/test/compatibility/package.scala b/tests/jvm/src/test/scala/coursier/test/compatibility/package.scala index b257db280..808c739d4 100644 --- a/tests/jvm/src/test/scala/coursier/test/compatibility/package.scala +++ b/tests/jvm/src/test/scala/coursier/test/compatibility/package.scala @@ -14,10 +14,10 @@ package object compatibility { } def textResource(path: String)(implicit ec: ExecutionContext): Future[String] = Future { - def is = getClass - .getClassLoader - .getResource(path) - .openStream() + val res = Option(getClass.getClassLoader.getResource(path)).getOrElse { + throw new Exception(s"Not found: resource $path") + } + val is = res.openStream() new String(Platform.readFullySync(is), "UTF-8") } diff --git a/tests/shared/src/test/resources/resolutions/org.scala-js/sbt-scalajs/sbtVersion_0.13_scalaVersion_2.10/0.6.6 b/tests/shared/src/test/resources/resolutions/org.scala-js/sbt-scalajs/sbtVersion_0.13_scalaVersion_2.10/0.6.6 new file mode 100644 index 000000000..76c6e1e6a --- /dev/null +++ b/tests/shared/src/test/resources/resolutions/org.scala-js/sbt-scalajs/sbtVersion_0.13_scalaVersion_2.10/0.6.6 @@ -0,0 +1,18 @@ +args4j:args4j:jar:2.0.16 +com.google.code.findbugs:jsr305:jar:1.3.9 +com.google.guava:guava:jar:14.0.1 +com.google.javascript:closure-compiler:jar:v20130603 +com.google.protobuf:protobuf-java:jar:2.4.1 +com.googlecode.json-simple:json-simple:jar:1.1.1 +io.apigee:rhino:jar:1.7R5pre4 +junit:junit:jar:4.10 +org.hamcrest:hamcrest-core:jar:1.1 +org.json:json:jar:20090211 +org.scala-js:sbt-scalajs;sbtVersion=0.13;scalaVersion=2.10:jar:0.6.6 +org.scala-js:scalajs-ir_2.10:jar:0.6.6 +org.scala-js:scalajs-js-envs_2.10:jar:0.6.6 +org.scala-js:scalajs-sbt-test-adapter_2.10:jar:0.6.6 +org.scala-js:scalajs-tools_2.10:jar:0.6.6 +org.scala-lang:scala-library:jar:2.10.6 +org.scala-sbt:test-interface:jar:1.0 +org.webjars:envjs:jar:1.2 diff --git a/tests/shared/src/test/scala/coursier/test/CentralTests.scala b/tests/shared/src/test/scala/coursier/test/CentralTests.scala index 3e0704f39..db05027ee 100644 --- a/tests/shared/src/test/scala/coursier/test/CentralTests.scala +++ b/tests/shared/src/test/scala/coursier/test/CentralTests.scala @@ -29,8 +29,7 @@ object CentralTests extends TestSuite { def repr(dep: Dependency) = ( Seq( - dep.module.organization, - dep.module.name, + dep.module, dep.attributes.`type` ) ++ Some(dep.attributes.classifier) @@ -48,9 +47,17 @@ object CentralTests extends TestSuite { configuration: String = "" ) = async { + val attrPathPart = + if (module.attributes.isEmpty) + "" + else + "/" + module.attributes.toVector.sorted.map { + case (k, v) => k + "_" + v + }.mkString("_") + val expected = await( - textResource(s"resolutions/${module.organization}/${module.name}/$version") + textResource(s"resolutions/${module.organization}/${module.name}$attrPathPart/$version") ) .split('\n') .toSeq