From 6b89af392447187a77661b6b82e0313e24581bdb Mon Sep 17 00:00:00 2001 From: Alexandre Archambault Date: Fri, 3 Feb 2017 00:57:01 +0100 Subject: [PATCH] Better handling of artifacts from Maven repos Doesn't seem to break things --- .ci/travis.sh | 1 + appveyor.yml | 2 +- build.sbt | 17 +++ .../scala/coursier/core/Definitions.scala | 2 + .../main/scala/coursier/core/Resolution.scala | 2 +- .../src/main/scala/coursier/ivy/IvyXml.scala | 3 +- .../coursier/maven/MavenRepository.scala | 123 +++++++++++------ .../scala/coursier/maven/MavenSource.scala | 129 ++++++------------ .../src/main/scala/coursier/maven/Pom.scala | 6 +- .../src/main/scala/coursier/package.scala | 2 +- .../main/scala-2.11/coursier/HttpServer.scala | 68 +++++++-- .../scala-2.10/coursier/CoursierPlugin.scala | 2 - .../FallbackDependenciesRepository.scala | 5 +- .../main/scala-2.10/coursier/FromSbt.scala | 13 +- .../src/main/scala-2.10/coursier/Keys.scala | 1 - .../src/main/scala-2.10/coursier/Tasks.scala | 16 +-- .../main/scala-2.10/coursier/Shading.scala | 9 +- .../scala-2.10/coursier/ShadingPlugin.scala | 1 + .../scala/coursier/test/CentralTests.scala | 36 +++-- .../scala/coursier/test/PomParsingTests.scala | 6 +- .../test/scala/coursier/test/package.scala | 3 +- 21 files changed, 266 insertions(+), 181 deletions(-) diff --git a/.ci/travis.sh b/.ci/travis.sh index 6a853d75e..f28ce63b3 100755 --- a/.ci/travis.sh +++ b/.ci/travis.sh @@ -37,6 +37,7 @@ function isMasterOrDevelop() { -- \ -d tests/jvm/src/test/resources/test-repo/http/abc.com \ -u user -P pass -r realm \ + --list-pages \ -v & # TODO Add coverage once https://github.com/scoverage/sbt-scoverage/issues/111 is fixed diff --git a/appveyor.yml b/appveyor.yml index 88b57bc96..35c89eb68 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -27,7 +27,7 @@ build_script: - sbt ++2.10.6 clean compile - sbt ++2.10.6 coreJVM/publishLocal cache/publishLocal # to make the scripted tests happy test_script: - - ps: Start-Job { & java -jar -noverify C:\projects\coursier\coursier launch -r http://dl.bintray.com/scalaz/releases io.get-coursier:http-server-java7_2.11:1.0.0-SNAPSHOT -- -d /C:/projects/coursier/tests/jvm/src/test/resources/test-repo/http/abc.com -u user -P pass -r realm -v } + - ps: Start-Job { & java -jar -noverify C:\projects\coursier\coursier launch -r http://dl.bintray.com/scalaz/releases io.get-coursier:http-server-java7_2.11:1.0.0-SNAPSHOT -- -d /C:/projects/coursier/tests/jvm/src/test/resources/test-repo/http/abc.com -u user -P pass -r realm --list-pages -v } - sbt ++2.12.1 testsJVM/test testsJVM/it:test # Would node be around for testsJS/test? - sbt ++2.11.8 testsJVM/test testsJVM/it:test - sbt ++2.10.6 testsJVM/test testsJVM/it:test sbt-coursier/scripted sbt-coursier/publishLocal sbt-shading/scripted diff --git a/build.sbt b/build.sbt index 55eed0e38..3cf0bd8f0 100644 --- a/build.sbt +++ b/build.sbt @@ -20,6 +20,23 @@ lazy val core = crossProject import com.typesafe.tools.mima.core._ Seq( + ProblemFilters.exclude[DirectMissingMethodProblem]("coursier.maven.MavenRepository.defaultPublications"), + ProblemFilters.exclude[DirectMissingMethodProblem]("coursier.maven.MavenRepository.defaultPackaging"), + ProblemFilters.exclude[MissingClassProblem]("coursier.maven.MavenSource$DocSourcesArtifactExtensions"), + ProblemFilters.exclude[MissingTypesProblem]("coursier.core.Project$"), + ProblemFilters.exclude[DirectMissingMethodProblem]("coursier.core.Project.apply"), + ProblemFilters.exclude[IncompatibleResultTypeProblem]("coursier.core.Project.copy$default$13"), + ProblemFilters.exclude[IncompatibleResultTypeProblem]("coursier.core.Project.copy$default$12"), + ProblemFilters.exclude[DirectMissingMethodProblem]("coursier.core.Project.copy"), + ProblemFilters.exclude[DirectMissingMethodProblem]("coursier.core.Project.this"), + ProblemFilters.exclude[DirectMissingMethodProblem]("coursier.maven.MavenRepository.copy$default$5"), + ProblemFilters.exclude[DirectMissingMethodProblem]("coursier.maven.MavenRepository.packagingBlacklist"), + ProblemFilters.exclude[DirectMissingMethodProblem]("coursier.maven.MavenRepository.copy"), + ProblemFilters.exclude[DirectMissingMethodProblem]("coursier.maven.MavenRepository.this"), + ProblemFilters.exclude[DirectMissingMethodProblem]("coursier.maven.MavenRepository.apply$default$5"), + ProblemFilters.exclude[DirectMissingMethodProblem]("coursier.maven.MavenRepository.ignorePackaging"), + ProblemFilters.exclude[DirectMissingMethodProblem]("coursier.maven.MavenRepository.$default$5"), + ProblemFilters.exclude[DirectMissingMethodProblem]("coursier.maven.MavenRepository.apply"), ProblemFilters.exclude[FinalClassProblem]("coursier.core.Activation$Os"), ProblemFilters.exclude[FinalClassProblem]("coursier.core.Version"), ProblemFilters.exclude[FinalClassProblem]("coursier.core.Authentication"), diff --git a/core/shared/src/main/scala/coursier/core/Definitions.scala b/core/shared/src/main/scala/coursier/core/Definitions.scala index 3331b8fc2..eb842b623 100644 --- a/core/shared/src/main/scala/coursier/core/Definitions.scala +++ b/core/shared/src/main/scala/coursier/core/Definitions.scala @@ -81,6 +81,8 @@ final case class Project( profiles: Seq[Profile], versions: Option[Versions], snapshotVersioning: Option[SnapshotVersioning], + packagingOpt: Option[String], + /** * Optional exact version used to get this project metadata. * May not match `version` for projects having a wrong version in their metadata. diff --git a/core/shared/src/main/scala/coursier/core/Resolution.scala b/core/shared/src/main/scala/coursier/core/Resolution.scala index 50de8d699..6a1beb59f 100644 --- a/core/shared/src/main/scala/coursier/core/Resolution.scala +++ b/core/shared/src/main/scala/coursier/core/Resolution.scala @@ -63,7 +63,7 @@ object Resolution { type Key = (String, String, String) def key(dep: Dependency): Key = - (dep.module.organization, dep.module.name, dep.attributes.`type`) + (dep.module.organization, dep.module.name, if (dep.attributes.`type`.isEmpty) "jar" else dep.attributes.`type`) def add( dict: Map[Key, (String, Dependency)], diff --git a/core/shared/src/main/scala/coursier/ivy/IvyXml.scala b/core/shared/src/main/scala/coursier/ivy/IvyXml.scala index 464d3a5ab..19e941f4a 100644 --- a/core/shared/src/main/scala/coursier/ivy/IvyXml.scala +++ b/core/shared/src/main/scala/coursier/ivy/IvyXml.scala @@ -80,7 +80,7 @@ object IvyXml { version, toConf, allConfsExcludes ++ excludes.getOrElse(fromConf, Set.empty), - Attributes("jar", ""), // should come from possible artifact nodes + Attributes("", ""), // should come from possible artifact nodes optional = false, transitive = transitive ) @@ -158,6 +158,7 @@ object IvyXml { None, None, None, + None, if (publicationsOpt.isEmpty) // no publications node -> default JAR artifact Seq("*" -> Publication(module.name, "jar", "jar", "")) diff --git a/core/shared/src/main/scala/coursier/maven/MavenRepository.scala b/core/shared/src/main/scala/coursier/maven/MavenRepository.scala index 71322222c..23559f5a8 100644 --- a/core/shared/src/main/scala/coursier/maven/MavenRepository.scala +++ b/core/shared/src/main/scala/coursier/maven/MavenRepository.scala @@ -45,19 +45,6 @@ object MavenRepository { "test" -> Seq("runtime") ) - val defaultPackaging = "jar" - - def defaultPublications(moduleName: String, packaging: String) = Seq( - "compile" -> Publication( - moduleName, - packaging, - MavenSource.typeExtension(packaging), - MavenSource.typeDefaultClassifier(packaging) - ), - "docs" -> Publication(moduleName, "doc", "jar", "javadoc"), - "sources" -> Publication(moduleName, "src", "jar", "sources") - ) - def dirModuleName(module: Module, sbtAttrStub: Boolean): String = if (sbtAttrStub) { var name = module.name @@ -69,10 +56,6 @@ object MavenRepository { } else module.name - val ignorePackaging = Set( - Module("org.apache.zookeeper", "zookeeper", Map.empty) - ) - } final case class MavenRepository( @@ -80,8 +63,7 @@ final case class MavenRepository( changing: Option[Boolean] = None, /** Hackish hack for sbt plugins mainly - what this does really sucks */ sbtAttrStub: Boolean = false, - authentication: Option[Authentication] = None, - packagingBlacklist: Set[Module] = MavenRepository.ignorePackaging + authentication: Option[Authentication] = None ) extends Repository { import Repository._ @@ -262,30 +244,89 @@ final case class MavenRepository( F: Monad[F] ): EitherT[F, String, Project] = { - fetch(projectArtifact(module, version, versioningValue)).flatMap { str => - EitherT { - F.point[String \/ Project] { - for { - xml <- \/.fromEither(compatibility.xmlParse(str)) - _ <- if (xml.label == "project") \/-(()) else -\/("Project definition not found") - proj <- Pom.project(xml) - } yield { - val packagingOpt = - if (packagingBlacklist(module)) - None - else - Pom.packagingOpt(xml) + def parseRawPom(str: String) = + for { + xml <- \/.fromEither(compatibility.xmlParse(str)) + _ <- if (xml.label == "project") \/-(()) else -\/("Project definition not found") + proj <- Pom.project(xml) + } yield proj - proj.copy( - configurations = defaultConfigurations, - publications = defaultPublications( - module.name, - packagingOpt.getOrElse(defaultPackaging) - ) - ) - } + def artifactFor(url: String) = + Artifact( + url, + Map.empty, + Map.empty, + Attributes("", ""), + changing = true, + authentication + ) + + def isArtifact(fileName: String, prefix: String): Option[(String, String)] = + // TODO There should be a regex for that... + if (fileName.startsWith(prefix)) { + val end = fileName.stripPrefix(prefix) + val idx = end.lastIndexOf('.') + if (idx >= 0) { + val ext = end.drop(idx + 1) + val rem = end.take(idx) + if (rem.isEmpty) + Some(("", ext)) + else if (rem.startsWith("-")) + Some((rem.drop(1), ext)) + else + None + } else + None + } else + None + + + val listFilesUrl = urlFor(modulePath(module, version)) + "/" + + for { + str <- fetch(projectArtifact(module, version, versioningValue)) + rawListFilesPage <- fetch(artifactFor(listFilesUrl)) + proj <- EitherT(F.point[String \/ Project](parseRawPom(str))) + } yield { + + val files = coursier.core.compatibility.listWebPageFiles(listFilesUrl, rawListFilesPage) + + val versioning = proj + .snapshotVersioning + .flatMap(versioning => + mavenVersioning(versioning, "", "") + ) + + val prefix = s"${module.name}-${versioning.getOrElse(version)}" + + val packagingTpeMap = proj.packagingOpt + .map { packaging => + (MavenSource.typeDefaultClassifier(packaging), MavenSource.typeExtension(packaging)) -> packaging } - } + .toMap + + val foundPublications = files + .flatMap(isArtifact(_, prefix)) + .map { + case (classifier, ext) => + val tpe = packagingTpeMap.getOrElse( + (classifier, ext), + MavenSource.classifierExtensionDefaultTypeOpt(classifier, ext).getOrElse(ext) + ) + val config = MavenSource.typeDefaultConfig(tpe).getOrElse("compile") + config -> Publication( + module.name, + tpe, + ext, + classifier + ) + } + + proj.copy( + actualVersionOpt = Some(version), + configurations = defaultConfigurations, + publications = foundPublications + ) } } diff --git a/core/shared/src/main/scala/coursier/maven/MavenSource.scala b/core/shared/src/main/scala/coursier/maven/MavenSource.scala index 6bdec3c94..931fb9a62 100644 --- a/core/shared/src/main/scala/coursier/maven/MavenSource.scala +++ b/core/shared/src/main/scala/coursier/maven/MavenSource.scala @@ -13,34 +13,6 @@ final case class MavenSource( import Repository._ import MavenRepository._ - private implicit class DocSourcesArtifactExtensions(val underlying: Artifact) { - def withJavadocSources: Artifact = { - val base = underlying.url.stripSuffix(".jar") - underlying.copy(extra = underlying.extra ++ Seq( - "sources" -> Artifact( - base + "-sources.jar", - Map.empty, - Map.empty, - Attributes("jar", "src"), // Are these the right attributes? - changing = underlying.changing, - authentication = authentication - ) - .withDefaultChecksums - .withDefaultSignature, - "javadoc" -> Artifact( - base + "-javadoc.jar", - Map.empty, - Map.empty, - Attributes("jar", "javadoc"), // Same comment as above - changing = underlying.changing, - authentication = authentication - ) - .withDefaultChecksums - .withDefaultSignature - )) - } - } - def artifacts( dependency: Dependency, project: Project, @@ -73,9 +45,9 @@ final case class MavenSource( ) .withDefaultChecksums - if (publication.ext == "jar") { + if (publication.ext == "jar") + // TODO Get available signature / checksums from directory listing artifact = artifact.withDefaultSignature - } artifact } @@ -92,68 +64,33 @@ final case class MavenSource( val publications0 = overrideClassifiers match { case Some(classifiers) => val classifiersSet = classifiers.toSet - val publications = project.publications.collect { + + project.publications.collect { case (_, p) if classifiersSet(p.classifier) => p } - // Unlike with Ivy metadata, Maven POMs don't list the available publications (~artifacts) - // so we give a chance to any classifier we're given by returning some publications - // no matter what, even if we're unsure they're available. - if (publications.isEmpty) - classifiers.map { classifier => - Publication( - dependency.module.name, - "jar", - "jar", - classifier - ) - } - else - publications - case None => - val publications = - if (dependency.attributes.classifier.nonEmpty) - // FIXME We're ignoring dependency.attributes.`type` in this case - project.publications.collect { - case (_, p) if p.classifier == dependency.attributes.classifier => - p - } - else if (dependency.attributes.`type`.nonEmpty) - project.publications.collect { - case (_, p) if p.`type` == dependency.attributes.`type` => - p - } - else - project.publications.collect { - case (_, p) if p.classifier.isEmpty => - p - } - - // See comment above - if (publications.isEmpty) { - val type0 = if (dependency.attributes.`type`.isEmpty) "jar" else dependency.attributes.`type` - - val extension = MavenSource.typeExtension(type0) - - val classifier = - if (dependency.attributes.classifier.isEmpty) - MavenSource.typeDefaultClassifier(type0) - else - dependency.attributes.classifier - - Seq( - Publication( - dependency.module.name, - type0, - extension, - classifier - ) - ) - } else - publications + if (dependency.attributes.classifier.nonEmpty) + // FIXME We're ignoring dependency.attributes.`type` in this case + project.publications.collect { + case (_, p) if p.classifier == dependency.attributes.classifier => + p + } + else if (dependency.attributes.`type`.nonEmpty) + project.publications.collect { + case (_, p) + if p.`type` == dependency.attributes.`type` || + p.ext == dependency.attributes.`type` // wow + => + p + } + else + project.publications.collect { + case (_, p) if p.classifier.isEmpty => + p + } } publications0.map(artifactWithExtra) @@ -194,4 +131,22 @@ object MavenSource { def typeDefaultClassifier(`type`: String): String = typeDefaultClassifierOpt(`type`).getOrElse("") -} \ No newline at end of file + val classifierExtensionDefaultTypes: Map[(String, String), String] = Map( + ("tests", "jar") -> "test-jar", + ("javadoc", "jar") -> "doc", + ("sources", "jar") -> "src" + // don't know much about "client" classifier, not including it here + ) + + def classifierExtensionDefaultTypeOpt(classifier: String, ext: String): Option[String] = + classifierExtensionDefaultTypes.get((classifier, ext)) + + val typeDefaultConfigs: Map[String, String] = Map( + "doc" -> "docs", + "src" -> "sources" + ) + + def typeDefaultConfig(`type`: String): Option[String] = + typeDefaultConfigs.get(`type`) + +} diff --git a/core/shared/src/main/scala/coursier/maven/Pom.scala b/core/shared/src/main/scala/coursier/maven/Pom.scala index f24d85923..b799113d7 100644 --- a/core/shared/src/main/scala/coursier/maven/Pom.scala +++ b/core/shared/src/main/scala/coursier/maven/Pom.scala @@ -28,9 +28,6 @@ object Pom { private def readVersion(node: Node) = text(node, "version", "Version").getOrElse("").trim - private val defaultType = "jar" - private val defaultClassifier = "" - def dependency(node: Node): String \/ (String, Dependency) = { for { mod <- module(node) @@ -52,7 +49,7 @@ object Pom { version0, "", exclusions.map(mod => (mod.organization, mod.name)).toSet, - Attributes(typeOpt getOrElse defaultType, classifierOpt getOrElse defaultClassifier), + Attributes(typeOpt.getOrElse(""), classifierOpt.getOrElse("")), optional, transitive = true ) @@ -253,6 +250,7 @@ object Pom { profiles, None, None, + packagingOpt(pom), None, Nil, Info( diff --git a/core/shared/src/main/scala/coursier/package.scala b/core/shared/src/main/scala/coursier/package.scala index 0105f7853..c8d5ee792 100644 --- a/core/shared/src/main/scala/coursier/package.scala +++ b/core/shared/src/main/scala/coursier/package.scala @@ -12,7 +12,7 @@ package object coursier { version: String, // Substituted by Resolver with its own default configuration (compile) configuration: String = "", - attributes: Attributes = Attributes("jar"), + attributes: Attributes = Attributes(), exclusions: Set[(String, String)] = Set.empty, optional: Boolean = false, transitive: Boolean = true diff --git a/http-server/src/main/scala-2.11/coursier/HttpServer.scala b/http-server/src/main/scala-2.11/coursier/HttpServer.scala index 11e3b732b..283cbedb4 100644 --- a/http-server/src/main/scala-2.11/coursier/HttpServer.scala +++ b/http-server/src/main/scala-2.11/coursier/HttpServer.scala @@ -5,10 +5,10 @@ import java.net.NetworkInterface import java.nio.channels.{ FileLock, OverlappingFileLockException } import org.http4s.dsl._ -import org.http4s.headers.Authorization +import org.http4s.headers.{ Authorization, `Content-Type` } import org.http4s.server.HttpService import org.http4s.server.blaze.BlazeBuilder -import org.http4s.{ BasicCredentials, Challenge, EmptyBody, Request, Response } +import org.http4s.{ BasicCredentials, Challenge, EmptyBody, MediaType, Request, Response } import caseapp._ @@ -45,7 +45,10 @@ final case class HttpServerApp( password: String, @ExtraName("r") @ValueDescription("realm") - realm: String + realm: String, + @ExtraName("l") + @HelpMessage("Generate content listing pages for directories") + listPages: Boolean ) extends App { val baseDir = new File(if (directory.isEmpty) "." else directory) @@ -171,16 +174,65 @@ final case class HttpServerApp( Locked() } + def isDirectory(f: File): Task[Option[Boolean]] = + Task { + if (f.isDirectory) + Some(true) + else if (f.isFile) + Some(false) + else + None + } + + def directoryListingPage(dir: File, title: String): Task[String] = + Task { + val entries = dir + .listFiles() + .flatMap { f => + def name = f.getName + if (f.isDirectory) + Seq(name + "/") + else if (f.isFile) + Seq(name) + else + Nil + } + + // meh escaping + // TODO Use to scalatags to generate that + s""" + | + | + |$title + | + | + | + | + | + """.stripMargin + } + def getService = authenticated { case (method @ (GET | HEAD)) -> path => if (verbosityLevel >= 1) Console.err.println(s"${method.name} $path") - val f = new File(baseDir, path.toList.mkString("/")) - val resp = if (f.exists()) - Ok(f) - else - NotFound() + val relPath = path.toList.mkString("/") + val f = new File(baseDir, relPath) + val resp = + for { + isDirOpt <- isDirectory(f) + resp <- isDirOpt match { + case Some(true) if listPages => + directoryListingPage(f, relPath).flatMap(page => + Ok(page).withContentType(Some(`Content-Type`(MediaType.`text/html`))) + ) + case Some(false) => Ok(f) + case _ => NotFound() + } + } yield resp method match { case HEAD => diff --git a/sbt-coursier/src/main/scala-2.10/coursier/CoursierPlugin.scala b/sbt-coursier/src/main/scala-2.10/coursier/CoursierPlugin.scala index c2c04c982..3fbe81270 100644 --- a/sbt-coursier/src/main/scala-2.10/coursier/CoursierPlugin.scala +++ b/sbt-coursier/src/main/scala-2.10/coursier/CoursierPlugin.scala @@ -12,7 +12,6 @@ object CoursierPlugin extends AutoPlugin { object autoImport { val coursierParallelDownloads = Keys.coursierParallelDownloads val coursierMaxIterations = Keys.coursierMaxIterations - val coursierDefaultArtifactType = Keys.coursierDefaultArtifactType val coursierChecksums = Keys.coursierChecksums val coursierArtifactsChecksums = Keys.coursierArtifactsChecksums val coursierCachePolicies = Keys.coursierCachePolicies @@ -76,7 +75,6 @@ object CoursierPlugin extends AutoPlugin { ) = Seq( coursierParallelDownloads := 6, coursierMaxIterations := 50, - coursierDefaultArtifactType := "", coursierChecksums := Seq(Some("SHA-1"), None), coursierArtifactsChecksums := Seq(None), coursierCachePolicies := CachePolicy.default, diff --git a/sbt-coursier/src/main/scala-2.10/coursier/FallbackDependenciesRepository.scala b/sbt-coursier/src/main/scala-2.10/coursier/FallbackDependenciesRepository.scala index 43ea07d77..172baa4a8 100644 --- a/sbt-coursier/src/main/scala-2.10/coursier/FallbackDependenciesRepository.scala +++ b/sbt-coursier/src/main/scala-2.10/coursier/FallbackDependenciesRepository.scala @@ -78,8 +78,10 @@ final case class FallbackDependenciesRepository( fallbacks.get(dependency.moduleVersion) match { case None => Nil case Some((url, changing)) => + val url0 = url.toString + val ext = url0.substring(url0.lastIndexOf('.') + 1) Seq( - Artifact(url.toString, Map.empty, Map.empty, Attributes("jar", ""), changing, None) + Artifact(url0, Map.empty, Map.empty, Attributes(ext, ""), changing, None) ) } } @@ -121,6 +123,7 @@ final case class FallbackDependenciesRepository( None, None, None, + None, Nil, Info.empty ) diff --git a/sbt-coursier/src/main/scala-2.10/coursier/FromSbt.scala b/sbt-coursier/src/main/scala-2.10/coursier/FromSbt.scala index befd22c47..262bb3c52 100644 --- a/sbt-coursier/src/main/scala-2.10/coursier/FromSbt.scala +++ b/sbt-coursier/src/main/scala-2.10/coursier/FromSbt.scala @@ -53,8 +53,7 @@ object FromSbt { def dependencies( module: ModuleID, scalaVersion: String, - scalaBinaryVersion: String, - defaultArtifactType: String + scalaBinaryVersion: String ): Seq[(String, Dependency)] = { // TODO Warn about unsupported properties in `module` @@ -76,10 +75,10 @@ object FromSbt { val attributes = if (module.explicitArtifacts.isEmpty) - Seq(Attributes(defaultArtifactType, "")) + Seq(Attributes("", "")) else module.explicitArtifacts.map { a => - Attributes(`type` = a.extension, classifier = a.classifier.getOrElse("")) + Attributes(`type` = a.`type`, classifier = a.classifier.getOrElse("")) } for { @@ -107,15 +106,14 @@ object FromSbt { allDependencies: Seq[ModuleID], ivyConfigurations: Map[String, Seq[String]], scalaVersion: String, - scalaBinaryVersion: String, - defaultArtifactType: String + scalaBinaryVersion: String ): Project = { // FIXME Ignored for now - easy to support though // val sbtDepOverrides = dependencyOverrides.value // val sbtExclusions = excludeDependencies.value - val deps = allDependencies.flatMap(dependencies(_, scalaVersion, scalaBinaryVersion, defaultArtifactType)) + val deps = allDependencies.flatMap(dependencies(_, scalaVersion, scalaBinaryVersion)) Project( Module( @@ -133,6 +131,7 @@ object FromSbt { None, None, None, + None, Nil, Info.empty ) diff --git a/sbt-coursier/src/main/scala-2.10/coursier/Keys.scala b/sbt-coursier/src/main/scala-2.10/coursier/Keys.scala index f2c894163..155ff3b1f 100644 --- a/sbt-coursier/src/main/scala-2.10/coursier/Keys.scala +++ b/sbt-coursier/src/main/scala-2.10/coursier/Keys.scala @@ -13,7 +13,6 @@ import scalaz.\/ object Keys { val coursierParallelDownloads = SettingKey[Int]("coursier-parallel-downloads") val coursierMaxIterations = SettingKey[Int]("coursier-max-iterations") - val coursierDefaultArtifactType = SettingKey[String]("coursier-default-artifact-type") val coursierChecksums = SettingKey[Seq[Option[String]]]("coursier-checksums") val coursierArtifactsChecksums = SettingKey[Seq[Option[String]]]("coursier-artifacts-checksums") val coursierCachePolicies = SettingKey[Seq[CachePolicy]]("coursier-cache-policies") diff --git a/sbt-coursier/src/main/scala-2.10/coursier/Tasks.scala b/sbt-coursier/src/main/scala-2.10/coursier/Tasks.scala index ebd28996c..34768533d 100644 --- a/sbt-coursier/src/main/scala-2.10/coursier/Tasks.scala +++ b/sbt-coursier/src/main/scala-2.10/coursier/Tasks.scala @@ -118,7 +118,6 @@ object Tasks { lazy val projId = projectID.in(projectRef).get(state) lazy val sv = scalaVersion.in(projectRef).get(state) lazy val sbv = scalaBinaryVersion.in(projectRef).get(state) - lazy val defaultArtifactType = coursierDefaultArtifactType.in(projectRef).get(state) for { allDependencies <- allDependenciesTask @@ -129,8 +128,7 @@ object Tasks { allDependencies, configurations.map { cfg => cfg.name -> cfg.extendsConfigs.map(_.name) }.toMap, sv, - sbv, - defaultArtifactType + sbv ) } } @@ -333,15 +331,13 @@ object Tasks { if (sbtClassifiers) { val sv = scalaVersion.value val sbv = scalaBinaryVersion.value - val defaultArtifactType = coursierDefaultArtifactType.value val proj = FromSbt.project( cm.id, cm.modules, cm.configurations.map(cfg => cfg.name -> cfg.extendsConfigs.map(_.name)).toMap, sv, - sbv, - defaultArtifactType + sbv ) val fallbackDeps = FromSbt.fallbackDependencies( @@ -828,15 +824,13 @@ object Tasks { if (sbtClassifiers) { val sv = scalaVersion.value val sbv = scalaBinaryVersion.value - val defaultArtifactType = coursierDefaultArtifactType.value FromSbt.project( cm.id, cm.modules, cm.configurations.map(cfg => cfg.name -> cfg.extendsConfigs.map(_.name)).toMap, sv, - sbv, - defaultArtifactType + sbv ) } else { val proj = coursierProject.value @@ -977,15 +971,13 @@ object Tasks { val cm = coursierSbtClassifiersModule.value val sv = scalaVersion.value val sbv = scalaBinaryVersion.value - val defaultArtifactType = coursierDefaultArtifactType.value FromSbt.project( cm.id, cm.modules, cm.configurations.map(cfg => cfg.name -> cfg.extendsConfigs.map(_.name)).toMap, sv, - sbv, - defaultArtifactType + sbv ) } else { val proj = coursierProject.value diff --git a/sbt-shading/src/main/scala-2.10/coursier/Shading.scala b/sbt-shading/src/main/scala-2.10/coursier/Shading.scala index 510c479fa..0d878728f 100644 --- a/sbt-shading/src/main/scala-2.10/coursier/Shading.scala +++ b/sbt-shading/src/main/scala-2.10/coursier/Shading.scala @@ -60,6 +60,7 @@ object Shading { res: Resolution, configs: Map[String, Set[String]], artifactFilesOrErrors: Map[Artifact, FileError \/ File], + classpathTypes: Set[String], shadingNamespace: String, baseConfig: String, shadedConf: String, @@ -97,7 +98,12 @@ object Shading { ) } - val dependencyArtifacts = res.dependencyArtifacts.toMap + val dependencyArtifacts = res.dependencyArtifacts + .filter { case (_, a) => classpathTypes(a.`type`) } + .groupBy(_._1) + .mapValues(_.map(_._2)) + .iterator + .toMap val artifactFilesOrErrors0 = artifactFilesOrErrors .collect { @@ -121,6 +127,7 @@ object Shading { .dependencies .toSeq .flatMap(dependencyArtifacts.get) + .flatten .map(_.url) .flatMap(artifactFilesOrErrors0.get) diff --git a/sbt-shading/src/main/scala-2.10/coursier/ShadingPlugin.scala b/sbt-shading/src/main/scala-2.10/coursier/ShadingPlugin.scala index 9b262a61a..93763f25e 100644 --- a/sbt-shading/src/main/scala-2.10/coursier/ShadingPlugin.scala +++ b/sbt-shading/src/main/scala-2.10/coursier/ShadingPlugin.scala @@ -83,6 +83,7 @@ object ShadingPlugin extends AutoPlugin { coursierResolution.in(baseSbtConfiguration).value, coursierConfigurations.in(baseSbtConfiguration).value, Keys.coursierArtifacts.in(baseSbtConfiguration).value, + classpathTypes.value, shadingNamespace.?.value.getOrElse { throw new NoSuchElementException("shadingNamespace key not set") }, diff --git a/tests/shared/src/test/scala/coursier/test/CentralTests.scala b/tests/shared/src/test/scala/coursier/test/CentralTests.scala index 3c6030e7e..8e84ed1bd 100644 --- a/tests/shared/src/test/scala/coursier/test/CentralTests.scala +++ b/tests/shared/src/test/scala/coursier/test/CentralTests.scala @@ -99,11 +99,12 @@ object CentralTests extends TestSuite { module: Module, version: String, artifactType: String, + attributes: Attributes = Attributes(), extraRepo: Option[Repository] = None )( f: Artifact => T ): Future[T] = - withArtifacts(module, version, artifactType, extraRepo) { + withArtifacts(module, version, artifactType, attributes, extraRepo) { case Seq(artifact) => f(artifact) case other => @@ -117,11 +118,12 @@ object CentralTests extends TestSuite { module: Module, version: String, artifactType: String, + attributes: Attributes = Attributes(), extraRepo: Option[Repository] = None )( f: Seq[Artifact] => T ): Future[T] = { - val dep = Dependency(module, version, transitive = false, attributes = Attributes()) + val dep = Dependency(module, version, transitive = false, attributes = attributes) withArtifacts(dep, artifactType, extraRepo)(f) } @@ -145,8 +147,14 @@ object CentralTests extends TestSuite { f(artifacts) } - def ensureHasArtifactWithExtension(module: Module, version: String, artifactType: String, extension: String): Future[Unit] = - withArtifact(module, version, artifactType) { artifact => + def ensureHasArtifactWithExtension( + module: Module, + version: String, + artifactType: String, + extension: String, + attributes: Attributes = Attributes() + ): Future[Unit] = + withArtifact(module, version, artifactType, attributes = attributes) { artifact => assert(artifact.url.endsWith("." + extension)) } @@ -161,8 +169,8 @@ object CentralTests extends TestSuite { rootDependencies = Set(dep), dependencies = Set( dep.withCompileScope, - Dependency(Module("ch.qos.logback", "logback-core"), "1.1.3").withCompileScope.withJarAttributeType, - Dependency(Module("org.slf4j", "slf4j-api"), "1.7.7").withCompileScope.withJarAttributeType)) + Dependency(Module("ch.qos.logback", "logback-core"), "1.1.3").withCompileScope, + Dependency(Module("org.slf4j", "slf4j-api"), "1.7.7").withCompileScope)) assert(res == expected) } @@ -177,8 +185,8 @@ object CentralTests extends TestSuite { rootDependencies = Set(dep), dependencies = Set( dep.withCompileScope, - Dependency(Module("org.ow2.asm", "asm-tree"), "5.0.2").withCompileScope.withJarAttributeType, - Dependency(Module("org.ow2.asm", "asm"), "5.0.2").withCompileScope.withJarAttributeType)) + Dependency(Module("org.ow2.asm", "asm-tree"), "5.0.2").withCompileScope, + Dependency(Module("org.ow2.asm", "asm"), "5.0.2").withCompileScope)) assert(res == expected) } @@ -338,12 +346,22 @@ object CentralTests extends TestSuite { 'bundle - { // has packaging bundle - ensuring coursier gives its artifact the .jar extension - ensureHasArtifactWithExtension( + * - ensureHasArtifactWithExtension( Module("com.google.guava", "guava"), "17.0", "bundle", "jar" ) + + // even though packaging is bundle, depending on attribute type "jar" should still find + // an artifact + * - ensureHasArtifactWithExtension( + Module("com.google.guava", "guava"), + "17.0", + "bundle", + "jar", + attributes = Attributes("jar") + ) } 'mavenPlugin - { diff --git a/tests/shared/src/test/scala/coursier/test/PomParsingTests.scala b/tests/shared/src/test/scala/coursier/test/PomParsingTests.scala index f4193b86b..b443d309e 100644 --- a/tests/shared/src/test/scala/coursier/test/PomParsingTests.scala +++ b/tests/shared/src/test/scala/coursier/test/PomParsingTests.scala @@ -26,7 +26,7 @@ object PomParsingTests extends TestSuite { Module("comp", "lib"), "2.1", attributes = Attributes(classifier = "extra") - ).withJarAttributeType + ) ) val result = Pom.dependency(xmlParse(depNode).right.get) @@ -131,7 +131,7 @@ object PomParsingTests extends TestSuite { None, Profile.Activation(Nil), Seq( - "" -> Dependency(Module("comp", "lib"), "0.2").withJarAttributeType), + "" -> Dependency(Module("comp", "lib"), "0.2")), Nil, Map.empty )) @@ -163,7 +163,7 @@ object PomParsingTests extends TestSuite { Profile.Activation(Nil), Nil, Seq( - "test" -> Dependency(Module("comp", "lib"), "0.2").withJarAttributeType), + "test" -> Dependency(Module("comp", "lib"), "0.2")), Map.empty )) diff --git a/tests/shared/src/test/scala/coursier/test/package.scala b/tests/shared/src/test/scala/coursier/test/package.scala index 2ed9fbb30..75c32ae88 100644 --- a/tests/shared/src/test/scala/coursier/test/package.scala +++ b/tests/shared/src/test/scala/coursier/test/package.scala @@ -4,7 +4,6 @@ package object test { implicit class DependencyOps(val underlying: Dependency) extends AnyVal { def withCompileScope: Dependency = underlying.copy(configuration = "compile") - def withJarAttributeType: Dependency = underlying.copy(attributes = underlying.attributes.copy(`type` = "jar")) } implicit class ResolutionOps(val underlying: Resolution) extends AnyVal { @@ -62,6 +61,7 @@ package object test { profiles: Seq[Profile] = Seq.empty, versions: Option[core.Versions] = None, snapshotVersioning: Option[core.SnapshotVersioning] = None, + packaging: Option[String] = None, publications: Seq[(String, core.Publication)] = Nil ): Project = core.Project( @@ -76,6 +76,7 @@ package object test { versions, snapshotVersioning, None, + packaging, publications, Info.empty )