mirror of https://github.com/sbt/sbt.git
Merge pull request #235 from alexarchambault/per-config-resolution
Per config resolution
This commit is contained in:
commit
dabf6c8c8b
|
|
@ -15,7 +15,7 @@ inThisBuild(List(
|
||||||
)
|
)
|
||||||
))
|
))
|
||||||
|
|
||||||
val coursierVersion0 = "2.0.0-RC6-16"
|
val coursierVersion0 = "2.0.0-RC6-18"
|
||||||
|
|
||||||
lazy val `lm-coursier` = project
|
lazy val `lm-coursier` = project
|
||||||
.in(file("modules/lm-coursier"))
|
.in(file("modules/lm-coursier"))
|
||||||
|
|
|
||||||
|
|
@ -25,14 +25,6 @@ class CoursierDependencyResolution(conf: CoursierConfiguration) extends Dependen
|
||||||
* sbt-coursier, that was moved to this module.
|
* sbt-coursier, that was moved to this module.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
private lazy val excludeDependencies = conf
|
|
||||||
.excludeDependencies
|
|
||||||
.map {
|
|
||||||
case (strOrg, strName) =>
|
|
||||||
(lmcoursier.definitions.Organization(strOrg), lmcoursier.definitions.ModuleName(strName))
|
|
||||||
}
|
|
||||||
.toSet
|
|
||||||
|
|
||||||
def moduleDescriptor(moduleSetting: ModuleDescriptorConfiguration): ModuleDescriptor =
|
def moduleDescriptor(moduleSetting: ModuleDescriptorConfiguration): ModuleDescriptor =
|
||||||
CoursierModuleDescriptor(moduleSetting, conf)
|
CoursierModuleDescriptor(moduleSetting, conf)
|
||||||
|
|
||||||
|
|
@ -125,13 +117,14 @@ class CoursierDependencyResolution(conf: CoursierConfiguration) extends Dependen
|
||||||
}
|
}
|
||||||
.map {
|
.map {
|
||||||
case (config, dep) =>
|
case (config, dep) =>
|
||||||
val dep0 = dep.withExclusions(dep.exclusions ++ excludeDependencies)
|
(ToCoursier.configuration(config), ToCoursier.dependency(dep))
|
||||||
(ToCoursier.configuration(config), ToCoursier.dependency(dep0))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val configGraphs = Inputs.ivyGraphs(
|
val orderedConfigs = Inputs.orderedConfigurations(Inputs.configExtendsSeq(module0.configurations))
|
||||||
Inputs.configExtends(module0.configurations)
|
.map {
|
||||||
).map(_.map(ToCoursier.configuration))
|
case (config, extends0) =>
|
||||||
|
(ToCoursier.configuration(config), extends0.map(ToCoursier.configuration))
|
||||||
|
}
|
||||||
|
|
||||||
val typelevel = so == Typelevel.typelevelOrg
|
val typelevel = so == Typelevel.typelevelOrg
|
||||||
|
|
||||||
|
|
@ -143,10 +136,18 @@ class CoursierDependencyResolution(conf: CoursierConfiguration) extends Dependen
|
||||||
.withCredentials(conf.credentials.map(ToCoursier.credentials))
|
.withCredentials(conf.credentials.map(ToCoursier.credentials))
|
||||||
.withFollowHttpToHttpsRedirections(conf.followHttpToHttpsRedirections.getOrElse(true))
|
.withFollowHttpToHttpsRedirections(conf.followHttpToHttpsRedirections.getOrElse(true))
|
||||||
|
|
||||||
|
val excludeDependencies = conf
|
||||||
|
.excludeDependencies
|
||||||
|
.map {
|
||||||
|
case (strOrg, strName) =>
|
||||||
|
(coursier.Organization(strOrg), coursier.ModuleName(strName))
|
||||||
|
}
|
||||||
|
.toSet
|
||||||
|
|
||||||
val resolutionParams = ResolutionParams(
|
val resolutionParams = ResolutionParams(
|
||||||
dependencies = dependencies,
|
dependencies = dependencies,
|
||||||
fallbackDependencies = conf.fallbackDependencies,
|
fallbackDependencies = conf.fallbackDependencies,
|
||||||
configGraphs = configGraphs,
|
orderedConfigs = orderedConfigs,
|
||||||
autoScalaLibOpt = if (conf.autoScalaLibrary) Some((so, sv)) else None,
|
autoScalaLibOpt = if (conf.autoScalaLibrary) Some((so, sv)) else None,
|
||||||
mainRepositories = mainRepositories,
|
mainRepositories = mainRepositories,
|
||||||
parentProjectCache = Map.empty,
|
parentProjectCache = Map.empty,
|
||||||
|
|
@ -162,15 +163,16 @@ class CoursierDependencyResolution(conf: CoursierConfiguration) extends Dependen
|
||||||
.withProfiles(conf.mavenProfiles.toSet)
|
.withProfiles(conf.mavenProfiles.toSet)
|
||||||
.withForceVersion(conf.forceVersions.map { case (k, v) => (ToCoursier.module(k), v) }.toMap)
|
.withForceVersion(conf.forceVersions.map { case (k, v) => (ToCoursier.module(k), v) }.toMap)
|
||||||
.withTypelevel(typelevel)
|
.withTypelevel(typelevel)
|
||||||
.withReconciliation(ToCoursier.reconciliation(conf.reconciliation)),
|
.withReconciliation(ToCoursier.reconciliation(conf.reconciliation))
|
||||||
|
.withExclusions(excludeDependencies),
|
||||||
strictOpt = conf.strict.map(ToCoursier.strict),
|
strictOpt = conf.strict.map(ToCoursier.strict),
|
||||||
missingOk = conf.missingOk,
|
missingOk = conf.missingOk,
|
||||||
)
|
)
|
||||||
|
|
||||||
def artifactsParams(resolutions: Map[Set[Configuration], Resolution]): ArtifactsParams =
|
def artifactsParams(resolutions: Map[Configuration, Resolution]): ArtifactsParams =
|
||||||
ArtifactsParams(
|
ArtifactsParams(
|
||||||
classifiers = classifiers,
|
classifiers = classifiers,
|
||||||
resolutions = resolutions.values.toSeq,
|
resolutions = resolutions.values.toSeq.distinct,
|
||||||
includeSignatures = false,
|
includeSignatures = false,
|
||||||
loggerOpt = loggerOpt,
|
loggerOpt = loggerOpt,
|
||||||
projectName = projectName,
|
projectName = projectName,
|
||||||
|
|
@ -193,7 +195,7 @@ class CoursierDependencyResolution(conf: CoursierConfiguration) extends Dependen
|
||||||
}
|
}
|
||||||
|
|
||||||
def updateParams(
|
def updateParams(
|
||||||
resolutions: Map[Set[Configuration], Resolution],
|
resolutions: Map[Configuration, Resolution],
|
||||||
artifacts: Seq[(Dependency, Publication, Artifact, Option[File])]
|
artifacts: Seq[(Dependency, Publication, Artifact, Option[File])]
|
||||||
) =
|
) =
|
||||||
UpdateParams(
|
UpdateParams(
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,11 @@ object Inputs {
|
||||||
Configuration(from.value) -> Configuration(to.value)
|
Configuration(from.value) -> Configuration(to.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def configExtendsSeq(configurations: Seq[sbt.librarymanagement.Configuration]): Seq[(Configuration, Seq[Configuration])] =
|
||||||
|
configurations
|
||||||
|
.map(cfg => Configuration(cfg.name) -> cfg.extendsConfigs.map(c => Configuration(c.name)))
|
||||||
|
|
||||||
|
@deprecated("Now unused internally, to be removed in the future", "2.0.0-RC6-5")
|
||||||
def configExtends(configurations: Seq[sbt.librarymanagement.Configuration]): Map[Configuration, Seq[Configuration]] =
|
def configExtends(configurations: Seq[sbt.librarymanagement.Configuration]): Map[Configuration, Seq[Configuration]] =
|
||||||
configurations
|
configurations
|
||||||
.map(cfg => Configuration(cfg.name) -> cfg.extendsConfigs.map(c => Configuration(c.name)))
|
.map(cfg => Configuration(cfg.name) -> cfg.extendsConfigs.map(c => Configuration(c.name)))
|
||||||
|
|
@ -25,7 +30,7 @@ object Inputs {
|
||||||
shadedConfig: Option[(String, Configuration)] = None
|
shadedConfig: Option[(String, Configuration)] = None
|
||||||
): Map[Configuration, Set[Configuration]] = {
|
): Map[Configuration, Set[Configuration]] = {
|
||||||
|
|
||||||
val configs0 = configExtends(configurations)
|
val configs0 = configExtendsSeq(configurations).toMap
|
||||||
|
|
||||||
def allExtends(c: Configuration) = {
|
def allExtends(c: Configuration) = {
|
||||||
// possibly bad complexity
|
// possibly bad complexity
|
||||||
|
|
@ -55,6 +60,29 @@ object Inputs {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def orderedConfigurations(
|
||||||
|
configurations: Seq[(Configuration, Seq[Configuration])]
|
||||||
|
): Seq[(Configuration, Seq[Configuration])] = {
|
||||||
|
|
||||||
|
val map = configurations.toMap
|
||||||
|
|
||||||
|
def helper(done: Set[Configuration], toAdd: List[Configuration]): Stream[(Configuration, Seq[Configuration])] =
|
||||||
|
toAdd match {
|
||||||
|
case Nil => Stream.empty
|
||||||
|
case config :: rest =>
|
||||||
|
val extends0 = map.getOrElse(config, Nil)
|
||||||
|
val missingExtends = extends0.filterNot(done)
|
||||||
|
if (missingExtends.isEmpty)
|
||||||
|
(config, extends0) #:: helper(done + config, rest)
|
||||||
|
else
|
||||||
|
helper(done, missingExtends.toList ::: toAdd)
|
||||||
|
}
|
||||||
|
|
||||||
|
helper(Set.empty, configurations.map(_._1).toList)
|
||||||
|
.toVector
|
||||||
|
}
|
||||||
|
|
||||||
|
@deprecated("Now unused internally, to be removed in the future", "2.0.0-RC6-5")
|
||||||
def ivyGraphs(configurations: Map[Configuration, Seq[Configuration]]): Seq[Set[Configuration]] = {
|
def ivyGraphs(configurations: Map[Configuration, Seq[Configuration]]): Seq[Set[Configuration]] = {
|
||||||
|
|
||||||
// probably bad complexity, but that shouldn't matter given the size of the graphs involved...
|
// probably bad complexity, but that shouldn't matter given the size of the graphs involved...
|
||||||
|
|
@ -95,12 +123,12 @@ object Inputs {
|
||||||
sets.values.toVector.distinct.map(_.set.toSet)
|
sets.values.toVector.distinct.map(_.set.toSet)
|
||||||
}
|
}
|
||||||
|
|
||||||
def exclusions(
|
def exclusionsSeq(
|
||||||
excludeDeps: Seq[InclExclRule],
|
excludeDeps: Seq[InclExclRule],
|
||||||
sv: String,
|
sv: String,
|
||||||
sbv: String,
|
sbv: String,
|
||||||
log: Logger
|
log: Logger
|
||||||
): Set[(Organization, ModuleName)] = {
|
): Seq[(Organization, ModuleName)] = {
|
||||||
|
|
||||||
var anyNonSupportedExclusionRule = false
|
var anyNonSupportedExclusionRule = false
|
||||||
|
|
||||||
|
|
@ -116,7 +144,6 @@ object Inputs {
|
||||||
Seq((Organization(rule.organization), ModuleName(name)))
|
Seq((Organization(rule.organization), ModuleName(name)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.toSet
|
|
||||||
|
|
||||||
if (anyNonSupportedExclusionRule)
|
if (anyNonSupportedExclusionRule)
|
||||||
log.warn("Only supported exclusion rule fields: organization, name")
|
log.warn("Only supported exclusion rule fields: organization, name")
|
||||||
|
|
@ -124,6 +151,14 @@ object Inputs {
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def exclusions(
|
||||||
|
excludeDeps: Seq[InclExclRule],
|
||||||
|
sv: String,
|
||||||
|
sbv: String,
|
||||||
|
log: Logger
|
||||||
|
): Set[(Organization, ModuleName)] =
|
||||||
|
exclusionsSeq(excludeDeps, sv, sbv, log).toSet
|
||||||
|
|
||||||
def forceVersions(depOverrides: Seq[ModuleID], sv: String, sbv: String): Seq[(Module, String)] =
|
def forceVersions(depOverrides: Seq[ModuleID], sv: String, sbv: String): Seq[(Module, String)] =
|
||||||
depOverrides.map(FromSbt.moduleVersion(_, sv, sbv))
|
depOverrides.map(FromSbt.moduleVersion(_, sv, sbv))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,15 @@
|
||||||
package coursier.sbtcoursiershared
|
package lmcoursier
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets.UTF_8
|
|
||||||
import java.nio.file.Files
|
|
||||||
|
|
||||||
|
import lmcoursier.Inputs
|
||||||
import lmcoursier.definitions.{Configuration, Project}
|
import lmcoursier.definitions.{Configuration, Project}
|
||||||
import org.apache.ivy.core.module.id.ModuleRevisionId
|
|
||||||
import sbt.{Def, Setting, Task, TaskKey}
|
|
||||||
import sbt.internal.librarymanagement.IvySbt
|
|
||||||
import sbt.librarymanagement.PublishConfiguration
|
|
||||||
|
|
||||||
import scala.collection.JavaConverters._
|
|
||||||
import scala.xml.{Node, PrefixedAttribute}
|
import scala.xml.{Node, PrefixedAttribute}
|
||||||
|
|
||||||
object IvyXml {
|
object IvyXml {
|
||||||
|
|
||||||
private[sbtcoursiershared] def rawContent(
|
def apply(
|
||||||
currentProject: Project,
|
currentProject: Project,
|
||||||
|
exclusions: Seq[(String, String)],
|
||||||
shadedConfigOpt: Option[Configuration]
|
shadedConfigOpt: Option[Configuration]
|
||||||
): String = {
|
): String = {
|
||||||
|
|
||||||
|
|
@ -28,42 +22,15 @@ object IvyXml {
|
||||||
val printer = new scala.xml.PrettyPrinter(Int.MaxValue, 2)
|
val printer = new scala.xml.PrettyPrinter(Int.MaxValue, 2)
|
||||||
|
|
||||||
"""<?xml version="1.0" encoding="UTF-8"?>""" + '\n' +
|
"""<?xml version="1.0" encoding="UTF-8"?>""" + '\n' +
|
||||||
printer.format(content(currentProject, shadedConfigOpt))
|
printer.format(content(currentProject, exclusions, shadedConfigOpt))
|
||||||
}
|
}
|
||||||
|
|
||||||
// These are required for publish to be fine, later on.
|
// These are required for publish to be fine, later on.
|
||||||
private def writeFiles(
|
private def content(
|
||||||
currentProject: Project,
|
project0: Project,
|
||||||
shadedConfigOpt: Option[Configuration],
|
exclusions: Seq[(String, String)],
|
||||||
ivySbt: IvySbt,
|
shadedConfigOpt: Option[Configuration]
|
||||||
log: sbt.util.Logger
|
): Node = {
|
||||||
): Unit = {
|
|
||||||
|
|
||||||
val ivyCacheManager = ivySbt.withIvy(log)(ivy =>
|
|
||||||
ivy.getResolutionCacheManager
|
|
||||||
)
|
|
||||||
|
|
||||||
val ivyModule = ModuleRevisionId.newInstance(
|
|
||||||
currentProject.module.organization.value,
|
|
||||||
currentProject.module.name.value,
|
|
||||||
currentProject.version,
|
|
||||||
currentProject.module.attributes.asJava
|
|
||||||
)
|
|
||||||
|
|
||||||
val cacheIvyFile = ivyCacheManager.getResolvedIvyFileInCache(ivyModule)
|
|
||||||
val cacheIvyPropertiesFile = ivyCacheManager.getResolvedIvyPropertiesInCache(ivyModule)
|
|
||||||
|
|
||||||
val content0 = rawContent(currentProject, shadedConfigOpt)
|
|
||||||
cacheIvyFile.getParentFile.mkdirs()
|
|
||||||
log.info(s"Writing Ivy file $cacheIvyFile")
|
|
||||||
Files.write(cacheIvyFile.toPath, content0.getBytes(UTF_8))
|
|
||||||
|
|
||||||
// Just writing an empty file here... Are these only used?
|
|
||||||
cacheIvyPropertiesFile.getParentFile.mkdirs()
|
|
||||||
Files.write(cacheIvyPropertiesFile.toPath, Array.emptyByteArray)
|
|
||||||
}
|
|
||||||
|
|
||||||
private def content(project0: Project, shadedConfigOpt: Option[Configuration]): Node = {
|
|
||||||
|
|
||||||
val filterOutDependencies =
|
val filterOutDependencies =
|
||||||
shadedConfigOpt.toSet[Configuration].flatMap { shadedConfig =>
|
shadedConfigOpt.toSet[Configuration].flatMap { shadedConfig =>
|
||||||
|
|
@ -148,53 +115,17 @@ object IvyXml {
|
||||||
n % moduleAttrs
|
n % moduleAttrs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val excludeElems = exclusions.toVector.map {
|
||||||
|
case (org, name) =>
|
||||||
|
<exclude org={org} module={name} artifact="*" type="*" ext="*" matcher="exact"/>
|
||||||
|
}
|
||||||
|
|
||||||
<ivy-module version="2.0" xmlns:e="http://ant.apache.org/ivy/extra">
|
<ivy-module version="2.0" xmlns:e="http://ant.apache.org/ivy/extra">
|
||||||
{infoElem}
|
{infoElem}
|
||||||
<configurations>{confElems}</configurations>
|
<configurations>{confElems}</configurations>
|
||||||
<publications>{publicationElems}</publications>
|
<publications>{publicationElems}</publications>
|
||||||
<dependencies>{dependencyElems}</dependencies>
|
<dependencies>{dependencyElems}{excludeElems}</dependencies>
|
||||||
</ivy-module>
|
</ivy-module>
|
||||||
}
|
}
|
||||||
|
|
||||||
private def makeIvyXmlBefore[T](
|
|
||||||
task: TaskKey[T],
|
|
||||||
shadedConfigOpt: Option[Configuration]
|
|
||||||
): Setting[Task[T]] =
|
|
||||||
task := task.dependsOn {
|
|
||||||
Def.taskDyn {
|
|
||||||
import SbtCoursierShared.autoImport._
|
|
||||||
val doGen = coursierGenerateIvyXml.value
|
|
||||||
if (doGen)
|
|
||||||
Def.task {
|
|
||||||
val currentProject = {
|
|
||||||
val proj = coursierProject.value
|
|
||||||
val publications = coursierPublications.value
|
|
||||||
proj.withPublications(publications)
|
|
||||||
}
|
|
||||||
writeFiles(currentProject, shadedConfigOpt, sbt.Keys.ivySbt.value, sbt.Keys.streams.value.log)
|
|
||||||
}
|
|
||||||
else
|
|
||||||
Def.task(())
|
|
||||||
}
|
|
||||||
}.value
|
|
||||||
|
|
||||||
private lazy val needsIvyXmlLocal = Seq(sbt.Keys.publishLocalConfiguration) ++ getPubConf("makeIvyXmlLocalConfiguration")
|
|
||||||
private lazy val needsIvyXml = Seq(sbt.Keys.publishConfiguration) ++ getPubConf("makeIvyXmlConfiguration")
|
|
||||||
|
|
||||||
private[this] def getPubConf(method: String): List[TaskKey[PublishConfiguration]] =
|
|
||||||
try {
|
|
||||||
val cls = sbt.Keys.getClass
|
|
||||||
val m = cls.getMethod(method)
|
|
||||||
val task = m.invoke(sbt.Keys).asInstanceOf[TaskKey[PublishConfiguration]]
|
|
||||||
List(task)
|
|
||||||
} catch {
|
|
||||||
case _: Throwable => // FIXME Too wide
|
|
||||||
Nil
|
|
||||||
}
|
|
||||||
|
|
||||||
def generateIvyXmlSettings(
|
|
||||||
shadedConfigOpt: Option[Configuration] = None
|
|
||||||
): Seq[Setting[_]] =
|
|
||||||
(needsIvyXml ++ needsIvyXmlLocal).map(makeIvyXmlBefore(_, shadedConfigOpt))
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -10,11 +10,13 @@ import lmcoursier.FallbackDependency
|
||||||
import lmcoursier.definitions.ToCoursier
|
import lmcoursier.definitions.ToCoursier
|
||||||
import coursier.util.Task
|
import coursier.util.Task
|
||||||
|
|
||||||
|
import scala.collection.mutable
|
||||||
|
|
||||||
// private[coursier]
|
// private[coursier]
|
||||||
final case class ResolutionParams(
|
final case class ResolutionParams(
|
||||||
dependencies: Seq[(Configuration, Dependency)],
|
dependencies: Seq[(Configuration, Dependency)],
|
||||||
fallbackDependencies: Seq[FallbackDependency],
|
fallbackDependencies: Seq[FallbackDependency],
|
||||||
configGraphs: Seq[Set[Configuration]],
|
orderedConfigs: Seq[(Configuration, Seq[Configuration])],
|
||||||
autoScalaLibOpt: Option[(Organization, String)],
|
autoScalaLibOpt: Option[(Organization, String)],
|
||||||
mainRepositories: Seq[Repository],
|
mainRepositories: Seq[Repository],
|
||||||
parentProjectCache: ProjectCache,
|
parentProjectCache: ProjectCache,
|
||||||
|
|
@ -30,6 +32,18 @@ final case class ResolutionParams(
|
||||||
missingOk: Boolean,
|
missingOk: Boolean,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
lazy val allConfigExtends: Map[Configuration, Set[Configuration]] = {
|
||||||
|
val map = new mutable.HashMap[Configuration, Set[Configuration]]
|
||||||
|
for ((config, extends0) <- orderedConfigs) {
|
||||||
|
val allExtends = extends0
|
||||||
|
.iterator
|
||||||
|
// the else of the getOrElse shouldn't be hit (because of the ordering of the configurations)
|
||||||
|
.foldLeft(Set(config))((acc, ext) => acc ++ map.getOrElse(ext, Set(ext)))
|
||||||
|
map += config -> allExtends
|
||||||
|
}
|
||||||
|
map.toMap
|
||||||
|
}
|
||||||
|
|
||||||
val fallbackDependenciesRepositories =
|
val fallbackDependenciesRepositories =
|
||||||
if (fallbackDependencies.isEmpty)
|
if (fallbackDependencies.isEmpty)
|
||||||
Nil
|
Nil
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,8 @@ import coursier.maven.MavenRepository
|
||||||
import coursier.params.rule.RuleResolution
|
import coursier.params.rule.RuleResolution
|
||||||
import sbt.util.Logger
|
import sbt.util.Logger
|
||||||
|
|
||||||
|
import scala.collection.mutable
|
||||||
|
|
||||||
// private[coursier]
|
// private[coursier]
|
||||||
object ResolutionRun {
|
object ResolutionRun {
|
||||||
|
|
||||||
|
|
@ -16,7 +18,8 @@ object ResolutionRun {
|
||||||
params: ResolutionParams,
|
params: ResolutionParams,
|
||||||
verbosityLevel: Int,
|
verbosityLevel: Int,
|
||||||
log: Logger,
|
log: Logger,
|
||||||
configs: Set[Configuration]
|
configs: Set[Configuration],
|
||||||
|
startingResolutionOpt: Option[Resolution]
|
||||||
): Either[coursier.error.ResolutionError, Resolution] = {
|
): Either[coursier.error.ResolutionError, Resolution] = {
|
||||||
|
|
||||||
val isScalaToolConfig = configs(Configuration("scala-tool"))
|
val isScalaToolConfig = configs(Configuration("scala-tool"))
|
||||||
|
|
@ -80,6 +83,8 @@ object ResolutionRun {
|
||||||
ThreadUtil.withFixedThreadPool(params.parallel) { pool =>
|
ThreadUtil.withFixedThreadPool(params.parallel) { pool =>
|
||||||
|
|
||||||
Resolve()
|
Resolve()
|
||||||
|
// re-using various caches from a resolution of a configuration we extend
|
||||||
|
.withInitialResolution(startingResolutionOpt)
|
||||||
.withDependencies(
|
.withDependencies(
|
||||||
params.dependencies.collect {
|
params.dependencies.collect {
|
||||||
case (config, dep) if configs(config) =>
|
case (config, dep) if configs(config) =>
|
||||||
|
|
@ -126,7 +131,7 @@ object ResolutionRun {
|
||||||
params: ResolutionParams,
|
params: ResolutionParams,
|
||||||
verbosityLevel: Int,
|
verbosityLevel: Int,
|
||||||
log: Logger
|
log: Logger
|
||||||
): Either[coursier.error.ResolutionError, Map[Set[Configuration], Resolution]] = {
|
): Either[coursier.error.ResolutionError, Map[Configuration, Resolution]] = {
|
||||||
|
|
||||||
// TODO Warn about possible duplicated modules from source repositories?
|
// TODO Warn about possible duplicated modules from source repositories?
|
||||||
|
|
||||||
|
|
@ -141,13 +146,24 @@ object ResolutionRun {
|
||||||
// Downloads are already parallel, no need to parallelize further, anyway.
|
// Downloads are already parallel, no need to parallelize further, anyway.
|
||||||
val resOrError =
|
val resOrError =
|
||||||
Lock.lock.synchronized {
|
Lock.lock.synchronized {
|
||||||
params.configGraphs.foldLeft[Either[coursier.error.ResolutionError, Map[Set[Configuration], Resolution]]](Right(Map())) {
|
var map = new mutable.HashMap[Configuration, Resolution]
|
||||||
case (acc, config) =>
|
val either = params.orderedConfigs.foldLeft[Either[coursier.error.ResolutionError, Unit]](Right(())) {
|
||||||
|
case (acc, (config, extends0)) =>
|
||||||
for {
|
for {
|
||||||
m <- acc
|
_ <- acc
|
||||||
res <- resolution(params, verbosityLevel, log, config)
|
initRes = {
|
||||||
} yield m + (config -> res)
|
val it = extends0.iterator.flatMap(map.get(_).iterator)
|
||||||
|
if (it.hasNext) Some(it.next())
|
||||||
|
else None
|
||||||
}
|
}
|
||||||
|
allExtends = params.allConfigExtends.getOrElse(config, Set.empty)
|
||||||
|
res <- resolution(params, verbosityLevel, log, allExtends, initRes)
|
||||||
|
} yield {
|
||||||
|
map += config -> res
|
||||||
|
()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
either.map(_ => map.toMap)
|
||||||
}
|
}
|
||||||
for (res <- resOrError)
|
for (res <- resOrError)
|
||||||
SbtCoursierCache.default.putResolution(params.resolutionKey, res)
|
SbtCoursierCache.default.putResolution(params.resolutionKey, res)
|
||||||
|
|
|
||||||
|
|
@ -12,15 +12,15 @@ class SbtCoursierCache {
|
||||||
|
|
||||||
import SbtCoursierCache._
|
import SbtCoursierCache._
|
||||||
|
|
||||||
private val resolutionsCache = new ConcurrentHashMap[ResolutionKey, Map[Set[Configuration], Resolution]]
|
private val resolutionsCache = new ConcurrentHashMap[ResolutionKey, Map[Configuration, Resolution]]
|
||||||
// these may actually not need to be cached any more, now that the resolutions
|
// these may actually not need to be cached any more, now that the resolutions
|
||||||
// are cached
|
// are cached
|
||||||
private val reportsCache = new ConcurrentHashMap[ReportKey, UpdateReport]
|
private val reportsCache = new ConcurrentHashMap[ReportKey, UpdateReport]
|
||||||
|
|
||||||
|
|
||||||
def resolutionOpt(key: ResolutionKey): Option[Map[Set[Configuration], Resolution]] =
|
def resolutionOpt(key: ResolutionKey): Option[Map[Configuration, Resolution]] =
|
||||||
Option(resolutionsCache.get(key))
|
Option(resolutionsCache.get(key))
|
||||||
def putResolution(key: ResolutionKey, res: Map[Set[Configuration], Resolution]): Unit =
|
def putResolution(key: ResolutionKey, res: Map[Configuration, Resolution]): Unit =
|
||||||
resolutionsCache.put(key, res)
|
resolutionsCache.put(key, res)
|
||||||
|
|
||||||
def reportOpt(key: ReportKey): Option[UpdateReport] =
|
def reportOpt(key: ReportKey): Option[UpdateReport] =
|
||||||
|
|
@ -53,7 +53,7 @@ object SbtCoursierCache {
|
||||||
|
|
||||||
final case class ReportKey(
|
final case class ReportKey(
|
||||||
dependencies: Seq[(Configuration, Dependency)],
|
dependencies: Seq[(Configuration, Dependency)],
|
||||||
resolution: Map[Set[Configuration], Resolution],
|
resolution: Map[Configuration, Resolution],
|
||||||
withClassifiers: Boolean,
|
withClassifiers: Boolean,
|
||||||
sbtClassifiers: Boolean,
|
sbtClassifiers: Boolean,
|
||||||
includeSignatures: Boolean
|
includeSignatures: Boolean
|
||||||
|
|
|
||||||
|
|
@ -132,7 +132,6 @@ private[internal] object SbtUpdateReport {
|
||||||
|
|
||||||
private def moduleReports(
|
private def moduleReports(
|
||||||
thisModule: (Module, String),
|
thisModule: (Module, String),
|
||||||
config: Configuration,
|
|
||||||
res: Resolution,
|
res: Resolution,
|
||||||
interProjectDependencies: Seq[Project],
|
interProjectDependencies: Seq[Project],
|
||||||
classifiersOpt: Option[Seq[Classifier]],
|
classifiersOpt: Option[Seq[Classifier]],
|
||||||
|
|
@ -293,9 +292,8 @@ private[internal] object SbtUpdateReport {
|
||||||
def apply(
|
def apply(
|
||||||
thisModule: (Module, String),
|
thisModule: (Module, String),
|
||||||
configDependencies: Map[Configuration, Seq[Dependency]],
|
configDependencies: Map[Configuration, Seq[Dependency]],
|
||||||
resolutions: Map[Configuration, Resolution],
|
resolutions: Seq[(Configuration, Resolution)],
|
||||||
interProjectDependencies: Vector[Project],
|
interProjectDependencies: Vector[Project],
|
||||||
configs: Map[Configuration, Set[Configuration]],
|
|
||||||
classifiersOpt: Option[Seq[Classifier]],
|
classifiersOpt: Option[Seq[Classifier]],
|
||||||
artifactFileOpt: (Module, String, Attributes, Artifact) => Option[File],
|
artifactFileOpt: (Module, String, Attributes, Artifact) => Option[File],
|
||||||
fullArtifactsOpt: Option[Map[(Dependency, Publication, Artifact), Option[File]]],
|
fullArtifactsOpt: Option[Map[(Dependency, Publication, Artifact), Option[File]]],
|
||||||
|
|
@ -306,18 +304,11 @@ private[internal] object SbtUpdateReport {
|
||||||
missingOk: Boolean
|
missingOk: Boolean
|
||||||
): UpdateReport = {
|
): UpdateReport = {
|
||||||
|
|
||||||
val configReports = configs.map {
|
val configReports = resolutions.map {
|
||||||
case (config, extends0) =>
|
case (config, subRes) =>
|
||||||
val configDeps = extends0
|
|
||||||
.toSeq
|
|
||||||
.sortBy(_.value)
|
|
||||||
.flatMap(configDependencies.getOrElse(_, Nil))
|
|
||||||
.distinct
|
|
||||||
val subRes = resolutions(config).subset(configDeps)
|
|
||||||
|
|
||||||
val reports = moduleReports(
|
val reports = moduleReports(
|
||||||
thisModule,
|
thisModule,
|
||||||
config,
|
|
||||||
subRes,
|
subRes,
|
||||||
interProjectDependencies,
|
interProjectDependencies,
|
||||||
classifiersOpt,
|
classifiersOpt,
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ final case class UpdateParams(
|
||||||
configs: Map[Configuration, Set[Configuration]],
|
configs: Map[Configuration, Set[Configuration]],
|
||||||
dependencies: Seq[(Configuration, Dependency)],
|
dependencies: Seq[(Configuration, Dependency)],
|
||||||
interProjectDependencies: Seq[Project],
|
interProjectDependencies: Seq[Project],
|
||||||
res: Map[Set[Configuration], Resolution],
|
res: Map[Configuration, Resolution],
|
||||||
includeSignatures: Boolean,
|
includeSignatures: Boolean,
|
||||||
sbtBootJarOverrides: Map[(Module, String), File],
|
sbtBootJarOverrides: Map[(Module, String), File],
|
||||||
classpathOrder: Boolean,
|
classpathOrder: Boolean,
|
||||||
|
|
|
||||||
|
|
@ -57,11 +57,6 @@ object UpdateRun {
|
||||||
log: Logger
|
log: Logger
|
||||||
): UpdateReport = Lock.lock.synchronized {
|
): UpdateReport = Lock.lock.synchronized {
|
||||||
|
|
||||||
val configResolutions = params.res.flatMap {
|
|
||||||
case (configs, r) =>
|
|
||||||
configs.iterator.map((_, r))
|
|
||||||
}
|
|
||||||
|
|
||||||
val depsByConfig = grouped(params.dependencies)(
|
val depsByConfig = grouped(params.dependencies)(
|
||||||
config =>
|
config =>
|
||||||
params.shadedConfigOpt match {
|
params.shadedConfigOpt match {
|
||||||
|
|
@ -74,7 +69,7 @@ object UpdateRun {
|
||||||
|
|
||||||
if (verbosityLevel >= 2) {
|
if (verbosityLevel >= 2) {
|
||||||
val finalDeps = dependenciesWithConfig(
|
val finalDeps = dependenciesWithConfig(
|
||||||
configResolutions,
|
params.res,
|
||||||
depsByConfig,
|
depsByConfig,
|
||||||
params.configs
|
params.configs
|
||||||
)
|
)
|
||||||
|
|
@ -87,9 +82,8 @@ object UpdateRun {
|
||||||
SbtUpdateReport(
|
SbtUpdateReport(
|
||||||
params.thisModule,
|
params.thisModule,
|
||||||
depsByConfig,
|
depsByConfig,
|
||||||
configResolutions,
|
params.res.toVector.sortBy(_._1.value), // FIXME Order by config topologically?
|
||||||
params.interProjectDependencies.toVector,
|
params.interProjectDependencies.toVector,
|
||||||
params.configs,
|
|
||||||
params.classifiers,
|
params.classifiers,
|
||||||
params.artifactFileOpt,
|
params.artifactFileOpt,
|
||||||
params.fullArtifacts,
|
params.fullArtifacts,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
package lmcoursier
|
||||||
|
|
||||||
|
import lmcoursier.definitions.{Configuration, Info, Module, ModuleName, Organization, Project}
|
||||||
|
import org.scalatest.{Matchers, PropSpec}
|
||||||
|
|
||||||
|
object IvyXmlTests extends PropSpec with Matchers {
|
||||||
|
|
||||||
|
property("no truncation") {
|
||||||
|
val project = Project(
|
||||||
|
Module(Organization("org"), ModuleName("name"), Map()),
|
||||||
|
"ver",
|
||||||
|
Nil,
|
||||||
|
Map(
|
||||||
|
Configuration("foo") -> (1 to 80).map(n => Configuration("bar" + n)) // long list of configurations -> no truncation any way
|
||||||
|
),
|
||||||
|
Nil,
|
||||||
|
None,
|
||||||
|
Nil,
|
||||||
|
Info("", "", Nil, Nil, None)
|
||||||
|
)
|
||||||
|
|
||||||
|
val content = IvyXml(project, Nil, None)
|
||||||
|
|
||||||
|
assert(!content.contains("</conf>"))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -28,32 +28,21 @@ object InputsTasks {
|
||||||
private def coursierProject0(
|
private def coursierProject0(
|
||||||
projId: ModuleID,
|
projId: ModuleID,
|
||||||
dependencies: Seq[ModuleID],
|
dependencies: Seq[ModuleID],
|
||||||
excludeDeps: Seq[InclExclRule],
|
|
||||||
configurations: Seq[sbt.librarymanagement.Configuration],
|
configurations: Seq[sbt.librarymanagement.Configuration],
|
||||||
sv: String,
|
sv: String,
|
||||||
sbv: String,
|
sbv: String,
|
||||||
log: Logger
|
log: Logger
|
||||||
): Project = {
|
): Project = {
|
||||||
|
|
||||||
val exclusions0 = Inputs.exclusions(excludeDeps, sv, sbv, log)
|
val configMap = Inputs.configExtendsSeq(configurations).toMap
|
||||||
|
|
||||||
val configMap = Inputs.configExtends(configurations)
|
FromSbt.project(
|
||||||
|
|
||||||
val proj = FromSbt.project(
|
|
||||||
projId,
|
projId,
|
||||||
dependencies,
|
dependencies,
|
||||||
configMap,
|
configMap,
|
||||||
sv,
|
sv,
|
||||||
sbv
|
sbv
|
||||||
)
|
)
|
||||||
|
|
||||||
proj.withDependencies(
|
|
||||||
proj.dependencies.map {
|
|
||||||
case (config, dep) =>
|
|
||||||
val dep0 = dep.withExclusions(dep.exclusions ++ exclusions0)
|
|
||||||
(config, dep0)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private[sbtcoursiershared] def coursierProjectTask: Def.Initialize[sbt.Task[Project]] =
|
private[sbtcoursiershared] def coursierProjectTask: Def.Initialize[sbt.Task[Project]] =
|
||||||
|
|
@ -68,7 +57,6 @@ object InputsTasks {
|
||||||
coursierProject0(
|
coursierProject0(
|
||||||
projectID.in(projectRef).get(state),
|
projectID.in(projectRef).get(state),
|
||||||
allDependenciesTask.value,
|
allDependenciesTask.value,
|
||||||
actualExcludeDependencies.in(projectRef).get(state),
|
|
||||||
// should projectID.configurations be used instead?
|
// should projectID.configurations be used instead?
|
||||||
ivyConfigurations.in(projectRef).get(state),
|
ivyConfigurations.in(projectRef).get(state),
|
||||||
scalaVersion.in(projectRef).get(state),
|
scalaVersion.in(projectRef).get(state),
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,99 @@
|
||||||
|
package coursier.sbtcoursiershared
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets.UTF_8
|
||||||
|
import java.nio.file.Files
|
||||||
|
|
||||||
|
import lmcoursier.{Inputs, IvyXml}
|
||||||
|
import lmcoursier.definitions.{Configuration, Project}
|
||||||
|
import org.apache.ivy.core.module.id.ModuleRevisionId
|
||||||
|
import sbt.{Def, Setting, Task, TaskKey}
|
||||||
|
import sbt.internal.librarymanagement.IvySbt
|
||||||
|
import sbt.librarymanagement.{CrossVersion, PublishConfiguration}
|
||||||
|
|
||||||
|
import scala.collection.JavaConverters._
|
||||||
|
|
||||||
|
object IvyXmlGeneration {
|
||||||
|
|
||||||
|
// These are required for publish to be fine, later on.
|
||||||
|
private def writeFiles(
|
||||||
|
currentProject: Project,
|
||||||
|
exclusions: Seq[(String, String)],
|
||||||
|
shadedConfigOpt: Option[Configuration],
|
||||||
|
ivySbt: IvySbt,
|
||||||
|
log: sbt.util.Logger
|
||||||
|
): Unit = {
|
||||||
|
|
||||||
|
val ivyCacheManager = ivySbt.withIvy(log)(ivy =>
|
||||||
|
ivy.getResolutionCacheManager
|
||||||
|
)
|
||||||
|
|
||||||
|
val ivyModule = ModuleRevisionId.newInstance(
|
||||||
|
currentProject.module.organization.value,
|
||||||
|
currentProject.module.name.value,
|
||||||
|
currentProject.version,
|
||||||
|
currentProject.module.attributes.asJava
|
||||||
|
)
|
||||||
|
|
||||||
|
val cacheIvyFile = ivyCacheManager.getResolvedIvyFileInCache(ivyModule)
|
||||||
|
val cacheIvyPropertiesFile = ivyCacheManager.getResolvedIvyPropertiesInCache(ivyModule)
|
||||||
|
|
||||||
|
val content0 = IvyXml(currentProject, exclusions, shadedConfigOpt)
|
||||||
|
cacheIvyFile.getParentFile.mkdirs()
|
||||||
|
log.info(s"Writing Ivy file $cacheIvyFile")
|
||||||
|
Files.write(cacheIvyFile.toPath, content0.getBytes(UTF_8))
|
||||||
|
|
||||||
|
// Just writing an empty file here... Are these only used?
|
||||||
|
cacheIvyPropertiesFile.getParentFile.mkdirs()
|
||||||
|
Files.write(cacheIvyPropertiesFile.toPath, Array.emptyByteArray)
|
||||||
|
}
|
||||||
|
|
||||||
|
private def makeIvyXmlBefore[T](
|
||||||
|
task: TaskKey[T],
|
||||||
|
shadedConfigOpt: Option[Configuration]
|
||||||
|
): Setting[Task[T]] =
|
||||||
|
task := task.dependsOn {
|
||||||
|
Def.taskDyn {
|
||||||
|
import SbtCoursierShared.autoImport._
|
||||||
|
val doGen = coursierGenerateIvyXml.value
|
||||||
|
if (doGen)
|
||||||
|
Def.task {
|
||||||
|
val sv = sbt.Keys.scalaVersion.value
|
||||||
|
val sbv = sbt.Keys.scalaBinaryVersion.value
|
||||||
|
val log = sbt.Keys.streams.value.log
|
||||||
|
val currentProject = {
|
||||||
|
val proj = coursierProject.value
|
||||||
|
val publications = coursierPublications.value
|
||||||
|
proj.withPublications(publications)
|
||||||
|
}
|
||||||
|
val excludeDeps = Inputs.exclusionsSeq(InputsTasks.actualExcludeDependencies.value, sv, sbv, log)
|
||||||
|
.map {
|
||||||
|
case (org, name) =>
|
||||||
|
(org.value, name.value)
|
||||||
|
}
|
||||||
|
writeFiles(currentProject, excludeDeps, shadedConfigOpt, sbt.Keys.ivySbt.value, log)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Def.task(())
|
||||||
|
}
|
||||||
|
}.value
|
||||||
|
|
||||||
|
private lazy val needsIvyXmlLocal = Seq(sbt.Keys.publishLocalConfiguration) ++ getPubConf("makeIvyXmlLocalConfiguration")
|
||||||
|
private lazy val needsIvyXml = Seq(sbt.Keys.publishConfiguration) ++ getPubConf("makeIvyXmlConfiguration")
|
||||||
|
|
||||||
|
private[this] def getPubConf(method: String): List[TaskKey[PublishConfiguration]] =
|
||||||
|
try {
|
||||||
|
val cls = sbt.Keys.getClass
|
||||||
|
val m = cls.getMethod(method)
|
||||||
|
val task = m.invoke(sbt.Keys).asInstanceOf[TaskKey[PublishConfiguration]]
|
||||||
|
List(task)
|
||||||
|
} catch {
|
||||||
|
case _: Throwable => // FIXME Too wide
|
||||||
|
Nil
|
||||||
|
}
|
||||||
|
|
||||||
|
def generateIvyXmlSettings(
|
||||||
|
shadedConfigOpt: Option[Configuration] = None
|
||||||
|
): Seq[Setting[_]] =
|
||||||
|
(needsIvyXml ++ needsIvyXmlLocal).map(makeIvyXmlBefore(_, shadedConfigOpt))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -174,7 +174,7 @@ object SbtCoursierShared extends AutoPlugin {
|
||||||
versionReconciliation := Seq.empty
|
versionReconciliation := Seq.empty
|
||||||
) ++ {
|
) ++ {
|
||||||
if (pubSettings)
|
if (pubSettings)
|
||||||
IvyXml.generateIvyXmlSettings()
|
IvyXmlGeneration.generateIvyXmlSettings()
|
||||||
else
|
else
|
||||||
Nil
|
Nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
package coursier.sbtcoursiershared
|
|
||||||
|
|
||||||
import lmcoursier.definitions.{Configuration, Info, Module, ModuleName, Organization, Project}
|
|
||||||
import utest._
|
|
||||||
|
|
||||||
object IvyXmlTests extends TestSuite {
|
|
||||||
|
|
||||||
val tests = Tests {
|
|
||||||
"no truncation" - {
|
|
||||||
|
|
||||||
val project = Project(
|
|
||||||
Module(Organization("org"), ModuleName("name"), Map()),
|
|
||||||
"ver",
|
|
||||||
Nil,
|
|
||||||
Map(
|
|
||||||
Configuration("foo") -> (1 to 80).map(n => Configuration("bar" + n)) // long list of configurations -> no truncation any way
|
|
||||||
),
|
|
||||||
Nil,
|
|
||||||
None,
|
|
||||||
Nil,
|
|
||||||
Info("", "", Nil, Nil, None)
|
|
||||||
)
|
|
||||||
|
|
||||||
val content = IvyXml.rawContent(project, None)
|
|
||||||
|
|
||||||
assert(!content.contains("</conf>"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -24,7 +24,7 @@ object ArtifactsTasks {
|
||||||
|
|
||||||
val resTask: sbt.Def.Initialize[sbt.Task[Seq[Resolution]]] =
|
val resTask: sbt.Def.Initialize[sbt.Task[Seq[Resolution]]] =
|
||||||
if (withClassifiers && sbtClassifiers)
|
if (withClassifiers && sbtClassifiers)
|
||||||
Def.task(Seq(coursierSbtClassifiersResolution.value))
|
Def.task(coursierSbtClassifiersResolutions.value.values.toVector)
|
||||||
else
|
else
|
||||||
Def.task(coursierResolutions.value.values.toVector)
|
Def.task(coursierResolutions.value.values.toVector)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ object CoursierPlugin extends AutoPlugin {
|
||||||
val coursierParentProjectCache = Keys.coursierParentProjectCache
|
val coursierParentProjectCache = Keys.coursierParentProjectCache
|
||||||
val coursierResolutions = Keys.coursierResolutions
|
val coursierResolutions = Keys.coursierResolutions
|
||||||
|
|
||||||
val coursierSbtClassifiersResolution = Keys.coursierSbtClassifiersResolution
|
val coursierSbtClassifiersResolutions = Keys.coursierSbtClassifiersResolutions
|
||||||
|
|
||||||
val coursierDependencyTree = Keys.coursierDependencyTree
|
val coursierDependencyTree = Keys.coursierDependencyTree
|
||||||
val coursierDependencyInverseTree = Keys.coursierDependencyInverseTree
|
val coursierDependencyInverseTree = Keys.coursierDependencyInverseTree
|
||||||
|
|
@ -176,21 +176,18 @@ object CoursierPlugin extends AutoPlugin {
|
||||||
|
|
||||||
coursierResolutions
|
coursierResolutions
|
||||||
.value
|
.value
|
||||||
.collectFirst {
|
.getOrElse(
|
||||||
case (configs, res) if configs(config) =>
|
config,
|
||||||
res
|
|
||||||
}
|
|
||||||
.getOrElse {
|
|
||||||
sys.error(s"Resolution for configuration $config not found")
|
sys.error(s"Resolution for configuration $config not found")
|
||||||
}
|
)
|
||||||
},
|
},
|
||||||
coursierSbtClassifiersResolution := (Def.taskDyn {
|
coursierSbtClassifiersResolutions := (Def.taskDyn {
|
||||||
val missingOk = (updateConfiguration in updateSbtClassifiers).value.missingOk
|
val missingOk = (updateConfiguration in updateSbtClassifiers).value.missingOk
|
||||||
ResolutionTasks.resolutionsTask(
|
ResolutionTasks.resolutionsTask(
|
||||||
sbtClassifiers = true,
|
sbtClassifiers = true,
|
||||||
missingOk = missingOk,
|
missingOk = missingOk,
|
||||||
)
|
)
|
||||||
}).value.head._2
|
}).value
|
||||||
)
|
)
|
||||||
|
|
||||||
override lazy val buildSettings = super.buildSettings ++ Seq(
|
override lazy val buildSettings = super.buildSettings ++ Seq(
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ import scala.collection.mutable
|
||||||
|
|
||||||
object DisplayTasks {
|
object DisplayTasks {
|
||||||
|
|
||||||
private case class ResolutionResult(configs: Set[Configuration], resolution: Resolution, dependencies: Seq[Dependency])
|
private case class ResolutionResult(config: Configuration, resolution: Resolution, dependencies: Seq[Dependency])
|
||||||
|
|
||||||
private def coursierResolutionTask(
|
private def coursierResolutionTask(
|
||||||
sbtClassifiers: Boolean = false,
|
sbtClassifiers: Boolean = false,
|
||||||
|
|
@ -37,13 +37,9 @@ object DisplayTasks {
|
||||||
|
|
||||||
val resolutionsTask =
|
val resolutionsTask =
|
||||||
if (sbtClassifiers)
|
if (sbtClassifiers)
|
||||||
Def.task {
|
coursierSbtClassifiersResolutions
|
||||||
val currentProject = currentProjectTask.value
|
|
||||||
val classifiersRes = coursierSbtClassifiersResolution.value
|
|
||||||
Map(currentProject.configurations.keySet.map(ToCoursier.configuration) -> classifiersRes)
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
Def.task(coursierResolutions.value)
|
coursierResolutions
|
||||||
|
|
||||||
Def.task {
|
Def.task {
|
||||||
|
|
||||||
|
|
@ -57,19 +53,23 @@ object DisplayTasks {
|
||||||
val resolutions = resolutionsTask.value
|
val resolutions = resolutionsTask.value
|
||||||
|
|
||||||
for {
|
for {
|
||||||
(subGraphConfigs, res) <- resolutions.toSeq
|
(subGraphConfig, res) <- resolutions.toSeq
|
||||||
if subGraphConfigs.exists(includedConfigs)
|
if includedConfigs(subGraphConfig)
|
||||||
} yield {
|
} yield {
|
||||||
|
|
||||||
val dependencies0 = currentProject.dependencies.collect {
|
val dependencies0 = currentProject
|
||||||
case (cfg, dep) if includedConfigs(cfg) && subGraphConfigs(cfg) => dep
|
.dependencies
|
||||||
}.sortBy { dep =>
|
.collect {
|
||||||
|
case (`subGraphConfig`, dep) =>
|
||||||
|
dep
|
||||||
|
}
|
||||||
|
.sortBy { dep =>
|
||||||
(dep.module.organization, dep.module.name, dep.version)
|
(dep.module.organization, dep.module.name, dep.version)
|
||||||
}
|
}
|
||||||
|
|
||||||
val subRes = res.subset(dependencies0)
|
val subRes = res.subset(dependencies0)
|
||||||
|
|
||||||
ResolutionResult(subGraphConfigs, subRes, dependencies0)
|
ResolutionResult(subGraphConfig, subRes, dependencies0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -82,9 +82,9 @@ object DisplayTasks {
|
||||||
val projectName = thisProjectRef.value.project
|
val projectName = thisProjectRef.value.project
|
||||||
|
|
||||||
val resolutions = coursierResolutionTask(sbtClassifiers, ignoreArtifactErrors).value
|
val resolutions = coursierResolutionTask(sbtClassifiers, ignoreArtifactErrors).value
|
||||||
for (ResolutionResult(subGraphConfigs, resolution, dependencies) <- resolutions) {
|
for (ResolutionResult(subGraphConfig, resolution, dependencies) <- resolutions) {
|
||||||
streams.value.log.info(
|
streams.value.log.info(
|
||||||
s"$projectName (configurations ${subGraphConfigs.toVector.sorted.mkString(", ")})" + "\n" +
|
s"$projectName (configuration ${subGraphConfig.value})" + "\n" +
|
||||||
Print.dependencyTree(
|
Print.dependencyTree(
|
||||||
resolution,
|
resolution,
|
||||||
dependencies,
|
dependencies,
|
||||||
|
|
@ -110,13 +110,13 @@ object DisplayTasks {
|
||||||
|
|
||||||
val resolutions = coursierResolutionTask(sbtClassifiers, ignoreArtifactErrors).value
|
val resolutions = coursierResolutionTask(sbtClassifiers, ignoreArtifactErrors).value
|
||||||
val result = new mutable.StringBuilder
|
val result = new mutable.StringBuilder
|
||||||
for (ResolutionResult(subGraphConfigs, resolution, _) <- resolutions) {
|
for (ResolutionResult(subGraphConfig, resolution, _) <- resolutions) {
|
||||||
val roots = resolution
|
val roots = resolution
|
||||||
.minDependencies
|
.minDependencies
|
||||||
.filter(f => f.module == module)
|
.filter(f => f.module == module)
|
||||||
.toVector
|
.toVector
|
||||||
.sortBy(_.toString) // elements already have the same module, there's not much left for sorting…
|
.sortBy(_.toString) // elements already have the same module, there's not much left for sorting…
|
||||||
val strToPrint = s"$projectName (configurations ${subGraphConfigs.toVector.sorted.map(_.value).mkString(", ")})" + "\n" +
|
val strToPrint = s"$projectName (configurations ${subGraphConfig.value})" + "\n" +
|
||||||
Print.dependencyTree(
|
Print.dependencyTree(
|
||||||
resolution,
|
resolution,
|
||||||
roots,
|
roots,
|
||||||
|
|
|
||||||
|
|
@ -26,10 +26,13 @@ object InputsTasks {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def ivyGraphsTask: Def.Initialize[sbt.Task[Seq[Set[Configuration]]]] =
|
def ivyGraphsTask: Def.Initialize[sbt.Task[Seq[(Configuration, Seq[Configuration])]]] =
|
||||||
Def.task {
|
Def.task {
|
||||||
val p = coursierProject.value
|
val p = coursierProject.value
|
||||||
Inputs.ivyGraphs(p.configurations).map(_.map(ToCoursier.configuration))
|
Inputs.orderedConfigurations(p.configurations.toSeq).map {
|
||||||
|
case (config, extends0) =>
|
||||||
|
(ToCoursier.configuration(config), extends0.map(ToCoursier.configuration))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def parentProjectCacheTask: Def.Initialize[sbt.Task[Map[Seq[sbt.librarymanagement.Resolver], Seq[coursier.ProjectCache]]]] =
|
def parentProjectCacheTask: Def.Initialize[sbt.Task[Map[Seq[sbt.librarymanagement.Resolver], Seq[coursier.ProjectCache]]]] =
|
||||||
|
|
@ -53,7 +56,7 @@ object InputsTasks {
|
||||||
n.foldLeft(Map.empty[Seq[Resolver], Seq[ProjectCache]]) {
|
n.foldLeft(Map.empty[Seq[Resolver], Seq[ProjectCache]]) {
|
||||||
case (caches, (ref, resolutions)) =>
|
case (caches, (ref, resolutions)) =>
|
||||||
val mainResOpt = resolutions.collectFirst {
|
val mainResOpt = resolutions.collectFirst {
|
||||||
case (k, v) if k(Configuration.compile) => v
|
case (Configuration.compile, v) => v
|
||||||
}
|
}
|
||||||
|
|
||||||
val r = for {
|
val r = for {
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ object Keys {
|
||||||
|
|
||||||
val coursierVerbosity = SettingKey[Int]("coursier-verbosity")
|
val coursierVerbosity = SettingKey[Int]("coursier-verbosity")
|
||||||
|
|
||||||
val coursierConfigGraphs = TaskKey[Seq[Set[Configuration]]]("coursier-config-graphs")
|
val coursierConfigGraphs = TaskKey[Seq[(Configuration, Seq[Configuration])]]("coursier-config-graphs")
|
||||||
|
|
||||||
val coursierSbtClassifiersModule = TaskKey[GetClassifiersModule]("coursier-sbt-classifiers-module")
|
val coursierSbtClassifiersModule = TaskKey[GetClassifiersModule]("coursier-sbt-classifiers-module")
|
||||||
|
|
||||||
|
|
@ -29,11 +29,11 @@ object Keys {
|
||||||
|
|
||||||
|
|
||||||
val coursierParentProjectCache = TaskKey[Map[Seq[Resolver], Seq[ProjectCache]]]("coursier-parent-project-cache")
|
val coursierParentProjectCache = TaskKey[Map[Seq[Resolver], Seq[ProjectCache]]]("coursier-parent-project-cache")
|
||||||
val coursierResolutions = TaskKey[Map[Set[Configuration], Resolution]]("coursier-resolutions")
|
val coursierResolutions = TaskKey[Map[Configuration, Resolution]]("coursier-resolutions")
|
||||||
|
|
||||||
private[coursier] val actualCoursierResolution = TaskKey[Resolution]("coursier-resolution")
|
private[coursier] val actualCoursierResolution = TaskKey[Resolution]("coursier-resolution")
|
||||||
|
|
||||||
val coursierSbtClassifiersResolution = TaskKey[Resolution]("coursier-sbt-classifiers-resolution")
|
val coursierSbtClassifiersResolutions = TaskKey[Map[Configuration, Resolution]]("coursier-sbt-classifiers-resolution")
|
||||||
|
|
||||||
val coursierDependencyTree = TaskKey[Unit](
|
val coursierDependencyTree = TaskKey[Unit](
|
||||||
"coursier-dependency-tree",
|
"coursier-dependency-tree",
|
||||||
|
|
|
||||||
|
|
@ -19,9 +19,9 @@ object ResolutionTasks {
|
||||||
def resolutionsTask(
|
def resolutionsTask(
|
||||||
sbtClassifiers: Boolean = false,
|
sbtClassifiers: Boolean = false,
|
||||||
missingOk: Boolean = false,
|
missingOk: Boolean = false,
|
||||||
): Def.Initialize[sbt.Task[Map[Set[Configuration], coursier.Resolution]]] = {
|
): Def.Initialize[sbt.Task[Map[Configuration, coursier.Resolution]]] = {
|
||||||
|
|
||||||
val currentProjectTask: sbt.Def.Initialize[sbt.Task[(Project, Seq[FallbackDependency], Seq[Set[Configuration]])]] =
|
val currentProjectTask: sbt.Def.Initialize[sbt.Task[(Project, Seq[FallbackDependency], Seq[(Configuration, Seq[Configuration])])]] =
|
||||||
if (sbtClassifiers)
|
if (sbtClassifiers)
|
||||||
Def.task {
|
Def.task {
|
||||||
val sv = scalaVersion.value
|
val sv = scalaVersion.value
|
||||||
|
|
@ -35,7 +35,7 @@ object ResolutionTasks {
|
||||||
sbv
|
sbv
|
||||||
)
|
)
|
||||||
|
|
||||||
(proj, fallbackDeps, Vector(cm.configurations.map(c => Configuration(c.name)).toSet))
|
(proj, fallbackDeps, cm.configurations.map(c => Configuration(c.name) -> Nil))
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
Def.task {
|
Def.task {
|
||||||
|
|
@ -97,7 +97,7 @@ object ResolutionTasks {
|
||||||
|
|
||||||
val authenticationByRepositoryId = coursierCredentials.value.mapValues(_.authentication)
|
val authenticationByRepositoryId = coursierCredentials.value.mapValues(_.authentication)
|
||||||
|
|
||||||
val (currentProject, fallbackDependencies, configGraphs) = currentProjectTask.value
|
val (currentProject, fallbackDependencies, orderedConfigs) = currentProjectTask.value
|
||||||
|
|
||||||
val autoScalaLib = autoScalaLibrary.value && scalaModuleInfo.value.forall(_.overrideScalaVersion)
|
val autoScalaLib = autoScalaLibrary.value && scalaModuleInfo.value.forall(_.overrideScalaVersion)
|
||||||
|
|
||||||
|
|
@ -114,6 +114,16 @@ object ResolutionTasks {
|
||||||
.map(_.foldLeft[ProjectCache](Map.empty)(_ ++ _))
|
.map(_.foldLeft[ProjectCache](Map.empty)(_ ++ _))
|
||||||
.getOrElse(Map.empty)
|
.getOrElse(Map.empty)
|
||||||
|
|
||||||
|
val excludeDeps = Inputs.exclusions(
|
||||||
|
coursier.sbtcoursiershared.InputsTasks.actualExcludeDependencies.value,
|
||||||
|
sv,
|
||||||
|
sbv,
|
||||||
|
log
|
||||||
|
).map {
|
||||||
|
case (org, name) =>
|
||||||
|
(Organization(org.value), ModuleName(name.value))
|
||||||
|
}
|
||||||
|
|
||||||
val mainRepositories = resolvers
|
val mainRepositories = resolvers
|
||||||
.flatMap { resolver =>
|
.flatMap { resolver =>
|
||||||
Resolvers.repository(
|
Resolvers.repository(
|
||||||
|
|
@ -132,7 +142,7 @@ object ResolutionTasks {
|
||||||
ResolutionParams(
|
ResolutionParams(
|
||||||
dependencies = currentProject.dependencies,
|
dependencies = currentProject.dependencies,
|
||||||
fallbackDependencies = fallbackDependencies,
|
fallbackDependencies = fallbackDependencies,
|
||||||
configGraphs = configGraphs,
|
orderedConfigs = orderedConfigs,
|
||||||
autoScalaLibOpt = if (autoScalaLib) Some((so, sv)) else None,
|
autoScalaLibOpt = if (autoScalaLib) Some((so, sv)) else None,
|
||||||
mainRepositories = mainRepositories,
|
mainRepositories = mainRepositories,
|
||||||
parentProjectCache = parentProjectCache,
|
parentProjectCache = parentProjectCache,
|
||||||
|
|
@ -154,7 +164,8 @@ object ResolutionTasks {
|
||||||
.withProfiles(userEnabledProfiles)
|
.withProfiles(userEnabledProfiles)
|
||||||
.withForceVersion(userForceVersions.map { case (k, v) => (ToCoursier.module(k), v) }.toMap)
|
.withForceVersion(userForceVersions.map { case (k, v) => (ToCoursier.module(k), v) }.toMap)
|
||||||
.withTypelevel(typelevel)
|
.withTypelevel(typelevel)
|
||||||
.addReconciliation(versionReconciliations0: _*),
|
.addReconciliation(versionReconciliations0: _*)
|
||||||
|
.withExclusions(excludeDeps),
|
||||||
strictOpt = strictOpt,
|
strictOpt = strictOpt,
|
||||||
missingOk = missingOk,
|
missingOk = missingOk,
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -34,13 +34,9 @@ object UpdateTasks {
|
||||||
|
|
||||||
val resTask =
|
val resTask =
|
||||||
if (withClassifiers && sbtClassifiers)
|
if (withClassifiers && sbtClassifiers)
|
||||||
Def.task {
|
coursierSbtClassifiersResolutions
|
||||||
val cm = coursierSbtClassifiersModule.value
|
|
||||||
val classifiersRes = coursierSbtClassifiersResolution.value
|
|
||||||
Map(cm.configurations.map(c => Configuration(c.name)).toSet -> classifiersRes)
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
Def.task(coursierResolutions.value)
|
coursierResolutions
|
||||||
|
|
||||||
// we should be able to call .value on that one here, its conditions don't originate from other tasks
|
// we should be able to call .value on that one here, its conditions don't originate from other tasks
|
||||||
val artifactFilesOrErrors0Task =
|
val artifactFilesOrErrors0Task =
|
||||||
|
|
|
||||||
|
|
@ -12,5 +12,6 @@ import CoursierPlugin.autoImport._
|
||||||
whatDependsOnCheck := {
|
whatDependsOnCheck := {
|
||||||
val result = (coursierWhatDependsOn in Compile).toTask(" log4j:log4j").value
|
val result = (coursierWhatDependsOn in Compile).toTask(" log4j:log4j").value
|
||||||
val file = new File("whatDependsOnResult.log")
|
val file = new File("whatDependsOnResult.log")
|
||||||
assert(IO.read(file).toString == result)
|
val expected = IO.read(file).toString
|
||||||
|
assert(expected == result, s"Expected '$expected', got '$result'")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
import java.io.File
|
|
||||||
import java.nio.file.Files
|
|
||||||
|
|
||||||
import org.apache.zookeeper.ZooKeeper
|
|
||||||
|
|
||||||
object Main extends App {
|
|
||||||
Files.write(new File("output").toPath, classOf[ZooKeeper].getSimpleName.getBytes("UTF-8"))
|
|
||||||
}
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
dependency-graph (configurations compile, compile-internal, optional, provided, runtime, runtime-internal, test, test-internal)
|
dependency-graph (configurations compile)
|
||||||
└─ log4j:log4j:1.2.17
|
└─ log4j:log4j:1.2.17
|
||||||
├─ org.apache.zookeeper:zookeeper:3.5.0-alpha log4j:log4j:1.2.16 -> 1.2.17
|
├─ org.apache.zookeeper:zookeeper:3.5.0-alpha log4j:log4j:1.2.16 -> 1.2.17
|
||||||
└─ org.slf4j:slf4j-log4j12:1.7.5
|
└─ org.slf4j:slf4j-log4j12:1.7.5
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -27,6 +27,4 @@ object Main extends App {
|
||||||
!argonautFound,
|
!argonautFound,
|
||||||
"Expected not to find classes from argonaut"
|
"Expected not to find classes from argonaut"
|
||||||
)
|
)
|
||||||
|
|
||||||
Files.write(new File("output").toPath, "OK".getBytes("UTF-8"))
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
$ delete output
|
|
||||||
> run
|
> run
|
||||||
$ exists output
|
|
||||||
> publishLocal
|
> publishLocal
|
||||||
$ exec java -jar coursier launch io.get-coursier.test:sbt-coursier-all-exclude-dependencies_2.12:0.1.0-SNAPSHOT
|
$ exec java -jar coursier launch io.get-coursier.test:sbt-coursier-all-exclude-dependencies_2.12:0.1.0-SNAPSHOT
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,4 @@ object Main extends App {
|
||||||
!argonautFound,
|
!argonautFound,
|
||||||
"Expected not to find classes from argonaut"
|
"Expected not to find classes from argonaut"
|
||||||
)
|
)
|
||||||
|
|
||||||
Files.write(new File("output").toPath, "OK".getBytes("UTF-8"))
|
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
import java.io.File
|
||||||
|
import java.nio.file.Files
|
||||||
|
|
||||||
|
import scala.util.Try
|
||||||
|
|
||||||
|
object Main extends App {
|
||||||
|
|
||||||
|
def classFound(clsName: String) = Try(
|
||||||
|
Thread.currentThread()
|
||||||
|
.getContextClassLoader()
|
||||||
|
.loadClass(clsName)
|
||||||
|
).toOption.nonEmpty
|
||||||
|
|
||||||
|
val shapelessFound = classFound("shapeless.HList")
|
||||||
|
val argonautFound = classFound("argonaut.Json")
|
||||||
|
val argonautShapelessFound = classFound("argonaut.derive.MkEncodeJson")
|
||||||
|
|
||||||
|
assert(
|
||||||
|
argonautShapelessFound,
|
||||||
|
"Expected to find class from argonaut-shapeless"
|
||||||
|
)
|
||||||
|
assert(
|
||||||
|
!shapelessFound,
|
||||||
|
"Expected not to find classes from shapeless"
|
||||||
|
)
|
||||||
|
assert(
|
||||||
|
!argonautFound,
|
||||||
|
"Expected not to find classes from argonaut"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -1,11 +1,26 @@
|
||||||
|
|
||||||
scalaVersion := "2.12.8"
|
lazy val a = project
|
||||||
|
.settings(
|
||||||
organization := "io.get-coursier.test"
|
organization := "io.get-coursier.test",
|
||||||
name := "sbt-coursier-exclude-dependencies"
|
name := "sbt-coursier-exclude-dependencies",
|
||||||
version := "0.1.0-SNAPSHOT"
|
version := "0.1.0-SNAPSHOT",
|
||||||
|
scalaVersion := "2.12.8",
|
||||||
libraryDependencies += "com.github.alexarchambault" %% "argonaut-shapeless_6.2" % "1.2.0-M11"
|
libraryDependencies += "com.github.alexarchambault" %% "argonaut-shapeless_6.2" % "1.2.0-M11",
|
||||||
|
excludeDependencies += sbt.ExclusionRule("com.chuusai", "shapeless_2.12"),
|
||||||
excludeDependencies += sbt.ExclusionRule("com.chuusai", "shapeless_2.12")
|
|
||||||
excludeDependencies += "io.argonaut" %% "argonaut"
|
excludeDependencies += "io.argonaut" %% "argonaut"
|
||||||
|
)
|
||||||
|
|
||||||
|
lazy val b = project
|
||||||
|
.settings(
|
||||||
|
organization := "io.get-coursier.test",
|
||||||
|
name := "sbt-coursier-exclude-dependencies-2",
|
||||||
|
version := "0.1.0-SNAPSHOT",
|
||||||
|
scalaVersion := "2.12.8",
|
||||||
|
libraryDependencies ++= Seq(
|
||||||
|
"com.github.alexarchambault" %% "argonaut-shapeless_6.2" % "1.2.0-M11",
|
||||||
|
"com.chuusai" %% "shapeless" % "2.3.3",
|
||||||
|
"io.argonaut" %% "argonaut" % "6.2.3"
|
||||||
|
),
|
||||||
|
excludeDependencies += sbt.ExclusionRule("com.chuusai", "shapeless_2.12"),
|
||||||
|
excludeDependencies += "io.argonaut" %% "argonaut"
|
||||||
|
)
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -1,5 +1,6 @@
|
||||||
$ delete output
|
> a/run
|
||||||
> run
|
> a/publishLocal
|
||||||
$ exists output
|
|
||||||
> publishLocal
|
|
||||||
$ exec java -jar coursier launch io.get-coursier.test:sbt-coursier-exclude-dependencies_2.12:0.1.0-SNAPSHOT
|
$ exec java -jar coursier launch io.get-coursier.test:sbt-coursier-exclude-dependencies_2.12:0.1.0-SNAPSHOT
|
||||||
|
> b/run
|
||||||
|
> b/publishLocal
|
||||||
|
$ exec java -jar coursier launch io.get-coursier.test:sbt-coursier-exclude-dependencies-2_2.12:0.1.0-SNAPSHOT
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
scalaVersion := "2.13.2"
|
||||||
|
libraryDependencies ++= Seq(
|
||||||
|
"io.get-coursier" %% "coursier-core" % "2.0.0-RC6",
|
||||||
|
// depends on coursier-core 2.0.0-RC6-16
|
||||||
|
"io.get-coursier" %% "coursier" % "2.0.0-RC6-16" % Test
|
||||||
|
)
|
||||||
|
mainClass.in(Compile) := Some("Main")
|
||||||
|
mainClass.in(Test) := Some("Test")
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
object Main {
|
||||||
|
def main(args: Array[String]): Unit = {
|
||||||
|
val version = coursier.util.Properties.version
|
||||||
|
val expected = "2.0.0-RC6"
|
||||||
|
assert(version == expected, s"version: $version, expected: $expected")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
object Test {
|
||||||
|
def main(args: Array[String]): Unit = {
|
||||||
|
val version = coursier.util.Properties.version
|
||||||
|
val expected = "2.0.0-RC6-16"
|
||||||
|
assert(version == expected, s"version: $version, expected: $expected")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
> run
|
||||||
|
> test:run
|
||||||
Loading…
Reference in New Issue