From 0047a9803b8513b8d2703af18cb763e73a68f7fb Mon Sep 17 00:00:00 2001 From: eugene yokota Date: Tue, 5 May 2020 11:35:12 -0400 Subject: [PATCH] Implement missingOk (#212) Ref https://github.com/coursier/coursier/issues/1541 Ref https://github.com/sbt/sbt/issues/4707 This adds `missingOk` setting to `CoursierConfiguration`, forwarding the `missingOk` setting in `UpdateConfiguration` from LM API. lmcoursier _not_ respecting this setting is causing various issues on sbt side since the expected behavior of some plugins (including IntelliJ import feature) is that the source JARs missing would not fail the entire operation. Ideally we should return a partially resolved graph (for example if one out of 20 depdencies are missing source JARs it's still useful), but for now I'm going to return an empty `UpdateReport`. Co-authored-by: Alexandre Archambault --- .../lmcoursier/CoursierConfiguration.scala | 2 + .../CoursierDependencyResolution.scala | 4 +- .../internal/ResolutionParams.scala | 3 +- .../lmcoursier/internal/ResolutionRun.scala | 5 ++- .../coursier/sbtcoursier/CoursierPlugin.scala | 15 +++++-- .../sbtcoursier/ResolutionTasks.scala | 6 ++- .../src/sbt-test/shared-2/missingok/build.sbt | 40 +++++++++++++++++++ .../shared-2/missingok/project/plugins.sbt | 13 ++++++ .../src/sbt-test/shared-2/missingok/test | 1 + .../sbtlmcoursier/LmCoursierPlugin.scala | 4 +- 10 files changed, 82 insertions(+), 11 deletions(-) create mode 100644 modules/sbt-coursier/src/sbt-test/shared-2/missingok/build.sbt create mode 100644 modules/sbt-coursier/src/sbt-test/shared-2/missingok/project/plugins.sbt create mode 100644 modules/sbt-coursier/src/sbt-test/shared-2/missingok/test diff --git a/modules/lm-coursier/src/main/scala/lmcoursier/CoursierConfiguration.scala b/modules/lm-coursier/src/main/scala/lmcoursier/CoursierConfiguration.scala index 45ea1b886..34fa1282e 100644 --- a/modules/lm-coursier/src/main/scala/lmcoursier/CoursierConfiguration.scala +++ b/modules/lm-coursier/src/main/scala/lmcoursier/CoursierConfiguration.scala @@ -49,6 +49,8 @@ import scala.concurrent.duration.Duration ttl: Option[Duration] = CacheDefaults.ttl, checksums: Vector[Option[String]] = CacheDefaults.checksums.to[Vector], cachePolicies: Vector[CachePolicy] = CacheDefaults.cachePolicies.to[Vector].map(FromCoursier.cachePolicy), + @since + missingOk: Boolean = false, ) { 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 dedd09910..0adb719f4 100644 --- a/modules/lm-coursier/src/main/scala/lmcoursier/CoursierDependencyResolution.scala +++ b/modules/lm-coursier/src/main/scala/lmcoursier/CoursierDependencyResolution.scala @@ -159,7 +159,8 @@ class CoursierDependencyResolution(conf: CoursierConfiguration) extends Dependen .withForceVersion(conf.forceVersions.map { case (k, v) => (ToCoursier.module(k), v) }.toMap) .withTypelevel(typelevel) .withReconciliation(ToCoursier.reconciliation(conf.reconciliation)), - strictOpt = conf.strict.map(ToCoursier.strict) + strictOpt = conf.strict.map(ToCoursier.strict), + missingOk = conf.missingOk, ) def artifactsParams(resolutions: Map[Set[Configuration], Resolution]): ArtifactsParams = @@ -212,7 +213,6 @@ class CoursierDependencyResolution(conf: CoursierConfiguration) extends Dependen val updateParams0 = updateParams(resolutions, artifacts) UpdateRun.update(updateParams0, verbosityLevel, log) } - e.left.map(unresolvedWarningOrThrow(uwconfig, _)) } 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 2dcdf4837..b262b3414 100644 --- a/modules/lm-coursier/src/main/scala/lmcoursier/internal/ResolutionParams.scala +++ b/modules/lm-coursier/src/main/scala/lmcoursier/internal/ResolutionParams.scala @@ -26,7 +26,8 @@ final case class ResolutionParams( cache: coursier.cache.FileCache[Task], parallel: Int, params: coursier.params.ResolutionParams, - strictOpt: Option[Strict] + strictOpt: Option[Strict], + missingOk: Boolean, ) { val fallbackDependenciesRepositories = 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 ee1425f13..dc34688e8 100644 --- a/modules/lm-coursier/src/main/scala/lmcoursier/internal/ResolutionRun.scala +++ b/modules/lm-coursier/src/main/scala/lmcoursier/internal/ResolutionRun.scala @@ -115,7 +115,10 @@ object ResolutionRun { } ) ) - .either() + .either() match { + case Left(err) if params.missingOk => Right(err.resolution) + case others => others + } } } diff --git a/modules/sbt-coursier/src/main/scala/coursier/sbtcoursier/CoursierPlugin.scala b/modules/sbt-coursier/src/main/scala/coursier/sbtcoursier/CoursierPlugin.scala index 953fa2df0..7ccb8b98e 100644 --- a/modules/sbt-coursier/src/main/scala/coursier/sbtcoursier/CoursierPlugin.scala +++ b/modules/sbt-coursier/src/main/scala/coursier/sbtcoursier/CoursierPlugin.scala @@ -166,7 +166,10 @@ object CoursierPlugin extends AutoPlugin { coursierSbtClassifiersModule := classifiersModule.in(updateSbtClassifiers).value, coursierConfigurations := InputsTasks.coursierConfigurationsTask(None).value, coursierParentProjectCache := InputsTasks.parentProjectCacheTask.value, - coursierResolutions := ResolutionTasks.resolutionsTask().value, + coursierResolutions := (Def.taskDyn { + val missingOk = updateConfiguration.value.missingOk + ResolutionTasks.resolutionsTask(missingOk = missingOk) + }).value, Keys.actualCoursierResolution := { val config = Configuration(Compile.name) @@ -181,9 +184,13 @@ object CoursierPlugin extends AutoPlugin { sys.error(s"Resolution for configuration $config not found") } }, - coursierSbtClassifiersResolution := ResolutionTasks.resolutionsTask( - sbtClassifiers = true - ).value.head._2 + coursierSbtClassifiersResolution := (Def.taskDyn { + val missingOk = (updateConfiguration in updateSbtClassifiers).value.missingOk + ResolutionTasks.resolutionsTask( + sbtClassifiers = true, + missingOk = missingOk, + ) + }).value.head._2 ) override lazy val buildSettings = super.buildSettings ++ Seq( 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 1b9f8392b..ef7e923ba 100644 --- a/modules/sbt-coursier/src/main/scala/coursier/sbtcoursier/ResolutionTasks.scala +++ b/modules/sbt-coursier/src/main/scala/coursier/sbtcoursier/ResolutionTasks.scala @@ -17,7 +17,8 @@ import sbt.Keys._ object ResolutionTasks { def resolutionsTask( - sbtClassifiers: Boolean = false + sbtClassifiers: Boolean = false, + missingOk: Boolean = false, ): Def.Initialize[sbt.Task[Map[Set[Configuration], coursier.Resolution]]] = { val currentProjectTask: sbt.Def.Initialize[sbt.Task[(Project, Seq[FallbackDependency], Seq[Set[Configuration]])]] = @@ -154,7 +155,8 @@ object ResolutionTasks { .withForceVersion(userForceVersions.map { case (k, v) => (ToCoursier.module(k), v) }.toMap) .withTypelevel(typelevel) .addReconciliation(versionReconciliations0: _*), - strictOpt = strictOpt + strictOpt = strictOpt, + missingOk = missingOk, ), verbosityLevel, log diff --git a/modules/sbt-coursier/src/sbt-test/shared-2/missingok/build.sbt b/modules/sbt-coursier/src/sbt-test/shared-2/missingok/build.sbt new file mode 100644 index 000000000..886ddeebb --- /dev/null +++ b/modules/sbt-coursier/src/sbt-test/shared-2/missingok/build.sbt @@ -0,0 +1,40 @@ +scalaVersion := "2.13.2" +libraryDependencies ++= Seq( + "com.chuusai" %% "shapeless" % "2.3.3", + // non-existing + "org.webjars" % "npm" % "0.0.99" +) +updateConfiguration := updateConfiguration.value.withMissingOk(true) + +lazy val check = taskKey[Unit]("") + +check := { + val updateReport = update.value + val updateClassifiersReport = updateClassifiers.value + + val compileReport = updateReport + .configuration(Compile) + .getOrElse { + sys.error("Compile configuration not found in update report") + } + + val compileClassifiersReport = updateClassifiersReport + .configuration(Compile) + .getOrElse { + sys.error("Compile configuration not found in update classifiers report") + } + + val shapelessModule = compileReport + .modules + .find(_.module.name == "shapeless_2.13") + .getOrElse { + sys.error(s"shapeless module not found in ${compileReport.modules.map(_.module)}") + } + + val shapelessClassifiersModule = compileClassifiersReport + .modules + .find(_.module.name == "shapeless_2.13") + .getOrElse { + sys.error(s"shapeless module not found in ${compileClassifiersReport.modules.map(_.module)}") + } +} diff --git a/modules/sbt-coursier/src/sbt-test/shared-2/missingok/project/plugins.sbt b/modules/sbt-coursier/src/sbt-test/shared-2/missingok/project/plugins.sbt new file mode 100644 index 000000000..503ac2871 --- /dev/null +++ b/modules/sbt-coursier/src/sbt-test/shared-2/missingok/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 +} diff --git a/modules/sbt-coursier/src/sbt-test/shared-2/missingok/test b/modules/sbt-coursier/src/sbt-test/shared-2/missingok/test new file mode 100644 index 000000000..15675b169 --- /dev/null +++ b/modules/sbt-coursier/src/sbt-test/shared-2/missingok/test @@ -0,0 +1 @@ +> check diff --git a/modules/sbt-lm-coursier/src/main/scala/coursier/sbtlmcoursier/LmCoursierPlugin.scala b/modules/sbt-lm-coursier/src/main/scala/coursier/sbtlmcoursier/LmCoursierPlugin.scala index b6bac8e3e..b687e6627 100644 --- a/modules/sbt-lm-coursier/src/main/scala/coursier/sbtlmcoursier/LmCoursierPlugin.scala +++ b/modules/sbt-lm-coursier/src/main/scala/coursier/sbtlmcoursier/LmCoursierPlugin.scala @@ -7,7 +7,7 @@ import coursier.sbtcoursiershared.{InputsTasks, SbtCoursierShared} import sbt.{AutoPlugin, Classpaths, Def, Setting, Task, taskKey} import sbt.Project.inTask import sbt.KeyRanks.DTask -import sbt.Keys.{appConfiguration, autoScalaLibrary, classpathTypes, dependencyOverrides, dependencyResolution, ivyPaths, scalaBinaryVersion, scalaModuleInfo, scalaOrganization, scalaVersion, streams, updateClassifiers, updateSbtClassifiers} +import sbt.Keys.{appConfiguration, autoScalaLibrary, classpathTypes, dependencyOverrides, dependencyResolution, ivyPaths, scalaBinaryVersion, scalaModuleInfo, scalaOrganization, scalaVersion, streams, updateClassifiers, updateConfiguration, updateSbtClassifiers} import sbt.librarymanagement.DependencyResolution import scala.language.reflectiveCalls @@ -125,6 +125,7 @@ object LmCoursierPlugin extends AutoPlugin { val sbtScalaVersion = internalSbtScalaProvider.version() val sbtScalaOrganization = "org.scala-lang" // always assuming sbt uses mainline scala val classifiers = classifiersTask.value + val updateConfig = updateConfiguration.value val s = streams.value Classpaths.warnResolversConflict(rs, s.log) CoursierConfiguration() @@ -159,6 +160,7 @@ object LmCoursierPlugin extends AutoPlugin { .withIvyHome(ivyPaths.value.ivyHome) .withStrict(strict) .withForceVersions(userForceVersions.toVector) + .withMissingOk(updateConfig.missingOk) } } private def mkDependencyResolution: Def.Initialize[Task[DependencyResolution]] =