diff --git a/.ci/travis.sh b/.ci/travis.sh index d9d91e885..bff111d15 100755 --- a/.ci/travis.sh +++ b/.ci/travis.sh @@ -48,7 +48,7 @@ if echo "$TRAVIS_SCALA_VERSION" | grep -q "^2\.10"; then SBT_COMMANDS="$SBT_COMMANDS plugin/scripted" fi -SBT_COMMANDS="$SBT_COMMANDS coreJVM/mimaReportBinaryIssues cache/mimaReportBinaryIssues" +SBT_COMMANDS="$SBT_COMMANDS tut coreJVM/mimaReportBinaryIssues cache/mimaReportBinaryIssues" if isNotPr && publish && isMaster; then SBT_COMMANDS="$SBT_COMMANDS publish" diff --git a/README.md b/README.md index 898ac51d9..45fdebcac 100644 --- a/README.md +++ b/README.md @@ -447,7 +447,7 @@ scala> val repositories = Seq( | Cache.ivy2Local, | MavenRepository("https://repo1.maven.org/maven2") | ) -repositories: Seq[coursier.core.Repository] = List(IvyRepository(file://${user.home}/.ivy2/local/[organisation]/[module]/(scala_[scalaVersion]/)(sbt_[sbtVersion]/)[revision]/[type]s/[artifact](-[classifier]).[ext],None,None,Map(),true,true,true,true,None), MavenRepository(https://repo1.maven.org/maven2,None,false,None)) +repositories: Seq[coursier.core.Repository] = List(IvyRepository(Pattern(List(Const(file://), Var(user.home), Const(/local/), Var(organisation), Const(/), Var(module), Const(/), Opt(WrappedArray(Const(scala_), Var(scalaVersion), Const(/))), Opt(WrappedArray(Const(sbt_), Var(sbtVersion), Const(/))), Var(revision), Const(/), Var(type), Const(s/), Var(artifact), Opt(WrappedArray(Const(-), Var(classifier))), Const(.), Var(ext))),None,None,true,true,true,true,None), MavenRepository(https://repo1.maven.org/maven2,None,false,None)) ``` The first one, `Cache.ivy2Local`, is defined in `coursier.Cache`, itself from the `coursier-cache` module that we added above. As we can see, it is an `IvyRepository`, picking things under `~/.ivy2/local`. An `IvyRepository` @@ -554,6 +554,8 @@ We're using the `Cache.file` method, that can also be given a `Logger` (for more #### Inter-project repository in the SBT plugin is a bit naive +**Fixed in 1.0.0-M13** + The inter-project repository is the pseudo-repository, nesting the metadata of sub-projects. It gets confused in at least these two cases: diff --git a/build.sbt b/build.sbt index 827671710..4a590b795 100644 --- a/build.sbt +++ b/build.sbt @@ -148,6 +148,14 @@ lazy val core = crossProject Seq( // Since 1.0.0-M13 + // reworked VersionConstraint + ProblemFilters.exclude[MissingClassProblem]("coursier.core.VersionConstraint$Interval"), + ProblemFilters.exclude[MissingClassProblem]("coursier.core.VersionConstraint$Preferred"), + ProblemFilters.exclude[MissingClassProblem]("coursier.core.VersionConstraint$Preferred$"), + ProblemFilters.exclude[MissingClassProblem]("coursier.core.VersionConstraint$Interval$"), + ProblemFilters.exclude[FinalClassProblem]("coursier.core.VersionConstraint"), + ProblemFilters.exclude[IncompatibleResultTypeProblem]("coursier.core.VersionConstraint.repr"), + ProblemFilters.exclude[IncompatibleMethTypeProblem]("coursier.core.VersionConstraint.this"), // Extra `actualVersion` field in `Project` ProblemFilters.exclude[MissingTypesProblem]("coursier.core.Project$"), ProblemFilters.exclude[MissingMethodProblem]("coursier.core.Project.apply"), diff --git a/cli/src/main/scala-2.11/coursier/cli/Bootstrap.scala b/cli/src/main/scala-2.11/coursier/cli/Bootstrap.scala index fa28ff693..024d87eef 100644 --- a/cli/src/main/scala-2.11/coursier/cli/Bootstrap.scala +++ b/cli/src/main/scala-2.11/coursier/cli/Bootstrap.scala @@ -75,10 +75,12 @@ case class Bootstrap( val helper = new Helper(options.common, remainingArgs) + val isolatedDeps = options.isolated.isolatedDeps(options.common.defaultArtifactType) + val (_, isolatedArtifactFiles) = options.isolated.targets.foldLeft((Vector.empty[String], Map.empty[String, (Seq[String], Seq[File])])) { case ((done, acc), target) => - val subRes = helper.res.subset(options.isolated.isolatedDeps.getOrElse(target, Nil).toSet) + val subRes = helper.res.subset(isolatedDeps.getOrElse(target, Nil).toSet) val subArtifacts = subRes.artifacts.map(_.url) val filteredSubArtifacts = subArtifacts.diff(done) @@ -86,7 +88,7 @@ case class Bootstrap( def subFiles0 = helper.fetch( sources = false, javadoc = false, - subset = options.isolated.isolatedDeps.getOrElse(target, Seq.empty).toSet + subset = isolatedDeps.getOrElse(target, Seq.empty).toSet ) val (subUrls, subFiles) = diff --git a/cli/src/main/scala-2.11/coursier/cli/Helper.scala b/cli/src/main/scala-2.11/coursier/cli/Helper.scala index 571885178..cee03e086 100644 --- a/cli/src/main/scala-2.11/coursier/cli/Helper.scala +++ b/cli/src/main/scala-2.11/coursier/cli/Helper.scala @@ -244,6 +244,7 @@ class Helper( Dependency( module, version, + attributes = Attributes(defaultArtifactType, ""), configuration = configOpt.getOrElse(defaultConfiguration), exclusions = excludes ) @@ -254,6 +255,7 @@ class Helper( Dependency( module, version, + attributes = Attributes(defaultArtifactType, ""), configuration = configOpt.getOrElse(defaultConfiguration), exclusions = excludes, transitive = false diff --git a/cli/src/main/scala-2.11/coursier/cli/Launch.scala b/cli/src/main/scala-2.11/coursier/cli/Launch.scala index 76261243c..8b73ed099 100644 --- a/cli/src/main/scala-2.11/coursier/cli/Launch.scala +++ b/cli/src/main/scala-2.11/coursier/cli/Launch.scala @@ -104,6 +104,9 @@ case class Launch( if (options.isolated.isolated.isEmpty) (parentLoader0, files0) else { + + val isolatedDeps = options.isolated.isolatedDeps(options.common.defaultArtifactType) + val (isolatedLoader, filteredFiles0) = options.isolated.targets.foldLeft((parentLoader0, files0)) { case ((parent, files0), target) => @@ -111,7 +114,7 @@ case class Launch( val isolatedFiles = helper.fetch( sources = false, javadoc = false, - subset = options.isolated.isolatedDeps.getOrElse(target, Seq.empty).toSet + subset = isolatedDeps.getOrElse(target, Seq.empty).toSet ) if (options.common.verbosityLevel >= 2) { @@ -199,6 +202,7 @@ case class Launch( Helper.errPrintln(s"Error: method main not found in $mainClass0") sys.exit(255) } + method.setAccessible(true) if (options.common.verbosityLevel >= 2) Helper.errPrintln(s"Launching $mainClass0 ${userArgs.mkString(" ")}") @@ -206,5 +210,9 @@ case class Launch( Helper.errPrintln(s"Launching") Thread.currentThread().setContextClassLoader(loader) - method.invoke(null, userArgs.toArray) + try method.invoke(null, userArgs.toArray) + catch { + case e: java.lang.reflect.InvocationTargetException => + throw Option(e.getCause).getOrElse(e) + } } \ No newline at end of file diff --git a/cli/src/main/scala-2.11/coursier/cli/Options.scala b/cli/src/main/scala-2.11/coursier/cli/Options.scala index 4fa545714..905368710 100644 --- a/cli/src/main/scala-2.11/coursier/cli/Options.scala +++ b/cli/src/main/scala-2.11/coursier/cli/Options.scala @@ -58,6 +58,10 @@ case class CommonOptions( @Value("configuration") @Short("c") defaultConfiguration: String = "default(compile)", + @Help("Default artifact type (make it empty to follow POM packaging - default: jar)") + @Value("type") + @Short("a") + defaultArtifactType: String = "jar", @Help("Maximum number of parallel downloads (default: 6)") @Short("n") parallel: Int = 6, @@ -145,13 +149,19 @@ case class IsolatedLoaderOptions( t -> modVers } - lazy val isolatedDeps = isolatedModuleVersions.map { - case (t, l) => - t -> l.map { - case (mod, ver) => - Dependency(mod, ver, configuration = "runtime") - } - } + def isolatedDeps(defaultArtifactType: String) = + isolatedModuleVersions.map { + case (t, l) => + t -> l.map { + case (mod, ver) => + Dependency( + mod, + ver, + configuration = "runtime", + attributes = Attributes(defaultArtifactType, "") + ) + } + } } diff --git a/core/shared/src/main/scala/coursier/core/Parse.scala b/core/shared/src/main/scala/coursier/core/Parse.scala index 8465ca05c..83bcabd6e 100644 --- a/core/shared/src/main/scala/coursier/core/Parse.scala +++ b/core/shared/src/main/scala/coursier/core/Parse.scala @@ -43,12 +43,12 @@ object Parse { } def versionConstraint(s: String): Option[VersionConstraint] = { - def noConstraint = if (s.isEmpty) Some(VersionConstraint.None) else None + def noConstraint = if (s.isEmpty) Some(VersionConstraint.all) else None noConstraint - .orElse(ivyLatestSubRevisionInterval(s).map(VersionConstraint.Interval)) - .orElse(version(s).map(VersionConstraint.Preferred)) - .orElse(versionInterval(s).map(VersionConstraint.Interval)) + .orElse(ivyLatestSubRevisionInterval(s).map(VersionConstraint.interval)) + .orElse(version(s).map(VersionConstraint.preferred)) + .orElse(versionInterval(s).map(VersionConstraint.interval)) } val fallbackConfigRegex = { diff --git a/core/shared/src/main/scala/coursier/core/Resolution.scala b/core/shared/src/main/scala/coursier/core/Resolution.scala index 5241a3335..f2ee7e0ec 100644 --- a/core/shared/src/main/scala/coursier/core/Resolution.scala +++ b/core/shared/src/main/scala/coursier/core/Resolution.scala @@ -140,25 +140,26 @@ object Resolution { * Returns `None` in case of conflict. */ def mergeVersions(versions: Seq[String]): Option[String] = { - val (nonParsedConstraints, parsedConstraints) = - versions - .map(v => v -> Parse.versionConstraint(v)) - .partition(_._2.isEmpty) + + val parseResults = versions.map(v => v -> Parse.versionConstraint(v)) + + val nonParsedConstraints = parseResults.collect { + case (repr, None) => repr + } // FIXME Report this in return type, not this way if (nonParsedConstraints.nonEmpty) Console.err.println( - s"Ignoring unparsed versions: ${nonParsedConstraints.map(_._1)}" + s"Ignoring unparsed versions: $nonParsedConstraints" ) - val intervalOpt = - (Option(VersionInterval.zero) /: parsedConstraints) { - case (acc, (_, someCstr)) => - acc.flatMap(_.merge(someCstr.get.interval)) - } + val parsedConstraints = parseResults.collect { + case (_, Some(c)) => c + } - intervalOpt - .map(_.constraint.repr) + VersionConstraint + .merge(parsedConstraints: _*) + .flatMap(_.repr) } /** diff --git a/core/shared/src/main/scala/coursier/core/Versions.scala b/core/shared/src/main/scala/coursier/core/Versions.scala index 5398f262c..d59ecfec9 100644 --- a/core/shared/src/main/scala/coursier/core/Versions.scala +++ b/core/shared/src/main/scala/coursier/core/Versions.scala @@ -1,5 +1,8 @@ package coursier.core +import scalaz.{ -\/, \/, \/- } +import scalaz.Scalaz.ToEitherOps + case class VersionInterval(from: Option[Version], to: Option[Version], fromIncluded: Boolean, @@ -64,9 +67,9 @@ case class VersionInterval(from: Option[Version], def constraint: VersionConstraint = this match { - case VersionInterval.zero => VersionConstraint.None - case VersionInterval(Some(version), None, true, false) => VersionConstraint.Preferred(version) - case itv => VersionConstraint.Interval(itv) + case VersionInterval.zero => VersionConstraint.all + case VersionInterval(Some(version), None, true, false) => VersionConstraint.preferred(version) + case itv => VersionConstraint.interval(itv) } def repr: String = Seq( @@ -82,23 +85,54 @@ object VersionInterval { val zero = VersionInterval(None, None, fromIncluded = false, toIncluded = false) } -sealed abstract class VersionConstraint( - val interval: VersionInterval, - val repr: String -) +final case class VersionConstraint( + interval: VersionInterval, + preferred: Seq[Version] +) { + def blend: Option[VersionInterval \/ Version] = + if (interval.isValid) { + val preferredInInterval = preferred.filter(interval.contains) + + if (preferredInInterval.isEmpty) + Some(interval.left) + else + Some(preferredInInterval.max.right) + } else + None + + def repr: Option[String] = + blend.map { + case -\/(itv) => + if (itv == VersionInterval.zero) + "" + else + itv.repr + case \/-(v) => v.repr + } +} object VersionConstraint { - /** Currently treated as minimum... */ - final case class Preferred(version: Version) extends VersionConstraint( - VersionInterval(Some(version), Option.empty, fromIncluded = true, toIncluded = false), - version.repr - ) - final case class Interval(interval0: VersionInterval) extends VersionConstraint( - interval0, - interval0.repr - ) - case object None extends VersionConstraint( - VersionInterval.zero, - "" // Once parsed, "(,)" becomes "" because of this - ) + + def preferred(version: Version): VersionConstraint = + VersionConstraint(VersionInterval.zero, Seq(version)) + def interval(interval: VersionInterval): VersionConstraint = + VersionConstraint(interval, Nil) + + val all = VersionConstraint(VersionInterval.zero, Nil) + + def merge(constraints: VersionConstraint*): Option[VersionConstraint] = { + + val intervals = constraints.map(_.interval) + + val intervalOpt = + (Option(VersionInterval.zero) /: intervals) { + case (acc, itv) => + acc.flatMap(_.merge(itv)) + } + + for (interval <- intervalOpt) yield { + val preferreds = constraints.flatMap(_.preferred).distinct + VersionConstraint(interval, preferreds) + } + } } diff --git a/core/shared/src/main/scala/coursier/maven/MavenRepository.scala b/core/shared/src/main/scala/coursier/maven/MavenRepository.scala index dc3267a74..9cdf9982e 100644 --- a/core/shared/src/main/scala/coursier/maven/MavenRepository.scala +++ b/core/shared/src/main/scala/coursier/maven/MavenRepository.scala @@ -48,7 +48,12 @@ object MavenRepository { val defaultPackaging = "jar" def defaultPublications(moduleName: String, packaging: String) = Seq( - "compile" -> Publication(moduleName, packaging, MavenSource.typeExtension(packaging), ""), + "compile" -> Publication( + moduleName, + packaging, + MavenSource.typeExtension(packaging), + MavenSource.typeDefaultClassifier(packaging) + ), "docs" -> Publication(moduleName, "doc", "jar", "javadoc"), "sources" -> Publication(moduleName, "src", "jar", "sources") ) diff --git a/core/shared/src/main/scala/coursier/maven/MavenSource.scala b/core/shared/src/main/scala/coursier/maven/MavenSource.scala index 4a020eaed..fd3c60145 100644 --- a/core/shared/src/main/scala/coursier/maven/MavenSource.scala +++ b/core/shared/src/main/scala/coursier/maven/MavenSource.scala @@ -136,12 +136,20 @@ case class MavenSource( if (publications.isEmpty) { val type0 = if (dependency.attributes.`type`.isEmpty) "jar" else dependency.attributes.`type` + val extension = MavenSource.typeExtension(type0) + + val classifier = + if (dependency.attributes.classifier.isEmpty) + MavenSource.typeDefaultClassifier(type0) + else + dependency.attributes.classifier + Seq( Publication( dependency.module.name, type0, - MavenSource.typeExtension(type0), - dependency.attributes.classifier + extension, + classifier ) ) } else @@ -163,10 +171,27 @@ object MavenSource { "jar" -> "jar", "bundle" -> "jar", "doc" -> "jar", - "src" -> "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/alexarchambault/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("") + } \ No newline at end of file diff --git a/core/shared/src/main/scala/coursier/package.scala b/core/shared/src/main/scala/coursier/package.scala index e663aba10..32a0adb63 100644 --- a/core/shared/src/main/scala/coursier/package.scala +++ b/core/shared/src/main/scala/coursier/package.scala @@ -11,7 +11,7 @@ package object coursier { version: String, // Substituted by Resolver with its own default configuration (compile) configuration: String = "", - attributes: Attributes = Attributes(), + attributes: Attributes = Attributes("jar"), exclusions: Set[(String, String)] = Set.empty, optional: Boolean = false, transitive: Boolean = true diff --git a/core/shared/src/main/scala/coursier/util/Parse.scala b/core/shared/src/main/scala/coursier/util/Parse.scala index 25ba942ce..14a79d052 100644 --- a/core/shared/src/main/scala/coursier/util/Parse.scala +++ b/core/shared/src/main/scala/coursier/util/Parse.scala @@ -136,7 +136,7 @@ object Parse { else if (s.startsWith("sonatype:")) MavenRepository(s"https://oss.sonatype.org/content/repositories/${s.stripPrefix("sonatype:")}").right else if (s.startsWith("bintray:")) - MavenRepository(s"https://dl.bintray.com/${s.stripPrefix("bintray:")}/maven").right + MavenRepository(s"https://dl.bintray.com/${s.stripPrefix("bintray:")}").right else if (s.startsWith("typesafe:ivy-")) IvyRepository.fromPattern( (s"https://repo.typesafe.com/typesafe/ivy-" + s.stripPrefix("typesafe:ivy-") + "/") +: diff --git a/doc/README.md b/doc/README.md index d5aafe0b1..273910e87 100644 --- a/doc/README.md +++ b/doc/README.md @@ -135,8 +135,13 @@ object Cache { // but it would then have required properties, which would have cluttered // output here. - val ivy2Local = coursier.Cache.ivy2Local.copy( - pattern = coursier.Cache.ivy2Local.pattern.replace("file:" + sys.props("user.home"), "file://${user.home}") + import coursier.ivy.Pattern.Chunk, Chunk._ + + val ivy2Local = coursier.ivy.IvyRepository.fromPattern( + coursier.ivy.Pattern( + Seq[Chunk]("file://", Var("user.home"), "/local/") ++ coursier.ivy.Pattern.default.chunks + ), + dropInfoAttributes = true ) def fetch() = coursier.Cache.fetch() @@ -576,6 +581,8 @@ We're using the `Cache.file` method, that can also be given a `Logger` (for more #### Inter-project repository in the SBT plugin is a bit naive +**Fixed in 1.0.0-M13** + The inter-project repository is the pseudo-repository, nesting the metadata of sub-projects. It gets confused in at least these two cases: diff --git a/plugin/src/main/scala-2.10/coursier/CoursierPlugin.scala b/plugin/src/main/scala-2.10/coursier/CoursierPlugin.scala index 521f5d3bd..745848d75 100644 --- a/plugin/src/main/scala-2.10/coursier/CoursierPlugin.scala +++ b/plugin/src/main/scala-2.10/coursier/CoursierPlugin.scala @@ -26,7 +26,7 @@ object CoursierPlugin extends AutoPlugin { val coursierFallbackDependencies = Keys.coursierFallbackDependencies val coursierCache = Keys.coursierCache val coursierProject = Keys.coursierProject - val coursierProjects = Keys.coursierProjects + val coursierInterProjectDependencies = Keys.coursierInterProjectDependencies val coursierPublications = Keys.coursierPublications val coursierSbtClassifiersModule = Keys.coursierSbtClassifiersModule @@ -67,7 +67,7 @@ object CoursierPlugin extends AutoPlugin { coursierSourceRepositories := Nil, coursierResolvers <<= Tasks.coursierResolversTask, coursierSbtResolvers <<= externalResolvers in updateSbtClassifiers, - coursierUseSbtCredentials := true, + coursierUseSbtCredentials := false, coursierCredentials := Map.empty, coursierFallbackDependencies <<= Tasks.coursierFallbackDependenciesTask, coursierCache := Cache.default, @@ -82,7 +82,7 @@ object CoursierPlugin extends AutoPlugin { ignoreArtifactErrors = true ), coursierProject <<= Tasks.coursierProjectTask, - coursierProjects <<= Tasks.coursierProjectsTask, + coursierInterProjectDependencies <<= Tasks.coursierInterProjectDependenciesTask, coursierPublications <<= Tasks.coursierPublicationsTask, coursierSbtClassifiersModule <<= classifiersModule in updateSbtClassifiers, coursierConfigurations <<= Tasks.coursierConfigurationsTask, diff --git a/plugin/src/main/scala-2.10/coursier/Keys.scala b/plugin/src/main/scala-2.10/coursier/Keys.scala index 3aa4a297c..49d89be75 100644 --- a/plugin/src/main/scala-2.10/coursier/Keys.scala +++ b/plugin/src/main/scala-2.10/coursier/Keys.scala @@ -31,7 +31,7 @@ object Keys { val coursierFallbackDependencies = TaskKey[Seq[(Module, String, URL, Boolean)]]("coursier-fallback-dependencies") val coursierProject = TaskKey[Project]("coursier-project") - val coursierProjects = TaskKey[Seq[Project]]("coursier-projects") + val coursierInterProjectDependencies = TaskKey[Seq[Project]]("coursier-inter-project-dependencies", "Projects the current project depends on, possibly transitively") val coursierPublications = TaskKey[Seq[(String, Publication)]]("coursier-publications") val coursierSbtClassifiersModule = TaskKey[GetClassifiersModule]("coursier-sbt-classifiers-module") diff --git a/plugin/src/main/scala-2.10/coursier/Tasks.scala b/plugin/src/main/scala-2.10/coursier/Tasks.scala index 9e0246c7d..d563814fd 100644 --- a/plugin/src/main/scala-2.10/coursier/Tasks.scala +++ b/plugin/src/main/scala-2.10/coursier/Tasks.scala @@ -96,9 +96,32 @@ object Tasks { } } - def coursierProjectsTask: Def.Initialize[sbt.Task[Seq[Project]]] = - sbt.Keys.state.flatMap { state => - val projects = structure(state).allProjectRefs + def coursierInterProjectDependenciesTask: Def.Initialize[sbt.Task[Seq[Project]]] = + ( + sbt.Keys.state, + sbt.Keys.thisProjectRef + ).flatMap { (state, projectRef) => + + def dependencies(map: Map[String, Seq[String]], id: String): Set[String] = { + + def helper(map: Map[String, Seq[String]], acc: Set[String]): Set[String] = + if (acc.exists(map.contains)) { + val (kept, rem) = map.partition { case (k, _) => acc(k) } + helper(rem, acc ++ kept.valuesIterator.flatten) + } else + acc + + helper(map - id, map.getOrElse(id, Nil).toSet) + } + + val allProjectsDeps = + for (p <- structure(state).allProjects) + yield p.id -> p.dependencies.map(_.project.project) + + val deps = dependencies(allProjectsDeps.toMap, projectRef.project) + + val projects = structure(state).allProjectRefs.filter(p => deps(p.project)) + coursierProject.forAllProjects(state, projects).map(_.values.toVector) } @@ -271,7 +294,7 @@ object Tasks { (proj.copy(publications = publications), fallbackDeps) } - val projects = coursierProjects.value + val interProjectDependencies = coursierInterProjectDependencies.value val parallelDownloads = coursierParallelDownloads.value val checksums = coursierChecksums.value @@ -363,12 +386,12 @@ object Tasks { userForceVersions ++ sourceRepositoriesForcedDependencies ++ forcedScalaModules(so, sv) ++ - projects.map(_.moduleVersion) + interProjectDependencies.map(_.moduleVersion) ) if (verbosityLevel >= 2) { log.info("InterProjectRepository") - for (p <- projects) + for (p <- interProjectDependencies) log.info(s" ${p.module}:${p.version}") } @@ -380,7 +403,7 @@ object Tasks { withArtifacts = false ) - val interProjectRepo = InterProjectRepository(projects) + val interProjectRepo = InterProjectRepository(interProjectDependencies) val ivyProperties = Map( "ivy.home" -> (new File(sys.props("user.home")).toURI.getPath + ".ivy2") diff --git a/plugin/src/main/scala-2.10/coursier/ToSbt.scala b/plugin/src/main/scala-2.10/coursier/ToSbt.scala index df6e4ebc9..b29eb8156 100644 --- a/plugin/src/main/scala-2.10/coursier/ToSbt.scala +++ b/plugin/src/main/scala-2.10/coursier/ToSbt.scala @@ -23,7 +23,9 @@ object ToSbt { // FIXME Get these two from publications artifact.attributes.`type`, MavenSource.typeExtension(artifact.attributes.`type`), - Some(artifact.attributes.classifier).filter(_.nonEmpty), + Some(artifact.attributes.classifier) + .filter(_.nonEmpty) + .orElse(MavenSource.typeDefaultClassifierOpt(artifact.attributes.`type`)), Nil, Some(url(artifact.url)), Map.empty diff --git a/plugin/src/sbt-test/sbt-coursier/credentials-sbt/build.sbt b/plugin/src/sbt-test/sbt-coursier/credentials-sbt/build.sbt index 132e5248f..c8c8c3668 100644 --- a/plugin/src/sbt-test/sbt-coursier/credentials-sbt/build.sbt +++ b/plugin/src/sbt-test/sbt-coursier/credentials-sbt/build.sbt @@ -2,6 +2,7 @@ scalaVersion := "2.11.8" resolvers += "authenticated" at "http://localhost:8080" +coursierUseSbtCredentials := true credentials += Credentials("", "localhost", "user", "pass") coursierCachePolicies := { diff --git a/plugin/src/sbt-test/sbt-coursier/hadoop-yarn-server-resourcemanager/build.sbt b/plugin/src/sbt-test/sbt-coursier/hadoop-yarn-server-resourcemanager/build.sbt new file mode 100644 index 000000000..c7c7eda96 --- /dev/null +++ b/plugin/src/sbt-test/sbt-coursier/hadoop-yarn-server-resourcemanager/build.sbt @@ -0,0 +1,10 @@ +scalaVersion := "2.11.8" + +libraryDependencies += "org.apache.hadoop" % "hadoop-yarn-server-resourcemanager" % "2.7.1" + +coursierCachePolicies := { + if (sys.props("os.name").startsWith("Windows")) + coursierCachePolicies.value + else + Seq(coursier.CachePolicy.ForceDownload) +} diff --git a/plugin/src/sbt-test/sbt-coursier/hadoop-yarn-server-resourcemanager/project/plugins.sbt b/plugin/src/sbt-test/sbt-coursier/hadoop-yarn-server-resourcemanager/project/plugins.sbt new file mode 100644 index 000000000..152225a9e --- /dev/null +++ b/plugin/src/sbt-test/sbt-coursier/hadoop-yarn-server-resourcemanager/project/plugins.sbt @@ -0,0 +1,11 @@ +{ + val pluginVersion = sys.props.getOrElse( + "plugin.version", + throw new RuntimeException( + """|The system property 'plugin.version' is not defined. + |Specify this property using the scriptedLaunchOpts -D.""".stripMargin + ) + ) + + addSbtPlugin("io.get-coursier" % "sbt-coursier" % pluginVersion) +} diff --git a/plugin/src/sbt-test/sbt-coursier/hadoop-yarn-server-resourcemanager/src/main/scala/Main.scala b/plugin/src/sbt-test/sbt-coursier/hadoop-yarn-server-resourcemanager/src/main/scala/Main.scala new file mode 100644 index 000000000..032874759 --- /dev/null +++ b/plugin/src/sbt-test/sbt-coursier/hadoop-yarn-server-resourcemanager/src/main/scala/Main.scala @@ -0,0 +1,8 @@ +import java.io.File +import java.nio.file.Files + +import org.apache.zookeeper.ZooKeeper + +object Main extends App { + Files.write(new File("output").toPath, classOf[ZooKeeper].getSimpleName.getBytes("UTF-8")) +} diff --git a/plugin/src/sbt-test/sbt-coursier/hadoop-yarn-server-resourcemanager/test b/plugin/src/sbt-test/sbt-coursier/hadoop-yarn-server-resourcemanager/test new file mode 100644 index 000000000..2182f57b0 --- /dev/null +++ b/plugin/src/sbt-test/sbt-coursier/hadoop-yarn-server-resourcemanager/test @@ -0,0 +1,3 @@ +$ delete output +> run +$ exists output diff --git a/plugin/src/sbt-test/sbt-coursier/inter-project/a/src/main/scala/A.scala b/plugin/src/sbt-test/sbt-coursier/inter-project/a/src/main/scala/A.scala new file mode 100644 index 000000000..5308caa95 --- /dev/null +++ b/plugin/src/sbt-test/sbt-coursier/inter-project/a/src/main/scala/A.scala @@ -0,0 +1,6 @@ + +object A { + + def msg = "OK" + +} diff --git a/plugin/src/sbt-test/sbt-coursier/inter-project/b/src/main/scala/Main.scala b/plugin/src/sbt-test/sbt-coursier/inter-project/b/src/main/scala/Main.scala new file mode 100644 index 000000000..624039aa5 --- /dev/null +++ b/plugin/src/sbt-test/sbt-coursier/inter-project/b/src/main/scala/Main.scala @@ -0,0 +1,13 @@ +import java.io.File +import java.nio.file.Files + +import argonaut._, Argonaut._, ArgonautShapeless._ + +object Main extends App { + + case class CC(i: Int, s: String) + + val msg = CC(2, A.msg).asJson.spaces2 + + Files.write(new File("output").toPath, msg.getBytes("UTF-8")) +} diff --git a/plugin/src/sbt-test/sbt-coursier/inter-project/build.sbt b/plugin/src/sbt-test/sbt-coursier/inter-project/build.sbt new file mode 100644 index 000000000..8cb64b323 --- /dev/null +++ b/plugin/src/sbt-test/sbt-coursier/inter-project/build.sbt @@ -0,0 +1,38 @@ + +lazy val sharedSettings = Seq( + scalaVersion := "2.11.8", + coursierCachePolicies := { + if (sys.props("os.name").startsWith("Windows")) + coursierCachePolicies.value + else + Seq(coursier.CachePolicy.ForceDownload) + } +) + +/** Module with the same Maven coordinates as shapeless 2.3.1 */ +lazy val `shapeless-mock` = project + .settings(sharedSettings) + .settings( + organization := "com.chuusai", + name := "shapeless", + version := "2.3.1" + ) + +lazy val a = project + .settings(sharedSettings) + .settings( + organization := "com.pany", + name := "a", + version := "0.0.1" + ) + +/** Transitively depends on the - real - shapeless 2.3.1 */ +lazy val b = project + .dependsOn(a) + .settings(sharedSettings) + .settings( + organization := "com.pany", + name := "b", + version := "0.0.1", + libraryDependencies += "com.github.alexarchambault" %% "argonaut-shapeless_6.2" % "1.2.0-M1" + ) diff --git a/plugin/src/sbt-test/sbt-coursier/inter-project/project/plugins.sbt b/plugin/src/sbt-test/sbt-coursier/inter-project/project/plugins.sbt new file mode 100644 index 000000000..152225a9e --- /dev/null +++ b/plugin/src/sbt-test/sbt-coursier/inter-project/project/plugins.sbt @@ -0,0 +1,11 @@ +{ + val pluginVersion = sys.props.getOrElse( + "plugin.version", + throw new RuntimeException( + """|The system property 'plugin.version' is not defined. + |Specify this property using the scriptedLaunchOpts -D.""".stripMargin + ) + ) + + addSbtPlugin("io.get-coursier" % "sbt-coursier" % pluginVersion) +} diff --git a/plugin/src/sbt-test/sbt-coursier/inter-project/test b/plugin/src/sbt-test/sbt-coursier/inter-project/test new file mode 100644 index 000000000..ea53e1abb --- /dev/null +++ b/plugin/src/sbt-test/sbt-coursier/inter-project/test @@ -0,0 +1,3 @@ +$ delete output +> b/run +$ exists output diff --git a/tests/shared/src/test/resources/resolutions/org.webjars.bower/malihu-custom-scrollbar-plugin/3.1.5 b/tests/shared/src/test/resources/resolutions/org.webjars.bower/malihu-custom-scrollbar-plugin/3.1.5 new file mode 100644 index 000000000..2300dfd10 --- /dev/null +++ b/tests/shared/src/test/resources/resolutions/org.webjars.bower/malihu-custom-scrollbar-plugin/3.1.5 @@ -0,0 +1,3 @@ +org.webjars.bower:jquery:3.1.0:compile +org.webjars.bower:jquery-mousewheel:3.1.13:compile +org.webjars.bower:malihu-custom-scrollbar-plugin:3.1.5:compile diff --git a/tests/shared/src/test/scala/coursier/test/CentralTests.scala b/tests/shared/src/test/scala/coursier/test/CentralTests.scala index bc1fef336..afab031d7 100644 --- a/tests/shared/src/test/scala/coursier/test/CentralTests.scala +++ b/tests/shared/src/test/scala/coursier/test/CentralTests.scala @@ -104,7 +104,7 @@ object CentralTests extends TestSuite { )( f: Artifact => T ): Future[T] = async { - val dep = Dependency(module, version, transitive = false) + val dep = Dependency(module, version, transitive = false, attributes = Attributes()) val res = await(resolve(Set(dep), extraRepo = extraRepo)) res.artifacts match { @@ -237,6 +237,15 @@ object CentralTests extends TestSuite { ) } + 'versionInterval - { + // Warning: needs to be updated when new versions of org.webjars.bower:jquery and + // org.webjars.bower:jquery-mousewheel are published :-| + resolutionCheck( + Module("org.webjars.bower", "malihu-custom-scrollbar-plugin"), + "3.1.5" + ) + } + 'latestRevision - { * - resolutionCheck( Module("com.chuusai", "shapeless_2.11"), @@ -346,6 +355,42 @@ object CentralTests extends TestSuite { assert(nonUnique.isEmpty) } } + + 'testJarType - { + // dependencies with type "test-jar" should be given the classifier "tests" by default + + async { + val deps = Set( + Dependency( + Module("org.apache.hadoop", "hadoop-yarn-server-resourcemanager"), + "2.7.1" + ) + ) + + val res = await(resolve(deps)) + + assert(res.errors.isEmpty) + assert(res.conflicts.isEmpty) + assert(res.isDone) + + 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 + } + + assert(zookeeperTestArtifacts.length == 1) + + val zookeeperTestArtifact = zookeeperTestArtifacts.head + + assert(zookeeperTestArtifact.attributes.`type` == "test-jar") + assert(zookeeperTestArtifact.attributes.classifier == "tests") + zookeeperTestArtifact.url.endsWith("-tests.jar") + } + } } } diff --git a/tests/shared/src/test/scala/coursier/test/VersionConstraintTests.scala b/tests/shared/src/test/scala/coursier/test/VersionConstraintTests.scala index 2227e7537..3fa9f5e99 100644 --- a/tests/shared/src/test/scala/coursier/test/VersionConstraintTests.scala +++ b/tests/shared/src/test/scala/coursier/test/VersionConstraintTests.scala @@ -10,45 +10,30 @@ object VersionConstraintTests extends TestSuite { 'parse{ 'empty{ val c0 = Parse.versionConstraint("") - assert(c0 == Some(VersionConstraint.None)) + assert(c0 == Some(VersionConstraint.all)) } 'basicVersion{ val c0 = Parse.versionConstraint("1.2") - assert(c0 == Some(VersionConstraint.Preferred(Version("1.2")))) + assert(c0 == Some(VersionConstraint.preferred(Version("1.2")))) } 'basicVersionInterval{ val c0 = Parse.versionConstraint("(,1.2]") - assert(c0 == Some(VersionConstraint.Interval(VersionInterval(None, Some(Version("1.2")), false, true)))) + assert(c0 == Some(VersionConstraint.interval(VersionInterval(None, Some(Version("1.2")), false, true)))) } } 'repr{ 'empty{ - val s0 = VersionConstraint.None.repr - assert(s0 == "") + val s0 = VersionConstraint.all.repr + assert(s0 == Some("")) } 'preferred{ - val s0 = VersionConstraint.Preferred(Version("2.1")).repr - assert(s0 == "2.1") + val s0 = VersionConstraint.preferred(Version("2.1")).repr + assert(s0 == Some("2.1")) } 'interval{ - val s0 = VersionConstraint.Interval(VersionInterval(None, Some(Version("2.1")), false, true)).repr - assert(s0 == "(,2.1]") - } - } - - 'interval{ - 'empty{ - val s0 = VersionConstraint.None.interval - assert(s0 == VersionInterval.zero) - } - 'preferred{ - val s0 = VersionConstraint.Preferred(Version("2.1")).interval - assert(s0 == VersionInterval(Some(Version("2.1")), None, true, false)) - } - 'interval{ - val s0 = VersionConstraint.Interval(VersionInterval(None, Some(Version("2.1")), false, true)).interval - assert(s0 == VersionInterval(None, Some(Version("2.1")), false, true)) + val s0 = VersionConstraint.interval(VersionInterval(None, Some(Version("2.1")), false, true)).repr + assert(s0 == Some("(,2.1]")) } } } diff --git a/tests/shared/src/test/scala/coursier/test/VersionIntervalTests.scala b/tests/shared/src/test/scala/coursier/test/VersionIntervalTests.scala index 932df2ca8..95118627c 100644 --- a/tests/shared/src/test/scala/coursier/test/VersionIntervalTests.scala +++ b/tests/shared/src/test/scala/coursier/test/VersionIntervalTests.scala @@ -269,17 +269,17 @@ object VersionIntervalTests extends TestSuite { 'none{ val s1 = "(,)" val c1 = Parse.versionInterval(s1).map(_.constraint) - assert(c1 == Some(VersionConstraint.None)) + assert(c1 == Some(VersionConstraint.all)) } 'preferred{ val s1 = "[1.3,)" val c1 = Parse.versionInterval(s1).map(_.constraint) - assert(c1 == Some(VersionConstraint.Preferred(Parse.version("1.3").get))) + assert(c1 == Some(VersionConstraint.preferred(Parse.version("1.3").get))) } 'interval{ val s1 = "[1.3,2.4)" val c1 = Parse.versionInterval(s1).map(_.constraint) - assert(c1 == Some(VersionConstraint.Interval(VersionInterval(Parse.version("1.3"), Parse.version("2.4"), true, false)))) + assert(c1 == Some(VersionConstraint.interval(VersionInterval(Parse.version("1.3"), Parse.version("2.4"), true, false)))) } } }