Add DependencyResolutionInterface implementation in lm-coursier

Originally based on https://github.com/sbt/librarymanagement/pull/270
This commit is contained in:
Alexandre Archambault 2018-11-20 10:31:34 +01:00
parent 610bbf1113
commit 55f457a6f7
15 changed files with 793 additions and 3 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,5 @@
package sbt.librarymanagement.coursier
import sbt.librarymanagement.ModuleSettings
case class CoursierModuleSettings() extends ModuleSettings

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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