Better handling of artifacts from Maven repos

Doesn't seem to break things
This commit is contained in:
Alexandre Archambault 2017-02-03 00:57:01 +01:00
parent 5559c5ce01
commit 6b89af3924
21 changed files with 266 additions and 181 deletions

View File

@ -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

View File

@ -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

View File

@ -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.<init>$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"),

View File

@ -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.

View File

@ -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)],

View File

@ -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", ""))

View File

@ -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
)
}
}

View File

@ -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("")
}
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`)
}

View File

@ -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(

View File

@ -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

View File

@ -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"""<!DOCTYPE html>
|<html>
|<head>
|<title>$title</title>
|</head>
|<body>
|<ul>
|${entries.map(e => " <li><a href=\"" + e + "\">" + e + "</a></li>").mkString("\n")}
|</ul>
|</body>
|</html>
""".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 =>

View File

@ -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,

View File

@ -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
)

View File

@ -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
)

View File

@ -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")

View File

@ -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

View File

@ -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)

View File

@ -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")
},

View File

@ -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 - {

View File

@ -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
))

View File

@ -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
)