diff --git a/build.sbt b/build.sbt index c4e42019ca..05c713fb27 100644 --- a/build.sbt +++ b/build.sbt @@ -28,6 +28,7 @@ lazy val core = crossProject("core")(JSPlatform, JVMPlatform) .settings( shared, coursierPrefix, + libs += Deps.scalaReflect.value % Provided, Mima.previousArtifacts, Mima.coreFilters ) diff --git a/doc/docs/api.md b/doc/docs/api.md index 5f213ae079..a33f48523d 100644 --- a/doc/docs/api.md +++ b/doc/docs/api.md @@ -36,10 +36,10 @@ Resolving dependencies involves create an initial resolution state, with all the val start = Resolution( Set( Dependency( - Module("org.typelevel", "cats-core_2.11"), "0.6.0" + Module(org"org.typelevel", name"cats-core_2.11"), "0.6.0" ), Dependency( - Module("org.scalaz", "scalaz-core_2.11"), "7.2.3" + Module(org"org.scalaz", name"scalaz-core_2.11"), "7.2.3" ) ) ) diff --git a/doc/docs/quick-start-api.md b/doc/docs/quick-start-api.md index d79a4dc9d5..8b3d2f770a 100644 --- a/doc/docs/quick-start-api.md +++ b/doc/docs/quick-start-api.md @@ -53,10 +53,10 @@ To resolve dependencies, first create a `Resolution` case class with your depend val start = Resolution( Set( Dependency( - Module("org.scalaz", "scalaz-core_2.11"), "7.2.3" + Module(org"org.scalaz", name"scalaz-core_2.11"), "7.2.3" ), Dependency( - Module("org.typelevel", "cats-core_2.11"), "0.6.0" + Module(org"org.typelevel", name"cats-core_2.11"), "0.6.0" ) ) ) diff --git a/modules/cli/src/main/scala-2.12/coursier/cli/Fetch.scala b/modules/cli/src/main/scala-2.12/coursier/cli/Fetch.scala index caa1114c03..01684383bc 100644 --- a/modules/cli/src/main/scala-2.12/coursier/cli/Fetch.scala +++ b/modules/cli/src/main/scala-2.12/coursier/cli/Fetch.scala @@ -5,6 +5,7 @@ import java.io.File import caseapp._ import coursier.cli.options.FetchOptions +import coursier.core.Classifier final class Fetch(options: FetchOptions, args: RemainingArgs) { @@ -14,8 +15,8 @@ final class Fetch(options: FetchOptions, args: RemainingArgs) { sources = options.sources, javadoc = options.javadoc, artifactTypes = options.artifactOptions.artifactTypes( - options.sources || options.common.classifier0("sources"), - options.javadoc || options.common.classifier0("javadoc") + options.sources || options.common.classifier0(Classifier.sources), + options.javadoc || options.common.classifier0(Classifier.javadoc) ) ) diff --git a/modules/cli/src/main/scala-2.12/coursier/cli/Helper.scala b/modules/cli/src/main/scala-2.12/coursier/cli/Helper.scala index ed6ff47406..8e2d40bc3d 100644 --- a/modules/cli/src/main/scala-2.12/coursier/cli/Helper.scala +++ b/modules/cli/src/main/scala-2.12/coursier/cli/Helper.scala @@ -9,6 +9,7 @@ import java.util.jar.{Manifest => JManifest} import coursier.cli.options.{CommonOptions, IsolatedLoaderOptions} import coursier.cli.scaladex.Scaladex import coursier.cli.util.{JsonElem, JsonPrintRequirement, JsonReport} +import coursier.core.{Classifier, Type} import coursier.extra.Typelevel import coursier.interop.scalaz._ import coursier.ivy.IvyRepository @@ -230,30 +231,34 @@ class Helper( .mkString("\n") } - val globalExcludes: Set[(String, String)] = excludesNoAttr.map { mod => - (mod.organization, mod.name) - }.toSet + val globalExcludes: Set[(Organization, ModuleName)] = + excludesNoAttr + .map(mod => (mod.organization, mod.name)) + .toSet - val localExcludeMap: Map[String, Set[(String, String)]] = + val localExcludeMap: Map[String, Set[(Organization, ModuleName)]] = if (localExcludeFile.isEmpty) { Map() } else { val source = scala.io.Source.fromFile(localExcludeFile) val lines = try source.mkString.split("\n") finally source.close() - lines.map({ str => - val parent_and_child = str.split("--") - if (parent_and_child.length != 2) { - throw new SoftExcludeParsingException(s"Failed to parse $str") - } + lines + .map { str => + val parent_and_child = str.split("--") + if (parent_and_child.length != 2) + throw new SoftExcludeParsingException(s"Failed to parse $str") - val child_org_name = parent_and_child(1).split(":") - if (child_org_name.length != 2) { - throw new SoftExcludeParsingException(s"Failed to parse $child_org_name") - } + val child_org_name = parent_and_child(1).split(":") + if (child_org_name.length != 2) + throw new SoftExcludeParsingException(s"Failed to parse $child_org_name") - (parent_and_child(0), (child_org_name(0), child_org_name(1))) - }).groupBy(_._1).mapValues(_.map(_._2).toSet).toMap + (parent_and_child(0), (Organization(child_org_name(0)), ModuleName(child_org_name(1)))) + } + .groupBy(_._1) + .mapValues(_.map(_._2).toSet) + .iterator + .toMap } val moduleReq = ModuleRequirements(globalExcludes, localExcludeMap, defaultConfiguration) @@ -303,7 +308,7 @@ class Helper( for (((mod, version), _) <- depsWithUrls if forceVersions.get(mod).exists(_ != version)) throw new Exception(s"Cannot force a version that is different from the one specified " + - s"for the module ${mod}:${version} with url") + s"for the module $mod:$version with url") val checksums = { val splitChecksumArgs = checksum.flatMap(_.split(',')).filter(_.nonEmpty) @@ -560,7 +565,7 @@ class Helper( def artifacts( sources: Boolean, javadoc: Boolean, - artifactTypes: Set[String], + artifactTypes: Set[Type], subset: Set[Dependency] = null ): Seq[Artifact] = { @@ -583,41 +588,42 @@ class Helper( val res0 = Option(subset).fold(res)(res.subset) - val depArtTuples: Seq[(Dependency, Artifact)] = getDepArtifactsForClassifier(sources, javadoc, res0) + val artifacts0 = getDepArtifactsForClassifier(sources, javadoc, res0).map(t => (t._2, t._3)) - val artifacts0 = depArtTuples.map(_._2) - - if (artifactTypes("*")) - artifacts0 + if (artifactTypes(Type("*"))) + artifacts0.map(_._2) else - artifacts0.filter { artifact => - artifactTypes(artifact.`type`) + artifacts0.collect { + case (attr, artifact) if artifactTypes(attr.`type`) => + artifact } } - private def getDepArtifactsForClassifier(sources: Boolean, javadoc: Boolean, res0: Resolution): Seq[(Dependency, Artifact)] = { - val raw: Seq[(Dependency, Artifact)] = if (hasOverrideClassifiers(sources, javadoc)) { - //TODO: this function somehow gives duplicated things - res0.dependencyClassifiersArtifacts(overrideClassifiers(sources, javadoc).toVector.sorted) - } else { - res0.dependencyArtifacts(withOptional = true) - } + private def getDepArtifactsForClassifier(sources: Boolean, javadoc: Boolean, res0: Resolution): Seq[(Dependency, Attributes, Artifact)] = { + val raw = + if (hasOverrideClassifiers(sources, javadoc)) + //TODO: this function somehow gives duplicated things + res0.dependencyArtifacts(Some(overrideClassifiers(sources, javadoc).toVector.sorted)) + else + res0.dependencyArtifacts(None) - raw.map({ case (dep, artifact) => + raw.map { + case (dep, attr, artifact) => ( dep.copy( - attributes = dep.attributes.copy(classifier = artifact.classifier)), + attributes = dep.attributes.copy(classifier = attr.classifier)), + attr, artifact ) - }) + } } - private def overrideClassifiers(sources: Boolean, javadoc:Boolean): Set[String] = { + private def overrideClassifiers(sources: Boolean, javadoc:Boolean): Set[Classifier] = { var classifiers = classifier0 if (sources) - classifiers = classifiers + "sources" + classifiers = classifiers + Classifier.sources if (javadoc) - classifiers = classifiers + "javadoc" + classifiers = classifiers + Classifier.javadoc classifiers } @@ -628,13 +634,11 @@ class Helper( def fetchMap( sources: Boolean, javadoc: Boolean, - artifactTypes: Set[String], + artifactTypes: Set[Type], subset: Set[Dependency] = null ): Map[String, File] = { - val artifacts0 = artifacts(sources, javadoc, artifactTypes, subset).map { artifact => - artifact.copy(attributes = Attributes()) - }.distinct + val artifacts0 = artifacts(sources, javadoc, artifactTypes, subset).distinct val logger = if (verbosityLevel >= 0) @@ -683,7 +687,7 @@ class Helper( case _: FileError.NotFound => true case _ => false } - a.isOptional && notFound + a.optional && notFound } val artifactToFile = results.collect { @@ -714,8 +718,8 @@ class Helper( .mkString("\n") } - val depToArtifacts: Map[Dependency, Vector[Artifact]] = - getDepArtifactsForClassifier(sources, javadoc, res).groupBy(_._1).mapValues(_.map(_._2).toVector) + val depToArtifacts: Map[Dependency, Vector[(Attributes, Artifact)]] = + getDepArtifactsForClassifier(sources, javadoc, res).groupBy(_._1).mapValues(_.map(t => (t._2, t._3)).toVector) if (!jsonOutputFile.isEmpty) { @@ -735,14 +739,15 @@ class Helper( } }).filter(_.isDefined).map(_.get).toMap - val artifacts: Seq[(Dependency, Artifact)] = res.dependencyArtifacts + val artifacts: Seq[(Dependency, Artifact)] = res.dependencyArtifacts().map { + case (dep, _, artifact) => (dep, artifact) + } val jsonReq = JsonPrintRequirement(artifactToFile, depToArtifacts) val roots = deps.toVector.map(JsonElem(_, artifacts, Option(jsonReq), res, printExclusions = verbosityLevel >= 1, excluded = false, colors = false, overrideClassifiers = overrideClassifiers(sources, javadoc))) val jsonStr = JsonReport( roots, - conflictResolutionForRoots, - overrideClassifiers(sources, javadoc) + conflictResolutionForRoots )( _.children, _.reconciledVersionStr, @@ -759,10 +764,10 @@ class Helper( def fetch( sources: Boolean, javadoc: Boolean, - artifactTypes: Set[String], + artifactTypes: Set[Type], subset: Set[Dependency] = null ): Seq[File] = { - fetchMap(sources,javadoc,artifactTypes,subset).values.toSeq + fetchMap(sources, javadoc, artifactTypes, subset).values.toSeq } def contextLoader = Thread.currentThread().getContextClassLoader @@ -783,7 +788,7 @@ class Helper( // FIXME That shouldn't be hard-coded this way... // This whole class ought to be rewritten more cleanly. - val artifactTypes = Set("jar", "bundle") + val artifactTypes = core.Resolution.defaultTypes val files0 = fetch( sources = false, @@ -867,9 +872,9 @@ class Helper( module = dep.module mainClass <- mainClasses.collectFirst { case ((org, name), mainClass) - if org == module.organization && ( - module.name == name || - module.name.startsWith(name + "_") // Ignore cross version suffix + if org == module.organization.value && ( + module.name.value == name || + module.name.value.startsWith(name + "_") // Ignore cross version suffix ) => mainClass } @@ -880,7 +885,7 @@ class Helper( module = dep.module orgMainClasses = mainClasses.collect { case ((org, name), mainClass) - if org == module.organization => + if org == module.organization.value => mainClass }.toSet if orgMainClasses.size == 1 diff --git a/modules/cli/src/main/scala-2.12/coursier/cli/SparkSubmit.scala b/modules/cli/src/main/scala-2.12/coursier/cli/SparkSubmit.scala index 731b7d4ea4..913b2a5b5c 100644 --- a/modules/cli/src/main/scala-2.12/coursier/cli/SparkSubmit.scala +++ b/modules/cli/src/main/scala-2.12/coursier/cli/SparkSubmit.scala @@ -4,7 +4,7 @@ import java.io.File import java.net.URLClassLoader import caseapp._ -import coursier.Dependency +import coursier.{Dependency, moduleNameString, organizationString} import coursier.cli.options.SparkSubmitOptions import coursier.cli.spark.{SparkAssembly, Submit} @@ -22,15 +22,15 @@ object SparkSubmit extends CaseApp[SparkSubmitOptions] { def scalaSparkVersions(dependencies: Iterable[Dependency]): Either[String, (String, String)] = { val sparkCoreMods = dependencies.collect { - case dep if dep.module.organization == "org.apache.spark" && - (dep.module.name == "spark-core_2.10" || dep.module.name == "spark-core_2.11") => + case dep if dep.module.organization == org"org.apache.spark" && + (dep.module.name == name"spark-core_2.10" || dep.module.name == name"spark-core_2.11") => (dep.module, dep.version) } if (sparkCoreMods.isEmpty) Left("Cannot find spark among dependencies") else if (sparkCoreMods.size == 1) { - val scalaVersion = sparkCoreMods.head._1.name match { + val scalaVersion = sparkCoreMods.head._1.name.value match { case "spark-core_2.10" => "2.10" case "spark-core_2.11" => "2.11" case _ => throw new Exception("Cannot happen") diff --git a/modules/cli/src/main/scala-2.12/coursier/cli/options/ArtifactOptions.scala b/modules/cli/src/main/scala-2.12/coursier/cli/options/ArtifactOptions.scala index 3876a687f9..63092684bb 100644 --- a/modules/cli/src/main/scala-2.12/coursier/cli/options/ArtifactOptions.scala +++ b/modules/cli/src/main/scala-2.12/coursier/cli/options/ArtifactOptions.scala @@ -1,9 +1,10 @@ package coursier.cli.options -import caseapp.{ HelpMessage => Help, ValueDescription => Value, ExtraName => Short, _ } +import caseapp.{ExtraName => Short, HelpMessage => Help, ValueDescription => Value, _} +import coursier.core.{Resolution, Type} object ArtifactOptions { - def defaultArtifactTypes = Set("jar", "bundle", "test-jar") + def defaultArtifactTypes = Resolution.defaultTypes implicit val parser = Parser[ArtifactOptions] implicit val help = caseapp.core.help.Help[ArtifactOptions] @@ -17,19 +18,21 @@ final case class ArtifactOptions( @Help("Fetch artifacts even if the resolution is errored") force: Boolean = false ) { - def artifactTypes(sources: Boolean, javadoc: Boolean) = { + def artifactTypes(sources: Boolean, javadoc: Boolean): Set[Type] = { + val types0 = artifactType .flatMap(_.split(',')) .filter(_.nonEmpty) + .map(Type(_)) .toSet if (types0.isEmpty) { if (sources || javadoc) - Some("src").filter(_ => sources).toSet ++ Some("doc").filter(_ => javadoc) + Some(Type.source).filter(_ => sources).toSet ++ Some(Type.doc).filter(_ => javadoc) else ArtifactOptions.defaultArtifactTypes - } else if (types0("*")) - Set("*") + } else if (types0(Type("*"))) + Set(Type("*")) else types0 } diff --git a/modules/cli/src/main/scala-2.12/coursier/cli/options/CommonOptions.scala b/modules/cli/src/main/scala-2.12/coursier/cli/options/CommonOptions.scala index 6ee0456de4..8300bdacdc 100644 --- a/modules/cli/src/main/scala-2.12/coursier/cli/options/CommonOptions.scala +++ b/modules/cli/src/main/scala-2.12/coursier/cli/options/CommonOptions.scala @@ -1,8 +1,7 @@ package coursier.cli.options -import caseapp.{ HelpMessage => Help, ValueDescription => Value, ExtraName => Short, _ } - -import coursier.core.ResolutionProcess +import caseapp.{ExtraName => Short, HelpMessage => Help, ValueDescription => Value, _} +import coursier.core.{Classifier, ResolutionProcess} final case class CommonOptions( @Help("Keep optional dependencies (Maven)") @@ -109,7 +108,7 @@ final case class CommonOptions( ) { val verbosityLevel = Tag.unwrap(verbose) - (if (quiet) 1 else 0) - lazy val classifier0 = classifier.flatMap(_.split(',')).filter(_.nonEmpty).toSet + lazy val classifier0 = classifier.flatMap(_.split(',')).filter(_.nonEmpty).map(Classifier(_)).toSet } object CommonOptions { diff --git a/modules/cli/src/main/scala-2.12/coursier/cli/options/IsolatedLoaderOptions.scala b/modules/cli/src/main/scala-2.12/coursier/cli/options/IsolatedLoaderOptions.scala index b354e53396..2ac4e29fab 100644 --- a/modules/cli/src/main/scala-2.12/coursier/cli/options/IsolatedLoaderOptions.scala +++ b/modules/cli/src/main/scala-2.12/coursier/cli/options/IsolatedLoaderOptions.scala @@ -68,7 +68,7 @@ final case class IsolatedLoaderOptions( mod, ver, configuration = "runtime", - attributes = Attributes("", "") + attributes = Attributes() ) } } diff --git a/modules/cli/src/main/scala-2.12/coursier/cli/scaladex/Scaladex.scala b/modules/cli/src/main/scala-2.12/coursier/cli/scaladex/Scaladex.scala index 09a03741c3..f4806c71d7 100644 --- a/modules/cli/src/main/scala-2.12/coursier/cli/scaladex/Scaladex.scala +++ b/modules/cli/src/main/scala-2.12/coursier/cli/scaladex/Scaladex.scala @@ -4,8 +4,9 @@ import java.net.HttpURLConnection import java.nio.charset.StandardCharsets import java.util.concurrent.ExecutorService -import argonaut._, Argonaut._, ArgonautShapeless._ -import coursier.core.{Artifact, Attributes} +import argonaut._ +import argonaut.Argonaut._ +import coursier.core.{Artifact, ModuleName, Organization} import coursier.interop.scalaz._ import coursier.util.{EitherT, Gather} import coursier.{Fetch, Module} @@ -13,7 +14,7 @@ import scalaz.concurrent.Task object Scaladex { - case class SearchResult( + final case class SearchResult( /** GitHub organization */ organization: String, /** GitHub repository */ @@ -22,14 +23,29 @@ object Scaladex { artifacts: List[String] = Nil ) - case class ArtifactInfos( + object SearchResult { + import argonaut.ArgonautShapeless._ + implicit val decoder = DecodeJson.of[SearchResult] + } + + final case class ArtifactInfos( /** Dependency group ID (aka organization) */ groupId: String, /** Dependency artifact ID (aka name or module name) */ artifactId: String, /** Dependency version */ version: String - ) + ) { + def organization: Organization = + Organization(groupId) + def name: ModuleName = + ModuleName(artifactId) + } + + object ArtifactInfos { + import argonaut.ArgonautShapeless._ + implicit val decoder = DecodeJson.of[ArtifactInfos] + } def apply(pool: ExecutorService): Scaladex[Task] = Scaladex({ url => @@ -53,7 +69,7 @@ object Scaladex { url => def get(fetch: Fetch.Content[Task]) = fetch( - Artifact(url, Map(), Map(), Attributes("", ""), changing = true, optional = false, None) + Artifact(url, Map(), Map(), changing = true, optional = false, None) ) (get(fetch.head) /: fetch.tail)(_ orElse get(_)) @@ -107,7 +123,9 @@ case class Scaladex[F[_]](fetch: String => EitherT[F, String, String], G: Gather s"https://index.scala-lang.org/api/project?organization=$organization&repository=$repository" ) - case class Result(artifacts: List[String]) + import argonaut.ArgonautShapeless._ + + final case class Result(artifacts: List[String]) s.flatMap(s => EitherT.fromEither(s.decodeEither[Result].map(_.artifacts))) } @@ -146,7 +164,7 @@ case class Scaladex[F[_]](fetch: String => EitherT[F, String, String], G: Gather Nil case Right(infos) => logger(s"Found module ${infos.groupId}:${infos.artifactId}:${infos.version}") - Seq(Module(infos.groupId, infos.artifactId) -> infos.version) + Seq(Module(infos.organization, infos.name) -> infos.version) } }))(_.flatten) diff --git a/modules/cli/src/main/scala-2.12/coursier/cli/spark/SparkAssembly.scala b/modules/cli/src/main/scala-2.12/coursier/cli/spark/SparkAssembly.scala index 1fd8ab5494..72685e8eef 100644 --- a/modules/cli/src/main/scala-2.12/coursier/cli/spark/SparkAssembly.scala +++ b/modules/cli/src/main/scala-2.12/coursier/cli/spark/SparkAssembly.scala @@ -11,6 +11,7 @@ import coursier.Cache import coursier.cli.Helper import coursier.cli.options.CommonOptions import coursier.cli.util.Assembly +import coursier.core.Type object SparkAssembly { @@ -76,7 +77,7 @@ object SparkAssembly { default: Boolean, extraDependencies: Seq[String], options: CommonOptions, - artifactTypes: Set[String] + artifactTypes: Set[Type] ): Seq[File] = { val helper = sparkJarsHelper(scalaVersion, sparkVersion, yarnVersion, default, extraDependencies, options) @@ -91,7 +92,7 @@ object SparkAssembly { default: Boolean, extraDependencies: Seq[String], options: CommonOptions, - artifactTypes: Set[String], + artifactTypes: Set[Type], checksumSeed: Array[Byte] = "v1".getBytes(UTF_8), localArtifactsShouldBeCached: Boolean = false ): Either[String, (File, Seq[File])] = { diff --git a/modules/cli/src/main/scala-2.12/coursier/cli/spark/Submit.scala b/modules/cli/src/main/scala-2.12/coursier/cli/spark/Submit.scala index 7cf0c17fa2..72aef5d01b 100644 --- a/modules/cli/src/main/scala-2.12/coursier/cli/spark/Submit.scala +++ b/modules/cli/src/main/scala-2.12/coursier/cli/spark/Submit.scala @@ -4,6 +4,7 @@ import java.io.File import coursier.cli.Helper import coursier.cli.options.CommonOptions +import coursier.core.Type object Submit { @@ -12,7 +13,7 @@ object Submit { sparkVersion: String, noDefault: Boolean, extraDependencies: Seq[String], - artifactTypes: Set[String], + artifactTypes: Set[Type], common: CommonOptions ): Seq[File] = { diff --git a/modules/cli/src/main/scala-2.12/coursier/cli/util/JsonReport.scala b/modules/cli/src/main/scala-2.12/coursier/cli/util/JsonReport.scala index 33dec84ca6..f0c1d1f577 100644 --- a/modules/cli/src/main/scala-2.12/coursier/cli/util/JsonReport.scala +++ b/modules/cli/src/main/scala-2.12/coursier/cli/util/JsonReport.scala @@ -4,7 +4,7 @@ import java.io.File import java.util.Objects import coursier.Artifact -import coursier.core.{Attributes, Dependency, Resolution} +import coursier.core._ import coursier.util.Print import scala.collection.mutable @@ -15,7 +15,7 @@ import Argonaut._ /** * Lookup table for files and artifacts to print in the JsonReport. */ -final case class JsonPrintRequirement(fileByArtifact: Map[String, File], depToArtifacts: Map[Dependency, Vector[Artifact]]) +final case class JsonPrintRequirement(fileByArtifact: Map[String, File], depToArtifacts: Map[Dependency, Vector[(Attributes, Artifact)]]) /** * Represents a resolved dependency's artifact in the JsonReport. @@ -51,7 +51,7 @@ object JsonReport { private val printer = PrettyParams.nospace.copy(preserveOrder = true) - def apply[T](roots: IndexedSeq[T], conflictResolutionForRoots: Map[String, String], overrideClassifiers: Set[String]) + def apply[T](roots: IndexedSeq[T], conflictResolutionForRoots: Map[String, String]) (children: T => Seq[T], reconciledVersionStr: T => String, requestedVersionStr: T => String, getFile: T => Option[String]): String = { val rootDeps: ParSeq[DepNode] = roots.par.map(r => { @@ -90,7 +90,7 @@ final case class JsonElem(dep: Dependency, colors: Boolean, printExclusions: Boolean, excluded: Boolean, - overrideClassifiers: Set[String] + overrideClassifiers: Set[Classifier] ) { val (red, yellow, reset) = @@ -104,8 +104,8 @@ final case class JsonElem(dep: Dependency, lazy val downloadedFile: Option[String] = { jsonPrintRequirement.flatMap(req => req.depToArtifacts.getOrElse(dep, Seq()) - .filter(_.classifier == dep.attributes.classifier) - .map(x => req.fileByArtifact.get(x.url)) + .filter(_._1.classifier == dep.attributes.classifier) + .map(x => req.fileByArtifact.get(x._2.url)) .filter(_.isDefined) .filter(_.nonEmpty) .map(_.get.getPath) @@ -182,7 +182,7 @@ final case class JsonElem(dep: Dependency, .filterNot(dependencies.map(_.moduleVersion).toSet).map { case (mod, ver) => JsonElem( - Dependency(mod, ver, "", Set.empty, Attributes("", ""), optional = false, transitive = false), + Dependency(mod, ver, "", Set.empty, Attributes.empty, optional = false, transitive = false), artifacts, jsonPrintRequirement, resolution, diff --git a/modules/cli/src/test/scala-2.12/coursier/cli/CliUnitTest.scala b/modules/cli/src/test/scala-2.12/coursier/cli/CliUnitTest.scala index b0ca1c7fe7..370beddf4e 100644 --- a/modules/cli/src/test/scala-2.12/coursier/cli/CliUnitTest.scala +++ b/modules/cli/src/test/scala-2.12/coursier/cli/CliUnitTest.scala @@ -2,6 +2,7 @@ package coursier.cli import java.io.{File, FileWriter} +import coursier.{moduleNameString, organizationString} import coursier.cli.options.CommonOptions import org.junit.runner.RunWith import org.scalatest.FlatSpec @@ -29,7 +30,7 @@ class CliUnitTest extends FlatSpec { "org1:name1--org2:name2") { (file, writer) => val opt = CommonOptions(localExcludeFile = file.getAbsolutePath) val helper = new Helper(opt, Seq()) - assert(helper.localExcludeMap.equals(Map("org1:name1" -> Set(("org2", "name2"))))) + assert(helper.localExcludeMap.equals(Map("org1:name1" -> Set((org"org2", name"name2"))))) } "Multiple excludes" should "be combined" in withFile( @@ -40,8 +41,8 @@ class CliUnitTest extends FlatSpec { val opt = CommonOptions(localExcludeFile = file.getAbsolutePath) val helper = new Helper(opt, Seq()) assert(helper.localExcludeMap.equals(Map( - "org1:name1" -> Set(("org2", "name2"), ("org3", "name3")), - "org4:name4" -> Set(("org5", "name5"))))) + "org1:name1" -> Set((org"org2", name"name2"), (org"org3", name"name3")), + "org4:name4" -> Set((org"org5", name"name5"))))) } "extra --" should "error" in withFile( diff --git a/modules/cli/src/test/scala-2.12/coursier/cli/util/JsonReportTest.scala b/modules/cli/src/test/scala-2.12/coursier/cli/util/JsonReportTest.scala index 39ec06e2c0..f2a3ea1063 100644 --- a/modules/cli/src/test/scala-2.12/coursier/cli/util/JsonReportTest.scala +++ b/modules/cli/src/test/scala-2.12/coursier/cli/util/JsonReportTest.scala @@ -8,7 +8,7 @@ import org.scalatest.junit.JUnitRunner @RunWith(classOf[JUnitRunner]) class JsonReportTest extends FlatSpec with CliTestLib { "empty JsonReport" should "be empty" in { - val report: String = JsonReport[String](IndexedSeq(), Map(), Set())( + val report: String = JsonReport[String](IndexedSeq(), Map())( children = _ => Seq(), reconciledVersionStr = _ => "", requestedVersionStr = _ => "", @@ -23,8 +23,7 @@ class JsonReportTest extends FlatSpec with CliTestLib { val children = Map("a" -> Seq("b"), "b" -> Seq()) val report: String = JsonReport[String]( roots = IndexedSeq("a", "b"), - conflictResolutionForRoots = Map(), - overrideClassifiers = Set() + conflictResolutionForRoots = Map() )( children = children(_), reconciledVersionStr = s => s"$s:reconciled", @@ -42,8 +41,7 @@ class JsonReportTest extends FlatSpec with CliTestLib { val children = Map("a" -> Seq("b"), "b" -> Seq()) val report: String = JsonReport[String]( roots = IndexedSeq( "b", "a"), - conflictResolutionForRoots = Map(), - overrideClassifiers = Set() + conflictResolutionForRoots = Map() )( children = children(_), reconciledVersionStr = s => s"$s:reconciled", diff --git a/modules/core/shared/src/main/scala/coursier/core/Definitions.scala b/modules/core/shared/src/main/scala/coursier/core/Definitions.scala index 5fcbf8e070..b6a4bfceab 100644 --- a/modules/core/shared/src/main/scala/coursier/core/Definitions.scala +++ b/modules/core/shared/src/main/scala/coursier/core/Definitions.scala @@ -1,5 +1,25 @@ package coursier.core +final case class Organization(value: String) extends AnyVal { + def map(f: String => String): Organization = + Organization(f(value)) +} + +object Organization { + implicit val ordering: Ordering[Organization] = + Ordering[String].on(_.value) +} + +final case class ModuleName(value: String) extends AnyVal { + def map(f: String => String): ModuleName = + ModuleName(f(value)) +} + +object ModuleName { + implicit val ordering: Ordering[ModuleName] = + Ordering[String].on(_.value) +} + /** * Identifies a "module". * @@ -10,14 +30,14 @@ package coursier.core * Using the same terminology as Ivy. */ final case class Module( - organization: String, - name: String, + organization: Organization, + name: ModuleName, attributes: Map[String, String] ) { def trim: Module = copy( - organization = organization.trim, - name = name.trim + organization = organization.map(_.trim), + name = name.map(_.trim) ) private def attributesStr = attributes.toSeq @@ -26,13 +46,13 @@ final case class Module( .mkString(";") def nameWithAttributes: String = - name + (if (attributes.nonEmpty) s";$attributesStr" else "") + name.value + (if (attributes.nonEmpty) s";$attributesStr" else "") override def toString: String = - s"$organization:$nameWithAttributes" + s"${organization.value}:$nameWithAttributes" def orgName: String = - s"$organization:$name" + s"${organization.value}:${name.value}" override final lazy val hashCode = Module.unapply(this).get.hashCode() } @@ -47,7 +67,7 @@ final case class Dependency( module: Module, version: String, configuration: String, - exclusions: Set[(String, String)], + exclusions: Set[(Organization, ModuleName)], // Maven-specific attributes: Attributes, @@ -68,14 +88,84 @@ final case class Dependency( } } +final case class Type(value: String) extends AnyVal { + def isEmpty: Boolean = + value.isEmpty + def nonEmpty: Boolean = + value.nonEmpty + def map(f: String => String): Type = + Type(f(value)) + + def asExtension: Extension = + Extension(value) +} + +object Type { + implicit val ordering: Ordering[Type] = + Ordering[String].on(_.value) + + val jar = Type("jar") + val testJar = Type("test-jar") + val bundle = Type("bundle") + val doc = Type("doc") + val source = Type("src") + + // Typo for doc and src ??? + val javadoc = Type("javadoc") + val javaSource = Type("java-source") + + val ivy = Type("ivy") + val pom = Type("pom") + + val empty = Type("") +} + +final case class Classifier(value: String) extends AnyVal { + def isEmpty: Boolean = + value.isEmpty + def nonEmpty: Boolean = + value.nonEmpty + def map(f: String => String): Classifier = + Classifier(f(value)) +} + +object Classifier { + implicit val ordering: Ordering[Classifier] = + Ordering[String].on(_.value) + + val empty = Classifier("") + + val tests = Classifier("tests") + val javadoc = Classifier("javadoc") + val sources = Classifier("sources") +} + +final case class Extension(value: String) extends AnyVal { + def map(f: String => String): Extension = + Extension(f(value)) + + def asType: Type = + Type(value) +} + +object Extension { + implicit val ordering: Ordering[Extension] = + Ordering[String].on(_.value) + + val jar = Extension("jar") + val pom = Extension("pom") + + val empty = Extension("") +} + // Maven-specific final case class Attributes( - `type`: String, - classifier: String + `type`: Type, + classifier: Classifier ) { - def packaging: String = + def packaging: Type = if (`type`.isEmpty) - "jar" + Type.jar else `type` @@ -83,17 +173,21 @@ final case class Attributes( if (isEmpty) "" else if (classifier.isEmpty) - packaging + packaging.value else - s"$packaging:$classifier" + s"${packaging.value}:${classifier.value}" - def publication(name: String, ext: String): Publication = + def publication(name: String, ext: Extension): Publication = Publication(name, `type`, ext, classifier) def isEmpty: Boolean = `type`.isEmpty && classifier.isEmpty } +object Attributes { + val empty = Attributes(Type.empty, Classifier.empty) +} + final case class Project( module: Module, version: String, @@ -109,7 +203,8 @@ final case class Project( profiles: Seq[Profile], versions: Option[Versions], snapshotVersioning: Option[SnapshotVersioning], - packagingOpt: Option[String], + packagingOpt: Option[Type], + relocated: Boolean, /** * Optional exact version used to get this project metadata. @@ -187,8 +282,8 @@ object Versions { // Maven-specific final case class SnapshotVersion( - classifier: String, - extension: String, + classifier: Classifier, + extension: Extension, value: String, updated: Option[Versions.DateTime] ) @@ -209,9 +304,9 @@ final case class SnapshotVersioning( // Ivy-specific final case class Publication( name: String, - `type`: String, - ext: String, - classifier: String + `type`: Type, + ext: Extension, + classifier: Classifier ) { def attributes: Attributes = Attributes(`type`, classifier) } @@ -220,13 +315,13 @@ final case class Artifact( url: String, checksumUrls: Map[String, String], extra: Map[String, Artifact], - attributes: Attributes, changing: Boolean, optional: Boolean, authentication: Option[Authentication] ) { - def `type`: String = attributes.`type` - def classifier: String = attributes.classifier + + // attributes, `type`, and classifier don't live here anymore. + // Get them via the dependencyArtifacts method on Resolution. @deprecated("Use optional instead", "1.1.0-M8") def isOptional: Boolean = optional @@ -238,19 +333,10 @@ object Artifact { def artifacts( dependency: Dependency, project: Project, - overrideClassifiers: Option[Seq[String]] - ): Seq[Artifact] + overrideClassifiers: Option[Seq[Classifier]] + ): Seq[(Attributes, Artifact)] } - object Source { - val empty: Source = new Source { - def artifacts( - dependency: Dependency, - project: Project, - overrideClassifiers: Option[Seq[String]] - ): Seq[Artifact] = Nil - } - } } final case class Authentication( diff --git a/modules/core/shared/src/main/scala/coursier/core/Exclusions.scala b/modules/core/shared/src/main/scala/coursier/core/Exclusions.scala index 997c9bc61b..443678abe3 100644 --- a/modules/core/shared/src/main/scala/coursier/core/Exclusions.scala +++ b/modules/core/shared/src/main/scala/coursier/core/Exclusions.scala @@ -2,23 +2,23 @@ package coursier.core object Exclusions { - def partition(exclusions: Set[(String, String)]): (Boolean, Set[String], Set[String], Set[(String, String)]) = { + def partition(exclusions: Set[(Organization, ModuleName)]): (Boolean, Set[Organization], Set[ModuleName], Set[(Organization, ModuleName)]) = { val (wildCards, remaining) = exclusions - .partition{case (org, name) => org == "*" || name == "*" } + .partition{case (org, name) => org == allOrganizations || name == allNames } val all = wildCards .contains(one.head) val excludeByOrg = wildCards - .collect{case (org, "*") if org != "*" => org } + .collect{case (org, `allNames`) if org != allOrganizations => org } val excludeByName = wildCards - .collect{case ("*", name) if name != "*" => name } + .collect{case (`allOrganizations`, name) if name != allNames => name } (all, excludeByOrg, excludeByName, remaining) } - def apply(exclusions: Set[(String, String)]): (String, String) => Boolean = { + def apply(exclusions: Set[(Organization, ModuleName)]): (Organization, ModuleName) => Boolean = { val (all, excludeByOrg, excludeByName, remaining) = partition(exclusions) @@ -31,7 +31,7 @@ object Exclusions { } } - def minimize(exclusions: Set[(String, String)]): Set[(String, String)] = { + def minimize(exclusions: Set[(Organization, ModuleName)]): Set[(Organization, ModuleName)] = { val (all, excludeByOrg, excludeByName, remaining) = partition(exclusions) @@ -43,19 +43,22 @@ object Exclusions { !excludeByName(name) } - excludeByOrg.map((_, "*")) ++ - excludeByName.map(("*", _)) ++ + excludeByOrg.map((_, allNames)) ++ + excludeByName.map((allOrganizations, _)) ++ filteredRemaining } } - val zero = Set.empty[(String, String)] - val one = Set(("*", "*")) + val allOrganizations = Organization("*") + val allNames = ModuleName("*") - def join(x: Set[(String, String)], y: Set[(String, String)]): Set[(String, String)] = + val zero = Set.empty[(Organization, ModuleName)] + val one = Set((allOrganizations, allNames)) + + def join(x: Set[(Organization, ModuleName)], y: Set[(Organization, ModuleName)]): Set[(Organization, ModuleName)] = minimize(x ++ y) - def meet(x: Set[(String, String)], y: Set[(String, String)]): Set[(String, String)] = { + def meet(x: Set[(Organization, ModuleName)], y: Set[(Organization, ModuleName)]): Set[(Organization, ModuleName)] = { val ((xAll, xExcludeByOrg, xExcludeByName, xRemaining), (yAll, yExcludeByOrg, yExcludeByName, yRemaining)) = (partition(x), partition(y)) @@ -78,8 +81,8 @@ object Exclusions { yRemaining.filter{case (org, name) => xAll || xExcludeByOrg(org) || xExcludeByName(name)} ++ (xRemaining intersect yRemaining) - excludeByOrg.map((_, "*")) ++ - excludeByName.map(("*", _)) ++ + excludeByOrg.map((_, allNames)) ++ + excludeByName.map((allOrganizations, _)) ++ remaining } } diff --git a/modules/core/shared/src/main/scala/coursier/core/Orders.scala b/modules/core/shared/src/main/scala/coursier/core/Orders.scala index fc70b30fdc..22e0843bde 100644 --- a/modules/core/shared/src/main/scala/coursier/core/Orders.scala +++ b/modules/core/shared/src/main/scala/coursier/core/Orders.scala @@ -74,8 +74,8 @@ object Orders { * * In particular, no exclusions <= anything <= Set(("*", "*")) */ - val exclusionsPartialOrder: PartialOrdering[Set[(String, String)]] = - new PartialOrdering[Set[(String, String)]] { + val exclusionsPartialOrder: PartialOrdering[Set[(Organization, ModuleName)]] = + new PartialOrdering[Set[(Organization, ModuleName)]] { def boolCmp(a: Boolean, b: Boolean) = (a, b) match { case (true, true) => Some(0) case (true, false) => Some(1) @@ -83,12 +83,12 @@ object Orders { case (false, false) => None } - def tryCompare(x: Set[(String, String)], y: Set[(String, String)]) = { + def tryCompare(x: Set[(Organization, ModuleName)], y: Set[(Organization, ModuleName)]) = { val (xAll, xExcludeByOrg1, xExcludeByName1, xRemaining0) = Exclusions.partition(x) val (yAll, yExcludeByOrg1, yExcludeByName1, yRemaining0) = Exclusions.partition(y) boolCmp(xAll, yAll).orElse { - def filtered(e: Set[(String, String)]) = + def filtered(e: Set[(Organization, ModuleName)]) = e.filter{case (org, name) => !xExcludeByOrg1(org) && !yExcludeByOrg1(org) && !xExcludeByName1(name) && !yExcludeByName1(name) diff --git a/modules/core/shared/src/main/scala/coursier/core/Repository.scala b/modules/core/shared/src/main/scala/coursier/core/Repository.scala index 5a652da39e..7c3dcf2acb 100644 --- a/modules/core/shared/src/main/scala/coursier/core/Repository.scala +++ b/modules/core/shared/src/main/scala/coursier/core/Repository.scala @@ -2,10 +2,9 @@ package coursier.core import coursier.Fetch import coursier.core.compatibility.encodeURIComponent -import coursier.maven.MavenSource import coursier.util.{EitherT, Monad} -trait Repository extends Product with Serializable { +trait Repository extends Product with Serializable with Artifact.Source { def find[F[_]]( module: Module, version: String, @@ -24,29 +23,19 @@ object Repository { "SHA-1" -> (underlying.url + ".sha1"), "SHA-256" -> (underlying.url + ".sha256") )) - def withDefaultSignature: Artifact = { - - val underlyingExt = - if (underlying.attributes.`type`.isEmpty) - "jar" - else - // TODO move MavenSource.typeExtension elsewhere - MavenSource.typeExtension(underlying.attributes.`type`) - + def withDefaultSignature: Artifact = underlying.copy(extra = underlying.extra ++ Seq( "sig" -> Artifact( underlying.url + ".asc", Map.empty, Map.empty, - Attributes(s"$underlyingExt.asc", ""), changing = underlying.changing, - optional = underlying.optional, + optional = true, authentication = underlying.authentication ) .withDefaultChecksums )) - } } } diff --git a/modules/core/shared/src/main/scala/coursier/core/Resolution.scala b/modules/core/shared/src/main/scala/coursier/core/Resolution.scala index a315fa8117..71851c00b6 100644 --- a/modules/core/shared/src/main/scala/coursier/core/Resolution.scala +++ b/modules/core/shared/src/main/scala/coursier/core/Resolution.scala @@ -55,10 +55,10 @@ object Resolution { } object DepMgmt { - type Key = (String, String, String) + type Key = (Organization, ModuleName, Type) def key(dep: Dependency): Key = - (dep.module.organization, dep.module.name, if (dep.attributes.`type`.isEmpty) "jar" else dep.attributes.`type`) + (dep.module.organization, dep.module.name, if (dep.attributes.`type`.isEmpty) Type.jar else dep.attributes.`type`) def add( dict: Map[Key, (String, Dependency)], @@ -131,18 +131,18 @@ object Resolution { .map {case (config, dep) => substituteProps0(config) -> dep.copy( module = dep.module.copy( - organization = substituteProps0(dep.module.organization), - name = substituteProps0(dep.module.name) + organization = dep.module.organization.map(substituteProps0), + name = dep.module.name.map(substituteProps0) ), version = substituteProps0(dep.version), attributes = dep.attributes.copy( - `type` = substituteProps0(dep.attributes.`type`), - classifier = substituteProps0(dep.attributes.classifier) + `type` = dep.attributes.`type`.map(substituteProps0), + classifier = dep.attributes.classifier.map(substituteProps0) ), configuration = substituteProps0(dep.configuration), exclusions = dep.exclusions .map{case (org, name) => - (substituteProps0(org), substituteProps0(name)) + (org.map(substituteProps0), name.map(substituteProps0)) } // FIXME The content of the optional tag may also be a property in // the original POM. Maybe not parse it that earlier? @@ -293,7 +293,7 @@ object Resolution { */ def withExclusions( dependencies: Seq[(String, Dependency)], - exclusions: Set[(String, String)] + exclusions: Set[(Organization, ModuleName)] ): Seq[(String, Dependency)] = { val filter = Exclusions(exclusions) @@ -362,26 +362,26 @@ object Resolution { val properties0 = project.properties ++ Seq( // some artifacts seem to require these (e.g. org.jmock:jmock-legacy:2.5.1) // although I can find no mention of them in any manual / spec - "pom.groupId" -> project.module.organization, - "pom.artifactId" -> project.module.name, + "pom.groupId" -> project.module.organization.value, + "pom.artifactId" -> project.module.name.value, "pom.version" -> project.actualVersion, // Required by some dependencies too (org.apache.directory.shared:shared-ldap:0.9.19 in particular) - "groupId" -> project.module.organization, - "artifactId" -> project.module.name, + "groupId" -> project.module.organization.value, + "artifactId" -> project.module.name.value, "version" -> project.actualVersion, - "project.groupId" -> project.module.organization, - "project.artifactId" -> project.module.name, + "project.groupId" -> project.module.organization.value, + "project.artifactId" -> project.module.name.value, "project.version" -> project.actualVersion ) ++ packagingOpt.toSeq.map { packaging => - "project.packaging" -> packaging + "project.packaging" -> packaging.value } ++ project.parent.toSeq.flatMap { case (parModule, parVersion) => Seq( - "project.parent.groupId" -> parModule.organization, - "project.parent.artifactId" -> parModule.name, + "project.parent.groupId" -> parModule.organization.value, + "project.parent.artifactId" -> parModule.name.value, "project.parent.version" -> parVersion, - "parent.groupId" -> parModule.organization, - "parent.artifactId" -> parModule.name, + "parent.groupId" -> parModule.organization.value, + "parent.artifactId" -> parModule.name.value, "parent.version" -> parVersion ) } @@ -530,6 +530,8 @@ object Resolution { def defaultFilter(dep: Dependency): Boolean = !dep.optional + val defaultTypes = Set[Type](Type.jar, Type.testJar, Type.bundle) + } @@ -1045,65 +1047,55 @@ final case class Resolution( .getOrElse(Map.empty) ) - private def artifacts0( - overrideClassifiers: Option[Seq[String]], - keepAttributes: Boolean, - optional: Boolean - ): Seq[Artifact] = - dependencyArtifacts0(overrideClassifiers, optional).map { - case (_, artifact) => - if (keepAttributes) artifact else artifact.copy(attributes = Attributes("", "")) - }.distinct - - // keepAttributes to false is a temporary hack :-| - // if one wants the attributes field of artifacts not to be cleared, call dependencyArtifacts - - def classifiersArtifacts(classifiers: Seq[String]): Seq[Artifact] = - artifacts0(Some(classifiers), keepAttributes = false, optional = true) - - def artifacts: Seq[Artifact] = - artifacts0(None, keepAttributes = false, optional = false) - - def artifacts(withOptional: Boolean): Seq[Artifact] = - artifacts0(None, keepAttributes = false, optional = withOptional) + def artifacts(types: Set[Type] = defaultTypes, classifiers: Option[Seq[Classifier]] = None): Seq[Artifact] = + dependencyArtifacts(classifiers) + .collect { + case (_, attr, artifact) if types(attr.`type`) => + artifact + } + .distinct - private def dependencyArtifacts0( - overrideClassifiers: Option[Seq[String]], - optional: Boolean - ): Seq[(Dependency, Artifact)] = + def dependencyArtifacts(classifiers: Option[Seq[Classifier]] = None): Seq[(Dependency, Attributes, Artifact)] = for { dep <- minDependencies.toSeq (source, proj) <- projectCache .get(dep.moduleVersion) .toSeq - classifiers = { - if (!dep.attributes.classifier.isEmpty) { - val stringSeq: Seq[String] = overrideClassifiers.getOrElse(Seq()) ++ Seq(dep.attributes.classifier) - if (stringSeq.isEmpty) { - Option.empty - } - else { - Some(stringSeq) - } - } else { - overrideClassifiers - } - } + classifiers0 = + if (dep.attributes.classifier.isEmpty) + classifiers + else + Some(classifiers.getOrElse(Nil) ++ Seq(dep.attributes.classifier)) - artifact <- source - .artifacts(dep, proj, classifiers) - if optional || !artifact.optional - } yield dep -> artifact + (attributes, artifact) <- source.artifacts(dep, proj, classifiers0) + } yield (dep, attributes, artifact) + + + @deprecated("Use the artifacts overload accepting types and classifiers instead", "1.1.0-M8") + def classifiersArtifacts(classifiers: Seq[String]): Seq[Artifact] = + artifacts(classifiers = Some(classifiers.map(Classifier(_)))) + @deprecated("Use artifacts overload accepting types and classifiers instead", "1.1.0-M8") + def artifacts: Seq[Artifact] = + artifacts() + + @deprecated("Use artifacts overload accepting types and classifiers instead", "1.1.0-M8") + def artifacts(withOptional: Boolean): Seq[Artifact] = + artifacts() + + @deprecated("Use dependencyArtifacts overload accepting classifiers instead", "1.1.0-M8") def dependencyArtifacts: Seq[(Dependency, Artifact)] = - dependencyArtifacts0(None, optional = false) + dependencyArtifacts(None).map(t => (t._1, t._3)) + @deprecated("Use dependencyArtifacts overload accepting classifiers instead", "1.1.0-M8") def dependencyArtifacts(withOptional: Boolean): Seq[(Dependency, Artifact)] = - dependencyArtifacts0(None, optional = withOptional) + dependencyArtifacts().map(t => (t._1, t._3)) + @deprecated("Use dependencyArtifacts overload accepting classifiers instead", "1.1.0-M8") def dependencyClassifiersArtifacts(classifiers: Seq[String]): Seq[(Dependency, Artifact)] = - dependencyArtifacts0(Some(classifiers), optional = true) + dependencyArtifacts(Some(classifiers.map(Classifier(_)))).map(t => (t._1, t._3)) + /** * Returns errors on dependencies diff --git a/modules/core/shared/src/main/scala/coursier/ivy/IvyRepository.scala b/modules/core/shared/src/main/scala/coursier/ivy/IvyRepository.scala index 0d664410b8..2ebea6afa9 100644 --- a/modules/core/shared/src/main/scala/coursier/ivy/IvyRepository.scala +++ b/modules/core/shared/src/main/scala/coursier/ivy/IvyRepository.scala @@ -37,108 +37,104 @@ final case class IvyRepository( private def variables( module: Module, versionOpt: Option[String], - `type`: String, + `type`: Type, artifact: String, - ext: String, - classifierOpt: Option[String] - ) = + ext: Extension, + classifierOpt: Option[Classifier] + ): Map[String, String] = Map( - "organization" -> module.organization, - "organisation" -> module.organization, - "orgPath" -> module.organization.replace('.', '/'), - "module" -> module.name, - "type" -> `type`, + "organization" -> module.organization.value, + "organisation" -> module.organization.value, + "orgPath" -> module.organization.value.replace('.', '/'), + "module" -> module.name.value, + "type" -> `type`.value, "artifact" -> artifact, - "ext" -> ext + "ext" -> ext.value ) ++ module.attributes ++ - classifierOpt.map("classifier" -> _).toSeq ++ + classifierOpt.map("classifier" -> _.value).toSeq ++ versionOpt.map("revision" -> _).toSeq - val source: Artifact.Source = - if (withArtifacts) - new Artifact.Source { - def artifacts( - dependency: Dependency, - project: Project, - overrideClassifiers: Option[Seq[String]] - ) = { - - val retained = - overrideClassifiers match { - case None => - - // FIXME Some duplication with what's done in MavenSource - - 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 (conf, p) - if (conf == "*" || - conf == dependency.configuration || - project.allConfigurations.getOrElse(dependency.configuration, Set.empty).contains(conf)) && - ( - p.`type` == dependency.attributes.`type` || - (p.ext == dependency.attributes.`type` && project.packagingOpt.toSeq.contains(p.`type`)) // wow - ) => - p - } - else - project.publications.collect { - case (conf, p) - if conf == "*" || - conf == dependency.configuration || - project.allConfigurations.getOrElse(dependency.configuration, Set.empty).contains(conf) => - p - } - case Some(classifiers) => - val classifiersSet = classifiers.toSet - project.publications.collect { - case (_, p) if classifiersSet(p.classifier) => - p - } - } + def artifacts( + dependency: Dependency, + project: Project, + overrideClassifiers: Option[Seq[Classifier]] + ): Seq[(Attributes, Artifact)] = + if (withArtifacts) { + + val retained = + overrideClassifiers match { + case None => - val retainedWithUrl = retained.distinct.flatMap { p => - pattern.substituteVariables(variables( - dependency.module, - Some(project.actualVersion), - p.`type`, - p.name, - p.ext, - Some(p.classifier).filter(_.nonEmpty) - )).right.toSeq.toList.map(p -> _) // FIXME Validation errors are ignored - } - - retainedWithUrl.map { case (p, url) => - var artifact = Artifact( - url, - Map.empty, - Map.empty, - p.attributes, - changing = changing.getOrElse(project.version.contains("-SNAPSHOT")), // could be more reliable - optional = false, - authentication = authentication - ) - - if (withChecksums) - artifact = artifact.withDefaultChecksums - if (withSignatures) - artifact = artifact.withDefaultSignature - - artifact - } + // FIXME Some duplication with what's done in MavenSource + + 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 (conf, p) + if (conf == "*" || + conf == dependency.configuration || + project.allConfigurations.getOrElse(dependency.configuration, Set.empty).contains(conf)) && + ( + p.`type` == dependency.attributes.`type` || + (p.ext == dependency.attributes.`type`.value && project.packagingOpt.toSeq.contains(p.`type`)) // wow + ) => + p + } + else + project.publications.collect { + case (conf, p) + if conf == "*" || + conf == dependency.configuration || + project.allConfigurations.getOrElse(dependency.configuration, Set.empty).contains(conf) => + p + } + case Some(classifiers) => + val classifiersSet = classifiers.toSet + project.publications.collect { + case (_, p) if classifiersSet(p.classifier) => + p + } } + + val retainedWithUrl = retained.distinct.flatMap { p => + pattern.substituteVariables(variables( + dependency.module, + Some(project.actualVersion), + p.`type`, + p.name, + p.ext, + Some(p.classifier).filter(_.nonEmpty) + )).right.toSeq.toList.map(p -> _) // FIXME Validation errors are ignored } - else - Artifact.Source.empty + retainedWithUrl.map { + case (p, url) => + + var artifact = Artifact( + url, + Map.empty, + Map.empty, + changing = changing.getOrElse(project.version.contains("-SNAPSHOT")), // could be more reliable + optional = false, + authentication = authentication + ) + + if (withChecksums) + artifact = artifact.withDefaultChecksums + if (withSignatures) + artifact = artifact.withDefaultSignature + + (p.attributes, artifact) + } + } else + Nil def find[F[_]]( module: Module, @@ -160,7 +156,7 @@ final case class IvyRepository( findNoInverval(module, version, fetch) case Some(itv) => val listingUrl = revisionListingPattern - .substituteVariables(variables(module, None, "ivy", "ivy", "xml", None)) + .substituteVariables(variables(module, None, Type.ivy, "ivy", Extension("xml"), None)) .right .flatMap { s => if (s.endsWith("/")) @@ -190,7 +186,6 @@ final case class IvyRepository( url, Map.empty, Map.empty, - Attributes("", ""), changing = changing.getOrElse(version.contains("-SNAPSHOT")), optional = false, authentication @@ -216,14 +211,13 @@ final case class IvyRepository( val eitherArtifact: Either[String, Artifact] = for { url <- metadataPattern.substituteVariables( - variables(module, Some(version), "ivy", "ivy", "xml", None) + variables(module, Some(version), Type.ivy, "ivy", Extension("xml"), None) ).right } yield { var artifact = Artifact( url, Map.empty, Map.empty, - Attributes("ivy", ""), changing = changing.getOrElse(version.contains("-SNAPSHOT")), optional = false, authentication = authentication @@ -274,7 +268,7 @@ final case class IvyRepository( else proj0 - source -> proj.copy( + this -> proj.copy( actualVersionOpt = Some(version) ) } diff --git a/modules/core/shared/src/main/scala/coursier/ivy/IvyXml.scala b/modules/core/shared/src/main/scala/coursier/ivy/IvyXml.scala index 1b7e310831..d13b45b690 100644 --- a/modules/core/shared/src/main/scala/coursier/ivy/IvyXml.scala +++ b/modules/core/shared/src/main/scala/coursier/ivy/IvyXml.scala @@ -9,8 +9,16 @@ object IvyXml { private def info(node: Node): Either[String, (Module, String)] = for { - org <- node.attribute("organisation").right - name <- node.attribute("module").right + org <- node + .attribute("organisation") + .right + .map(Organization(_)) + .right + name <- node + .attribute("module") + .right + .map(ModuleName(_)) + .right version <- node.attribute("revision").right } yield { val attr = node.attributesFromNamespace(attributesNamespace) @@ -49,13 +57,16 @@ object IvyXml { .flatMap { node => // artifact and include sub-nodes are ignored here - val excludes = node.children + val excludes = node + .children .filter(_.label == "exclude") .flatMap { node0 => - val org = node0.attribute("org").right.getOrElse("*") - val name = node0.attribute("module").right.toOption - .orElse(node0.attribute("name").right.toOption) - .getOrElse("*") + val org = Organization(node0.attribute("org").right.getOrElse("*")) + val name = ModuleName( + node0.attribute("module").right.toOption + .orElse(node0.attribute("name").right.toOption) + .getOrElse("*") + ) val confs = node0.attribute("conf").right.toOption.filter(_.nonEmpty).fold(Seq("*"))(_.split(',')) confs.map(_ -> (org, name)) } @@ -65,8 +76,18 @@ object IvyXml { val allConfsExcludes = excludes.getOrElse("*", Set.empty) for { - org <- node.attribute("org").right.toOption.toSeq - name <- node.attribute("name").right.toOption.toSeq + org <- node + .attribute("org") + .right + .toOption + .toSeq + .map(Organization(_)) + name <- node + .attribute("name") + .right + .toOption + .toSeq + .map(ModuleName(_)) version <- node.attribute("rev").right.toOption.toSeq rawConf <- node.attribute("conf").right.toOption.toSeq (fromConf, toConf) <- mappings(rawConf) @@ -82,7 +103,7 @@ object IvyXml { version, toConf, allConfsExcludes ++ excludes.getOrElse(fromConf, Set.empty), - Attributes("", ""), // should come from possible artifact nodes + Attributes.empty, // should come from possible artifact nodes optional = false, transitive = transitive ) @@ -94,10 +115,16 @@ object IvyXml { .filter(_.label == "artifact") .flatMap { node => val name = node.attribute("name").right.getOrElse("") - val type0 = node.attribute("type").right.getOrElse("jar") - val ext = node.attribute("ext").right.getOrElse(type0) + val type0 = node.attribute("type") + .right.map(Type(_)) + .right.getOrElse(Type.jar) + val ext = node.attribute("ext") + .right.map(Extension(_)) + .right.getOrElse(type0.asExtension) val confs = node.attribute("conf").fold(_ => Seq("*"), _.split(',').toSeq) - val classifier = node.attribute("classifier").right.getOrElse("") + val classifier = node.attribute("classifier") + .right.map(Classifier(_)) + .right.getOrElse(Classifier.empty) confs.map(_ -> Publication(name, type0, ext, classifier)) } .groupBy { case (conf, _) => conf } @@ -162,10 +189,11 @@ object IvyXml { None, None, None, + relocated = false, None, if (publicationsOpt.isEmpty) // no publications node -> default JAR artifact - Seq("*" -> Publication(module.name, "jar", "jar", "")) + Seq("*" -> Publication(module.name.value, Type.jar, Extension.jar, Classifier.empty)) else { // publications node is there -> only its content (if it is empty, no artifacts, // as per the Ivy manual) diff --git a/modules/core/shared/src/main/scala/coursier/maven/MavenAttributes.scala b/modules/core/shared/src/main/scala/coursier/maven/MavenAttributes.scala new file mode 100644 index 0000000000..1b84bb2860 --- /dev/null +++ b/modules/core/shared/src/main/scala/coursier/maven/MavenAttributes.scala @@ -0,0 +1,49 @@ +package coursier.maven + +import coursier.core.{Classifier, Extension, Type} + +object MavenAttributes { + + val typeExtensions: Map[Type, Extension] = Map( + Type("eclipse-plugin") -> Extension.jar, + Type("maven-plugin") -> Extension.jar, + Type("hk2-jar") -> Extension.jar, + Type("orbit") -> Extension.jar, + Type("scala-jar") -> Extension.jar, + Type.jar -> Extension.jar, + Type.bundle -> Extension.jar, + Type("doc") -> Extension.jar, + Type("src") -> Extension.jar, + Type.testJar -> Extension.jar, + Type("ejb-client") -> Extension.jar + ) + + def typeExtension(`type`: Type): Extension = + typeExtensions.getOrElse(`type`, `type`.asExtension) + + // see https://github.com/apache/maven/blob/c023e58104b71e27def0caa034d39ab0fa0373b6/maven-core/src/main/resources/META-INF/plexus/artifact-handlers.xml + // discussed in https://github.com/coursier/coursier/issues/298 + val typeDefaultClassifiers: Map[Type, Classifier] = Map( + Type.testJar -> Classifier.tests, + Type.javadoc -> Classifier.javadoc, + Type.javaSource -> Classifier.sources, + Type("ejb-client") -> Classifier("client") + ) + + def typeDefaultClassifierOpt(`type`: Type): Option[Classifier] = + typeDefaultClassifiers.get(`type`) + + def typeDefaultClassifier(`type`: Type): Classifier = + typeDefaultClassifierOpt(`type`).getOrElse(Classifier.empty) + + val classifierExtensionDefaultTypes: Map[(Classifier, Extension), Type] = Map( + (Classifier.tests, Extension.jar) -> Type.testJar, + (Classifier.javadoc, Extension.jar) -> Type.doc, + (Classifier.sources, Extension.jar) -> Type.source + // don't know much about "client" classifier, not including it here + ) + + def classifierExtensionDefaultTypeOpt(classifier: Classifier, ext: Extension): Option[Type] = + classifierExtensionDefaultTypes.get((classifier, ext)) + +} diff --git a/modules/core/shared/src/main/scala/coursier/maven/MavenRepository.scala b/modules/core/shared/src/main/scala/coursier/maven/MavenRepository.scala index 0e404da40a..9021d6aaad 100644 --- a/modules/core/shared/src/main/scala/coursier/maven/MavenRepository.scala +++ b/modules/core/shared/src/main/scala/coursier/maven/MavenRepository.scala @@ -36,14 +36,14 @@ object MavenRepository { def mavenVersioning( snapshotVersioning: SnapshotVersioning, - classifier: String, - extension: String + classifier: Classifier, + extension: Extension ): Option[String] = snapshotVersioning .snapshotVersions .find(v => - (v.classifier == classifier || v.classifier == "*") && - (v.extension == extension || v.extension == "*") + (v.classifier == classifier || v.classifier == Classifier("*")) && + (v.extension == extension || v.extension == Extension("*")) ) .map(_.value) .filter(_.nonEmpty) @@ -56,16 +56,16 @@ object MavenRepository { "test" -> Seq("runtime") ) - def dirModuleName(module: Module, sbtAttrStub: Boolean): String = + private def dirModuleName(module: Module, sbtAttrStub: Boolean): String = if (sbtAttrStub) { - var name = module.name + var name = module.name.value for (scalaVersion <- module.attributes.get("scalaVersion")) name = name + "_" + scalaVersion for (sbtVersion <- module.attributes.get("sbtVersion")) name = name + "_" + sbtVersion name } else - module.name + module.name.value } @@ -80,11 +80,13 @@ final case class MavenRepository( import Repository._ import MavenRepository._ - val root0 = if (root.endsWith("/")) root else root + "/" - val source = MavenSource(root0, changing, sbtAttrStub, authentication) + // FIXME Ideally, we should silently drop a '/' suffix from `root` + // so that + // MavenRepository("http://foo.com/repo") == MavenRepository("http://foo.com/repo/") + private val root0 = if (root.endsWith("/")) root else root + "/" private def modulePath(module: Module): Seq[String] = - module.organization.split('.').toSeq :+ dirModuleName(module, sbtAttrStub) + module.organization.value.split('.').toSeq :+ dirModuleName(module, sbtAttrStub) private def moduleVersionPath(module: Module, version: String): Seq[String] = modulePath(module) :+ toBaseVersion(version) @@ -99,13 +101,12 @@ final case class MavenRepository( ): Artifact = { val path = moduleVersionPath(module, version) :+ - s"${module.name}-${versioningValue getOrElse version}.pom" + s"${module.name.value}-${versioningValue getOrElse version}.pom" Artifact( urlFor(path), Map.empty, Map.empty, - Attributes("pom", ""), changing = changing.getOrElse(isSnapshot(version)), optional = false, authentication = authentication @@ -116,7 +117,7 @@ final case class MavenRepository( def versionsArtifact(module: Module): Option[Artifact] = { - val path = module.organization.split('.').toSeq ++ Seq( + val path = module.organization.value.split('.').toSeq ++ Seq( dirModuleName(module, sbtAttrStub), "maven-metadata.xml" ) @@ -126,7 +127,6 @@ final case class MavenRepository( urlFor(path), Map.empty, Map.empty, - Attributes("pom", ""), changing = true, optional = false, authentication = authentication @@ -149,7 +149,6 @@ final case class MavenRepository( urlFor(path), Map.empty, Map.empty, - Attributes("pom", ""), changing = true, optional = false, authentication = authentication @@ -262,9 +261,9 @@ final case class MavenRepository( def withSnapshotVersioning = snapshotVersioning(module, version, fetch).flatMap { snapshotVersioning => val versioningOption = - mavenVersioning(snapshotVersioning, "", "jar") - .orElse(mavenVersioning(snapshotVersioning, "", "pom")) - .orElse(mavenVersioning(snapshotVersioning, "", "")) + mavenVersioning(snapshotVersioning, Classifier.empty, Extension.jar) + .orElse(mavenVersioning(snapshotVersioning, Classifier.empty, Extension.pom)) + .orElse(mavenVersioning(snapshotVersioning, Classifier.empty, Extension.empty)) versioningOption match { case None => @@ -298,7 +297,6 @@ final case class MavenRepository( url, Map.empty, Map.empty, - Attributes("", ""), changing = changing, optional = false, authentication @@ -350,7 +348,7 @@ final case class MavenRepository( .orElse(Parse.ivyLatestSubRevisionInterval(version)) .filter(_.isValid) match { case None => - findNoInterval(module, version, fetch).map((source, _)) + findNoInterval(module, version, fetch).map((this, _)) case Some(itv) => def v = versions(module, fetch) val v0 = @@ -379,10 +377,143 @@ final case class MavenRepository( case Right(version0) => findNoInterval(module, version0, fetch) .map(_.copy(versions = Some(versions0))) - .map((source, _)) + .map((this, _)) } } } } + + private def artifacts0( + dependency: Dependency, + project: Project, + overrideClassifiers: Option[Seq[Classifier]] + ): Seq[(Attributes, Artifact)] = { + + val packagingTpeMap = project + .packagingOpt + .map { packaging => + (MavenAttributes.typeDefaultClassifier(packaging), MavenAttributes.typeExtension(packaging)) -> packaging + } + .toMap + + def artifactOf(publication: Publication) = { + + val versioning = project + .snapshotVersioning + .flatMap(versioning => + mavenVersioning( + versioning, + publication.classifier, + MavenAttributes.typeExtension(publication.`type`) + ) + ) + + val path = dependency.module.organization.value.split('.').toSeq ++ Seq( + MavenRepository.dirModuleName(dependency.module, sbtAttrStub), + toBaseVersion(project.actualVersion), + s"${dependency.module.name.value}-${versioning getOrElse project.actualVersion}${Some(publication.classifier.value).filter(_.nonEmpty).map("-" + _).mkString}.${publication.ext.value}" + ) + + val changing0 = changing.getOrElse(isSnapshot(project.actualVersion)) + + val artifact = Artifact( + root0 + path.mkString("/"), + Map.empty, + Map.empty, + changing = changing0, + optional = true, + authentication = authentication + ) + .withDefaultChecksums + .withDefaultSignature + + (publication.attributes, artifact) + } + + val (_, metadataArtifact) = artifactOf(Publication(dependency.module.name.value, Type.pom, Extension.pom, Classifier.empty)) + + def artifactWithExtra(publication: Publication) = { + val (attr, artifact) = artifactOf(publication) + (attr, artifact.copy( + extra = artifact.extra + ("metadata" -> metadataArtifact) + )) + } + + lazy val defaultPublications = { + + val packagingPublicationOpt = project + .packagingOpt + .filter(_ => dependency.attributes.isEmpty) + .map { packaging => + Publication( + dependency.module.name.value, + packaging, + MavenAttributes.typeExtension(packaging), + MavenAttributes.typeDefaultClassifier(packaging) + ) + } + + val type0 = if (dependency.attributes.`type`.isEmpty) Type.jar else dependency.attributes.`type` + + val ext = MavenAttributes.typeExtension(type0) + + val classifier = + if (dependency.attributes.classifier.isEmpty) + MavenAttributes.typeDefaultClassifier(type0) + else + dependency.attributes.classifier + + val tpe = packagingTpeMap.getOrElse( + (classifier, ext), + MavenAttributes.classifierExtensionDefaultTypeOpt(classifier, ext).getOrElse(ext.asType) + ) + + val pubs = packagingPublicationOpt.toSeq :+ + Publication( + dependency.module.name.value, + tpe, + ext, + classifier + ) + + pubs.distinct + } + + overrideClassifiers + .fold(defaultPublications) { classifiers => + classifiers.flatMap { classifier => + if (classifier == dependency.attributes.classifier) + defaultPublications + else { + val ext = Extension.jar + val tpe = packagingTpeMap.getOrElse( + (classifier, ext), + MavenAttributes.classifierExtensionDefaultTypeOpt(classifier, ext).getOrElse(ext.asType) + ) + + Seq( + Publication( + dependency.module.name.value, + tpe, + ext, + classifier + ) + ) + } + } + } + .map(artifactWithExtra) + } + + def artifacts( + dependency: Dependency, + project: Project, + overrideClassifiers: Option[Seq[Classifier]] + ): Seq[(Attributes, Artifact)] = + if (project.relocated) + Nil + else + artifacts0(dependency, project, overrideClassifiers) + } diff --git a/modules/core/shared/src/main/scala/coursier/maven/MavenSource.scala b/modules/core/shared/src/main/scala/coursier/maven/MavenSource.scala deleted file mode 100644 index 074300448a..0000000000 --- a/modules/core/shared/src/main/scala/coursier/maven/MavenSource.scala +++ /dev/null @@ -1,201 +0,0 @@ -package coursier.maven - -import coursier.core._ - -final case class MavenSource( - root: String, - changing: Option[Boolean] = None, - /** See doc on MavenRepository */ - sbtAttrStub: Boolean, - authentication: Option[Authentication] -) extends Artifact.Source { - - import Repository._ - import MavenRepository._ - - private def artifactsUnknownPublications( - dependency: Dependency, - project: Project, - overrideClassifiers: Option[Seq[String]] - ): Seq[Artifact] = { - - val packagingOpt = project.packagingOpt.filter(_ != Pom.relocatedPackaging) - - val packagingTpeMap = packagingOpt - .map { packaging => - (MavenSource.typeDefaultClassifier(packaging), MavenSource.typeExtension(packaging)) -> packaging - } - .toMap - - def artifactOf(publication: Publication) = { - - val versioning = project - .snapshotVersioning - .flatMap(versioning => - mavenVersioning( - versioning, - publication.classifier, - MavenSource.typeExtension(publication.`type`) - ) - ) - - val path = dependency.module.organization.split('.').toSeq ++ Seq( - MavenRepository.dirModuleName(dependency.module, sbtAttrStub), - toBaseVersion(project.actualVersion), - s"${dependency.module.name}-${versioning getOrElse project.actualVersion}${Some(publication.classifier).filter(_.nonEmpty).map("-" + _).mkString}.${publication.ext}" - ) - - val changing0 = changing.getOrElse(isSnapshot(project.actualVersion)) - - Artifact( - root + path.mkString("/"), - Map.empty, - Map.empty, - publication.attributes, - changing = changing0, - optional = false, - authentication = authentication - ) - .withDefaultChecksums - .withDefaultSignature - } - - val metadataArtifact = artifactOf(Publication(dependency.module.name, "pom", "pom", "")) - - def artifactWithExtra(publication: Publication) = { - val a = artifactOf(publication) - a.copy( - extra = a.extra + ("metadata" -> metadataArtifact) - ) - } - - lazy val defaultPublications = { - - val packagingPublicationOpt = packagingOpt - .filter(_ => dependency.attributes.isEmpty) - .map { packaging => - Publication( - dependency.module.name, - packaging, - MavenSource.typeExtension(packaging), - MavenSource.typeDefaultClassifier(packaging) - ) - } - - val type0 = if (dependency.attributes.`type`.isEmpty) "jar" else dependency.attributes.`type` - - val ext = MavenSource.typeExtension(type0) - - val classifier = - if (dependency.attributes.classifier.isEmpty) - MavenSource.typeDefaultClassifier(type0) - else - dependency.attributes.classifier - - val tpe = packagingTpeMap.getOrElse( - (classifier, ext), - MavenSource.classifierExtensionDefaultTypeOpt(classifier, ext).getOrElse(ext) - ) - - val pubs = packagingPublicationOpt.toSeq :+ - Publication( - dependency.module.name, - tpe, - ext, - classifier - ) - - pubs.distinct - } - - overrideClassifiers - .fold(defaultPublications) { classifiers => - classifiers.flatMap { classifier => - if (classifier == dependency.attributes.classifier) - defaultPublications - else { - val ext = "jar" - val tpe = packagingTpeMap.getOrElse( - (classifier, ext), - MavenSource.classifierExtensionDefaultTypeOpt(classifier, ext).getOrElse(ext) - ) - - Seq( - Publication( - dependency.module.name, - tpe, - ext, - classifier - ) - ) - } - } - } - .map(artifactWithExtra) - } - - def artifacts( - dependency: Dependency, - project: Project, - overrideClassifiers: Option[Seq[String]] - ): Seq[Artifact] = - if (project.packagingOpt.toSeq.contains(Pom.relocatedPackaging)) - Nil - else { - - def makeOptional(a: Artifact): Artifact = - a.copy( - extra = a.extra.mapValues(makeOptional).iterator.toMap, - optional = true - ) - - artifactsUnknownPublications(dependency, project, overrideClassifiers) - .map(makeOptional) - } -} - -object MavenSource { - - val typeExtensions: Map[String, String] = Map( - "eclipse-plugin" -> "jar", - "maven-plugin" -> "jar", - "hk2-jar" -> "jar", - "orbit" -> "jar", - "scala-jar" -> "jar", - "jar" -> "jar", - "bundle" -> "jar", - "doc" -> "jar", - "src" -> "jar", - "test-jar" -> "jar", - "ejb-client" -> "jar" - ) - - def typeExtension(`type`: String): String = - typeExtensions.getOrElse(`type`, `type`) - - // see https://github.com/apache/maven/blob/c023e58104b71e27def0caa034d39ab0fa0373b6/maven-core/src/main/resources/META-INF/plexus/artifact-handlers.xml - // discussed in https://github.com/coursier/coursier/issues/298 - val typeDefaultClassifiers: Map[String, String] = Map( - "test-jar" -> "tests", - "javadoc" -> "javadoc", - "java-source" -> "sources", - "ejb-client" -> "client" - ) - - def typeDefaultClassifierOpt(`type`: String): Option[String] = - typeDefaultClassifiers.get(`type`) - - 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)) - -} diff --git a/modules/core/shared/src/main/scala/coursier/maven/Pom.scala b/modules/core/shared/src/main/scala/coursier/maven/Pom.scala index ccc5f3cf22..f02b1ffb19 100644 --- a/modules/core/shared/src/main/scala/coursier/maven/Pom.scala +++ b/modules/core/shared/src/main/scala/coursier/maven/Pom.scala @@ -27,16 +27,20 @@ object Pom { // TODO Allow no version in some contexts private def module( node: Node, - defaultGroupId: Option[String] = None, - defaultArtifactId: Option[String] = None + defaultGroupId: Option[Organization] = None, + defaultArtifactId: Option[ModuleName] = None ): Either[String, Module] = { for { organization <- { val e = text(node, "groupId", "Organization") + .right + .map(Organization(_)) defaultGroupId.fold(e)(g => Right(e.right.getOrElse(g))).right } name <- { val n = text(node, "artifactId", "Name") + .right + .map(ModuleName(_)) defaultArtifactId.fold(n)(n0 => Right(n.right.getOrElse(n0))).right } } yield Module(organization, name, Map.empty).trim @@ -50,15 +54,19 @@ object Pom { val version0 = readVersion(node) val scopeOpt = text(node, "scope", "").right.toOption - val typeOpt = text(node, "type", "").right.toOption - val classifierOpt = text(node, "classifier", "").right.toOption + val typeOpt = text(node, "type", "") + .right.map(Type(_)) + .right.toOption + val classifierOpt = text(node, "classifier", "") + .right.map(Classifier(_)) + .right.toOption val xmlExclusions = node.children .find(_.label == "exclusions") .map(_.children.filter(_.label == "exclusion")) .getOrElse(Seq.empty) xmlExclusions - .eitherTraverse(module(_, defaultArtifactId = Some("*"))) + .eitherTraverse(module(_, defaultArtifactId = Some(ModuleName("*")))) .right .map { exclusions => @@ -69,7 +77,7 @@ object Pom { version0, "", exclusions.map(mod => (mod.organization, mod.name)).toSet, - Attributes(typeOpt.getOrElse(""), classifierOpt.getOrElse("")), + Attributes(typeOpt.getOrElse(Type.empty), classifierOpt.getOrElse(Classifier.empty)), optional, transitive = true ) @@ -152,8 +160,10 @@ object Pom { } yield Profile(id, activeByDefault, activation, deps, depMgmts, properties.toMap) } - def packagingOpt(pom: Node): Option[String] = - text(pom, "packaging", "").right.toOption + def packagingOpt(pom: Node): Option[Type] = + text(pom, "packaging", "") + .right.map(Type(_)) + .right.toOption def project(pom: Node): Either[String, Project] = project(pom, relocationAsDependency = false) @@ -164,7 +174,7 @@ object Pom { ): Either[String, Project] = { for { - projModule <- module(pom, defaultGroupId = Some("")).right + projModule <- module(pom, defaultGroupId = Some(Organization(""))).right parentOpt <- point(pom.children.find(_.label == "parent")) parentModuleOpt <- parentOpt @@ -190,8 +200,8 @@ object Pom { ) depMgmts <- xmlDepMgmts.eitherTraverse(dependency).right - groupId <- Some(projModule.organization).filter(_.nonEmpty) - .orElse(parentModuleOpt.map(_.organization).filter(_.nonEmpty)) + groupId <- Some(projModule.organization).filter(_.value.nonEmpty) + .orElse(parentModuleOpt.map(_.organization).filter(_.value.nonEmpty)) .toRight("No organization found") .right version <- Some(readVersion(pom)).filter(_.nonEmpty) @@ -204,7 +214,7 @@ object Pom { .getOrElse(Right(())) .right _ <- parentModuleOpt - .map(mod => if (mod.organization.isEmpty) Left("Parent organization missing") else Right(())) + .map(mod => if (mod.organization.value.isEmpty) Left("Parent organization missing") else Right(())) .getOrElse(Right(())) .right @@ -287,8 +297,12 @@ object Pom { // see https://maven.apache.org/guides/mini/guide-relocation.html - val relocatedGroupId = text(n, "groupId", "").right.getOrElse(finalProjModule.organization) - val relocatedArtifactId = text(n, "artifactId", "").right.getOrElse(finalProjModule.name) + val relocatedGroupId = text(n, "groupId", "") + .right.map(Organization(_)) + .right.getOrElse(finalProjModule.organization) + val relocatedArtifactId = text(n, "artifactId", "") + .right.map(ModuleName(_)) + .right.getOrElse(finalProjModule.name) val relocatedVersion = text(n, "version", "").right.getOrElse(version) "" -> Dependency( @@ -299,7 +313,7 @@ object Pom { relocatedVersion, "", Set(), - Attributes("", ""), + Attributes.empty, optional = false, transitive = true ) @@ -324,7 +338,8 @@ object Pom { profiles, None, None, - relocationDependencyOpt.fold(packagingOpt(pom))(_ => Some(relocatedPackaging)), + packagingOpt(pom), + relocationDependencyOpt.nonEmpty, None, Nil, Info( @@ -378,8 +393,8 @@ object Pom { .right .getOrElse("") - val classifier = textOrEmpty("classifier", "Classifier") - val ext = textOrEmpty("extension", "Extensions") + val classifier = Classifier(textOrEmpty("classifier", "Classifier")) + val ext = Extension(textOrEmpty("extension", "Extensions")) val value = textOrEmpty("value", "Value") val updatedOpt = text(node, "updated", "Updated") @@ -405,14 +420,18 @@ object Pom { buildNumber: Int ): SnapshotVersion = { val value = s"${version.dropRight("SNAPSHOT".length)}$timestamp-$buildNumber" - SnapshotVersion("*", "*", value, None) + SnapshotVersion(Classifier("*"), Extension("*"), value, None) } def snapshotVersioning(node: Node): Either[String, SnapshotVersioning] = // FIXME Quite similar to Versions above for { - organization <- text(node, "groupId", "Organization").right - name <- text(node, "artifactId", "Name").right + organization <- text(node, "groupId", "Organization") + .right.map(Organization(_)) + .right + name <- text(node, "artifactId", "Name") + .right.map(ModuleName(_)) + .right xmlVersioning <- node .children @@ -496,8 +515,6 @@ object Pom { ) } - val relocatedPackaging = s"$$relocated" - val extraAttributeSeparator = ":#@#:" val extraAttributePrefix = "+" @@ -548,8 +565,12 @@ object Pom { } .toMap ) - org <- attrFrom(attrs, extraAttributeOrg).right - name <- attrFrom(attrs, extraAttributeName).right + org <- attrFrom(attrs, extraAttributeOrg) + .right.map(Organization(_)) + .right + name <- attrFrom(attrs, extraAttributeName) + .right.map(ModuleName(_)) + .right version <- attrFrom(attrs, extraAttributeVersion).right } yield { val remainingAttrs = attrs.filterKeys(!extraAttributeBase(_)) diff --git a/modules/core/shared/src/main/scala/coursier/package.scala b/modules/core/shared/src/main/scala/coursier/package.scala index 277cdad98c..fb442abc0e 100644 --- a/modules/core/shared/src/main/scala/coursier/package.scala +++ b/modules/core/shared/src/main/scala/coursier/package.scala @@ -1,4 +1,7 @@ -import coursier.core.{Activation, Parse, Version} +import coursier.core._ +import coursier.util.StringInterpolators.{SafeModuleName, SafeOrganization} + +import scala.language.implicitConversions /** * Mainly pulls definitions from coursier.core, sometimes with default arguments. @@ -7,6 +10,12 @@ package object coursier { // `extends Serializable` added here-or-there for bin compat while switching from 2.12.1 to 2.12.4 + type Organization = core.Organization + val Organization = core.Organization + + type ModuleName = core.ModuleName + val ModuleName = core.ModuleName + type Dependency = core.Dependency object Dependency extends Serializable { def apply( @@ -15,7 +24,7 @@ package object coursier { // Substituted by Resolver with its own default configuration (compile) configuration: String = "", attributes: Attributes = Attributes(), - exclusions: Set[(String, String)] = Set.empty, + exclusions: Set[(Organization, ModuleName)] = Set.empty, optional: Boolean = false, transitive: Boolean = true ): Dependency = @@ -33,8 +42,8 @@ package object coursier { type Attributes = core.Attributes object Attributes extends Serializable { def apply( - `type`: String = "", - classifier: String = "" + `type`: Type = Type.empty, + classifier: Classifier = Classifier.empty ): Attributes = core.Attributes(`type`, classifier) } @@ -50,7 +59,7 @@ package object coursier { type Module = core.Module object Module extends Serializable { - def apply(organization: String, name: String, attributes: Map[String, String] = Map.empty): Module = + def apply(organization: Organization, name: ModuleName, attributes: Map[String, String] = Map.empty): Module = core.Module(organization, name, attributes) } @@ -110,4 +119,9 @@ package object coursier { def process: ResolutionProcess = ResolutionProcess(underlying) } + implicit def organizationString(sc: StringContext): SafeOrganization = + SafeOrganization(sc) + implicit def moduleNameString(sc: StringContext): SafeModuleName = + SafeModuleName(sc) + } diff --git a/modules/core/shared/src/main/scala/coursier/util/Parse.scala b/modules/core/shared/src/main/scala/coursier/util/Parse.scala index 24a19d221e..47253c4d21 100644 --- a/modules/core/shared/src/main/scala/coursier/util/Parse.scala +++ b/modules/core/shared/src/main/scala/coursier/util/Parse.scala @@ -1,7 +1,7 @@ package coursier.util import coursier.{Attributes, Dependency} -import coursier.core.{Module, Repository} +import coursier.core._ import coursier.ivy.IvyRepository import coursier.maven.MavenRepository @@ -26,9 +26,9 @@ object Parse { val values = parts match { case Array(org, rawName) => - Right((org, rawName, "")) + Right((Organization(org), rawName, "")) case Array(org, "", rawName) => - Right((org, rawName, "_" + defaultScalaVersion.split('.').take(2).mkString("."))) + Right((Organization(org), rawName, "_" + defaultScalaVersion.split('.').take(2).mkString("."))) case _ => Left(s"malformed module: $s") } @@ -46,7 +46,7 @@ object Parse { case Array(key, value) => key -> value }.toMap - Right(Module(org, name + suffix, attributes)) + Right(Module(org, ModuleName(name + suffix), attributes)) } } } @@ -165,8 +165,8 @@ object Parse { case None => val attributes = attrs.get("classifier") match { - case Some(c) => Attributes("", c) - case None => Attributes("", "") + case Some(c) => Attributes(classifier = Classifier(c)) + case None => Attributes() } val extraDependencyParams: Map[String, String] = attrs.get("url") match { @@ -279,8 +279,8 @@ object Parse { * @param localExcludes excludes to be applied to specific modules * @param defaultConfiguration default configuration */ - case class ModuleRequirements(globalExcludes: Set[(String, String)] = Set(), - localExcludes: Map[String, Set[(String, String)]] = Map(), + case class ModuleRequirements(globalExcludes: Set[(Organization, ModuleName)] = Set(), + localExcludes: Map[String, Set[(Organization, ModuleName)]] = Map(), defaultConfiguration: String = "default(compile)") /** diff --git a/modules/core/shared/src/main/scala/coursier/util/Print.scala b/modules/core/shared/src/main/scala/coursier/util/Print.scala index 7d10ce024f..246436739e 100644 --- a/modules/core/shared/src/main/scala/coursier/util/Print.scala +++ b/modules/core/shared/src/main/scala/coursier/util/Print.scala @@ -1,6 +1,6 @@ package coursier.util -import coursier.core.{ Attributes, Dependency, Module, Orders, Project, Resolution } +import coursier.core._ object Print { @@ -74,7 +74,7 @@ object Print { ) val deps1 = minDeps - .groupBy(_.copy(configuration = "", attributes = Attributes("", ""))) + .groupBy(_.copy(configuration = "", attributes = Attributes.empty)) .toVector .map { case (k, l) => k.copy(configuration = l.toVector.map(_.configuration).sorted.distinct.mkString(";")) @@ -181,7 +181,7 @@ object Print { .filterNot(dependencies.map(_.moduleVersion).toSet).map { case (mod, ver) => ElemImpl( - Dependency(mod, ver, "", Set.empty, Attributes("", ""), false, false), + Dependency(mod, ver, "", Set.empty, Attributes.empty, false, false), excluded = true ) } diff --git a/modules/core/shared/src/main/scala/coursier/util/StringInterpolators.scala b/modules/core/shared/src/main/scala/coursier/util/StringInterpolators.scala new file mode 100644 index 0000000000..b0b5d5ba6d --- /dev/null +++ b/modules/core/shared/src/main/scala/coursier/util/StringInterpolators.scala @@ -0,0 +1,41 @@ +package coursier.util + +import coursier.core.{ModuleName, Organization} + +import scala.language.experimental.macros +import scala.reflect.macros.blackbox + +object StringInterpolators { + + // adapted from https://github.com/criteo/cuttle/blob/7e04a8f93c2c44992da270242d8b94ea808ac623/timeseries/src/main/scala/com/criteo/cuttle/timeseries/package.scala#L39-L56 + + implicit class SafeOrganization(val sc: StringContext) extends AnyVal { + def org(args: Any*): Organization = macro safeOrganization + } + + def safeOrganization(c: blackbox.Context)(args: c.Expr[Any]*): c.Expr[Organization] = { + import c.universe._ + c.prefix.tree match { + case Apply(_, List(Apply(_, Literal(Constant(orgString: String)) :: Nil))) => + // TODO Check for invalid characters + c.Expr(q"""_root_.coursier.core.Organization($orgString)""") + case _ => + c.abort(c.enclosingPosition, s"Only a single String literal is allowed here") + } + } + + implicit class SafeModuleName(val sc: StringContext) extends AnyVal { + def name(args: Any*): ModuleName = macro safeModuleName + } + + def safeModuleName(c: blackbox.Context)(args: c.Expr[Any]*): c.Expr[ModuleName] = { + import c.universe._ + c.prefix.tree match { + case Apply(_, List(Apply(_, Literal(Constant(nameString: String)) :: Nil))) => + // TODO Check for invalid characters + c.Expr(q"""_root_.coursier.core.ModuleName($nameString)""") + case _ => + c.abort(c.enclosingPosition, s"Only a single String literal is allowed here") + } + } +} diff --git a/modules/extra/src/main/scala/coursier/FallbackDependenciesRepository.scala b/modules/extra/src/main/scala/coursier/FallbackDependenciesRepository.scala index 3d93d4d151..f16dc66c29 100644 --- a/modules/extra/src/main/scala/coursier/FallbackDependenciesRepository.scala +++ b/modules/extra/src/main/scala/coursier/FallbackDependenciesRepository.scala @@ -3,6 +3,7 @@ package coursier import java.io.{File, FileNotFoundException, IOException} import java.net.{HttpURLConnection, URL, URLConnection} +import coursier.core.{Classifier, Type} import coursier.util.{EitherT, Monad} object FallbackDependenciesRepository { @@ -81,24 +82,6 @@ final case class FallbackDependenciesRepository( localArtifactsShouldBeCached: Boolean = false ) extends Repository { - private val source: Artifact.Source = - new Artifact.Source { - def artifacts( - dependency: Dependency, - project: Project, - overrideClassifiers: Option[Seq[String]] - ) = - fallbacks - .get(dependency.moduleVersion) - .toSeq - .map { - case (url, changing) => - val url0 = url.toString - val ext = url0.substring(url0.lastIndexOf('.') + 1) - Artifact(url0, Map.empty, Map.empty, Attributes(ext, ""), changing, optional = false, None) - } - } - def find[F[_]]( module: Module, version: String, @@ -133,12 +116,13 @@ final case class FallbackDependenciesRepository( None, None, None, + relocated = false, None, Nil, Info.empty ) - Right((source, proj)) + Right((this, proj)) } else Left(s"$fileName not found under $dirUrlStr") } @@ -146,4 +130,21 @@ final case class FallbackDependenciesRepository( EitherT(F.point(res)) } + + def artifacts( + dependency: Dependency, + project: Project, + overrideClassifiers: Option[Seq[Classifier]] + ): Seq[(Attributes, Artifact)] = + fallbacks + .get(dependency.moduleVersion) + .toSeq + .map { + case (url, changing) => + val url0 = url.toString + val ext = url0.substring(url0.lastIndexOf('.') + 1) + val attr = Attributes(Type(ext)) + (attr, Artifact(url0, Map.empty, Map.empty, changing, optional = false, None)) + } + } diff --git a/modules/extra/src/main/scala/coursier/extra/Typelevel.scala b/modules/extra/src/main/scala/coursier/extra/Typelevel.scala index b0d88adfb6..9478d2584d 100644 --- a/modules/extra/src/main/scala/coursier/extra/Typelevel.scala +++ b/modules/extra/src/main/scala/coursier/extra/Typelevel.scala @@ -1,18 +1,18 @@ package coursier.extra -import coursier.{Dependency, Module} +import coursier.{Dependency, Module, moduleNameString, organizationString} object Typelevel { - val mainLineOrg = "org.scala-lang" - val typelevelOrg = "org.typelevel" + val mainLineOrg = org"org.scala-lang" + val typelevelOrg = org"org.typelevel" val modules = Set( - "scala-compiler", - "scala-library", - "scala-library-all", - "scala-reflect", - "scalap" + name"scala-compiler", + name"scala-library", + name"scala-library-all", + name"scala-reflect", + name"scalap" // any other? ) diff --git a/modules/tests/js/src/test/scala/coursier/test/JsTests.scala b/modules/tests/js/src/test/scala/coursier/test/JsTests.scala index eadc9d8a0e..903d6793cb 100644 --- a/modules/tests/js/src/test/scala/coursier/test/JsTests.scala +++ b/modules/tests/js/src/test/scala/coursier/test/JsTests.scala @@ -26,9 +26,9 @@ object JsTests extends TestSuite { 'getProj{ MavenRepository("https://repo1.maven.org/maven2/") - .find(Module("ch.qos.logback", "logback-classic"), "1.1.3", Platform.artifact) + .find(Module(org"ch.qos.logback", name"logback-classic"), "1.1.3", Platform.artifact) .map{case (_, proj) => - assert(proj.parent == Some(Module("ch.qos.logback", "logback-parent"), "1.1.3")) + assert(proj.parent == Some(Module(org"ch.qos.logback", name"logback-parent"), "1.1.3")) } .run .map { res => diff --git a/modules/tests/jvm/src/it/scala/coursier/test/DirectoryListingTests.scala b/modules/tests/jvm/src/it/scala/coursier/test/DirectoryListingTests.scala index 03f91b652c..7db20b17fc 100644 --- a/modules/tests/jvm/src/it/scala/coursier/test/DirectoryListingTests.scala +++ b/modules/tests/jvm/src/it/scala/coursier/test/DirectoryListingTests.scala @@ -1,7 +1,7 @@ package coursier.test import coursier._ -import coursier.core.Authentication +import coursier.core.{Authentication, Type} import utest._ object DirectoryListingTests extends TestSuite { @@ -14,14 +14,14 @@ object DirectoryListingTests extends TestSuite { authentication = Some(Authentication(user, password)) ) - val module = Module("com.abc", "test") + val module = Module(org"com.abc", name"test") val version = "0.1" val tests = Tests { 'jar - CentralTests.withArtifacts( module, version, - attributes = Attributes("jar"), + attributes = Attributes(Type.jar), extraRepos = Seq(repo) ) { artifacts => @@ -32,7 +32,7 @@ object DirectoryListingTests extends TestSuite { 'jarFoo - CentralTests.withArtifacts( module, version, - attributes = Attributes("jar-foo"), + attributes = Attributes(Type("jar-foo")), extraRepos = Seq(repo) ) { artifacts => diff --git a/modules/tests/jvm/src/it/scala/coursier/test/IvyLocalTests.scala b/modules/tests/jvm/src/it/scala/coursier/test/IvyLocalTests.scala index d1da12f20d..0ad2f7ea2d 100644 --- a/modules/tests/jvm/src/it/scala/coursier/test/IvyLocalTests.scala +++ b/modules/tests/jvm/src/it/scala/coursier/test/IvyLocalTests.scala @@ -1,17 +1,17 @@ package coursier.test -import coursier.{ Dependency, Module, Cache } +import coursier.core.{Classifier, Type} +import coursier.{Cache, Dependency, Module, moduleNameString, organizationString} import coursier.test.compatibility._ -import scala.async.Async.{ async, await } - +import scala.async.Async.{async, await} import utest._ object IvyLocalTests extends TestSuite { val tests = TestSuite{ 'coursier { - val module = Module("io.get-coursier", "coursier-core_2.11") + val module = Module(org"io.get-coursier", name"coursier-core_2.11") val version = coursier.util.Properties.version val extraRepos = Seq(Cache.ivy2Local) @@ -25,13 +25,13 @@ object IvyLocalTests extends TestSuite { 'uniqueArtifacts - async { val res = await(CentralTests.resolve( - Set(Dependency(Module("io.get-coursier", "coursier-cli_2.12"), version, transitive = false)), + Set(Dependency(Module(org"io.get-coursier", name"coursier-cli_2.12"), version, transitive = false)), extraRepos = extraRepos )) - val artifacts = res.dependencyClassifiersArtifacts(Seq("standalone")) - .map(_._2) - .filter(a => a.`type` == "jar" && !a.isOptional) + val artifacts = res.dependencyArtifacts(classifiers = Some(Seq(Classifier("standalone")))) + .filter(t => t._2.`type` == Type.jar && !t._3.optional) + .map(_._3) .map(_.url) .groupBy(s => s) @@ -46,7 +46,7 @@ object IvyLocalTests extends TestSuite { extraRepos = extraRepos )) - val artifacts = res.dependencyArtifacts(withOptional = true).filter(_._2.`type` == "jar").map(_._2.url) + val artifacts = res.dependencyArtifacts().filter(_._2.`type` == Type.jar).map(_._3.url) val anyJavadoc = artifacts.exists(_.contains("-javadoc")) val anySources = artifacts.exists(_.contains("-sources")) diff --git a/modules/tests/jvm/src/test/scala/coursier/test/CacheFetchTests.scala b/modules/tests/jvm/src/test/scala/coursier/test/CacheFetchTests.scala index 33c9831746..b0a15a526f 100644 --- a/modules/tests/jvm/src/test/scala/coursier/test/CacheFetchTests.scala +++ b/modules/tests/jvm/src/test/scala/coursier/test/CacheFetchTests.scala @@ -45,7 +45,7 @@ object CacheFetchTests extends TestSuite { val startRes = Resolution( Set( Dependency( - Module("com.github.alexarchambault", "coursier_2.11"), "1.0.0-M9-test" + Module(org"com.github.alexarchambault", name"coursier_2.11"), "1.0.0-M9-test" ) ) ) diff --git a/modules/tests/jvm/src/test/scala/coursier/test/ChecksumTests.scala b/modules/tests/jvm/src/test/scala/coursier/test/ChecksumTests.scala index aba360ddf3..87e3a57c77 100644 --- a/modules/tests/jvm/src/test/scala/coursier/test/ChecksumTests.scala +++ b/modules/tests/jvm/src/test/scala/coursier/test/ChecksumTests.scala @@ -98,7 +98,6 @@ object ChecksumTests extends TestSuite { "SHA-256" -> (url + ".sha256") ), Map.empty, - Attributes("jar"), changing = false, optional = false, authentication = None diff --git a/modules/tests/jvm/src/test/scala/coursier/test/IvyTests.scala b/modules/tests/jvm/src/test/scala/coursier/test/IvyTests.scala index 2990cfc4dc..b3a124fb74 100644 --- a/modules/tests/jvm/src/test/scala/coursier/test/IvyTests.scala +++ b/modules/tests/jvm/src/test/scala/coursier/test/IvyTests.scala @@ -2,7 +2,8 @@ package coursier.test import java.io.File -import coursier.{Attributes, Dependency, Module} +import coursier.core.{Classifier, Type} +import coursier.{Attributes, Dependency, Module, moduleNameString, organizationString} import coursier.ivy.IvyRepository import utest._ @@ -23,7 +24,7 @@ object IvyTests extends TestSuite { 'dropInfoAttributes - { CentralTests.resolutionCheck( module = Module( - "org.scala-js", "sbt-scalajs", Map("sbtVersion" -> "0.13", "scalaVersion" -> "2.10") + org"org.scala-js", name"sbt-scalajs", Map("sbtVersion" -> "0.13", "scalaVersion" -> "2.10") ), version = "0.6.6", extraRepos = Seq(sbtRepo), @@ -35,7 +36,7 @@ object IvyTests extends TestSuite { // will likely break if new 0.6.x versions are published :-) val mod = Module( - "com.github.ddispaltro", "sbt-reactjs", Map("sbtVersion" -> "0.13", "scalaVersion" -> "2.10") + org"com.github.ddispaltro", name"sbt-reactjs", Map("sbtVersion" -> "0.13", "scalaVersion" -> "2.10") ) val ver = "0.6.+" @@ -47,7 +48,7 @@ object IvyTests extends TestSuite { extraRepos = Seq(sbtRepo) ) - * - CentralTests.withArtifacts(mod, ver, Attributes("jar"), extraRepos = Seq(sbtRepo)) { artifacts => + * - CentralTests.withArtifacts(mod, ver, Attributes(Type.jar), extraRepos = Seq(sbtRepo)) { artifacts => assert(artifacts.exists(_.url == expectedArtifactUrl)) } } @@ -55,7 +56,7 @@ object IvyTests extends TestSuite { 'testArtifacts - { val dep = Dependency( - Module("com.example", "a_2.11"), + Module(org"com.example", name"a_2.11"), "0.1.0-SNAPSHOT", transitive = false, attributes = Attributes() @@ -75,7 +76,7 @@ object IvyTests extends TestSuite { val testJarUrl = repoBase + "com.example/a_2.11/0.1.0-SNAPSHOT/jars/a_2.11-tests.jar" "no conf or classifier" - CentralTests.withArtifacts( - dep = dep.copy(attributes = Attributes("jar")), + dep = dep.copy(attributes = Attributes(Type.jar)), extraRepos = Seq(repo), classifierOpt = None ) { @@ -97,7 +98,7 @@ object IvyTests extends TestSuite { } "attributes" - CentralTests.withArtifacts( - dep = dep.copy(configuration = "test", attributes = Attributes("jar")), + dep = dep.copy(configuration = "test", attributes = Attributes(Type.jar)), extraRepos = Seq(repo), classifierOpt = None ) { artifacts => @@ -108,7 +109,7 @@ object IvyTests extends TestSuite { } "tests classifier" - { - val testsDep = dep.copy(attributes = Attributes("jar", "tests")) + val testsDep = dep.copy(attributes = Attributes(Type.jar, Classifier.tests)) * - CentralTests.withArtifacts( deps = Set(dep, testsDep), diff --git a/modules/tests/jvm/src/test/scala/coursier/test/MavenTests.scala b/modules/tests/jvm/src/test/scala/coursier/test/MavenTests.scala index e60f33a3a3..e4e4753e00 100644 --- a/modules/tests/jvm/src/test/scala/coursier/test/MavenTests.scala +++ b/modules/tests/jvm/src/test/scala/coursier/test/MavenTests.scala @@ -2,7 +2,8 @@ package coursier.test import java.io.File -import coursier.{Attributes, Dependency, Module} +import coursier.core.{Classifier, Type} +import coursier.{Attributes, Dependency, Module, moduleNameString, organizationString} import coursier.maven.MavenRepository import utest._ @@ -14,7 +15,7 @@ object MavenTests extends TestSuite { 'testSnapshotNoVersioning - { val dep = Dependency( - Module("com.abc", "test-snapshot-special"), + Module(org"com.abc", name"test-snapshot-special"), "0.1.0-SNAPSHOT", transitive = false, attributes = Attributes() @@ -30,7 +31,7 @@ object MavenTests extends TestSuite { val sourcesJarUrl = repoBase + "com/abc/test-snapshot-special/0.1.0-SNAPSHOT/test-snapshot-special-0.1.0-20170421.034426-82-sources.jar" * - CentralTests.withArtifacts( - dep = dep.copy(attributes = Attributes("jar")), + dep = dep.copy(attributes = Attributes(Type.jar)), extraRepos = Seq(repo), classifierOpt = None ) { @@ -41,9 +42,9 @@ object MavenTests extends TestSuite { } * - CentralTests.withArtifacts( - dep = dep.copy(attributes = Attributes("src")), + dep = dep.copy(attributes = Attributes(Type.source)), extraRepos = Seq(repo), - classifierOpt = Some("sources") + classifierOpt = Some(Classifier.sources) ) { case Seq(artifact) => assert(artifact.url == sourcesJarUrl) diff --git a/modules/tests/jvm/src/test/scala/coursier/test/ResolutionProcessTests.scala b/modules/tests/jvm/src/test/scala/coursier/test/ResolutionProcessTests.scala index 2b0c21ebbd..dd4bc6cc0b 100644 --- a/modules/tests/jvm/src/test/scala/coursier/test/ResolutionProcessTests.scala +++ b/modules/tests/jvm/src/test/scala/coursier/test/ResolutionProcessTests.scala @@ -2,7 +2,7 @@ package coursier.test import java.util.concurrent.ConcurrentHashMap -import coursier.{Fetch, Module} +import coursier.{Fetch, Module, moduleNameString, organizationString} import coursier.core.ResolutionProcess import coursier.interop.scalaz._ import utest._ @@ -21,7 +21,7 @@ object ResolutionProcessTests extends TestSuite { // rather than all at once def check(extra: Int): Unit = { - val mod = Module("org", "name") + val mod = Module(org"org", name"name") val modVers = (1 to (9 + extra)) .map(_.toString) .map((mod, _)) diff --git a/modules/tests/shared/src/test/scala/coursier/test/CentralTests.scala b/modules/tests/shared/src/test/scala/coursier/test/CentralTests.scala index 0e645d5373..f5e03069ac 100644 --- a/modules/tests/shared/src/test/scala/coursier/test/CentralTests.scala +++ b/modules/tests/shared/src/test/scala/coursier/test/CentralTests.scala @@ -2,10 +2,11 @@ package coursier package test import utest._ -import scala.async.Async.{async, await} +import scala.async.Async.{async, await} import coursier.MavenRepository import coursier.Platform.fetch +import coursier.core.{Classifier, Extension, Type} import coursier.test.compatibility._ import scala.concurrent.Future @@ -75,8 +76,8 @@ abstract class CentralTests extends TestSuite { val path = Seq( "resolutions", - module.organization, - module.name, + module.organization.value, + module.name.value, attrPathPart, version + ( if (configuration.isEmpty) @@ -102,7 +103,7 @@ abstract class CentralTests extends TestSuite { val dep0 = dep.copy( version = projOpt.fold(dep.version)(_.actualVersion) ) - (dep0.module.organization, dep0.module.nameWithAttributes, dep0.version, dep0.configuration) + (dep0.module.organization.value, dep0.module.nameWithAttributes, dep0.version, dep0.configuration) } .sorted .distinct @@ -131,7 +132,7 @@ abstract class CentralTests extends TestSuite { version: String, attributes: Attributes = Attributes(), extraRepos: Seq[Repository] = Nil, - classifierOpt: Option[String] = None, + classifierOpt: Option[Classifier] = None, transitive: Boolean = false )( f: Seq[Artifact] => T @@ -143,7 +144,7 @@ abstract class CentralTests extends TestSuite { def withArtifacts[T]( dep: Dependency, extraRepos: Seq[Repository], - classifierOpt: Option[String] + classifierOpt: Option[Classifier] )( f: Seq[Artifact] => T ): Future[T] = @@ -152,50 +153,58 @@ abstract class CentralTests extends TestSuite { def withArtifacts[T]( deps: Set[Dependency], extraRepos: Seq[Repository], - classifierOpt: Option[String] + classifierOpt: Option[Classifier] )( f: Seq[Artifact] => T - ): Future[T] = async { - val res = await(resolve(deps, extraRepos = extraRepos)) + ): Future[T] = + withDetailedArtifacts(deps, extraRepos, classifierOpt)(l => f(l.map(_._2))) - val metadataErrors = res.errors - val conflicts = res.conflicts - val isDone = res.isDone - assert(metadataErrors.isEmpty) - assert(conflicts.isEmpty) - assert(isDone) + def withDetailedArtifacts[T]( + deps: Set[Dependency], + extraRepos: Seq[Repository], + classifierOpt: Option[Classifier] + )( + f: Seq[(Attributes, Artifact)] => T + ): Future[T] = + async { + val res = await(resolve(deps, extraRepos = extraRepos)) - val artifacts = classifierOpt - .fold(res.dependencyArtifacts(withOptional = true))(c => res.dependencyClassifiersArtifacts(Seq(c))) - .map(_._2) + val metadataErrors = res.errors + val conflicts = res.conflicts + val isDone = res.isDone + assert(metadataErrors.isEmpty) + assert(conflicts.isEmpty) + assert(isDone) - f(artifacts) - } + val artifacts = res.dependencyArtifacts(classifiers = classifierOpt.map(Seq(_))).map(t => (t._2, t._3)) + + f(artifacts) + } def ensureHasArtifactWithExtension( module: Module, version: String, - extension: String, + extension: Extension, attributes: Attributes = Attributes(), extraRepos: Seq[Repository] = Nil ): Future[Unit] = withArtifacts(module, version, attributes = attributes, extraRepos = extraRepos) { artifacts => - assert(artifacts.exists(_.url.endsWith("." + extension))) + assert(artifacts.exists(_.url.endsWith("." + extension.value))) } val tests = Tests { 'logback - { async { - val dep = Dependency(Module("ch.qos.logback", "logback-classic"), "1.1.3") + val dep = Dependency(Module(org"ch.qos.logback", name"logback-classic"), "1.1.3") val res = await(resolve(Set(dep))).clearCaches val expected = Resolution( rootDependencies = Set(dep), dependencies = Set( dep.withCompileScope, - Dependency(Module("ch.qos.logback", "logback-core"), "1.1.3").withCompileScope, - Dependency(Module("org.slf4j", "slf4j-api"), "1.7.7").withCompileScope)) + Dependency(Module(org"ch.qos.logback", name"logback-core"), "1.1.3").withCompileScope, + Dependency(Module(org"org.slf4j", name"slf4j-api"), "1.7.7").withCompileScope)) assert(res == expected) } @@ -203,15 +212,15 @@ abstract class CentralTests extends TestSuite { 'asm - { async { - val dep = Dependency(Module("org.ow2.asm", "asm-commons"), "5.0.2") + val dep = Dependency(Module(org"org.ow2.asm", name"asm-commons"), "5.0.2") val res = await(resolve(Set(dep))).clearCaches val expected = Resolution( rootDependencies = Set(dep), dependencies = Set( dep.withCompileScope, - Dependency(Module("org.ow2.asm", "asm-tree"), "5.0.2").withCompileScope, - Dependency(Module("org.ow2.asm", "asm"), "5.0.2").withCompileScope)) + Dependency(Module(org"org.ow2.asm", name"asm-tree"), "5.0.2").withCompileScope, + Dependency(Module(org"org.ow2.asm", name"asm"), "5.0.2").withCompileScope)) assert(res == expected) } @@ -219,7 +228,7 @@ abstract class CentralTests extends TestSuite { 'jodaVersionInterval - { async { - val dep = Dependency(Module("joda-time", "joda-time"), "[2.2,2.8]") + val dep = Dependency(Module(org"joda-time", name"joda-time"), "[2.2,2.8]") val res0 = await(resolve(Set(dep))) val res = res0.clearCaches @@ -238,13 +247,13 @@ abstract class CentralTests extends TestSuite { 'spark - { * - resolutionCheck( - Module("org.apache.spark", "spark-core_2.11"), + Module(org"org.apache.spark", name"spark-core_2.11"), "1.3.1", profiles = Some(Set("hadoop-2.2")) ) 'scala210 - resolutionCheck( - Module("org.apache.spark", "spark-core_2.10"), + Module(org"org.apache.spark", name"spark-core_2.10"), "2.1.1", profiles = Some(Set("hadoop-2.6", "scala-2.10", "!scala-2.11")) ) @@ -252,14 +261,14 @@ abstract class CentralTests extends TestSuite { 'argonautShapeless - { resolutionCheck( - Module("com.github.alexarchambault", "argonaut-shapeless_6.1_2.11"), + Module(org"com.github.alexarchambault", name"argonaut-shapeless_6.1_2.11"), "0.2.0" ) } 'snapshotMetadata - { 'simple - { - val mod = Module("com.github.fommil", "java-logging") + val mod = Module(org"com.github.fommil", name"java-logging") val version = "1.2-SNAPSHOT" val extraRepo = MavenRepository("https://oss.sonatype.org/content/repositories/public/") @@ -273,14 +282,14 @@ abstract class CentralTests extends TestSuite { * - ensureHasArtifactWithExtension( mod, version, - "jar", - Attributes("jar"), + Extension.jar, + Attributes(Type.jar), extraRepos = Seq(extraRepo) ) } * - { - val mod = Module("org.jitsi", "jitsi-videobridge") + val mod = Module(org"org.jitsi", name"jitsi-videobridge") val version = "1.0-SNAPSHOT" val extraRepos = Seq( MavenRepository("https://github.com/jitsi/jitsi-maven-repository/raw/master/releases"), @@ -299,42 +308,42 @@ abstract class CentralTests extends TestSuite { 'versionProperty - { // nasty one - in its POM, its version contains "${parent.project.version}" resolutionCheck( - Module("org.bytedeco.javacpp-presets", "opencv"), + Module(org"org.bytedeco.javacpp-presets", name"opencv"), "3.0.0-1.1" ) } 'parentProjectProperties - { resolutionCheck( - Module("com.github.fommil.netlib", "all"), + Module(org"com.github.fommil.netlib", name"all"), "1.1.2" ) } 'projectProperties - { resolutionCheck( - Module("org.glassfish.jersey.core", "jersey-client"), + Module(org"org.glassfish.jersey.core", name"jersey-client"), "2.19" ) } 'parentDependencyManagementProperties - { resolutionCheck( - Module("com.nativelibs4java", "jnaerator-runtime"), + Module(org"com.nativelibs4java", name"jnaerator-runtime"), "0.12" ) } 'propertySubstitution - { resolutionCheck( - Module("org.drools", "drools-compiler"), + Module(org"org.drools", name"drools-compiler"), "7.0.0.Final" ) } 'artifactIdProperties - { resolutionCheck( - Module("cc.factorie", "factorie_2.11"), + Module(org"cc.factorie", name"factorie_2.11"), "1.2" ) } @@ -344,7 +353,7 @@ abstract class CentralTests extends TestSuite { // that one involves version intervals, thus changing versions, so only // running it against our cached Central stuff resolutionCheck( - Module("org.webjars.bower", "malihu-custom-scrollbar-plugin"), + Module(org"org.webjars.bower", name"malihu-custom-scrollbar-plugin"), "3.1.5" ) else @@ -353,40 +362,40 @@ abstract class CentralTests extends TestSuite { 'latestRevision - { * - resolutionCheck( - Module("com.chuusai", "shapeless_2.11"), + Module(org"com.chuusai", name"shapeless_2.11"), "[2.2.0,2.3-a1)" ) * - resolutionCheck( - Module("com.chuusai", "shapeless_2.11"), + Module(org"com.chuusai", name"shapeless_2.11"), "2.2.+" ) * - resolutionCheck( - Module("com.googlecode.libphonenumber", "libphonenumber"), + Module(org"com.googlecode.libphonenumber", name"libphonenumber"), "[7.0,7.1)" ) * - resolutionCheck( - Module("com.googlecode.libphonenumber", "libphonenumber"), + Module(org"com.googlecode.libphonenumber", name"libphonenumber"), "7.0.+" ) } 'versionFromDependency - { - val mod = Module("org.apache.ws.commons", "XmlSchema") + val mod = Module(org"org.apache.ws.commons", name"XmlSchema") val version = "1.1" val expectedArtifactUrl = s"$centralBase/org/apache/ws/commons/XmlSchema/1.1/XmlSchema-1.1.jar" * - resolutionCheck(mod, version) - * - withArtifacts(mod, version, Attributes("jar")) { artifacts => + * - withArtifacts(mod, version, Attributes(Type.jar)) { artifacts => assert(artifacts.exists(_.url == expectedArtifactUrl)) } } 'fixedVersionDependency - { - val mod = Module("io.grpc", "grpc-netty") + val mod = Module(org"io.grpc", name"grpc-netty") val version = "0.14.1" resolutionCheck(mod, version) @@ -394,7 +403,7 @@ abstract class CentralTests extends TestSuite { 'mavenScopes - { def check(config: String) = resolutionCheck( - Module("com.android.tools", "sdklib"), + Module(org"com.android.tools", name"sdklib"), "24.5.0", configuration = config ) @@ -407,10 +416,10 @@ abstract class CentralTests extends TestSuite { def intransitiveCompiler(config: String) = Dependency( - Module("org.scala-lang", "scala-compiler"), "2.11.8", + Module(org"org.scala-lang", name"scala-compiler"), "2.11.8", configuration = config, transitive = false, - attributes = Attributes("jar") + attributes = Attributes(Type.jar) ) withArtifacts( @@ -433,49 +442,48 @@ abstract class CentralTests extends TestSuite { 'packaging - { 'aar - { // random aar-based module found on Central - val module = Module("com.yandex.android", "speechkit") + val module = Module(org"com.yandex.android", name"speechkit") val version = "2.5.0" - val tpe = "aar" * - ensureHasArtifactWithExtension( module, version, - tpe, - attributes = Attributes(tpe) + Extension("aar"), + attributes = Attributes(Type("aar")) ) * - ensureHasArtifactWithExtension( module, version, - tpe + Extension("aar") ) } 'bundle - { // has packaging bundle - ensuring coursier gives its artifact the .jar extension * - ensureHasArtifactWithExtension( - Module("com.google.guava", "guava"), + Module(org"com.google.guava", name"guava"), "17.0", - "jar" + Extension.jar ) // even though packaging is bundle, depending on attribute type "jar" should still find // an artifact * - ensureHasArtifactWithExtension( - Module("com.google.guava", "guava"), + Module(org"com.google.guava", name"guava"), "17.0", - "jar", - attributes = Attributes("jar") + Extension.jar, + attributes = Attributes(Type.jar) ) } 'mavenPlugin - { // has packaging maven-plugin - ensuring coursier gives its artifact the .jar extension ensureHasArtifactWithExtension( - Module("org.bytedeco", "javacpp"), + Module(org"org.bytedeco", name"javacpp"), "1.1", - "jar", - Attributes("maven-plugin") + Extension.jar, + Attributes(Type("maven-plugin")) ) } } @@ -486,11 +494,11 @@ abstract class CentralTests extends TestSuite { async { val deps = Set( Dependency( - Module("org.apache.avro", "avro"), "1.8.1" + Module(org"org.apache.avro", name"avro"), "1.8.1" ) ) val res = await(resolve(deps)) - val filenames: Set[String] = res.artifacts(withOptional = true).map(_.url.split("/").last).toSet + val filenames: Set[String] = res.artifacts().map(_.url.split("/").last).toSet assert(filenames.contains("avro-1.8.1.jar")) assert(!filenames.contains("avro-1.8.1-tests.jar")) } @@ -500,11 +508,11 @@ abstract class CentralTests extends TestSuite { async { val deps = Set( Dependency( - Module("org.apache.avro", "avro"), "1.8.1", attributes = Attributes("", "tests") + Module(org"org.apache.avro", name"avro"), "1.8.1", attributes = Attributes(Type.empty, Classifier.tests) ) ) val res = await(resolve(deps)) - val filenames: Set[String] = res.artifacts(withOptional = true).map(_.url.split("/").last).toSet + val filenames: Set[String] = res.artifacts().map(_.url.split("/").last).toSet assert(!filenames.contains("avro-1.8.1.jar")) assert(filenames.contains("avro-1.8.1-tests.jar")) } @@ -514,14 +522,14 @@ abstract class CentralTests extends TestSuite { async { val deps = Set( Dependency( - Module("org.apache.avro", "avro"), "1.8.1" + Module(org"org.apache.avro", name"avro"), "1.8.1" ), Dependency( - Module("org.apache.avro", "avro"), "1.8.1", attributes = Attributes("", "tests") + Module(org"org.apache.avro", name"avro"), "1.8.1", attributes = Attributes(Type.empty, Classifier.tests) ) ) val res = await(resolve(deps)) - val filenames: Set[String] = res.artifacts(withOptional = true).map(_.url.split("/").last).toSet + val filenames: Set[String] = res.artifacts().map(_.url.split("/").last).toSet assert(filenames.contains("avro-1.8.1.jar")) assert(filenames.contains("avro-1.8.1-tests.jar")) } @@ -533,10 +541,10 @@ abstract class CentralTests extends TestSuite { async { val deps = Set( Dependency( - Module("org.scala-lang", "scala-compiler"), "2.11.8" + Module(org"org.scala-lang", name"scala-compiler"), "2.11.8" ), Dependency( - Module("org.scala-js", "scalajs-compiler_2.11.8"), "0.6.8" + Module(org"org.scala-js", name"scalajs-compiler_2.11.8"), "0.6.8" ) ) @@ -549,7 +557,7 @@ abstract class CentralTests extends TestSuite { assert(conflicts.isEmpty) assert(isDone) - val artifacts = res.artifacts(withOptional = true) + val artifacts = res.artifacts() val map = artifacts.groupBy(a => a) @@ -573,7 +581,7 @@ abstract class CentralTests extends TestSuite { async { val deps = Set( Dependency( - Module("org.apache.hadoop", "hadoop-yarn-server-resourcemanager"), + Module(org"org.apache.hadoop", name"hadoop-yarn-server-resourcemanager"), "2.7.1" ) ) @@ -587,36 +595,36 @@ abstract class CentralTests extends TestSuite { assert(conflicts.isEmpty) assert(isDone) - val dependencyArtifacts = res.dependencyArtifacts(withOptional = true) + val dependencyArtifacts = res.dependencyArtifacts() val zookeeperTestArtifacts = dependencyArtifacts.collect { - case (dep, artifact) - if dep.module == Module("org.apache.zookeeper", "zookeeper") && - dep.attributes.`type` == "test-jar" => - artifact + case (dep, attributes, artifact) + if dep.module == Module(org"org.apache.zookeeper", name"zookeeper") && + attributes.`type` == Type.testJar => + (attributes, artifact) } assert(zookeeperTestArtifacts.length == 1) - val zookeeperTestArtifact = zookeeperTestArtifacts.head + val (attr, artifact) = zookeeperTestArtifacts.head - assert(zookeeperTestArtifact.attributes.`type` == "test-jar") - assert(zookeeperTestArtifact.attributes.classifier == "tests") - zookeeperTestArtifact.url.endsWith("-tests.jar") + assert(attr.`type` == Type.testJar) + assert(attr.classifier == Classifier.tests) + artifact.url.endsWith("-tests.jar") } } } 'ignoreUtf8Bom - { resolutionCheck( - Module("dk.brics.automaton", "automaton"), + Module(org"dk.brics.automaton", name"automaton"), "1.11-8" ) } 'ignoreWhitespaces - { resolutionCheck( - Module("org.jboss.resteasy", "resteasy-jaxrs"), + Module(org"org.jboss.resteasy", name"resteasy-jaxrs"), "3.0.9.Final" ) } @@ -627,7 +635,7 @@ abstract class CentralTests extends TestSuite { // - requires converting a "x86-64" to "x86_64" in it, and // - uses "project.packaging" property resolutionCheck( - Module("org.nd4j", "nd4j-native"), + Module(org"org.nd4j", name"nd4j-native"), "0.5.0" ) } @@ -637,12 +645,12 @@ abstract class CentralTests extends TestSuite { // optional should bring jline * - resolutionCheck( - Module("org.scala-lang", "scala-compiler"), + Module(org"org.scala-lang", name"scala-compiler"), "2.11.8" ) * - resolutionCheck( - Module("org.scala-lang", "scala-compiler"), + Module(org"org.scala-lang", name"scala-compiler"), "2.11.8", configuration = "optional" ) @@ -650,13 +658,13 @@ abstract class CentralTests extends TestSuite { 'deepLearning4j - { resolutionCheck( - Module("org.deeplearning4j", "deeplearning4j-core"), + Module(org"org.deeplearning4j", name"deeplearning4j-core"), "0.8.0" ) } 'tarGzZipArtifacts - { - val mod = Module("org.apache.maven", "apache-maven") + val mod = Module(org"org.apache.maven", name"apache-maven") val version = "3.3.9" * - resolutionCheck(mod, version) @@ -666,14 +674,14 @@ abstract class CentralTests extends TestSuite { 'tarGz - { * - { - withArtifacts(mod, version, attributes = Attributes("tar.gz", "bin"), transitive = true) { artifacts => + withArtifacts(mod, version, attributes = Attributes(Type("tar.gz"), Classifier("bin")), transitive = true) { artifacts => assert(artifacts.nonEmpty) val urls = artifacts.map(_.url).toSet assert(urls.contains(mainTarGzUrl)) } } * - { - withArtifacts(mod, version, attributes = Attributes("tar.gz", "bin"), classifierOpt = Some("bin"), transitive = true) { artifacts => + withArtifacts(mod, version, attributes = Attributes(Type("tar.gz"), Classifier("bin")), classifierOpt = Some(Classifier("bin")), transitive = true) { artifacts => assert(artifacts.nonEmpty) val urls = artifacts.map(_.url).toSet assert(urls.contains(mainTarGzUrl)) @@ -683,14 +691,14 @@ abstract class CentralTests extends TestSuite { 'zip - { * - { - withArtifacts(mod, version, attributes = Attributes("zip", "bin"), transitive = true) { artifacts => + withArtifacts(mod, version, attributes = Attributes(Type("zip"), Classifier("bin")), transitive = true) { artifacts => assert(artifacts.nonEmpty) val urls = artifacts.map(_.url).toSet assert(urls.contains(mainZipUrl)) } } * - { - withArtifacts(mod, version, attributes = Attributes("zip", "bin"), classifierOpt = Some("bin"), transitive = true) { artifacts => + withArtifacts(mod, version, attributes = Attributes(Type("zip"), Classifier("bin")), classifierOpt = Some(Classifier("bin")), transitive = true) { artifacts => assert(artifacts.nonEmpty) val urls = artifacts.map(_.url).toSet assert(urls.contains(mainZipUrl)) @@ -701,19 +709,19 @@ abstract class CentralTests extends TestSuite { 'groupIdVersionProperties - { resolutionCheck( - Module("org.apache.directory.shared", "shared-ldap"), + Module(org"org.apache.directory.shared", name"shared-ldap"), "0.9.19" ) } 'relocation - { * - resolutionCheck( - Module("bouncycastle", "bctsp-jdk14"), + Module(org"bouncycastle", name"bctsp-jdk14"), "138" ) 'ignoreRelocationJars - { - val mod = Module("org.apache.commons", "commons-io") + val mod = Module(org"org.apache.commons", name"commons-io") val ver = "1.3.2" val expectedUrl = s"$centralBase/commons-io/commons-io/1.3.2/commons-io-1.3.2.jar" @@ -728,28 +736,28 @@ abstract class CentralTests extends TestSuite { 'entities - { 'odash - resolutionCheck( - Module("org.codehaus.plexus", "plexus"), + Module(org"org.codehaus.plexus", name"plexus"), "1.0.4" ) } 'parentVersionInPom - { resolutionCheck( - Module("io.swagger.parser.v3", "swagger-parser-v3"), + Module(org"io.swagger.parser.v3", name"swagger-parser-v3"), "2.0.1" ) } 'parentBeforeImports - { resolutionCheck( - Module("org.kie", "kie-api"), + Module(org"org.kie", name"kie-api"), "6.5.0.Final", extraRepos = Seq(MavenRepository("https://repository.jboss.org/nexus/content/repositories/public")) ) } 'signaturesOfSignatures - { - val mod = Module("org.yaml", "snakeyaml") + val mod = Module(org"org.yaml", name"snakeyaml") val ver = "1.17" def hasSha1(a: Artifact) = a.checksumUrls.contains("SHA-1") @@ -758,9 +766,12 @@ abstract class CentralTests extends TestSuite { * - resolutionCheck(mod, ver) - * - withArtifacts(mod, ver, Attributes("bundle")) { artifacts => + * - withDetailedArtifacts(Set(Dependency(mod, ver, attributes = Attributes(Type.bundle))), Nil, None) { artifacts => - val jarOpt = artifacts.find(_.`type` == "bundle").orElse(artifacts.find(_.`type` == "jar")) + val jarOpt = artifacts.collect { + case (attr, artifact) if attr.`type` == Type.bundle || attr.`type` == Type.jar => + artifact + } assert(jarOpt.nonEmpty) assert(jarOpt.forall(hasSha1)) @@ -768,9 +779,12 @@ abstract class CentralTests extends TestSuite { assert(jarOpt.forall(hasSig)) } - * - withArtifacts(mod, ver, Attributes("pom")) { artifacts => + * - withDetailedArtifacts(Set(Dependency(mod, ver, attributes = Attributes(Type.pom))), Nil, None) { artifacts => - val pomOpt = artifacts.find(_.`type` == "pom") + val pomOpt = artifacts.collect { + case (attr, artifact) if attr.`type` == Type.pom => + artifact + } assert(pomOpt.nonEmpty) assert(pomOpt.forall(hasSha1)) @@ -780,7 +794,7 @@ abstract class CentralTests extends TestSuite { } 'sbtPluginVersionRange - { - val mod = Module("org.ensime", "sbt-ensime", attributes = Map("scalaVersion" -> "2.10", "sbtVersion" -> "0.13")) + val mod = Module(org"org.ensime", name"sbt-ensime", attributes = Map("scalaVersion" -> "2.10", "sbtVersion" -> "0.13")) val ver = "1.12.+" * - { @@ -792,7 +806,7 @@ abstract class CentralTests extends TestSuite { } 'multiVersionRanges - { - val mod = Module("org.webjars.bower", "dgrid") + val mod = Module(org"org.webjars.bower", name"dgrid") val ver = "1.0.0" * - { @@ -804,27 +818,27 @@ abstract class CentralTests extends TestSuite { } 'dependencyManagementScopeOverriding - { - val mod = Module("org.apache.tika", "tika-app") + val mod = Module(org"org.apache.tika", name"tika-app") val ver = "1.13" * - resolutionCheck(mod, ver) } 'optionalArtifacts - { - val mod = Module("io.monix", "monix_2.12") + val mod = Module(org"io.monix", name"monix_2.12") val ver = "2.3.0" val mainUrl = s"$centralBase/io/monix/monix_2.12/2.3.0/monix_2.12-2.3.0.jar" * - resolutionCheck(mod, ver) - * - withArtifacts(mod, ver, Attributes("jar")) { artifacts => + * - withArtifacts(mod, ver, Attributes(Type.jar)) { artifacts => val mainArtifactOpt = artifacts.find(_.url == mainUrl) assert(mainArtifactOpt.nonEmpty) assert(mainArtifactOpt.forall(_.optional)) } - * - withArtifacts(Module("com.lihaoyi", "scalatags_2.12"), "0.6.2", Attributes("jar"), transitive = true) { artifacts => + * - withArtifacts(Module(org"com.lihaoyi", name"scalatags_2.12"), "0.6.2", Attributes(Type.jar), transitive = true) { artifacts => val urls = artifacts.map(_.url).toSet @@ -838,14 +852,14 @@ abstract class CentralTests extends TestSuite { } 'packagingTpe - { - val mod = Module("android.arch.lifecycle", "extensions") + val mod = Module(org"android.arch.lifecycle", name"extensions") val ver = "1.0.0-alpha3" val extraRepo = MavenRepository("https://maven.google.com") * - resolutionCheck(mod, ver, extraRepos = Seq(extraRepo)) - * - withArtifacts(mod, ver, Attributes("aar"), extraRepos = Seq(extraRepo), transitive = true) { artifacts => + * - withArtifacts(mod, ver, Attributes(Type("aar")), extraRepos = Seq(extraRepo), transitive = true) { artifacts => val urls = artifacts.map(_.url).toSet val expectedUrls = Set( "https://maven.google.com/com/android/support/support-fragment/25.3.1/support-fragment-25.3.1.aar", @@ -865,14 +879,14 @@ abstract class CentralTests extends TestSuite { } 'noArtifactIdExclusion - { - val mod = Module("org.datavec", "datavec-api") + val mod = Module(org"org.datavec", name"datavec-api") val ver = "0.9.1" * - resolutionCheck(mod, ver) } 'snapshotVersioningBundlePackaging - { - val mod = Module("org.talend.daikon", "daikon") + val mod = Module(org"org.talend.daikon", name"daikon") val ver = "0.19.0-SNAPSHOT" val extraRepos = Seq( @@ -882,7 +896,7 @@ abstract class CentralTests extends TestSuite { * - resolutionCheck(mod, ver, extraRepos = extraRepos) - * - withArtifacts(mod, ver, Attributes("jar"), extraRepos = extraRepos, transitive = true) { artifacts => + * - withArtifacts(mod, ver, Attributes(Type.jar), extraRepos = extraRepos, transitive = true) { artifacts => val urls = artifacts.map(_.url).toSet val expectedUrls = Set( "https://artifacts-oss.talend.com/nexus/content/repositories/TalendOpenSourceRelease/com/cedarsoftware/json-io/4.9.9-TALEND/json-io-4.9.9-TALEND.jar", diff --git a/modules/tests/shared/src/test/scala/coursier/test/ExclusionsTests.scala b/modules/tests/shared/src/test/scala/coursier/test/ExclusionsTests.scala index 87d5a18e02..acae1705c8 100644 --- a/modules/tests/shared/src/test/scala/coursier/test/ExclusionsTests.scala +++ b/modules/tests/shared/src/test/scala/coursier/test/ExclusionsTests.scala @@ -5,16 +5,16 @@ import utest._ object ExclusionsTests extends TestSuite { - def exclusionsAdd(e1: Set[(String, String)], e2: Set[(String, String)]) = + def exclusionsAdd(e1: Set[(Organization, ModuleName)], e2: Set[(Organization, ModuleName)]): Set[(Organization, ModuleName)] = core.Exclusions.minimize(e1 ++ e2) val tests = Tests { - val e1 = Set(("org1", "name1")) - val e2 = Set(("org2", "name2")) + val e1 = Set((org"org1", name"name1")) + val e2 = Set((org"org2", name"name2")) - val enb = Set(("org1", "*")) - val eob = Set(("*", "name1")) - val eb = Set(("*", "*")) + val enb = Set((org"org1", name"*")) + val eob = Set((org"*", name"name1")) + val eb = Set((org"*", name"*")) 'add{ 'basicZero{ diff --git a/modules/tests/shared/src/test/scala/coursier/test/ParseTests.scala b/modules/tests/shared/src/test/scala/coursier/test/ParseTests.scala index 121745363c..8251774294 100644 --- a/modules/tests/shared/src/test/scala/coursier/test/ParseTests.scala +++ b/modules/tests/shared/src/test/scala/coursier/test/ParseTests.scala @@ -1,9 +1,10 @@ package coursier.test -import coursier.{Attributes, MavenRepository, Repository} +import coursier.core.{Classifier, Type} +import coursier.{Attributes, MavenRepository, Repository, moduleNameString, organizationString} import coursier.ivy.IvyRepository import coursier.util.Parse -import coursier.util.Parse.{ModuleParseError, ModuleRequirements} +import coursier.util.Parse.ModuleRequirements import utest._ object ParseTests extends TestSuite { @@ -56,8 +57,8 @@ object ParseTests extends TestSuite { Parse.moduleVersionConfig("org.apache.avro:avro:1.7.4", ModuleRequirements(), transitive = true, "2.11.11") match { case Left(err) => assert(false) case Right((dep, _)) => - assert(dep.module.organization == "org.apache.avro") - assert(dep.module.name == "avro") + assert(dep.module.organization == org"org.apache.avro") + assert(dep.module.name == name"avro") assert(dep.version == "1.7.4") assert(dep.configuration == "default(compile)") assert(dep.attributes == Attributes()) @@ -68,8 +69,8 @@ object ParseTests extends TestSuite { Parse.moduleVersionConfig("org.apache.avro:avro:1.7.4:runtime", ModuleRequirements(), transitive = true, "2.11.11") match { case Left(err) => assert(false) case Right((dep, _)) => - assert(dep.module.organization == "org.apache.avro") - assert(dep.module.name == "avro") + assert(dep.module.organization == org"org.apache.avro") + assert(dep.module.name == name"avro") assert(dep.version == "1.7.4") assert(dep.configuration == "runtime") assert(dep.attributes == Attributes()) @@ -80,11 +81,11 @@ object ParseTests extends TestSuite { Parse.moduleVersionConfig("org.apache.avro:avro:1.7.4:runtime,classifier=tests", ModuleRequirements(), transitive = true, "2.11.11") match { case Left(err) => assert(false) case Right((dep, _)) => - assert(dep.module.organization == "org.apache.avro") - assert(dep.module.name == "avro") + assert(dep.module.organization == org"org.apache.avro") + assert(dep.module.name == name"avro") assert(dep.version == "1.7.4") assert(dep.configuration == "runtime") - assert(dep.attributes == Attributes("", "tests")) + assert(dep.attributes == Attributes(Type.empty, Classifier.tests)) } } @@ -92,11 +93,11 @@ object ParseTests extends TestSuite { Parse.moduleVersionConfig("org.apache.avro:avro:1.7.4:runtime,url=" + url, ModuleRequirements(), transitive = true, "2.11.11") match { case Left(err) => assert(false) case Right((dep, extraParams)) => - assert(dep.module.organization == "org.apache.avro") - assert(dep.module.name == "avro") + assert(dep.module.organization == org"org.apache.avro") + assert(dep.module.name == name"avro") assert(dep.version == "1.7.4") assert(dep.configuration == "runtime") - assert(dep.attributes == Attributes("", "")) + assert(dep.attributes == Attributes()) assert(extraParams.isDefinedAt("url")) assert(extraParams.getOrElse("url", "") == url) } @@ -106,11 +107,11 @@ object ParseTests extends TestSuite { Parse.moduleVersionConfig("org.apache.avro:avro:1.7.4:runtime,classifier=tests,url=" + url, ModuleRequirements(), transitive = true, "2.11.11") match { case Left(err) => assert(false) case Right((dep, extraParams)) => - assert(dep.module.organization == "org.apache.avro") - assert(dep.module.name == "avro") + assert(dep.module.organization == org"org.apache.avro") + assert(dep.module.name == name"avro") assert(dep.version == "1.7.4") assert(dep.configuration == "runtime") - assert(dep.attributes == Attributes("", "tests")) + assert(dep.attributes == Attributes(Type.empty, Classifier.tests)) assert(extraParams.isDefinedAt("url")) assert(extraParams.getOrElse("url", "") == url) } @@ -120,10 +121,10 @@ object ParseTests extends TestSuite { Parse.moduleVersionConfig("io.get-coursier.scala-native::sandbox_native0.3:0.3.0-coursier-1,classifier=tests", ModuleRequirements(), transitive = true, "2.11.11") match { case Left(err) => assert(false) case Right((dep, _)) => - assert(dep.module.organization == "io.get-coursier.scala-native") - assert(dep.module.name.contains("sandbox_native0.3")) // use `contains` to be scala version agnostic + assert(dep.module.organization == org"io.get-coursier.scala-native") + assert(dep.module.name.value.contains("sandbox_native0.3")) // use `contains` to be scala version agnostic assert(dep.version == "0.3.0-coursier-1") - assert(dep.attributes == Attributes("", "tests")) + assert(dep.attributes == Attributes(Type.empty, Classifier.tests)) } } diff --git a/modules/tests/shared/src/test/scala/coursier/test/PomParsingTests.scala b/modules/tests/shared/src/test/scala/coursier/test/PomParsingTests.scala index eec377c906..d203e4ebd5 100644 --- a/modules/tests/shared/src/test/scala/coursier/test/PomParsingTests.scala +++ b/modules/tests/shared/src/test/scala/coursier/test/PomParsingTests.scala @@ -1,6 +1,7 @@ package coursier package test +import coursier.core.Classifier import coursier.core.compatibility._ import coursier.util.Traverse.TraverseOps import coursier.maven.Pom @@ -21,9 +22,9 @@ object PomParsingTests extends TestSuite { val expected = Right( "" -> Dependency( - Module("comp", "lib"), + Module(org"comp", name"lib"), "2.1", - attributes = Attributes(classifier = "extra") + attributes = Attributes(classifier = Classifier("extra")) ) ) @@ -129,7 +130,7 @@ object PomParsingTests extends TestSuite { None, Profile.Activation(Nil), Seq( - "" -> Dependency(Module("comp", "lib"), "0.2")), + "" -> Dependency(Module(org"comp", name"lib"), "0.2")), Nil, Map.empty )) @@ -161,7 +162,7 @@ object PomParsingTests extends TestSuite { Profile.Activation(Nil), Nil, Seq( - "test" -> Dependency(Module("comp", "lib"), "0.2")), + "test" -> Dependency(Module(org"comp", name"lib"), "0.2")), Map.empty )) diff --git a/modules/tests/shared/src/test/scala/coursier/test/ResolutionTests.scala b/modules/tests/shared/src/test/scala/coursier/test/ResolutionTests.scala index f27e72c509..44be88ac9b 100644 --- a/modules/tests/shared/src/test/scala/coursier/test/ResolutionTests.scala +++ b/modules/tests/shared/src/test/scala/coursier/test/ResolutionTests.scala @@ -22,125 +22,125 @@ object ResolutionTests extends TestSuite { .future() implicit class ProjectOps(val p: Project) extends AnyVal { - def kv: (ModuleVersion, (Artifact.Source, Project)) = p.moduleVersion -> (testRepository.source, p) + def kv: (ModuleVersion, (Artifact.Source, Project)) = p.moduleVersion -> (testRepository, p) } val projects = Seq( - Project(Module("acme", "config"), "1.3.0"), + Project(Module(org"acme", name"config"), "1.3.0"), - Project(Module("acme", "play"), "2.4.0", Seq( - "" -> Dependency(Module("acme", "play-json"), "2.4.0"))), + Project(Module(org"acme", name"play"), "2.4.0", Seq( + "" -> Dependency(Module(org"acme", name"play-json"), "2.4.0"))), - Project(Module("acme", "play-json"), "2.4.0"), + Project(Module(org"acme", name"play-json"), "2.4.0"), - Project(Module("acme", "play"), "2.4.1", + Project(Module(org"acme", name"play"), "2.4.1", dependencies = Seq( - "" -> Dependency(Module("acme", "play-json"), "${play_json_version}"), - "" -> Dependency(Module("${project.groupId}", "${WithSpecialChar©}"), "1.3.0")), + "" -> Dependency(Module(org"acme", name"play-json"), "${play_json_version}"), + "" -> Dependency(Module(org"$${project.groupId}", name"$${WithSpecialChar©}"), "1.3.0")), properties = Seq( "play_json_version" -> "2.4.0", "WithSpecialChar©" -> "config")), - Project(Module("acme", "play-extra-no-config"), "2.4.1", + Project(Module(org"acme", name"play-extra-no-config"), "2.4.1", Seq( - "" -> Dependency(Module("acme", "play"), "2.4.1", - exclusions = Set(("acme", "config"))))), + "" -> Dependency(Module(org"acme", name"play"), "2.4.1", + exclusions = Set((org"acme", name"config"))))), - Project(Module("acme", "play-extra-no-config-no"), "2.4.1", + Project(Module(org"acme", name"play-extra-no-config-no"), "2.4.1", Seq( - "" -> Dependency(Module("acme", "play"), "2.4.1", - exclusions = Set(("*", "config"))))), + "" -> Dependency(Module(org"acme", name"play"), "2.4.1", + exclusions = Set((org"*", name"config"))))), - Project(Module("acme", "module-with-missing-pom"), "1.0.0", + Project(Module(org"acme", name"module-with-missing-pom"), "1.0.0", dependencyManagement = Seq( - "import" -> Dependency(Module("acme", "missing-pom"), "1.0.0"))), + "import" -> Dependency(Module(org"acme", name"missing-pom"), "1.0.0"))), - Project(Module("hudsucker", "mail"), "10.0", + Project(Module(org"hudsucker", name"mail"), "10.0", Seq( - "test" -> Dependency(Module("${project.groupId}", "test-util"), "${project.version}"))), + "test" -> Dependency(Module(org"$${project.groupId}", name"test-util"), "${project.version}"))), - Project(Module("hudsucker", "test-util"), "10.0"), + Project(Module(org"hudsucker", name"test-util"), "10.0"), - Project(Module("se.ikea", "parent"), "18.0", + Project(Module(org"se.ikea", name"parent"), "18.0", dependencyManagement = Seq( - "" -> Dependency(Module("acme", "play"), "2.4.0", - exclusions = Set(("acme", "play-json"))))), + "" -> Dependency(Module(org"acme", name"play"), "2.4.0", + exclusions = Set((org"acme", name"play-json"))))), - Project(Module("se.ikea", "billy"), "18.0", + Project(Module(org"se.ikea", name"billy"), "18.0", dependencies = Seq( - "" -> Dependency(Module("acme", "play"), "")), - parent = Some(Module("se.ikea", "parent"), "18.0")), + "" -> Dependency(Module(org"acme", name"play"), "")), + parent = Some(Module(org"se.ikea", name"parent"), "18.0")), - Project(Module("org.gnome", "parent"), "7.0", + Project(Module(org"org.gnome", name"parent"), "7.0", Seq( - "" -> Dependency(Module("org.gnu", "glib"), "13.4"))), + "" -> Dependency(Module(org"org.gnu", name"glib"), "13.4"))), - Project(Module("org.gnome", "panel-legacy"), "7.0", + Project(Module(org"org.gnome", name"panel-legacy"), "7.0", dependencies = Seq( - "" -> Dependency(Module("org.gnome", "desktop"), "${project.version}")), - parent = Some(Module("org.gnome", "parent"), "7.0")), + "" -> Dependency(Module(org"org.gnome", name"desktop"), "${project.version}")), + parent = Some(Module(org"org.gnome", name"parent"), "7.0")), - Project(Module("gov.nsa", "secure-pgp"), "10.0", + Project(Module(org"gov.nsa", name"secure-pgp"), "10.0", Seq( - "" -> Dependency(Module("gov.nsa", "crypto"), "536.89"))), + "" -> Dependency(Module(org"gov.nsa", name"crypto"), "536.89"))), - Project(Module("com.mailapp", "mail-client"), "2.1", + Project(Module(org"com.mailapp", name"mail-client"), "2.1", dependencies = Seq( - "" -> Dependency(Module("gov.nsa", "secure-pgp"), "10.0", - exclusions = Set(("*", "${crypto.name}")))), + "" -> Dependency(Module(org"gov.nsa", name"secure-pgp"), "10.0", + exclusions = Set((org"*", name"$${crypto.name}")))), properties = Seq("crypto.name" -> "crypto", "dummy" -> "2")), - Project(Module("com.thoughtworks.paranamer", "paranamer-parent"), "2.6", + Project(Module(org"com.thoughtworks.paranamer", name"paranamer-parent"), "2.6", dependencies = Seq( - "" -> Dependency(Module("junit", "junit"), "")), + "" -> Dependency(Module(org"junit", name"junit"), "")), dependencyManagement = Seq( - "test" -> Dependency(Module("junit", "junit"), "4.11"))), + "test" -> Dependency(Module(org"junit", name"junit"), "4.11"))), - Project(Module("com.thoughtworks.paranamer", "paranamer"), "2.6", - parent = Some(Module("com.thoughtworks.paranamer", "paranamer-parent"), "2.6")), + Project(Module(org"com.thoughtworks.paranamer", name"paranamer"), "2.6", + parent = Some(Module(org"com.thoughtworks.paranamer", name"paranamer-parent"), "2.6")), - Project(Module("com.github.dummy", "libb"), "0.3.3", + Project(Module(org"com.github.dummy", name"libb"), "0.3.3", profiles = Seq( Profile("default", activeByDefault = Some(true), dependencies = Seq( - "" -> Dependency(Module("org.escalier", "librairie-standard"), "2.11.6"))))), + "" -> Dependency(Module(org"org.escalier", name"librairie-standard"), "2.11.6"))))), - Project(Module("com.github.dummy", "libb"), "0.4.2", + Project(Module(org"com.github.dummy", name"libb"), "0.4.2", dependencies = Seq( - "" -> Dependency(Module("org.scalaverification", "scala-verification"), "1.12.4")), + "" -> Dependency(Module(org"org.scalaverification", name"scala-verification"), "1.12.4")), profiles = Seq( Profile("default", activeByDefault = Some(true), dependencies = Seq( - "" -> Dependency(Module("org.escalier", "librairie-standard"), "2.11.6"), - "test" -> Dependency(Module("org.scalaverification", "scala-verification"), "1.12.4"))))), + "" -> Dependency(Module(org"org.escalier", name"librairie-standard"), "2.11.6"), + "test" -> Dependency(Module(org"org.scalaverification", name"scala-verification"), "1.12.4"))))), - Project(Module("com.github.dummy", "libb"), "0.5.3", + Project(Module(org"com.github.dummy", name"libb"), "0.5.3", properties = Seq("special" -> "true"), profiles = Seq( Profile("default", activation = Profile.Activation(properties = Seq("special" -> None)), dependencies = Seq( - "" -> Dependency(Module("org.escalier", "librairie-standard"), "2.11.6"))))), + "" -> Dependency(Module(org"org.escalier", name"librairie-standard"), "2.11.6"))))), - Project(Module("com.github.dummy", "libb"), "0.5.4", + Project(Module(org"com.github.dummy", name"libb"), "0.5.4", properties = Seq("special" -> "true"), profiles = Seq( Profile("default", activation = Profile.Activation(properties = Seq("special" -> Some("true"))), dependencies = Seq( - "" -> Dependency(Module("org.escalier", "librairie-standard"), "2.11.6"))))), + "" -> Dependency(Module(org"org.escalier", name"librairie-standard"), "2.11.6"))))), - Project(Module("com.github.dummy", "libb"), "0.5.5", + Project(Module(org"com.github.dummy", name"libb"), "0.5.5", properties = Seq("special" -> "true"), profiles = Seq( Profile("default", activation = Profile.Activation(properties = Seq("special" -> Some("!false"))), dependencies = Seq( - "" -> Dependency(Module("org.escalier", "librairie-standard"), "2.11.6"))))), + "" -> Dependency(Module(org"org.escalier", name"librairie-standard"), "2.11.6"))))), - Project(Module("com.github.dummy", "libb-parent"), "0.5.6", + Project(Module(org"com.github.dummy", name"libb-parent"), "0.5.6", properties = Seq("special" -> "true")), - Project(Module("com.github.dummy", "libb"), "0.5.6", - parent = Some(Module("com.github.dummy", "libb-parent"), "0.5.6"), + Project(Module(org"com.github.dummy", name"libb"), "0.5.6", + parent = Some(Module(org"com.github.dummy", name"libb-parent"), "0.5.6"), properties = Seq("special" -> "true"), profiles = Seq( Profile("default", activation = Profile.Activation(properties = Seq("special" -> Some("!false"))), dependencies = Seq( - "" -> Dependency(Module("org.escalier", "librairie-standard"), "2.11.6"))))), + "" -> Dependency(Module(org"org.escalier", name"librairie-standard"), "2.11.6"))))), - Project(Module("com.github.dummy", "libb"), "0.5.7", + Project(Module(org"com.github.dummy", name"libb"), "0.5.7", // This project demonstrates a build profile that activates only when // the property "special" is unset. Because "special" is set to "true" // here, the build profile should not be active and "librairie-standard" @@ -153,9 +153,9 @@ object ResolutionTests extends TestSuite { properties = Seq("special" -> "true", "!special" -> "true"), profiles = Seq( Profile("default", activation = Profile.Activation(properties = Seq("!special" -> None)), dependencies = Seq( - "" -> Dependency(Module("org.escalier", "librairie-standard"), "2.11.6"))))), + "" -> Dependency(Module(org"org.escalier", name"librairie-standard"), "2.11.6"))))), - Project(Module("com.github.dummy", "libb"), "0.5.8", + Project(Module(org"com.github.dummy", name"libb"), "0.5.8", // This project demonstrates a build profile that activates only when // the property "special" is unset. Because that is the case here, // the "default" build profile should be active and "librairie-standard" @@ -168,36 +168,36 @@ object ResolutionTests extends TestSuite { properties = Seq("!special" -> "true"), profiles = Seq( Profile("default", activation = Profile.Activation(properties = Seq("!special" -> None)), dependencies = Seq( - "" -> Dependency(Module("org.escalier", "librairie-standard"), "2.11.6"))))), + "" -> Dependency(Module(org"org.escalier", name"librairie-standard"), "2.11.6"))))), - Project(Module("an-org", "a-name"), "1.0"), + Project(Module(org"an-org", name"a-name"), "1.0"), - Project(Module("an-org", "a-name"), "1.2"), + Project(Module(org"an-org", name"a-name"), "1.2"), - Project(Module("an-org", "a-lib"), "1.0", - Seq("" -> Dependency(Module("an-org", "a-name"), "1.0"))), + Project(Module(org"an-org", name"a-lib"), "1.0", + Seq("" -> Dependency(Module(org"an-org", name"a-name"), "1.0"))), - Project(Module("an-org", "a-lib"), "1.1"), + Project(Module(org"an-org", name"a-lib"), "1.1"), - Project(Module("an-org", "a-lib"), "1.2", - Seq("" -> Dependency(Module("an-org", "a-name"), "1.2"))), + Project(Module(org"an-org", name"a-lib"), "1.2", + Seq("" -> Dependency(Module(org"an-org", name"a-name"), "1.2"))), - Project(Module("an-org", "another-lib"), "1.0", - Seq("" -> Dependency(Module("an-org", "a-name"), "1.0"))), + Project(Module(org"an-org", name"another-lib"), "1.0", + Seq("" -> Dependency(Module(org"an-org", name"a-name"), "1.0"))), // Must bring transitively an-org:a-name, as an optional dependency - Project(Module("an-org", "an-app"), "1.0", + Project(Module(org"an-org", name"an-app"), "1.0", Seq( - "" -> Dependency(Module("an-org", "a-lib"), "1.0", exclusions = Set(("an-org", "a-name"))), - "" -> Dependency(Module("an-org", "another-lib"), "1.0", optional = true))), + "" -> Dependency(Module(org"an-org", name"a-lib"), "1.0", exclusions = Set((org"an-org", name"a-name"))), + "" -> Dependency(Module(org"an-org", name"another-lib"), "1.0", optional = true))), - Project(Module("an-org", "an-app"), "1.1", + Project(Module(org"an-org", name"an-app"), "1.1", Seq( - "" -> Dependency(Module("an-org", "a-lib"), "1.1"))), + "" -> Dependency(Module(org"an-org", name"a-lib"), "1.1"))), - Project(Module("an-org", "an-app"), "1.2", + Project(Module(org"an-org", name"an-app"), "1.2", Seq( - "" -> Dependency(Module("an-org", "a-lib"), "1.2"))) + "" -> Dependency(Module(org"an-org", name"a-lib"), "1.2"))) ) val projectsMap = projects.map(p => p.moduleVersion -> p.copy(configurations = MavenRepository.defaultConfigurations)).toMap @@ -219,7 +219,7 @@ object ResolutionTests extends TestSuite { } 'notFound{ async { - val dep = Dependency(Module("acme", "playy"), "2.4.0") + val dep = Dependency(Module(org"acme", name"playy"), "2.4.0") val res = await(resolve0( Set(dep) )) @@ -235,7 +235,7 @@ object ResolutionTests extends TestSuite { } 'missingPom{ async { - val dep = Dependency(Module("acme", "module-with-missing-pom"), "1.0.0") + val dep = Dependency(Module(org"acme", name"module-with-missing-pom"), "1.0.0") val res = await(resolve0( Set(dep) )) @@ -252,12 +252,12 @@ object ResolutionTests extends TestSuite { assert(directDependencyErrors.isEmpty) // metadataErrors have that - assert(res.errors == Seq((Module("acme", "missing-pom"), "1.0.0") -> List("Not found"))) + assert(res.errors == Seq((Module(org"acme", name"missing-pom"), "1.0.0") -> List("Not found"))) } } 'single{ async { - val dep = Dependency(Module("acme", "config"), "1.3.0") + val dep = Dependency(Module(org"acme", name"config"), "1.3.0") val res = await(resolve0( Set(dep) )).clearFinalDependenciesCache.clearProjectProperties @@ -265,7 +265,7 @@ object ResolutionTests extends TestSuite { val expected = Resolution( rootDependencies = Set(dep), dependencies = Set(dep.withCompileScope), - projectCache = Map(dep.moduleVersion -> (testRepository.source, projectsMap(dep.moduleVersion))) + projectCache = Map(dep.moduleVersion -> (testRepository, projectsMap(dep.moduleVersion))) ) assert(res == expected) @@ -273,8 +273,8 @@ object ResolutionTests extends TestSuite { } 'oneTransitiveDependency{ async { - val dep = Dependency(Module("acme", "play"), "2.4.0") - val trDep = Dependency(Module("acme", "play-json"), "2.4.0") + val dep = Dependency(Module(org"acme", name"play"), "2.4.0") + val trDep = Dependency(Module(org"acme", name"play-json"), "2.4.0") val res = await(resolve0( Set(dep) )).clearFinalDependenciesCache.clearProjectProperties @@ -293,10 +293,10 @@ object ResolutionTests extends TestSuite { } 'twoTransitiveDependencyWithProps{ async { - val dep = Dependency(Module("acme", "play"), "2.4.1") + val dep = Dependency(Module(org"acme", name"play"), "2.4.1") val trDeps = Seq( - Dependency(Module("acme", "play-json"), "2.4.0"), - Dependency(Module("acme", "config"), "1.3.0") + Dependency(Module(org"acme", name"play-json"), "2.4.0"), + Dependency(Module(org"acme", name"config"), "1.3.0") ) val res = await(resolve0( Set(dep) @@ -312,12 +312,12 @@ object ResolutionTests extends TestSuite { } 'exclude{ async { - val dep = Dependency(Module("acme", "play-extra-no-config"), "2.4.1") + val dep = Dependency(Module(org"acme", name"play-extra-no-config"), "2.4.1") val trDeps = Seq( - Dependency(Module("acme", "play"), "2.4.1", - exclusions = Set(("acme", "config"))), - Dependency(Module("acme", "play-json"), "2.4.0", - exclusions = Set(("acme", "config"))) + Dependency(Module(org"acme", name"play"), "2.4.1", + exclusions = Set((org"acme", name"config"))), + Dependency(Module(org"acme", name"play-json"), "2.4.0", + exclusions = Set((org"acme", name"config"))) ) val res = await(resolve0( Set(dep) @@ -333,12 +333,12 @@ object ResolutionTests extends TestSuite { } 'excludeOrgWildcard{ async { - val dep = Dependency(Module("acme", "play-extra-no-config-no"), "2.4.1") + val dep = Dependency(Module(org"acme", name"play-extra-no-config-no"), "2.4.1") val trDeps = Seq( - Dependency(Module("acme", "play"), "2.4.1", - exclusions = Set(("*", "config"))), - Dependency(Module("acme", "play-json"), "2.4.0", - exclusions = Set(("*", "config"))) + Dependency(Module(org"acme", name"play"), "2.4.1", + exclusions = Set((org"*", name"config"))), + Dependency(Module(org"acme", name"play-json"), "2.4.0", + exclusions = Set((org"*", name"config"))) ) val res = await(resolve0( Set(dep) @@ -354,7 +354,7 @@ object ResolutionTests extends TestSuite { } 'filter{ async { - val dep = Dependency(Module("hudsucker", "mail"), "10.0") + val dep = Dependency(Module(org"hudsucker", name"mail"), "10.0") val res = await(resolve0( Set(dep) )).clearCaches @@ -369,10 +369,10 @@ object ResolutionTests extends TestSuite { } 'parentDepMgmt{ async { - val dep = Dependency(Module("se.ikea", "billy"), "18.0") + val dep = Dependency(Module(org"se.ikea", name"billy"), "18.0") val trDeps = Seq( - Dependency(Module("acme", "play"), "2.4.0", - exclusions = Set(("acme", "play-json"))) + Dependency(Module(org"acme", name"play"), "2.4.0", + exclusions = Set((org"acme", name"play-json"))) ) val res = await(resolve0( Set(dep) @@ -388,10 +388,10 @@ object ResolutionTests extends TestSuite { } 'parentDependencies{ async { - val dep = Dependency(Module("org.gnome", "panel-legacy"), "7.0") + val dep = Dependency(Module(org"org.gnome", name"panel-legacy"), "7.0") val trDeps = Seq( - Dependency(Module("org.gnu", "glib"), "13.4"), - Dependency(Module("org.gnome", "desktop"), "7.0")) + Dependency(Module(org"org.gnu", name"glib"), "13.4"), + Dependency(Module(org"org.gnome", name"desktop"), "7.0")) val res = await(resolve0( Set(dep) )).clearCaches @@ -406,9 +406,9 @@ object ResolutionTests extends TestSuite { } 'propertiesInExclusions{ async { - val dep = Dependency(Module("com.mailapp", "mail-client"), "2.1") + val dep = Dependency(Module(org"com.mailapp", name"mail-client"), "2.1") val trDeps = Seq( - Dependency(Module("gov.nsa", "secure-pgp"), "10.0", exclusions = Set(("*", "crypto")))) + Dependency(Module(org"gov.nsa", name"secure-pgp"), "10.0", exclusions = Set((org"*", name"crypto")))) val res = await(resolve0( Set(dep) )).clearCaches @@ -423,7 +423,7 @@ object ResolutionTests extends TestSuite { } 'depMgmtInParentDeps{ async { - val dep = Dependency(Module("com.thoughtworks.paranamer", "paranamer"), "2.6") + val dep = Dependency(Module(org"com.thoughtworks.paranamer", name"paranamer"), "2.6") val res = await(resolve0( Set(dep) )).clearCaches @@ -438,9 +438,9 @@ object ResolutionTests extends TestSuite { } 'depsFromDefaultProfile{ async { - val dep = Dependency(Module("com.github.dummy", "libb"), "0.3.3") + val dep = Dependency(Module(org"com.github.dummy", name"libb"), "0.3.3") val trDeps = Seq( - Dependency(Module("org.escalier", "librairie-standard"), "2.11.6")) + Dependency(Module(org"org.escalier", name"librairie-standard"), "2.11.6")) val res = await(resolve0( Set(dep) )).clearCaches @@ -457,9 +457,9 @@ object ResolutionTests extends TestSuite { val f = for (version <- Seq("0.5.3", "0.5.4", "0.5.5", "0.5.6", "0.5.8")) yield { async { - val dep = Dependency(Module("com.github.dummy", "libb"), version) + val dep = Dependency(Module(org"com.github.dummy", name"libb"), version) val trDeps = Seq( - Dependency(Module("org.escalier", "librairie-standard"), "2.11.6")) + Dependency(Module(org"org.escalier", name"librairie-standard"), "2.11.6")) val res = await(resolve0( Set(dep) )).clearCaches @@ -486,7 +486,7 @@ object ResolutionTests extends TestSuite { // the "special" attribute set to "true", the transitive dependency // should not appear. async { - val dep = Dependency(Module("com.github.dummy", "libb"), "0.5.7") + val dep = Dependency(Module(org"com.github.dummy", name"libb"), "0.5.7") val res = await(resolve0( Set(dep) )).clearCaches @@ -502,9 +502,9 @@ object ResolutionTests extends TestSuite { 'depsScopeOverrideFromProfile{ async { // Like com.google.inject:guice:3.0 with org.sonatype.sisu.inject:cglib - val dep = Dependency(Module("com.github.dummy", "libb"), "0.4.2") + val dep = Dependency(Module(org"com.github.dummy", name"libb"), "0.4.2") val trDeps = Seq( - Dependency(Module("org.escalier", "librairie-standard"), "2.11.6")) + Dependency(Module(org"org.escalier", name"librairie-standard"), "2.11.6")) val res = await(resolve0( Set(dep) )).clearCaches @@ -520,11 +520,11 @@ object ResolutionTests extends TestSuite { 'exclusionsAndOptionalShouldGoAlong{ async { - val dep = Dependency(Module("an-org", "an-app"), "1.0") + val dep = Dependency(Module(org"an-org", name"an-app"), "1.0") val trDeps = Seq( - Dependency(Module("an-org", "a-lib"), "1.0", exclusions = Set(("an-org", "a-name"))), - Dependency(Module("an-org", "another-lib"), "1.0", optional = true), - Dependency(Module("an-org", "a-name"), "1.0", optional = true)) + Dependency(Module(org"an-org", name"a-lib"), "1.0", exclusions = Set((org"an-org", name"a-name"))), + Dependency(Module(org"an-org", name"another-lib"), "1.0", optional = true), + Dependency(Module(org"an-org", name"a-name"), "1.0", optional = true)) val res = await(resolve0( Set(dep), filter = Some(_ => true) @@ -542,12 +542,12 @@ object ResolutionTests extends TestSuite { 'exclusionsOfDependenciesFromDifferentPathsShouldNotCollide{ async { val deps = Set( - Dependency(Module("an-org", "an-app"), "1.0"), - Dependency(Module("an-org", "a-lib"), "1.0", optional = true)) + Dependency(Module(org"an-org", name"an-app"), "1.0"), + Dependency(Module(org"an-org", name"a-lib"), "1.0", optional = true)) val trDeps = Seq( - Dependency(Module("an-org", "a-lib"), "1.0", exclusions = Set(("an-org", "a-name"))), - Dependency(Module("an-org", "another-lib"), "1.0", optional = true), - Dependency(Module("an-org", "a-name"), "1.0", optional = true)) + Dependency(Module(org"an-org", name"a-lib"), "1.0", exclusions = Set((org"an-org", name"a-name"))), + Dependency(Module(org"an-org", name"another-lib"), "1.0", optional = true), + Dependency(Module(org"an-org", name"a-name"), "1.0", optional = true)) val res = await(resolve0( deps, filter = Some(_ => true) @@ -566,9 +566,9 @@ object ResolutionTests extends TestSuite { * - { async { val deps = Set( - Dependency(Module("an-org", "a-name"), "1.1")) + Dependency(Module(org"an-org", name"a-name"), "1.1")) val depOverrides = Map( - Module("an-org", "a-name") -> "1.0") + Module(org"an-org", name"a-name") -> "1.0") val res = await(resolve0( deps, @@ -578,7 +578,7 @@ object ResolutionTests extends TestSuite { val expected = Resolution( rootDependencies = deps, dependencies = Set( - Dependency(Module("an-org", "a-name"), "1.0") + Dependency(Module(org"an-org", name"a-name"), "1.0") ).map(_.withCompileScope), forceVersions = depOverrides ) @@ -590,9 +590,9 @@ object ResolutionTests extends TestSuite { * - { async { val deps = Set( - Dependency(Module("an-org", "an-app"), "1.1")) + Dependency(Module(org"an-org", name"an-app"), "1.1")) val depOverrides = Map( - Module("an-org", "a-lib") -> "1.0") + Module(org"an-org", name"a-lib") -> "1.0") val res = await(resolve0( deps, @@ -602,9 +602,9 @@ object ResolutionTests extends TestSuite { val expected = Resolution( rootDependencies = deps, dependencies = Set( - Dependency(Module("an-org", "an-app"), "1.1"), - Dependency(Module("an-org", "a-lib"), "1.0"), - Dependency(Module("an-org", "a-name"), "1.0") + Dependency(Module(org"an-org", name"an-app"), "1.1"), + Dependency(Module(org"an-org", name"a-lib"), "1.0"), + Dependency(Module(org"an-org", name"a-name"), "1.0") ).map(_.withCompileScope), forceVersions = depOverrides ) @@ -616,9 +616,9 @@ object ResolutionTests extends TestSuite { * - { async { val deps = Set( - Dependency(Module("an-org", "an-app"), "1.2")) + Dependency(Module(org"an-org", name"an-app"), "1.2")) val depOverrides = Map( - Module("an-org", "a-lib") -> "1.1") + Module(org"an-org", name"a-lib") -> "1.1") val res = await(resolve0( deps, @@ -628,8 +628,8 @@ object ResolutionTests extends TestSuite { val expected = Resolution( rootDependencies = deps, dependencies = Set( - Dependency(Module("an-org", "an-app"), "1.2"), - Dependency(Module("an-org", "a-lib"), "1.1") + Dependency(Module(org"an-org", name"an-app"), "1.2"), + Dependency(Module(org"an-org", name"a-lib"), "1.1") ).map(_.withCompileScope), forceVersions = depOverrides ) @@ -643,9 +643,9 @@ object ResolutionTests extends TestSuite { 'propertySubstitution{ val res = core.Resolution.withProperties( - Seq("" -> Dependency(Module("a-company", "a-name"), "${a.property}")), + Seq("" -> Dependency(Module(org"a-company", name"a-name"), "${a.property}")), Map("a.property" -> "a-version")) - val expected = Seq("" -> Dependency(Module("a-company", "a-name"), "a-version")) + val expected = Seq("" -> Dependency(Module(org"a-company", name"a-name"), "a-version")) assert(res == expected) } @@ -654,7 +654,7 @@ object ResolutionTests extends TestSuite { 'forcedProperties - { async { val deps = Set( - Dependency(Module("com.github.dummy", "libb"), "0.5.4") + Dependency(Module(org"com.github.dummy", name"libb"), "0.5.4") ) val forceProperties = Map( @@ -668,7 +668,7 @@ object ResolutionTests extends TestSuite { val expected = Resolution( rootDependencies = deps, dependencies = Set( - Dependency(Module("com.github.dummy", "libb"), "0.5.4") + Dependency(Module(org"com.github.dummy", name"libb"), "0.5.4") ).map(_.withCompileScope), forceProperties = forceProperties ) diff --git a/modules/tests/shared/src/test/scala/coursier/test/TestRepository.scala b/modules/tests/shared/src/test/scala/coursier/test/TestRepository.scala index 47284cee3a..e9ea387eff 100644 --- a/modules/tests/shared/src/test/scala/coursier/test/TestRepository.scala +++ b/modules/tests/shared/src/test/scala/coursier/test/TestRepository.scala @@ -5,13 +5,7 @@ import coursier.core._ import coursier.util.{EitherT, Monad} final case class TestRepository(projects: Map[(Module, String), Project]) extends Repository { - val source = new core.Artifact.Source { - def artifacts( - dependency: Dependency, - project: Project, - overrideClassifiers: Option[Seq[String]] - ) = ??? - } + def find[F[_]]( module: Module, version: String, @@ -21,7 +15,14 @@ final case class TestRepository(projects: Map[(Module, String), Project]) extend ) = EitherT( F.point( - projects.get((module, version)).map((source, _)).toRight("Not found") + projects.get((module, version)).map((this, _)).toRight("Not found") ) ) + + def artifacts( + dependency: Dependency, + project: Project, + overrideClassifiers: Option[Seq[Classifier]] + ) = ??? + } diff --git a/modules/tests/shared/src/test/scala/coursier/test/package.scala b/modules/tests/shared/src/test/scala/coursier/test/package.scala index 9ed9fc4790..f84eee13bd 100644 --- a/modules/tests/shared/src/test/scala/coursier/test/package.scala +++ b/modules/tests/shared/src/test/scala/coursier/test/package.scala @@ -1,5 +1,7 @@ package coursier +import coursier.core.Type + package object test { implicit class DependencyOps(val underlying: Dependency) extends AnyVal { @@ -91,7 +93,8 @@ package object test { profiles: Seq[Profile] = Seq.empty, versions: Option[core.Versions] = None, snapshotVersioning: Option[core.SnapshotVersioning] = None, - packaging: Option[String] = None, + packaging: Option[Type] = None, + relocated: Boolean = false, publications: Seq[(String, core.Publication)] = Nil ): Project = core.Project( @@ -105,8 +108,9 @@ package object test { profiles, versions, snapshotVersioning, - None, packaging, + relocated, + None, publications, Info.empty ) diff --git a/modules/tests/shared/src/test/scala/coursier/util/PrintTests.scala b/modules/tests/shared/src/test/scala/coursier/util/PrintTests.scala index 17abdee24b..463e83ba4e 100644 --- a/modules/tests/shared/src/test/scala/coursier/util/PrintTests.scala +++ b/modules/tests/shared/src/test/scala/coursier/util/PrintTests.scala @@ -1,8 +1,8 @@ package coursier.util -import coursier.core.Attributes +import coursier.core.{Attributes, Classifier, Type} import coursier.test.CentralTests -import coursier.{Dependency, Module} +import coursier.{Dependency, Module, moduleNameString, organizationString} import utest._ import scala.concurrent.ExecutionContext.Implicits.global @@ -23,13 +23,13 @@ object PrintTests extends TestSuite { val tests = Tests { 'ignoreAttributes - { val dep = Dependency( - Module("org", "name"), + Module(org"org", name"name"), "0.1", configuration = "foo" ) val deps = Seq( dep, - dep.copy(attributes = Attributes("fooz", "")) + dep.copy(attributes = Attributes(Type("fooz"), Classifier.empty)) ) val res = Print.dependenciesUnknownConfigs(deps, Map()) @@ -39,11 +39,11 @@ object PrintTests extends TestSuite { } 'reverseTree - { - val junit = Module("junit", "junit") + val junit = Module(org"junit", name"junit") val junitVersion = "4.10" CentralTests.resolve(Set(Dependency(junit, junitVersion))).map(result => { - val hamcrest = Module("org.hamcrest", "hamcrest-core") + val hamcrest = Module(org"org.hamcrest", name"hamcrest-core") val hamcrestVersion = "1.1" val reverseTree = Print.reverseTree(Seq(Dependency(hamcrest, hamcrestVersion)), result, withExclusions = true) diff --git a/modules/web/src/main/scala/coursier/web/App.scala b/modules/web/src/main/scala/coursier/web/App.scala index b74959ba0a..0ecc65b369 100644 --- a/modules/web/src/main/scala/coursier/web/App.scala +++ b/modules/web/src/main/scala/coursier/web/App.scala @@ -1,7 +1,7 @@ package coursier.web -import coursier.{Dependency, MavenRepository, Module, Resolution} -import coursier.maven.MavenSource +import coursier.core.{ModuleName, Organization, Type} +import coursier.{Dependency, MavenRepository, Module, Resolution, moduleNameString, organizationString} import japgolly.scalajs.react.vdom.{Attr, TagMod} import japgolly.scalajs.react.vdom.HtmlAttrs.dangerouslySetInnerHtml import japgolly.scalajs.react._ @@ -37,30 +37,30 @@ object App { def depItem(dep: Dependency, finalVersionOpt: Option[String]) = { <.tr( ^.`class` := (if (res.errorCache.contains(dep.moduleVersion)) "danger" else ""), - <.td(dep.module.organization), - <.td(dep.module.name), + <.td(dep.module.organization.value), + <.td(dep.module.name.value), <.td(finalVersionOpt.fold(dep.version)(finalVersion => s"$finalVersion (for ${dep.version})")), <.td(TagMod( if (dep.configuration == "compile") TagMod() else TagMod(infoLabel(dep.configuration)), - if (dep.attributes.`type`.isEmpty || dep.attributes.`type` == "jar") TagMod() else TagMod(infoLabel(dep.attributes.`type`)), - if (dep.attributes.classifier.isEmpty) TagMod() else TagMod(infoLabel(dep.attributes.classifier)), + if (dep.attributes.`type`.isEmpty || dep.attributes.`type` == Type.jar) TagMod() else TagMod(infoLabel(dep.attributes.`type`.value)), + if (dep.attributes.classifier.isEmpty) TagMod() else TagMod(infoLabel(dep.attributes.classifier.value)), Some(dep.exclusions).filter(_.nonEmpty).map(excls => infoPopOver("Exclusions", excls.toList.sorted.map{case (org, name) => s"$org:$name"}.mkString("; "))).toSeq.toTagMod, if (dep.optional) TagMod(infoLabel("optional")) else TagMod(), res.errorCache.get(dep.moduleVersion).map(errs => errorPopOver("Error", errs.mkString("; "))).toSeq.toTagMod )), <.td(TagMod( res.projectCache.get(dep.moduleVersion) match { - case Some((source: MavenSource, proj)) => + case Some((source: MavenRepository, proj)) => // FIXME Maven specific, generalize with source.artifacts val version0 = finalVersionOpt getOrElse dep.version val relPath = - dep.module.organization.split('.').toSeq ++ Seq( + dep.module.organization.value.split('.').toSeq ++ Seq( dep.module.name, version0, s"${dep.module.name}-$version0" ) - val root = source.root + val root = source.root.stripSuffix("/") + "/" TagMod( <.a(^.href := s"$root${relPath.mkString("/")}.pom", @@ -136,15 +136,15 @@ object App { <.div(^.`class` := "form-group", <.label(^.`for` := "inputOrganization", "Organization"), <.input(^.`class` := "form-control", ^.id := "inputOrganization", ^.placeholder := "Organization", - ^.onChange ==> backend.updateModule(moduleIdx, (dep, value) => dep.copy(module = dep.module.copy(organization = value))), - ^.value := module.organization + ^.onChange ==> backend.updateModule(moduleIdx, (dep, value) => dep.copy(module = dep.module.copy(organization = Organization(value)))), + ^.value := module.organization.value ) ), <.div(^.`class` := "form-group", <.label(^.`for` := "inputName", "Name"), <.input(^.`class` := "form-control", ^.id := "inputName", ^.placeholder := "Name", - ^.onChange ==> backend.updateModule(moduleIdx, (dep, value) => dep.copy(module = dep.module.copy(name = value))), - ^.value := module.name + ^.onChange ==> backend.updateModule(moduleIdx, (dep, value) => dep.copy(module = dep.module.copy(name = ModuleName(value)))), + ^.value := module.name.value ) ), <.div(^.`class` := "form-group", @@ -170,8 +170,8 @@ object App { def depItem(dep: Dependency, idx: Int) = <.tr( - <.td(dep.module.organization), - <.td(dep.module.name), + <.td(dep.module.organization.value), + <.td(dep.module.name.value), <.td(dep.version), <.td( <.a(Attr("data-toggle") := "modal", Attr("data-target") := "#moduleEdit", ^.`class` := "icon-action", @@ -216,7 +216,7 @@ object App { moduleEditModal(( deps .lift(editModuleIdx) - .fold(Module("", "") -> "")(_.moduleVersion), + .fold(Module(org"", name"") -> "")(_.moduleVersion), editModuleIdx, backend )) @@ -375,7 +375,7 @@ object App { val initialState = State( List( - Dependency(Module("io.get-coursier", "coursier-cache_2.12"), "1.1.0-M7") // DEBUG + Dependency(Module(org"io.get-coursier", name"coursier-cache_2.12"), "1.1.0-M7") // DEBUG ), Seq("central" -> MavenRepository("https://repo1.maven.org/maven2")), ResolutionOptions(), diff --git a/modules/web/src/main/scala/coursier/web/Backend.scala b/modules/web/src/main/scala/coursier/web/Backend.scala index 53c072d8eb..e15195e580 100644 --- a/modules/web/src/main/scala/coursier/web/Backend.scala +++ b/modules/web/src/main/scala/coursier/web/Backend.scala @@ -1,7 +1,6 @@ package coursier.web -import coursier.{Dependency, Fetch, MavenRepository, Module, Platform, Repository, Resolution} -import coursier.maven.MavenSource +import coursier.{Dependency, Fetch, MavenRepository, Module, Platform, Repository, Resolution, moduleNameString, organizationString} import coursier.util.{EitherT, Gather, Task} import japgolly.scalajs.react._ import org.scalajs.dom @@ -254,7 +253,7 @@ final class Backend($: BackendScope[_, State]) { def addModule(e: raw.SyntheticEvent[_]) = { e.preventDefault() $.modState { state => - val modules = state.modules :+ Dependency(Module("", ""), "") + val modules = state.modules :+ Dependency(Module(org"", name""), "") println(s"Modules:\n${modules.mkString("\n")}") state.copy( modules = modules, diff --git a/project/Deps.scala b/project/Deps.scala index ba99d43e06..e8ff90e054 100644 --- a/project/Deps.scala +++ b/project/Deps.scala @@ -1,5 +1,6 @@ import sbt._ +import sbt.Def.setting import sbt.Defaults.sbtPluginExtra import sbt.Keys._ @@ -40,4 +41,6 @@ object Deps { def scalaNativeUtil = "org.scala-native" %% "util" % SharedVersions.scalaNative def slf4JNop = "org.slf4j" % "slf4j-nop" % "1.7.25" + + def scalaReflect = setting("org.scala-lang" % "scala-reflect" % scalaVersion.value) }