diff --git a/modules/lm-coursier/src/main/scala/lmcoursier/CoursierConfiguration.scala b/modules/lm-coursier/src/main/scala/lmcoursier/CoursierConfiguration.scala index 57ae835e5..81f70f07e 100644 --- a/modules/lm-coursier/src/main/scala/lmcoursier/CoursierConfiguration.scala +++ b/modules/lm-coursier/src/main/scala/lmcoursier/CoursierConfiguration.scala @@ -53,7 +53,9 @@ import scala.concurrent.duration.Duration @since missingOk: Boolean = false, @since - sbtClassifiers: Boolean = false + sbtClassifiers: Boolean = false, + @since + providedInCompile: Boolean = true ) { def withLog(log: Logger): CoursierConfiguration = diff --git a/modules/lm-coursier/src/main/scala/lmcoursier/CoursierDependencyResolution.scala b/modules/lm-coursier/src/main/scala/lmcoursier/CoursierDependencyResolution.scala index 8f21eb507..b3fbea90b 100644 --- a/modules/lm-coursier/src/main/scala/lmcoursier/CoursierDependencyResolution.scala +++ b/modules/lm-coursier/src/main/scala/lmcoursier/CoursierDependencyResolution.scala @@ -144,10 +144,15 @@ class CoursierDependencyResolution(conf: CoursierConfiguration) extends Dependen } .toSet + val providedOpt = orderedConfigs.collectFirst { + case (c, _) if conf.providedInCompile && c.value.equalsIgnoreCase("provided") => c + } + val resolutionParams = ResolutionParams( dependencies = dependencies, fallbackDependencies = conf.fallbackDependencies, - orderedConfigs = orderedConfigs, + orderedConfigs = providedOpt.fold(orderedConfigs)(provided => orderedConfigs.filter(_._1 != provided)), + subConfigs = providedOpt.map(_ -> coursier.core.Configuration.compile).toSeq, autoScalaLibOpt = if (conf.autoScalaLibrary) Some((so, sv)) else None, mainRepositories = mainRepositories, parentProjectCache = Map.empty, diff --git a/modules/lm-coursier/src/main/scala/lmcoursier/internal/ResolutionParams.scala b/modules/lm-coursier/src/main/scala/lmcoursier/internal/ResolutionParams.scala index 56a99067a..6a1153a3e 100644 --- a/modules/lm-coursier/src/main/scala/lmcoursier/internal/ResolutionParams.scala +++ b/modules/lm-coursier/src/main/scala/lmcoursier/internal/ResolutionParams.scala @@ -17,6 +17,7 @@ final case class ResolutionParams( dependencies: Seq[(Configuration, Dependency)], fallbackDependencies: Seq[FallbackDependency], orderedConfigs: Seq[(Configuration, Seq[Configuration])], + subConfigs: Seq[(Configuration, Configuration)], autoScalaLibOpt: Option[(Organization, String)], mainRepositories: Seq[Repository], parentProjectCache: ProjectCache, @@ -34,12 +35,18 @@ final case class ResolutionParams( lazy val allConfigExtends: Map[Configuration, Set[Configuration]] = { val map = new mutable.HashMap[Configuration, Set[Configuration]] + val subConfigMap = subConfigs + .map { case (config, parent) => parent -> config } + .groupBy(_._1) + .mapValues(_.map(_._2)) + .toMap for ((config, extends0) <- orderedConfigs) { val allExtends = extends0 .iterator // the else of the getOrElse shouldn't be hit (because of the ordering of the configurations) .foldLeft(Set(config))((acc, ext) => acc ++ map.getOrElse(ext, Set(ext))) - map += config -> allExtends + val viaSubConfig = subConfigMap.getOrElse(config, Nil) + map += config -> (allExtends ++ viaSubConfig) } map.toMap } diff --git a/modules/lm-coursier/src/main/scala/lmcoursier/internal/ResolutionRun.scala b/modules/lm-coursier/src/main/scala/lmcoursier/internal/ResolutionRun.scala index f853386af..3a976d71d 100644 --- a/modules/lm-coursier/src/main/scala/lmcoursier/internal/ResolutionRun.scala +++ b/modules/lm-coursier/src/main/scala/lmcoursier/internal/ResolutionRun.scala @@ -163,6 +163,31 @@ object ResolutionRun { () } } + val withSubResolutions = params.subConfigs.foldLeft(either) { + case (acc, (config, parent)) => + for { + _ <- acc + initResOpt = map.get(parent) + allExtends = params.allConfigExtends.getOrElse(config, Set.empty) + res <- { + initResOpt match { + case None => + val allExtendsWithParent = allExtends ++ + params.allConfigExtends.getOrElse(parent, Set.empty) + resolution(params, verbosityLevel, log, allExtendsWithParent, None) + case Some(initRes) => + val deps = params.dependencies.collect { + case (config, dep) if allExtends(config) => + dep + } + Right(initRes.subset(deps)) + } + } + } yield { + map += config -> res + () + } + } either.map(_ => map.toMap) } for (res <- resOrError) diff --git a/modules/sbt-coursier/src/main/scala/coursier/sbtcoursier/ResolutionTasks.scala b/modules/sbt-coursier/src/main/scala/coursier/sbtcoursier/ResolutionTasks.scala index c376a1139..81b091436 100644 --- a/modules/sbt-coursier/src/main/scala/coursier/sbtcoursier/ResolutionTasks.scala +++ b/modules/sbt-coursier/src/main/scala/coursier/sbtcoursier/ResolutionTasks.scala @@ -138,11 +138,16 @@ object ResolutionTasks { ) } + val providedOpt = orderedConfigs.collectFirst { + case (c, _) if c.value.equalsIgnoreCase("provided") => c + } + val resOrError = ResolutionRun.resolutions( ResolutionParams( dependencies = currentProject.dependencies, fallbackDependencies = fallbackDependencies, orderedConfigs = orderedConfigs, + subConfigs = providedOpt.map(_ -> coursier.core.Configuration.compile).toSeq, autoScalaLibOpt = if (autoScalaLib) Some((so, sv)) else None, mainRepositories = mainRepositories, parentProjectCache = parentProjectCache, diff --git a/modules/sbt-coursier/src/sbt-test/shared-2/provided/build.sbt b/modules/sbt-coursier/src/sbt-test/shared-2/provided/build.sbt new file mode 100644 index 000000000..654ced342 --- /dev/null +++ b/modules/sbt-coursier/src/sbt-test/shared-2/provided/build.sbt @@ -0,0 +1,41 @@ +libraryDependencies ++= Seq( + "com.github.alexarchambault" %% "argonaut-shapeless_6.2" % "1.2.0-M5", + "com.chuusai" %% "shapeless" % "2.3.3" % Provided +) +scalaVersion := "2.12.11" + +lazy val check = taskKey[Unit]("") + +check := { + + val updateReport = update.value + + def checkVersions(config: Configuration): Unit = { + + val configReport = updateReport + .configuration(Compile) + .getOrElse { + throw new Exception( + s"$config configuration not found in update report" + ) + } + + val shapelessVersions = configReport + .modules + .map(_.module) + .collect { + case m if m.organization == "com.chuusai" && m.name.startsWith("shapeless") => + m.revision + } + .toSet + + val expectedShapelessVersions = Set("2.3.3") + assert( + shapelessVersions == expectedShapelessVersions, + s"Expected shapeless versions $expectedShapelessVersions, got $shapelessVersions" + ) + } + + checkVersions(Compile) + checkVersions(Provided) +} diff --git a/modules/sbt-coursier/src/sbt-test/shared-2/provided/project/plugins.sbt b/modules/sbt-coursier/src/sbt-test/shared-2/provided/project/plugins.sbt new file mode 100644 index 000000000..71a44ffd3 --- /dev/null +++ b/modules/sbt-coursier/src/sbt-test/shared-2/provided/project/plugins.sbt @@ -0,0 +1,13 @@ +addSbtPlugin { + + val name = sys.props.getOrElse( + "plugin.name", + sys.error("plugin.name Java property not set") + ) + val version = sys.props.getOrElse( + "plugin.version", + sys.error("plugin.version Java property not set") + ) + + "io.get-coursier" % name % version +} \ No newline at end of file diff --git a/modules/sbt-coursier/src/sbt-test/shared-2/provided/test b/modules/sbt-coursier/src/sbt-test/shared-2/provided/test new file mode 100644 index 000000000..15675b169 --- /dev/null +++ b/modules/sbt-coursier/src/sbt-test/shared-2/provided/test @@ -0,0 +1 @@ +> check