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 <alexandre.archambault@gmail.com>
This commit is contained in:
eugene yokota 2020-05-05 11:35:12 -04:00 committed by GitHub
parent b1b8f2c441
commit 0047a9803b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 82 additions and 11 deletions

View File

@ -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 =

View File

@ -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, _))
}

View File

@ -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 =

View File

@ -115,7 +115,10 @@ object ResolutionRun {
}
)
)
.either()
.either() match {
case Left(err) if params.missingOk => Right(err.resolution)
case others => others
}
}
}

View File

@ -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(

View File

@ -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

View File

@ -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)}")
}
}

View File

@ -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
}

View File

@ -0,0 +1 @@
> check

View File

@ -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]] =