mirror of https://github.com/sbt/sbt.git
Add DependencyResolutionInterface implementation in lm-coursier
Originally based on https://github.com/sbt/librarymanagement/pull/270
This commit is contained in:
parent
610bbf1113
commit
55f457a6f7
|
|
@ -16,6 +16,7 @@ jobs:
|
|||
- env: SBT_COURSIER=1 SBT_COURSIER_TEST_GROUP=2
|
||||
- env: SBT_SHADING=1
|
||||
- env: SBT_PGP_COURSIER=1
|
||||
- env: LM_COURSIER=1
|
||||
- stage: release
|
||||
script: sbt ci-release
|
||||
branches:
|
||||
|
|
|
|||
15
build.sbt
15
build.sbt
|
|
@ -19,14 +19,25 @@ val coursierVersion = "1.1.0-M8"
|
|||
|
||||
lazy val `lm-coursier` = project
|
||||
.in(file("modules/lm-coursier"))
|
||||
.enablePlugins(ContrabandPlugin, JsonCodecPlugin)
|
||||
.settings(
|
||||
shared,
|
||||
libraryDependencies ++= Seq(
|
||||
"io.get-coursier" %% "coursier" % coursierVersion,
|
||||
"io.get-coursier" %% "coursier-cache" % coursierVersion,
|
||||
"io.get-coursier" %% "coursier-extra" % coursierVersion,
|
||||
"org.scala-sbt" %% "librarymanagement-core" % "1.0.2"
|
||||
)
|
||||
// We depend on librarymanagement-ivy rather than just
|
||||
// librarymanagement-core to handle the ModuleDescriptor passed
|
||||
// to DependencyResolutionInterface.update, which is an
|
||||
// IvySbt#Module (seems DependencyResolutionInterface.moduleDescriptor
|
||||
// is ignored).
|
||||
"org.scala-sbt" %% "librarymanagement-ivy" % "1.0.2",
|
||||
"org.scalatest" %% "scalatest" % "3.0.5" % Test
|
||||
),
|
||||
managedSourceDirectories in Compile +=
|
||||
baseDirectory.value / "src" / "main" / "contraband-scala",
|
||||
sourceManaged in (Compile, generateContrabands) := baseDirectory.value / "src" / "main" / "contraband-scala",
|
||||
contrabandFormatsForType in generateContrabands in Compile := DatatypeConfig.getFormats
|
||||
)
|
||||
|
||||
lazy val `sbt-coursier` = project
|
||||
|
|
|
|||
|
|
@ -0,0 +1,75 @@
|
|||
/**
|
||||
* This code is generated using [[http://www.scala-sbt.org/contraband/ sbt-contraband]].
|
||||
*/
|
||||
|
||||
// DO NOT EDIT MANUALLY
|
||||
package sbt.librarymanagement.coursier
|
||||
final class CoursierConfiguration private (
|
||||
val log: Option[xsbti.Logger],
|
||||
val resolvers: Vector[sbt.librarymanagement.Resolver],
|
||||
val otherResolvers: Vector[sbt.librarymanagement.Resolver],
|
||||
val reorderResolvers: Boolean,
|
||||
val parallelDownloads: Int,
|
||||
val maxIterations: Int,
|
||||
val sbtScalaOrganization: Option[String],
|
||||
val sbtScalaVersion: Option[String],
|
||||
val sbtScalaJars: Vector[java.io.File]) extends Serializable {
|
||||
|
||||
private def this() = this(None, sbt.librarymanagement.Resolver.defaults, Vector.empty, true, 6, 100, None, None, Vector.empty)
|
||||
|
||||
override def equals(o: Any): Boolean = o match {
|
||||
case x: CoursierConfiguration => (this.log == x.log) && (this.resolvers == x.resolvers) && (this.otherResolvers == x.otherResolvers) && (this.reorderResolvers == x.reorderResolvers) && (this.parallelDownloads == x.parallelDownloads) && (this.maxIterations == x.maxIterations) && (this.sbtScalaOrganization == x.sbtScalaOrganization) && (this.sbtScalaVersion == x.sbtScalaVersion) && (this.sbtScalaJars == x.sbtScalaJars)
|
||||
case _ => false
|
||||
}
|
||||
override def hashCode: Int = {
|
||||
37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (17 + "sbt.librarymanagement.coursier.CoursierConfiguration".##) + log.##) + resolvers.##) + otherResolvers.##) + reorderResolvers.##) + parallelDownloads.##) + maxIterations.##) + sbtScalaOrganization.##) + sbtScalaVersion.##) + sbtScalaJars.##)
|
||||
}
|
||||
override def toString: String = {
|
||||
"CoursierConfiguration(" + log + ", " + resolvers + ", " + otherResolvers + ", " + reorderResolvers + ", " + parallelDownloads + ", " + maxIterations + ", " + sbtScalaOrganization + ", " + sbtScalaVersion + ", " + sbtScalaJars + ")"
|
||||
}
|
||||
private[this] def copy(log: Option[xsbti.Logger] = log, resolvers: Vector[sbt.librarymanagement.Resolver] = resolvers, otherResolvers: Vector[sbt.librarymanagement.Resolver] = otherResolvers, reorderResolvers: Boolean = reorderResolvers, parallelDownloads: Int = parallelDownloads, maxIterations: Int = maxIterations, sbtScalaOrganization: Option[String] = sbtScalaOrganization, sbtScalaVersion: Option[String] = sbtScalaVersion, sbtScalaJars: Vector[java.io.File] = sbtScalaJars): CoursierConfiguration = {
|
||||
new CoursierConfiguration(log, resolvers, otherResolvers, reorderResolvers, parallelDownloads, maxIterations, sbtScalaOrganization, sbtScalaVersion, sbtScalaJars)
|
||||
}
|
||||
def withLog(log: Option[xsbti.Logger]): CoursierConfiguration = {
|
||||
copy(log = log)
|
||||
}
|
||||
def withLog(log: xsbti.Logger): CoursierConfiguration = {
|
||||
copy(log = Option(log))
|
||||
}
|
||||
def withResolvers(resolvers: Vector[sbt.librarymanagement.Resolver]): CoursierConfiguration = {
|
||||
copy(resolvers = resolvers)
|
||||
}
|
||||
def withOtherResolvers(otherResolvers: Vector[sbt.librarymanagement.Resolver]): CoursierConfiguration = {
|
||||
copy(otherResolvers = otherResolvers)
|
||||
}
|
||||
def withReorderResolvers(reorderResolvers: Boolean): CoursierConfiguration = {
|
||||
copy(reorderResolvers = reorderResolvers)
|
||||
}
|
||||
def withParallelDownloads(parallelDownloads: Int): CoursierConfiguration = {
|
||||
copy(parallelDownloads = parallelDownloads)
|
||||
}
|
||||
def withMaxIterations(maxIterations: Int): CoursierConfiguration = {
|
||||
copy(maxIterations = maxIterations)
|
||||
}
|
||||
def withSbtScalaOrganization(sbtScalaOrganization: Option[String]): CoursierConfiguration = {
|
||||
copy(sbtScalaOrganization = sbtScalaOrganization)
|
||||
}
|
||||
def withSbtScalaOrganization(sbtScalaOrganization: String): CoursierConfiguration = {
|
||||
copy(sbtScalaOrganization = Option(sbtScalaOrganization))
|
||||
}
|
||||
def withSbtScalaVersion(sbtScalaVersion: Option[String]): CoursierConfiguration = {
|
||||
copy(sbtScalaVersion = sbtScalaVersion)
|
||||
}
|
||||
def withSbtScalaVersion(sbtScalaVersion: String): CoursierConfiguration = {
|
||||
copy(sbtScalaVersion = Option(sbtScalaVersion))
|
||||
}
|
||||
def withSbtScalaJars(sbtScalaJars: Vector[java.io.File]): CoursierConfiguration = {
|
||||
copy(sbtScalaJars = sbtScalaJars)
|
||||
}
|
||||
}
|
||||
object CoursierConfiguration {
|
||||
|
||||
def apply(): CoursierConfiguration = new CoursierConfiguration()
|
||||
def apply(log: Option[xsbti.Logger], resolvers: Vector[sbt.librarymanagement.Resolver], otherResolvers: Vector[sbt.librarymanagement.Resolver], reorderResolvers: Boolean, parallelDownloads: Int, maxIterations: Int, sbtScalaOrganization: Option[String], sbtScalaVersion: Option[String], sbtScalaJars: Vector[java.io.File]): CoursierConfiguration = new CoursierConfiguration(log, resolvers, otherResolvers, reorderResolvers, parallelDownloads, maxIterations, sbtScalaOrganization, sbtScalaVersion, sbtScalaJars)
|
||||
def apply(log: xsbti.Logger, resolvers: Vector[sbt.librarymanagement.Resolver], otherResolvers: Vector[sbt.librarymanagement.Resolver], reorderResolvers: Boolean, parallelDownloads: Int, maxIterations: Int, sbtScalaOrganization: String, sbtScalaVersion: String, sbtScalaJars: Vector[java.io.File]): CoursierConfiguration = new CoursierConfiguration(Option(log), resolvers, otherResolvers, reorderResolvers, parallelDownloads, maxIterations, Option(sbtScalaOrganization), Option(sbtScalaVersion), sbtScalaJars)
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
/**
|
||||
* This code is generated using [[http://www.scala-sbt.org/contraband/ sbt-contraband]].
|
||||
*/
|
||||
|
||||
// DO NOT EDIT MANUALLY
|
||||
package sbt.librarymanagement.coursier
|
||||
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
|
||||
trait CoursierConfigurationFormats { self: sbt.internal.librarymanagement.formats.LoggerFormat with sbt.librarymanagement.ResolverFormats with sjsonnew.BasicJsonProtocol =>
|
||||
implicit lazy val CoursierConfigurationFormat: JsonFormat[sbt.librarymanagement.coursier.CoursierConfiguration] = new JsonFormat[sbt.librarymanagement.coursier.CoursierConfiguration] {
|
||||
override def read[J](jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.librarymanagement.coursier.CoursierConfiguration = {
|
||||
jsOpt match {
|
||||
case Some(js) =>
|
||||
unbuilder.beginObject(js)
|
||||
val log = unbuilder.readField[Option[xsbti.Logger]]("log")
|
||||
val resolvers = unbuilder.readField[Vector[sbt.librarymanagement.Resolver]]("resolvers")
|
||||
val otherResolvers = unbuilder.readField[Vector[sbt.librarymanagement.Resolver]]("otherResolvers")
|
||||
val reorderResolvers = unbuilder.readField[Boolean]("reorderResolvers")
|
||||
val parallelDownloads = unbuilder.readField[Int]("parallelDownloads")
|
||||
val maxIterations = unbuilder.readField[Int]("maxIterations")
|
||||
val sbtScalaOrganization = unbuilder.readField[Option[String]]("sbtScalaOrganization")
|
||||
val sbtScalaVersion = unbuilder.readField[Option[String]]("sbtScalaVersion")
|
||||
val sbtScalaJars = unbuilder.readField[Vector[java.io.File]]("sbtScalaJars")
|
||||
unbuilder.endObject()
|
||||
sbt.librarymanagement.coursier.CoursierConfiguration(log, resolvers, otherResolvers, reorderResolvers, parallelDownloads, maxIterations, sbtScalaOrganization, sbtScalaVersion, sbtScalaJars)
|
||||
case None =>
|
||||
deserializationError("Expected JsObject but found None")
|
||||
}
|
||||
}
|
||||
override def write[J](obj: sbt.librarymanagement.coursier.CoursierConfiguration, builder: Builder[J]): Unit = {
|
||||
builder.beginObject()
|
||||
builder.addField("log", obj.log)
|
||||
builder.addField("resolvers", obj.resolvers)
|
||||
builder.addField("otherResolvers", obj.otherResolvers)
|
||||
builder.addField("reorderResolvers", obj.reorderResolvers)
|
||||
builder.addField("parallelDownloads", obj.parallelDownloads)
|
||||
builder.addField("maxIterations", obj.maxIterations)
|
||||
builder.addField("sbtScalaOrganization", obj.sbtScalaOrganization)
|
||||
builder.addField("sbtScalaVersion", obj.sbtScalaVersion)
|
||||
builder.addField("sbtScalaJars", obj.sbtScalaJars)
|
||||
builder.endObject()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
{
|
||||
"codecNamespace": "sbt.librarymanagement.coursier",
|
||||
"types": [
|
||||
{
|
||||
"name": "CoursierConfiguration",
|
||||
"namespace": "sbt.librarymanagement.coursier",
|
||||
"target": "Scala",
|
||||
"type": "record",
|
||||
"fields": [
|
||||
{
|
||||
"name": "log",
|
||||
"type": "xsbti.Logger?",
|
||||
"default": "None",
|
||||
"since": "0.0.1"
|
||||
},
|
||||
{
|
||||
"name": "resolvers",
|
||||
"type": "sbt.librarymanagement.Resolver*",
|
||||
"default": "sbt.librarymanagement.Resolver.defaults",
|
||||
"since": "0.0.1"
|
||||
},
|
||||
{
|
||||
"name": "otherResolvers",
|
||||
"type": "sbt.librarymanagement.Resolver*",
|
||||
"default": "Vector.empty",
|
||||
"since": "0.0.1"
|
||||
},
|
||||
{
|
||||
"name": "reorderResolvers",
|
||||
"type": "Boolean",
|
||||
"default": "true",
|
||||
"since": "0.0.1"
|
||||
},
|
||||
{
|
||||
"name": "parallelDownloads",
|
||||
"type": "Int",
|
||||
"default": "6",
|
||||
"since": "0.0.1"
|
||||
},
|
||||
{
|
||||
"name": "maxIterations",
|
||||
"type": "Int",
|
||||
"default": "100",
|
||||
"since": "0.0.1"
|
||||
},
|
||||
{
|
||||
"name": "sbtScalaOrganization",
|
||||
"type": "String?",
|
||||
"default": "None",
|
||||
"since": "0.0.1"
|
||||
},
|
||||
{
|
||||
"name": "sbtScalaVersion",
|
||||
"type": "String?",
|
||||
"default": "None",
|
||||
"since": "0.0.1"
|
||||
},
|
||||
{
|
||||
"name": "sbtScalaJars",
|
||||
"type": "java.io.File*",
|
||||
"default": "Vector.empty",
|
||||
"since": "0.0.1"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,209 @@
|
|||
package sbt.librarymanagement.coursier
|
||||
|
||||
import java.io.{File, OutputStreamWriter}
|
||||
|
||||
import _root_.coursier.{Artifact, Cache, CachePolicy, FileError, Organization, Project, Resolution, TermDisplay, organizationString}
|
||||
import _root_.coursier.core.Configuration
|
||||
import _root_.coursier.ivy.IvyRepository
|
||||
import _root_.coursier.sbtcoursier.{ArtifactsParams, ArtifactsRun, FromSbt, Inputs, InterProjectRepository, ResolutionError, ResolutionParams, ResolutionRun, SbtBootJars, UpdateParams, UpdateRun}
|
||||
import sbt.internal.librarymanagement.IvySbt
|
||||
import sbt.librarymanagement._
|
||||
import sbt.util.Logger
|
||||
|
||||
class CoursierDependencyResolution(conf: CoursierConfiguration) extends DependencyResolutionInterface {
|
||||
|
||||
private def sbtBinaryVersion = "1.0"
|
||||
|
||||
lazy val resolvers =
|
||||
if (conf.reorderResolvers)
|
||||
ResolutionParams.reorderResolvers(conf.resolvers)
|
||||
else
|
||||
conf.resolvers
|
||||
|
||||
def moduleDescriptor(moduleSetting: ModuleDescriptorConfiguration): CoursierModuleDescriptor =
|
||||
CoursierModuleDescriptor(moduleSetting, conf)
|
||||
|
||||
def update(
|
||||
module: ModuleDescriptor,
|
||||
configuration: UpdateConfiguration,
|
||||
uwconfig: UnresolvedWarningConfiguration,
|
||||
log: Logger
|
||||
): Either[UnresolvedWarning, UpdateReport] = {
|
||||
|
||||
// TODO Take stuff in configuration into account? uwconfig too?
|
||||
|
||||
val module0 = module match {
|
||||
case c: CoursierModuleDescriptor =>
|
||||
// seems not to happen, not sure what DependencyResolutionInterface.moduleDescriptor is for
|
||||
c.descriptor
|
||||
case i: IvySbt#Module =>
|
||||
i.moduleSettings match {
|
||||
case d: ModuleDescriptorConfiguration => d
|
||||
case other => sys.error(s"unrecognized module settings: $other")
|
||||
}
|
||||
case _ =>
|
||||
sys.error(s"unrecognized ModuleDescriptor type: $module")
|
||||
}
|
||||
|
||||
val so = module0.scalaModuleInfo.fold(org"org.scala-lang")(m => Organization(m.scalaOrganization))
|
||||
val sv = module0.scalaModuleInfo.map(_.scalaFullVersion)
|
||||
// FIXME Manage to do stuff below without a scala version?
|
||||
.getOrElse(scala.util.Properties.versionNumberString)
|
||||
|
||||
val sbv = module0.scalaModuleInfo.map(_.scalaBinaryVersion).getOrElse {
|
||||
sv.split('.').take(2).mkString(".")
|
||||
}
|
||||
|
||||
val verbosityLevel = 0
|
||||
|
||||
val ttl = Cache.defaultTtl
|
||||
val createLogger = { () =>
|
||||
new TermDisplay(new OutputStreamWriter(System.err), fallbackMode = true)
|
||||
}
|
||||
val cache = Cache.default
|
||||
val cachePolicies = CachePolicy.default
|
||||
val checksums = Cache.defaultChecksums
|
||||
val projectName = "" // used for logging only…
|
||||
|
||||
val ivyProperties = ResolutionParams.defaultIvyProperties()
|
||||
|
||||
val mainRepositories = resolvers
|
||||
.flatMap { resolver =>
|
||||
FromSbt.repository(
|
||||
resolver,
|
||||
ivyProperties,
|
||||
log,
|
||||
None // FIXME What about authentication?
|
||||
)
|
||||
}
|
||||
|
||||
val globalPluginsRepos =
|
||||
for (p <- ResolutionParams.globalPluginPatterns(sbtBinaryVersion))
|
||||
yield IvyRepository.fromPattern(
|
||||
p,
|
||||
withChecksums = false,
|
||||
withSignatures = false,
|
||||
withArtifacts = false
|
||||
)
|
||||
|
||||
val interProjectDependencies: Seq[Project] = Nil // TODO Don't use Nil here
|
||||
val interProjectRepo = InterProjectRepository(interProjectDependencies)
|
||||
|
||||
val internalRepositories = globalPluginsRepos :+ interProjectRepo
|
||||
|
||||
val dependencies = module0.dependencies.flatMap { d =>
|
||||
// crossVersion already taken into account, wiping it here
|
||||
val d0 = d.withCrossVersion(CrossVersion.Disabled())
|
||||
FromSbt.dependencies(d0, sv, sbv)
|
||||
}
|
||||
|
||||
val configGraphs = Inputs.ivyGraphs(
|
||||
Inputs.configExtends(module0.configurations)
|
||||
)
|
||||
|
||||
val resolutionParams = ResolutionParams(
|
||||
dependencies = dependencies,
|
||||
fallbackDependencies = Nil,
|
||||
configGraphs = configGraphs,
|
||||
autoScalaLib = true,
|
||||
mainRepositories = mainRepositories,
|
||||
parentProjectCache = Map.empty,
|
||||
interProjectDependencies = interProjectDependencies,
|
||||
internalRepositories = internalRepositories,
|
||||
userEnabledProfiles = Set.empty,
|
||||
userForceVersions = Map.empty,
|
||||
typelevel = false,
|
||||
so = so,
|
||||
sv = sv,
|
||||
sbtClassifiers = false,
|
||||
parallelDownloads = conf.parallelDownloads,
|
||||
projectName = projectName,
|
||||
maxIterations = conf.maxIterations,
|
||||
createLogger = createLogger,
|
||||
cache = cache,
|
||||
cachePolicies = cachePolicies,
|
||||
ttl = ttl,
|
||||
checksums = checksums
|
||||
)
|
||||
|
||||
def artifactsParams(resolutions: Map[Set[Configuration], Resolution]) =
|
||||
ArtifactsParams(
|
||||
classifiers = None,
|
||||
res = resolutions.values.toSeq,
|
||||
includeSignatures = false,
|
||||
parallelDownloads = conf.parallelDownloads,
|
||||
createLogger = createLogger,
|
||||
cache = cache,
|
||||
artifactsChecksums = checksums,
|
||||
ttl = ttl,
|
||||
cachePolicies = cachePolicies,
|
||||
projectName = projectName,
|
||||
sbtClassifiers = false
|
||||
)
|
||||
|
||||
val sbtBootJarOverrides = SbtBootJars(
|
||||
conf.sbtScalaOrganization.fold(org"org.scala-lang")(Organization(_)),
|
||||
conf.sbtScalaVersion.getOrElse(sv),
|
||||
conf.sbtScalaJars
|
||||
)
|
||||
|
||||
val configs = Inputs.coursierConfigurations(module0.configurations)
|
||||
|
||||
def updateParams(
|
||||
resolutions: Map[Set[Configuration], Resolution],
|
||||
artifacts: Map[Artifact, Either[FileError, File]]
|
||||
) =
|
||||
UpdateParams(
|
||||
shadedConfigOpt = None,
|
||||
artifacts = artifacts,
|
||||
classifiers = None,
|
||||
configs = configs,
|
||||
dependencies = dependencies,
|
||||
res = resolutions,
|
||||
ignoreArtifactErrors = false,
|
||||
includeSignatures = false,
|
||||
sbtBootJarOverrides = sbtBootJarOverrides
|
||||
)
|
||||
|
||||
val e = for {
|
||||
resolutions <- ResolutionRun.resolutions(resolutionParams, verbosityLevel, log)
|
||||
artifactsParams0 = artifactsParams(resolutions)
|
||||
artifacts <- ArtifactsRun.artifacts(artifactsParams0, verbosityLevel, log)
|
||||
updateParams0 = updateParams(resolutions, artifacts)
|
||||
updateReport <- UpdateRun.update(updateParams0, verbosityLevel, log)
|
||||
} yield updateReport
|
||||
|
||||
e.left.map(unresolvedWarningOrThrow(uwconfig, _))
|
||||
}
|
||||
|
||||
private def resolutionException(ex: ResolutionError): Either[Throwable, ResolveException] =
|
||||
ex match {
|
||||
case e: ResolutionError.MetadataDownloadErrors =>
|
||||
val r = new ResolveException(
|
||||
e.errors.flatMap(_._2),
|
||||
e.errors.map {
|
||||
case ((mod, ver), _) =>
|
||||
ModuleID(mod.organization.value, mod.name.value, ver)
|
||||
.withExtraAttributes(mod.attributes)
|
||||
}
|
||||
)
|
||||
Right(r)
|
||||
case _ => Left(ex.exception())
|
||||
}
|
||||
|
||||
private def unresolvedWarningOrThrow(
|
||||
uwconfig: UnresolvedWarningConfiguration,
|
||||
ex: ResolutionError
|
||||
): UnresolvedWarning =
|
||||
resolutionException(ex) match {
|
||||
case Left(t) => throw t
|
||||
case Right(e) =>
|
||||
UnresolvedWarning(e, uwconfig)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
object CoursierDependencyResolution {
|
||||
def apply(configuration: CoursierConfiguration): DependencyResolution =
|
||||
DependencyResolution(new CoursierDependencyResolution(configuration))
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package sbt.librarymanagement
|
||||
package coursier
|
||||
|
||||
trait CoursierLibraryManagementCodec
|
||||
extends sjsonnew.BasicJsonProtocol
|
||||
with LibraryManagementCodec
|
||||
// with sbt.internal.librarymanagement.formats.GlobalLockFormat
|
||||
with sbt.internal.librarymanagement.formats.LoggerFormat
|
||||
with sbt.librarymanagement.ResolverFormats
|
||||
with CoursierConfigurationFormats
|
||||
|
||||
object CoursierLibraryManagementCodec extends CoursierLibraryManagementCodec
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
package sbt.librarymanagement.coursier
|
||||
|
||||
import sbt.librarymanagement._
|
||||
import sjsonnew.support.murmurhash.Hasher
|
||||
|
||||
final case class CoursierModuleDescriptor(
|
||||
descriptor: ModuleDescriptorConfiguration,
|
||||
conf: CoursierConfiguration
|
||||
) extends ModuleDescriptor {
|
||||
|
||||
def directDependencies: Vector[ModuleID] =
|
||||
descriptor.dependencies
|
||||
|
||||
def scalaModuleInfo: Option[ScalaModuleInfo] =
|
||||
descriptor.scalaModuleInfo
|
||||
|
||||
def moduleSettings: CoursierModuleSettings =
|
||||
CoursierModuleSettings()
|
||||
|
||||
lazy val extraInputHash: Long = {
|
||||
import sbt.librarymanagement.coursier.CustomLibraryManagementCodec._
|
||||
Hasher.hash(conf).toOption.fold(0L)(_.toLong)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
package sbt.librarymanagement.coursier
|
||||
|
||||
import sbt.librarymanagement.ModuleSettings
|
||||
|
||||
case class CoursierModuleSettings() extends ModuleSettings
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
package sbt.librarymanagement.coursier
|
||||
|
||||
import sbt.librarymanagement.Resolver
|
||||
import sjsonnew.JsonFormat
|
||||
|
||||
object CustomLibraryManagementCodec extends CoursierLibraryManagementCodec {
|
||||
|
||||
private type ConfFormat = (
|
||||
Vector[Resolver],
|
||||
Vector[Resolver],
|
||||
Boolean,
|
||||
Int,
|
||||
Int
|
||||
)
|
||||
|
||||
private def from(c: CoursierConfiguration): ConfFormat =
|
||||
(
|
||||
c.resolvers,
|
||||
c.otherResolvers,
|
||||
c.reorderResolvers,
|
||||
c.parallelDownloads,
|
||||
c.maxIterations
|
||||
)
|
||||
|
||||
private def to(c: ConfFormat): CoursierConfiguration =
|
||||
CoursierConfiguration()
|
||||
.withResolvers(c._1)
|
||||
.withOtherResolvers(c._2)
|
||||
.withReorderResolvers(c._3)
|
||||
.withParallelDownloads(c._4)
|
||||
.withMaxIterations(c._5)
|
||||
|
||||
// Redefine to use a subset of properties, that are serializable
|
||||
override implicit lazy val CoursierConfigurationFormat: JsonFormat[CoursierConfiguration] =
|
||||
projectFormat[CoursierConfiguration, ConfFormat](from, to)
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
package sbt.librarymanagement.coursier
|
||||
|
||||
import sbt.librarymanagement.{ MavenRepository, Resolver, URLRepository }
|
||||
|
||||
object Resolvers {
|
||||
|
||||
private val slowReposBase = Seq(
|
||||
"https://repo.typesafe.com/",
|
||||
"https://repo.scala-sbt.org/",
|
||||
"http://repo.typesafe.com/",
|
||||
"http://repo.scala-sbt.org/"
|
||||
)
|
||||
|
||||
private val fastReposBase = Seq(
|
||||
"http://repo1.maven.org/",
|
||||
"https://repo1.maven.org/"
|
||||
)
|
||||
|
||||
private def url(res: Resolver): Option[String] =
|
||||
res match {
|
||||
case m: MavenRepository =>
|
||||
Some(m.root)
|
||||
case u: URLRepository =>
|
||||
u.patterns.artifactPatterns.headOption
|
||||
.orElse(u.patterns.ivyPatterns.headOption)
|
||||
case _ =>
|
||||
None
|
||||
}
|
||||
|
||||
private def filterResolvers(bases: Seq[String],
|
||||
resolvers: Seq[(Resolver, Option[String])]): Seq[Resolver] =
|
||||
resolvers
|
||||
.filter(tuple => tuple._2.exists(url => bases.exists(base => url.startsWith(base))))
|
||||
.map(_._1)
|
||||
|
||||
def reorder(resolvers: Seq[Resolver]): Seq[Resolver] = {
|
||||
|
||||
val byUrl = resolvers.map(r => (r, url(r)))
|
||||
|
||||
val fast = filterResolvers(fastReposBase, byUrl)
|
||||
val slow = filterResolvers(slowReposBase, byUrl)
|
||||
val rest = resolvers.diff(fast).diff(slow)
|
||||
|
||||
val reordered = fast ++ rest ++ slow
|
||||
assert(reordered.size == resolvers.size,
|
||||
"Reordered resolvers should be the same size as the unordered ones.")
|
||||
|
||||
reordered
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,166 @@
|
|||
package sbt.librarymanagement.coursier
|
||||
|
||||
import org.scalatest.{Matchers, PropSpec}
|
||||
import sbt.internal.librarymanagement.cross.CrossVersionUtil
|
||||
import sbt.internal.util.ConsoleLogger
|
||||
import sbt.librarymanagement._
|
||||
import sbt.librarymanagement.Configurations.Component
|
||||
import sbt.librarymanagement.Resolver.{DefaultMavenRepository, JCenterRepository, JavaNet2Repository}
|
||||
import sbt.librarymanagement.{Resolver, UnresolvedWarningConfiguration, UpdateConfiguration}
|
||||
import sbt.librarymanagement.syntax._
|
||||
|
||||
final class ResolutionSpec extends PropSpec with Matchers {
|
||||
|
||||
lazy val log = ConsoleLogger()
|
||||
|
||||
def configurations = Vector(Compile, Test, Runtime, Provided, Optional, Component)
|
||||
def module(
|
||||
lmEngine: DependencyResolution,
|
||||
moduleId: ModuleID,
|
||||
deps: Vector[ModuleID],
|
||||
scalaFullVersion: Option[String],
|
||||
overrideScalaVersion: Boolean = true
|
||||
): ModuleDescriptor = {
|
||||
val scalaModuleInfo = scalaFullVersion map { fv =>
|
||||
ScalaModuleInfo(
|
||||
scalaFullVersion = fv,
|
||||
scalaBinaryVersion = CrossVersionUtil.binaryScalaVersion(fv),
|
||||
configurations = configurations,
|
||||
checkExplicit = true,
|
||||
filterImplicit = false,
|
||||
overrideScalaVersion = overrideScalaVersion
|
||||
)
|
||||
}
|
||||
|
||||
val moduleSetting = ModuleDescriptorConfiguration(moduleId, ModuleInfo("foo"))
|
||||
.withDependencies(deps)
|
||||
.withConfigurations(configurations)
|
||||
.withScalaModuleInfo(scalaModuleInfo)
|
||||
lmEngine.moduleDescriptor(moduleSetting)
|
||||
}
|
||||
|
||||
def resolvers = Vector(
|
||||
DefaultMavenRepository,
|
||||
JavaNet2Repository,
|
||||
JCenterRepository,
|
||||
Resolver.sbtPluginRepo("releases")
|
||||
)
|
||||
|
||||
val lmEngine = CoursierDependencyResolution(CoursierConfiguration().withResolvers(resolvers))
|
||||
|
||||
private final val stubModule = "com.example" % "foo" % "0.1.0" % "compile"
|
||||
|
||||
property("very simple module") {
|
||||
val dependencies = Vector(
|
||||
"com.typesafe.scala-logging" % "scala-logging_2.12" % "3.7.2" % "compile",
|
||||
"org.scalatest" % "scalatest_2.12" % "3.0.4" % "test"
|
||||
).map(_.withIsTransitive(false))
|
||||
|
||||
val coursierModule = module(lmEngine, stubModule, dependencies, Some("2.12.4"))
|
||||
val resolution =
|
||||
lmEngine.update(coursierModule, UpdateConfiguration(), UnresolvedWarningConfiguration(), log)
|
||||
|
||||
resolution should be('right)
|
||||
val r = resolution.right.get
|
||||
r.configurations.map(_.configuration) should have size configurations.length
|
||||
|
||||
val compileConfig = r.configurations.find(_.configuration == Compile.toConfigRef).get
|
||||
compileConfig.modules should have size 1
|
||||
|
||||
val runtimeConfig = r.configurations.find(_.configuration == Runtime.toConfigRef).get
|
||||
runtimeConfig.modules should have size 1
|
||||
|
||||
val testConfig = r.configurations.find(_.configuration == Test.toConfigRef).get
|
||||
testConfig.modules should have size 2
|
||||
}
|
||||
|
||||
property("resolve compiler bridge") {
|
||||
val dependencies =
|
||||
Vector(("org.scala-sbt" % "compiler-interface" % "1.0.4" % "component").sources())
|
||||
val coursierModule = module(lmEngine, stubModule, dependencies, Some("2.12.4"))
|
||||
val resolution =
|
||||
lmEngine.update(coursierModule, UpdateConfiguration(), UnresolvedWarningConfiguration(), log)
|
||||
|
||||
val r = resolution.right.get
|
||||
|
||||
val componentConfig = r.configurations.find(_.configuration == Component.toConfigRef).get
|
||||
componentConfig.modules should have size 2
|
||||
componentConfig.modules.head.artifacts should have size 1
|
||||
componentConfig.modules.head.artifacts.head._1.classifier should contain("sources")
|
||||
}
|
||||
|
||||
property("resolve sbt jars") {
|
||||
val dependencies =
|
||||
Vector("org.scala-sbt" % "sbt" % "1.1.0" % "provided")
|
||||
val coursierModule = module(lmEngine, stubModule, dependencies, Some("2.12.4"))
|
||||
val resolution =
|
||||
lmEngine.update(coursierModule, UpdateConfiguration(), UnresolvedWarningConfiguration(), log)
|
||||
|
||||
val r = resolution.right.get
|
||||
|
||||
val modules = r.configurations.flatMap(_.modules)
|
||||
modules.map(_.module.name) should contain("main_2.12")
|
||||
}
|
||||
|
||||
property("resolve with default resolvers") {
|
||||
val dependencies =
|
||||
Vector(("org.scala-sbt" % "compiler-interface" % "1.0.4" % "component").sources())
|
||||
val lmEngine =
|
||||
CoursierDependencyResolution(
|
||||
CoursierConfiguration()
|
||||
.withResolvers(Resolver.combineDefaultResolvers(Vector.empty))
|
||||
)
|
||||
val coursierModule = module(lmEngine, stubModule, dependencies, Some("2.12.4"))
|
||||
val resolution =
|
||||
lmEngine.update(coursierModule, UpdateConfiguration(), UnresolvedWarningConfiguration(), log)
|
||||
|
||||
resolution should be('right)
|
||||
}
|
||||
|
||||
property("resolve plugin") {
|
||||
val pluginAttributes = Map("scalaVersion" -> "2.12", "sbtVersion" -> "1.0")
|
||||
val dependencies =
|
||||
Vector(("org.xerial.sbt" % "sbt-sonatype" % "2.0").withExtraAttributes(pluginAttributes))
|
||||
val coursierModule = module(lmEngine, stubModule, dependencies, Some("2.12.4"))
|
||||
val resolution =
|
||||
lmEngine.update(coursierModule, UpdateConfiguration(), UnresolvedWarningConfiguration(), log)
|
||||
|
||||
val r = resolution.right.get
|
||||
|
||||
val componentConfig = r.configurations.find(_.configuration == Compile.toConfigRef).get
|
||||
componentConfig.modules.map(_.module.name) should have size 5
|
||||
}
|
||||
|
||||
property("strip e: prefix from plugin attributes") {
|
||||
val pluginAttributes = Map("e:scalaVersion" -> "2.12", "e:sbtVersion" -> "1.0")
|
||||
val dependencies =
|
||||
Vector(("org.xerial.sbt" % "sbt-sonatype" % "2.0").withExtraAttributes(pluginAttributes))
|
||||
val coursierModule = module(lmEngine, stubModule, dependencies, Some("2.12.4"))
|
||||
val resolution =
|
||||
lmEngine.update(coursierModule, UpdateConfiguration(), UnresolvedWarningConfiguration(), log)
|
||||
|
||||
resolution should be('right)
|
||||
}
|
||||
|
||||
property("resolve plugins hosted on repo.typesafe.com") {
|
||||
val pluginAttributes = Map("e:scalaVersion" -> "2.12", "e:sbtVersion" -> "1.0")
|
||||
val dependencies =
|
||||
Vector(("com.typesafe.sbt" % "sbt-git" % "0.9.3").withExtraAttributes(pluginAttributes))
|
||||
val coursierModule = module(lmEngine, stubModule, dependencies, Some("2.12.4"))
|
||||
val resolution =
|
||||
lmEngine.update(coursierModule, UpdateConfiguration(), UnresolvedWarningConfiguration(), log)
|
||||
|
||||
resolution should be('right)
|
||||
}
|
||||
|
||||
property("reorder fast and slow resolvers") {
|
||||
val resolvers = Vector(
|
||||
JavaNet2Repository,
|
||||
Resolver.sbtPluginRepo("releases"),
|
||||
DefaultMavenRepository
|
||||
)
|
||||
val engine = new CoursierDependencyResolution(CoursierConfiguration().withResolvers(resolvers))
|
||||
engine.resolvers.last.name should be("sbt-plugin-releases")
|
||||
engine.resolvers should have size resolvers.length
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
// from https://github.com/sbt/librarymanagement/blob/4a0a6c77bc24f9db139698cab0a6da78d0893a88/project/DatatypeConfig.scala
|
||||
|
||||
import sbt.contraband.ast._
|
||||
import sbt.contraband.CodecCodeGen
|
||||
|
||||
object DatatypeConfig {
|
||||
|
||||
/** Extract the only type parameter from a TpeRef */
|
||||
def oneArg(tpe: Type): Type = {
|
||||
val pat = s"""${tpe.removeTypeParameters.name}[<\\[](.+?)[>\\]]""".r
|
||||
val pat(arg0) = tpe.name
|
||||
NamedType(arg0 split '.' toList)
|
||||
}
|
||||
|
||||
/** Extract the two type parameters from a TpeRef */
|
||||
def twoArgs(tpe: Type): List[Type] = {
|
||||
val pat = s"""${tpe.removeTypeParameters.name}[<\\[](.+?), (.+?)[>\\]]""".r
|
||||
val pat(arg0, arg1) = tpe.name
|
||||
NamedType(arg0 split '.' toList) :: NamedType(arg1 split '.' toList) :: Nil
|
||||
}
|
||||
|
||||
/** Codecs that were manually written. */
|
||||
val myCodecs: PartialFunction[String, Type => List[String]] = {
|
||||
case "scala.xml.NodeSeq" => { _ =>
|
||||
"sbt.internal.librarymanagement.formats.NodeSeqFormat" :: Nil
|
||||
}
|
||||
|
||||
case "org.apache.ivy.plugins.resolver.DependencyResolver" => { _ =>
|
||||
"sbt.internal.librarymanagement.formats.DependencyResolverFormat" :: Nil
|
||||
}
|
||||
|
||||
case "xsbti.GlobalLock" => { _ =>
|
||||
"sbt.internal.librarymanagement.formats.GlobalLockFormat" :: Nil
|
||||
}
|
||||
case "xsbti.Logger" => { _ =>
|
||||
"sbt.internal.librarymanagement.formats.LoggerFormat" :: Nil
|
||||
}
|
||||
|
||||
case "sbt.librarymanagement.ivy.UpdateOptions" => { _ =>
|
||||
"sbt.librarymanagement.ivy.formats.UpdateOptionsFormat" :: Nil
|
||||
}
|
||||
|
||||
case "sbt.librarymanagement.LogicalClock" => { _ =>
|
||||
"sbt.internal.librarymanagement.formats.LogicalClockFormats" :: Nil
|
||||
}
|
||||
|
||||
// TODO: These are handled by BasicJsonProtocol, and sbt-datatype should handle them by default, imo
|
||||
case "Option" | "Set" | "scala.Vector" => { tpe =>
|
||||
getFormats(oneArg(tpe))
|
||||
}
|
||||
case "Map" | "Tuple2" | "scala.Tuple2" => { tpe =>
|
||||
twoArgs(tpe).flatMap(getFormats)
|
||||
}
|
||||
case "Int" | "Long" => { _ =>
|
||||
Nil
|
||||
}
|
||||
}
|
||||
|
||||
/** Types for which we don't include the format -- they're just aliases to InclExclRule */
|
||||
val excluded = Set("sbt.librarymanagement.InclusionRule", "sbt.librarymanagement.ExclusionRule")
|
||||
|
||||
/** Returns the list of formats required to encode the given `TpeRef`. */
|
||||
val getFormats: Type => List[String] =
|
||||
CodecCodeGen.extensibleFormatsForType {
|
||||
case NamedType(List("sbt", "internal", "librarymanagement", "RetrieveConfiguration"), _) =>
|
||||
"sbt.librarymanagement.RetrieveConfigurationFormats" :: Nil
|
||||
case tpe: Type if myCodecs isDefinedAt tpe.removeTypeParameters.name =>
|
||||
myCodecs(tpe.removeTypeParameters.name)(tpe)
|
||||
case tpe: Type if excluded contains tpe.removeTypeParameters.name =>
|
||||
Nil
|
||||
case other =>
|
||||
CodecCodeGen.formatsForType(other)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
|
||||
plugins_(
|
||||
"com.geirsson" % "sbt-ci-release" % "1.2.1",
|
||||
"org.scala-sbt" % "sbt-contraband" % "0.4.1",
|
||||
"io.get-coursier" % "sbt-coursier" % coursierVersion,
|
||||
"com.typesafe" % "sbt-mima-plugin" % "0.3.0",
|
||||
"com.jsuereth" % "sbt-pgp" % "1.1.1",
|
||||
|
|
|
|||
|
|
@ -7,6 +7,10 @@ downloadInstallSbtExtras() {
|
|||
chmod +x bin/sbt
|
||||
}
|
||||
|
||||
lmCoursier() {
|
||||
[ "${LM_COURSIER:-""}" = 1 ]
|
||||
}
|
||||
|
||||
sbtPgpCoursier() {
|
||||
[ "${SBT_PGP_COURSIER:-""}" = 1 ]
|
||||
}
|
||||
|
|
@ -15,8 +19,15 @@ sbtShading() {
|
|||
[ "${SBT_SHADING:-""}" = 1 ]
|
||||
}
|
||||
|
||||
runLmCoursierTests() {
|
||||
sbt ++$TRAVIS_SCALA_VERSION lm-coursier/test
|
||||
}
|
||||
|
||||
runSbtCoursierTests() {
|
||||
./metadata/scripts/with-test-repo.sh sbt ++$TRAVIS_SCALA_VERSION sbt-coursier/test "sbt-coursier/scripted sbt-coursier-group-$SBT_COURSIER_TEST_GROUP/*"
|
||||
./metadata/scripts/with-test-repo.sh sbt \
|
||||
++$TRAVIS_SCALA_VERSION \
|
||||
sbt-coursier/test \
|
||||
"sbt-coursier/scripted shared-$SBT_COURSIER_TEST_GROUP/* sbt-coursier-group-$SBT_COURSIER_TEST_GROUP/*"
|
||||
}
|
||||
|
||||
runSbtShadingTests() {
|
||||
|
|
@ -41,6 +52,8 @@ if sbtShading; then
|
|||
runSbtShadingTests
|
||||
elif sbtPgpCoursier; then
|
||||
runSbtPgpCoursierTests
|
||||
elif lmCoursier; then
|
||||
runLmCoursierTests
|
||||
else
|
||||
runSbtCoursierTests
|
||||
fi
|
||||
|
|
|
|||
Loading…
Reference in New Issue