diff --git a/modules/lm-coursier/src/main/scala/lmcoursier/CoursierDependencyResolution.scala b/modules/lm-coursier/src/main/scala/lmcoursier/CoursierDependencyResolution.scala index b3fbea90b..94ebf893e 100644 --- a/modules/lm-coursier/src/main/scala/lmcoursier/CoursierDependencyResolution.scala +++ b/modules/lm-coursier/src/main/scala/lmcoursier/CoursierDependencyResolution.scala @@ -210,6 +210,7 @@ class CoursierDependencyResolution(conf: CoursierConfiguration) extends Dependen classifiers = classifiers, configs = configs, dependencies = dependencies, + forceVersions = conf.forceVersions.map { case (m, v) => (ToCoursier.module(m), v) }.toMap, interProjectDependencies = interProjectDependencies, res = resolutions, includeSignatures = false, diff --git a/modules/lm-coursier/src/main/scala/lmcoursier/internal/SbtUpdateReport.scala b/modules/lm-coursier/src/main/scala/lmcoursier/internal/SbtUpdateReport.scala index 17a6e52d8..26e552030 100644 --- a/modules/lm-coursier/src/main/scala/lmcoursier/internal/SbtUpdateReport.scala +++ b/modules/lm-coursier/src/main/scala/lmcoursier/internal/SbtUpdateReport.scala @@ -138,8 +138,7 @@ private[internal] object SbtUpdateReport { artifactFileOpt: (Module, String, Attributes, Artifact) => Option[File], fullArtifactsOpt: Option[Map[(Dependency, Publication, Artifact), Option[File]]], log: Logger, - keepPomArtifact: Boolean = false, - includeSignatures: Boolean = false, + includeSignatures: Boolean, classpathOrder: Boolean, missingOk: Boolean ): Vector[ModuleReport] = { @@ -167,13 +166,10 @@ private[internal] object SbtUpdateReport { } } - val depArtifacts0 = - if (keepPomArtifact) - depArtifacts1 - else - depArtifacts1.filter { - case (_, pub, _, _) => pub.attributes != Attributes(Type.pom, Classifier.empty) - } + val depArtifacts0 = depArtifacts1.filter { + case (_, pub, _, _) => + pub.attributes != Attributes(Type.pom, Classifier.empty) + } val depArtifacts = if (includeSignatures) { @@ -298,10 +294,10 @@ private[internal] object SbtUpdateReport { artifactFileOpt: (Module, String, Attributes, Artifact) => Option[File], fullArtifactsOpt: Option[Map[(Dependency, Publication, Artifact), Option[File]]], log: Logger, - keepPomArtifact: Boolean = false, - includeSignatures: Boolean = false, + includeSignatures: Boolean, classpathOrder: Boolean, - missingOk: Boolean + missingOk: Boolean, + forceVersions: Map[Module, String] ): UpdateReport = { val configReports = resolutions.map { @@ -315,7 +311,6 @@ private[internal] object SbtUpdateReport { artifactFileOpt, fullArtifactsOpt, log, - keepPomArtifact = keepPomArtifact, includeSignatures = includeSignatures, classpathOrder = classpathOrder, missingOk = missingOk @@ -340,28 +335,30 @@ private[internal] object SbtUpdateReport { OrganizationArtifactReport(rep.module.organization, rep.module.name, Vector(rep)) } - val evicted = coursier.graph.Conflict(subRes).flatMap { c => - // FIXME The project for c.wantedVersion is possibly not around (it's likely it was just not fetched) - val projOpt = subRes.projectCache.get((c.module, c.wantedVersion)) + val evicted = for { + c <- coursier.graph.Conflict(subRes) + // ideally, forceVersions should be taken into account by coursier.core.Resolution itself, when + // it computes transitive dependencies. It only handles forced versions at a global level for now, + // rather than handing them for each dependency (where each dependency could have its own forced + // versions, and apply and pass them to its transitive dependencies, just like for exclusions today). + if !forceVersions.contains(c.module) + projOpt = subRes.projectCache.get((c.module, c.wantedVersion)) .orElse(subRes.projectCache.get((c.module, c.version))) - projOpt.toSeq.map { - case (_, proj) => - // likely misses some details (transitive, exclusions, …) - val dep = Dependency(c.module, c.wantedVersion) - val dependee = Dependency(c.dependeeModule, c.dependeeVersion) - val dependeeProj = subRes.projectCache - .get((c.dependeeModule, c.dependeeVersion)) match { - case Some((_, p)) => - ProjectInfo(p.version, p.configurations.keys.toVector.map(c => ConfigRef(c.value)), p.properties) - case _ => - // should not happen - ProjectInfo(c.dependeeVersion, Vector.empty, Vector.empty) - } - val rep = moduleReport((dep, Seq((dependee, dependeeProj)), proj.withVersion(c.wantedVersion), Nil)) - .withEvicted(true) - .withEvictedData(Some("version selection")) // ??? put latest-revision like sbt/ivy here? - OrganizationArtifactReport(c.module.organization.value, c.module.name.value, Vector(rep)) - } + (_, proj) <- projOpt.toSeq + } yield { + val dep = Dependency(c.module, c.wantedVersion) + val dependee = Dependency(c.dependeeModule, c.dependeeVersion) + val dependeeProj = subRes.projectCache.get((c.dependeeModule, c.dependeeVersion)) match { + case Some((_, p)) => + ProjectInfo(p.version, p.configurations.keys.toVector.map(c => ConfigRef(c.value)), p.properties) + case None => + // should not happen + ProjectInfo(c.dependeeVersion, Vector.empty, Vector.empty) + } + val rep = moduleReport((dep, Seq((dependee, dependeeProj)), proj.withVersion(c.wantedVersion), Nil)) + .withEvicted(true) + .withEvictedData(Some("version selection")) // ??? put latest-revision like sbt/ivy here? + OrganizationArtifactReport(c.module.organization.value, c.module.name.value, Vector(rep)) } val details = (mainReportDetails ++ evicted) diff --git a/modules/lm-coursier/src/main/scala/lmcoursier/internal/UpdateParams.scala b/modules/lm-coursier/src/main/scala/lmcoursier/internal/UpdateParams.scala index 8f23a70c0..3de9f73fd 100644 --- a/modules/lm-coursier/src/main/scala/lmcoursier/internal/UpdateParams.scala +++ b/modules/lm-coursier/src/main/scala/lmcoursier/internal/UpdateParams.scala @@ -13,6 +13,7 @@ final case class UpdateParams( classifiers: Option[Seq[Classifier]], configs: Map[Configuration, Set[Configuration]], dependencies: Seq[(Configuration, Dependency)], + forceVersions: Map[Module, String], interProjectDependencies: Seq[Project], res: Map[Configuration, Resolution], includeSignatures: Boolean, diff --git a/modules/lm-coursier/src/main/scala/lmcoursier/internal/UpdateRun.scala b/modules/lm-coursier/src/main/scala/lmcoursier/internal/UpdateRun.scala index 8cf470894..6b5fcb571 100644 --- a/modules/lm-coursier/src/main/scala/lmcoursier/internal/UpdateRun.scala +++ b/modules/lm-coursier/src/main/scala/lmcoursier/internal/UpdateRun.scala @@ -82,7 +82,8 @@ object UpdateRun { log, includeSignatures = params.includeSignatures, classpathOrder = params.classpathOrder, - missingOk = params.missingOk + missingOk = params.missingOk, + params.forceVersions ) } diff --git a/modules/sbt-coursier/src/main/scala/coursier/sbtcoursier/UpdateTasks.scala b/modules/sbt-coursier/src/main/scala/coursier/sbtcoursier/UpdateTasks.scala index 53b57b000..2429297a7 100644 --- a/modules/sbt-coursier/src/main/scala/coursier/sbtcoursier/UpdateTasks.scala +++ b/modules/sbt-coursier/src/main/scala/coursier/sbtcoursier/UpdateTasks.scala @@ -1,10 +1,11 @@ package coursier.sbtcoursier import coursier.core._ -import lmcoursier.definitions.ToCoursier -import lmcoursier.internal.{SbtBootJars, SbtCoursierCache, UpdateParams, UpdateRun} import coursier.sbtcoursier.Keys._ import coursier.sbtcoursiershared.SbtCoursierShared.autoImport._ +import lmcoursier.definitions.ToCoursier +import lmcoursier.Inputs +import lmcoursier.internal.{SbtBootJars, SbtCoursierCache, UpdateParams, UpdateRun} import sbt.Def import sbt.Keys._ import sbt.librarymanagement.UpdateReport @@ -110,6 +111,14 @@ object UpdateTasks { val artifactFilesOrErrors0 = artifactFilesOrErrors0Task.value val classifiers = classifiersTask.value val configs = configsTask.value + val sv = scalaVersion.value + val sbv = scalaBinaryVersion.value + val forceVersions = Inputs.forceVersions(dependencyOverrides.value, sv, sbv) + .map { + case (m, v) => + (ToCoursier.module(m), v) + } + .toMap val params = UpdateParams( (p.module, p.version), @@ -118,6 +127,7 @@ object UpdateTasks { classifiers, configs, dependencies, + forceVersions, interProjectDependencies, res, includeSignatures, diff --git a/modules/sbt-coursier/src/sbt-test/sbt-lm-coursier/evicted/build.sbt b/modules/sbt-coursier/src/sbt-test/sbt-lm-coursier/evicted/build.sbt index 3073df20e..cf0b4ab9b 100644 --- a/modules/sbt-coursier/src/sbt-test/sbt-lm-coursier/evicted/build.sbt +++ b/modules/sbt-coursier/src/sbt-test/sbt-lm-coursier/evicted/build.sbt @@ -19,14 +19,25 @@ lazy val b = project ) ) +lazy val c = project + .settings( + scalaVersion := "2.12.8", + libraryDependencies ++= Seq( + "org.slf4s" %% "slf4s-api" % "1.7.25", // depends on org.slf4j:slf4j-api:1.7.25 + "ch.qos.logback" % "logback-classic" % "1.1.2" // depends on org.slf4j:slf4j-api:1.7.6 + ), + dependencyOverrides += "org.slf4j" % "slf4j-api" % "1.7.30" +) + lazy val check = taskKey[Unit]("") check := { val aReport = update.in(a).value val bReport = update.in(b).value + val cReport = update.in(c).value - def doCheck(report: UpdateReport): Unit = { + def doCheck(report: UpdateReport, evictionsExpected: Boolean = true): Unit = { val compileReport = report .configurations @@ -36,12 +47,12 @@ check := { } val foundEvictions = compileReport.details.exists(_.modules.exists(_.evicted)) - if (!foundEvictions) + if (foundEvictions != evictionsExpected) compileReport.details.foreach(println) - assert(foundEvictions) + assert(foundEvictions == evictionsExpected) } - // needs https://github.com/coursier/coursier/pull/1217 - // doCheck(aReport) + doCheck(aReport) doCheck(bReport) + doCheck(cReport, evictionsExpected = false) } diff --git a/project/plugins.sbt b/project/plugins.sbt index 91493c162..37757aa67 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,6 +1,8 @@ addSbtPlugin("com.geirsson" % "sbt-ci-release" % "1.5.3") -addSbtPlugin("com.typesafe" % "sbt-mima-plugin" % "0.7.0") +addSbtPlugin("com.github.alexarchambault.tmp" % "sbt-mima-plugin" % "0.7.1-SNAPSHOT") addSbtPlugin("io.get-coursier" % "sbt-shading" % "2.0.0") libraryDependencies += "org.scala-sbt" %% "scripted-plugin" % sbtVersion.value + +resolvers += Resolver.sonatypeRepo("snapshots")