Replace scopes with Ivy-like configuration

This commit is contained in:
Alexandre Archambault 2015-12-30 01:34:32 +01:00
parent d3cd484c15
commit e4dfc862b4
13 changed files with 241 additions and 247 deletions

View File

@ -171,7 +171,7 @@ class Helper(
} }
val deps = moduleVersions.map{case (mod, ver) => val deps = moduleVersions.map{case (mod, ver) =>
Dependency(mod, ver, scope = Scope.Runtime) Dependency(mod, ver, configuration = "runtime")
} }
val forceVersions = { val forceVersions = {

View File

@ -24,8 +24,6 @@ case class Module(
override def toString = s"$organization:$name" override def toString = s"$organization:$name"
} }
sealed abstract class Scope(val name: String)
/** /**
* Dependencies with the same @module will typically see their @version-s merged. * Dependencies with the same @module will typically see their @version-s merged.
* *
@ -35,7 +33,7 @@ sealed abstract class Scope(val name: String)
case class Dependency( case class Dependency(
module: Module, module: Module,
version: String, version: String,
scope: Scope, configuration: String,
attributes: Attributes, attributes: Attributes,
exclusions: Set[(String, String)], exclusions: Set[(String, String)],
optional: Boolean optional: Boolean
@ -51,9 +49,10 @@ case class Attributes(
case class Project( case class Project(
module: Module, module: Module,
version: String, version: String,
dependencies: Seq[Dependency], dependencies: Seq[(String, Dependency)],
parent: Option[(Module, String)], parent: Option[(Module, String)],
dependencyManagement: Seq[Dependency], dependencyManagement: Seq[(String, Dependency)],
configurations: Map[String, Seq[String]],
properties: Map[String, String], properties: Map[String, String],
profiles: Seq[Profile], profiles: Seq[Profile],
versions: Option[Versions], versions: Option[Versions],
@ -62,23 +61,14 @@ case class Project(
def moduleVersion = (module, version) def moduleVersion = (module, version)
} }
object Scope {
case object Compile extends Scope("compile")
case object Runtime extends Scope("runtime")
case object Test extends Scope("test")
case object Provided extends Scope("provided")
case object Import extends Scope("import")
case class Other(override val name: String) extends Scope(name)
}
case class Activation(properties: Seq[(String, Option[String])]) case class Activation(properties: Seq[(String, Option[String])])
case class Profile( case class Profile(
id: String, id: String,
activeByDefault: Option[Boolean], activeByDefault: Option[Boolean],
activation: Activation, activation: Activation,
dependencies: Seq[Dependency], dependencies: Seq[(String, Dependency)],
dependencyManagement: Seq[Dependency], dependencyManagement: Seq[(String, Dependency)],
properties: Map[String, String] properties: Map[String, String]
) )

View File

@ -2,39 +2,56 @@ package coursier.core
object Orders { object Orders {
/** Minimal ad-hoc partial order */ trait PartialOrdering[T] extends scala.math.PartialOrdering[T] {
trait PartialOrder[A] { def lteq(x: T, y: T): Boolean =
/** tryCompare(x, y)
* x < y: Some(neg. integer) .exists(_ <= 0)
* x == y: Some(0)
* x > y: Some(pos. integer)
* x, y not related: None
*/
def cmp(x: A, y: A): Option[Int]
} }
/** /**
* Only relations: * Only relations:
* Compile < Runtime < Test * Compile < Runtime < Test
*/ */
implicit val mavenScopePartialOrder: PartialOrder[Scope] = def configurationPartialOrder(configurations: Map[String, Seq[String]]): PartialOrdering[String] =
new PartialOrder[Scope] { new PartialOrdering[String] {
val higher = Map[Scope, Set[Scope]]( def allParents(config: String): Set[String] = {
Scope.Compile -> Set(Scope.Runtime, Scope.Test), def helper(configs: Set[String], acc: Set[String]): Set[String] =
Scope.Runtime -> Set(Scope.Test) if (configs.isEmpty)
) acc
else if (configs.exists(acc))
helper(configs -- acc, acc)
else if (configs.exists(!configurations.contains(_))) {
val (remaining, notFound) = configs.partition(configurations.contains)
helper(remaining, acc ++ notFound)
} else {
val extraConfigs = configs.flatMap(configurations)
helper(extraConfigs, acc ++ configs)
}
def cmp(x: Scope, y: Scope) = helper(Set(config), Set.empty)
if (x == y) Some(0) }
else if (higher.get(x).exists(_(y))) Some(-1)
else if (higher.get(y).exists(_(x))) Some(1) val allParentsMap = configurations
else None .keys
.toList
.map(config => config -> (allParents(config) - config))
.toMap
def tryCompare(x: String, y: String) =
if (x == y)
Some(0)
else if (allParentsMap.get(x).exists(_(y)))
Some(-1)
else if (allParentsMap.get(y).exists(_(x)))
Some(1)
else
None
} }
/** Non-optional < optional */ /** Non-optional < optional */
implicit val optionalPartialOrder: PartialOrder[Boolean] = val optionalPartialOrder: PartialOrdering[Boolean] =
new PartialOrder[Boolean] { new PartialOrdering[Boolean] {
def cmp(x: Boolean, y: Boolean) = def tryCompare(x: Boolean, y: Boolean) =
Some( Some(
if (x == y) 0 if (x == y) 0
else if (x) 1 else if (x) 1
@ -51,8 +68,8 @@ object Orders {
* *
* In particular, no exclusions <= anything <= Set(("*", "*")) * In particular, no exclusions <= anything <= Set(("*", "*"))
*/ */
implicit val exclusionsPartialOrder: PartialOrder[Set[(String, String)]] = val exclusionsPartialOrder: PartialOrdering[Set[(String, String)]] =
new PartialOrder[Set[(String, String)]] { new PartialOrdering[Set[(String, String)]] {
def boolCmp(a: Boolean, b: Boolean) = (a, b) match { def boolCmp(a: Boolean, b: Boolean) = (a, b) match {
case (true, true) => Some(0) case (true, true) => Some(0)
case (true, false) => Some(1) case (true, false) => Some(1)
@ -60,7 +77,7 @@ object Orders {
case (false, false) => None case (false, false) => None
} }
def cmp(x: Set[(String, String)], y: Set[(String, String)]) = { def tryCompare(x: Set[(String, String)], y: Set[(String, String)]) = {
val (xAll, xExcludeByOrg1, xExcludeByName1, xRemaining0) = Exclusions.partition(x) val (xAll, xExcludeByOrg1, xExcludeByName1, xRemaining0) = Exclusions.partition(x)
val (yAll, yExcludeByOrg1, yExcludeByName1, yRemaining0) = Exclusions.partition(y) val (yAll, yExcludeByOrg1, yExcludeByName1, yRemaining0) = Exclusions.partition(y)
@ -102,19 +119,22 @@ object Orders {
* Assume all dependencies have same `module`, `version`, and `artifact`; see `minDependencies` * Assume all dependencies have same `module`, `version`, and `artifact`; see `minDependencies`
* if they don't. * if they don't.
*/ */
def minDependenciesUnsafe(dependencies: Set[Dependency]): Set[Dependency] = { def minDependenciesUnsafe(
dependencies: Set[Dependency],
configs: ((Module, String)) => Map[String, Seq[String]]
): Set[Dependency] = {
val groupedDependencies = dependencies val groupedDependencies = dependencies
.groupBy(dep => (dep.optional, dep.scope)) .groupBy(dep => (dep.optional, dep.configuration))
.mapValues(deps => deps.head.copy(exclusions = deps.foldLeft(Exclusions.one)((acc, dep) => Exclusions.meet(acc, dep.exclusions)))) .mapValues(deps => deps.head.copy(exclusions = deps.foldLeft(Exclusions.one)((acc, dep) => Exclusions.meet(acc, dep.exclusions))))
.toList .toList
val remove = val remove =
for { for {
List(((xOpt, xScope), xDep), ((yOpt, yScope), yDep)) <- groupedDependencies.combinations(2) List(((xOpt, xScope), xDep), ((yOpt, yScope), yDep)) <- groupedDependencies.combinations(2)
optCmp <- optionalPartialOrder.cmp(xOpt, yOpt).iterator optCmp <- optionalPartialOrder.tryCompare(xOpt, yOpt).iterator
scopeCmp <- mavenScopePartialOrder.cmp(xScope, yScope).iterator scopeCmp <- configurationPartialOrder(configs(xDep.moduleVersion)).tryCompare(xScope, yScope).iterator
if optCmp*scopeCmp >= 0 if optCmp*scopeCmp >= 0
exclCmp <- exclusionsPartialOrder.cmp(xDep.exclusions, yDep.exclusions).iterator exclCmp <- exclusionsPartialOrder.tryCompare(xDep.exclusions, yDep.exclusions).iterator
if optCmp*exclCmp >= 0 if optCmp*exclCmp >= 0
if scopeCmp*exclCmp >= 0 if scopeCmp*exclCmp >= 0
xIsMin = optCmp < 0 || scopeCmp < 0 || exclCmp < 0 xIsMin = optCmp < 0 || scopeCmp < 0 || exclCmp < 0
@ -130,10 +150,13 @@ object Orders {
* *
* The returned set brings exactly the same things as `dependencies`, with no redundancy. * The returned set brings exactly the same things as `dependencies`, with no redundancy.
*/ */
def minDependencies(dependencies: Set[Dependency]): Set[Dependency] = { def minDependencies(
dependencies: Set[Dependency],
configs: ((Module, String)) => Map[String, Seq[String]]
): Set[Dependency] = {
dependencies dependencies
.groupBy(_.copy(scope = Scope.Other(""), exclusions = Set.empty, optional = false)) .groupBy(_.copy(configuration = "", exclusions = Set.empty, optional = false))
.mapValues(minDependenciesUnsafe) .mapValues(minDependenciesUnsafe(_, configs))
.valuesIterator .valuesIterator
.fold(Set.empty)(_ ++ _) .fold(Set.empty)(_ ++ _)
} }

View File

@ -4,15 +4,6 @@ import coursier.core.compatibility._
object Parse { object Parse {
def scope(s: String): Scope = s match {
case "compile" => Scope.Compile
case "runtime" => Scope.Runtime
case "test" => Scope.Test
case "provided" => Scope.Provided
case "import" => Scope.Import
case other => Scope.Other(other)
}
def version(s: String): Option[Version] = { def version(s: String): Option[Version] = {
if (s.isEmpty || s.exists(c => c != '.' && c != '-' && c != '_' && !c.letterOrDigit)) None if (s.isEmpty || s.exists(c => c != '.' && c != '-' && c != '_' && !c.letterOrDigit)) None
else Some(Version(s)) else Some(Version(s))

View File

@ -37,22 +37,22 @@ object Resolution {
(dep.module.organization, dep.module.name, dep.attributes.`type`) (dep.module.organization, dep.module.name, dep.attributes.`type`)
def add( def add(
dict: Map[Key, Dependency], dict: Map[Key, (String, Dependency)],
dep: Dependency item: (String, Dependency)
): Map[Key, Dependency] = { ): Map[Key, (String, Dependency)] = {
val key0 = key(dep) val key0 = key(item._2)
if (dict.contains(key0)) if (dict.contains(key0))
dict dict
else else
dict + (key0 -> dep) dict + (key0 -> item)
} }
def addSeq( def addSeq(
dict: Map[Key, Dependency], dict: Map[Key, (String, Dependency)],
deps: Seq[Dependency] deps: Seq[(String, Dependency)]
): Map[Key, Dependency] = ): Map[Key, (String, Dependency)] =
(dict /: deps)(add) (dict /: deps)(add)
} }
@ -62,14 +62,14 @@ object Resolution {
): Map[String, String] = ): Map[String, String] =
dict ++ other.filterKeys(!dict.contains(_)) dict ++ other.filterKeys(!dict.contains(_))
def addDependencies(deps: Seq[Seq[Dependency]]): Seq[Dependency] = { def addDependencies(deps: Seq[Seq[(String, Dependency)]]): Seq[(String, Dependency)] = {
val res = val res =
(deps :\ (Set.empty[DepMgmt.Key], Seq.empty[Dependency])) { (deps :\ (Set.empty[DepMgmt.Key], Seq.empty[(String, Dependency)])) {
case (deps0, (set, acc)) => case (deps0, (set, acc)) =>
val deps = deps0 val deps = deps0
.filter(dep => !set(DepMgmt.key(dep))) .filter{case (_, dep) => !set(DepMgmt.key(dep))}
(set ++ deps.map(DepMgmt.key), acc ++ deps) (set ++ deps.map{case (_, dep) => DepMgmt.key(dep)}, acc ++ deps)
} }
res._2 res._2
@ -83,9 +83,9 @@ object Resolution {
* Substitutes `properties` in `dependencies`. * Substitutes `properties` in `dependencies`.
*/ */
def withProperties( def withProperties(
dependencies: Seq[Dependency], dependencies: Seq[(String, Dependency)],
properties: Map[String, String] properties: Map[String, String]
): Seq[Dependency] = { ): Seq[(String, Dependency)] = {
def substituteProps(s: String) = { def substituteProps(s: String) = {
val matches = propRegex val matches = propRegex
@ -107,8 +107,8 @@ object Resolution {
} }
dependencies dependencies
.map{ dep => .map {case (config, dep) =>
dep.copy( substituteProps(config) -> dep.copy(
module = dep.module.copy( module = dep.module.copy(
organization = substituteProps(dep.module.organization), organization = substituteProps(dep.module.organization),
name = substituteProps(dep.module.name) name = substituteProps(dep.module.name)
@ -118,7 +118,7 @@ object Resolution {
`type` = substituteProps(dep.attributes.`type`), `type` = substituteProps(dep.attributes.`type`),
classifier = substituteProps(dep.attributes.classifier) classifier = substituteProps(dep.attributes.classifier)
), ),
scope = Parse.scope(substituteProps(dep.scope.name)), configuration = substituteProps(dep.configuration),
exclusions = dep.exclusions exclusions = dep.exclusions
.map{case (org, name) => .map{case (org, name) =>
(substituteProps(org), substituteProps(name)) (substituteProps(org), substituteProps(name))
@ -209,25 +209,6 @@ object Resolution {
) )
} }
/**
* If one of our dependency has scope `base`, and a transitive
* dependency of it has scope `transitive`, return the scope of
* the latter for us, if any. If empty, means the transitive dependency
* should not be considered a dependency for us.
*
* See https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#Dependency_Scope.
*/
def resolveScope(
base: Scope,
transitive: Scope
): Option[Scope] =
(base, transitive) match {
case (other, Scope.Compile) => Some(other)
case (Scope.Compile, Scope.Runtime) => Some(Scope.Runtime)
case (other, Scope.Runtime) => Some(other)
case _ => None
}
/** /**
* Applies `dependencyManagement` to `dependencies`. * Applies `dependencyManagement` to `dependencies`.
* *
@ -235,36 +216,39 @@ object Resolution {
* `dependencyManagement`. * `dependencyManagement`.
*/ */
def depsWithDependencyManagement( def depsWithDependencyManagement(
dependencies: Seq[Dependency], dependencies: Seq[(String, Dependency)],
dependencyManagement: Seq[Dependency] dependencyManagement: Seq[(String, Dependency)]
): Seq[Dependency] = { ): Seq[(String, Dependency)] = {
// See http://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#Dependency_Management // See http://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#Dependency_Management
lazy val dict = DepMgmt.addSeq(Map.empty, dependencyManagement) lazy val dict = DepMgmt.addSeq(Map.empty, dependencyManagement)
dependencies dependencies
.map { dep0 => .map {case (config0, dep0) =>
var config = config0
var dep = dep0 var dep = dep0
for (mgmtDep <- dict.get(DepMgmt.key(dep0))) { for ((mgmtConfig, mgmtDep) <- dict.get(DepMgmt.key(dep0))) {
if (dep.version.isEmpty) if (dep.version.isEmpty)
dep = dep.copy(version = mgmtDep.version) dep = dep.copy(version = mgmtDep.version)
if (dep.scope.name.isEmpty) if (config.isEmpty)
dep = dep.copy(scope = mgmtDep.scope) config = mgmtConfig
if (dep.exclusions.isEmpty) if (dep.exclusions.isEmpty)
dep = dep.copy(exclusions = mgmtDep.exclusions) dep = dep.copy(exclusions = mgmtDep.exclusions)
} }
dep (config, dep)
} }
} }
def withDefaultScope(dep: Dependency): Dependency = val defaultConfiguration = "compile"
if (dep.scope.name.isEmpty)
dep.copy(scope = Scope.Compile) def withDefaultConfig(dep: Dependency): Dependency =
if (dep.configuration.isEmpty)
dep.copy(configuration = defaultConfiguration)
else else
dep dep
@ -272,19 +256,37 @@ object Resolution {
* Filters `dependencies` with `exclusions`. * Filters `dependencies` with `exclusions`.
*/ */
def withExclusions( def withExclusions(
dependencies: Seq[Dependency], dependencies: Seq[(String, Dependency)],
exclusions: Set[(String, String)] exclusions: Set[(String, String)]
): Seq[Dependency] = { ): Seq[(String, Dependency)] = {
val filter = Exclusions(exclusions) val filter = Exclusions(exclusions)
dependencies dependencies
.filter(dep => filter(dep.module.organization, dep.module.name)) .filter{case (_, dep) => filter(dep.module.organization, dep.module.name) }
.map(dep => .map{case (config, dep) =>
dep.copy( config -> dep.copy(
exclusions = Exclusions.minimize(dep.exclusions ++ exclusions) exclusions = Exclusions.minimize(dep.exclusions ++ exclusions)
) )
) }
}
def withParentConfigurations(config: String, configurations: Map[String, Seq[String]]): Set[String] = {
@tailrec
def helper(configs: Set[String], acc: Set[String]): Set[String] =
if (configs.isEmpty)
acc
else if (configs.exists(acc))
helper(configs -- acc, acc)
else if (configs.exists(!configurations.contains(_))) {
val (remaining, notFound) = configs.partition(configurations.contains)
helper(remaining, acc ++ notFound)
} else {
val extraConfigs = configs.flatMap(configurations)
helper(extraConfigs, acc ++ configs)
}
helper(Set(config), Set.empty)
} }
/** /**
@ -312,7 +314,8 @@ object Resolution {
) )
) )
val deps = val configurations = withParentConfigurations(from.configuration, project.configurations)
withExclusions( withExclusions(
depsWithDependencyManagement( depsWithDependencyManagement(
// Important: properties have to be applied to both, // Important: properties have to be applied to both,
@ -323,17 +326,20 @@ object Resolution {
), ),
from.exclusions from.exclusions
) )
.map(withDefaultScope) .map{
case (config, dep) =>
deps (if (config.isEmpty) defaultConfiguration else config) -> {
.flatMap { trDep => if (dep.configuration.isEmpty)
resolveScope(from.scope, trDep.scope) dep.copy(configuration = defaultConfiguration)
.map(scope => else
trDep.copy( dep
scope = scope, }
optional = trDep.optional || from.optional }
) .collect{case (config, dep) if configurations(config) =>
) if (from.optional)
dep.copy(optional = true)
else
dep
} }
} }
@ -438,7 +444,7 @@ case class Resolution(
def nextDependenciesAndConflicts: (Seq[Dependency], Seq[Dependency]) = def nextDependenciesAndConflicts: (Seq[Dependency], Seq[Dependency]) =
// TODO Provide the modules whose version was forced by dependency overrides too // TODO Provide the modules whose version was forced by dependency overrides too
merge( merge(
rootDependencies.map(withDefaultScope) ++ dependencies ++ transitiveDependencies, rootDependencies.map(withDefaultConfig) ++ dependencies ++ transitiveDependencies,
forceVersions forceVersions
) )
@ -507,7 +513,7 @@ case class Resolution(
*/ */
def remainingDependencies: Set[Dependency] = { def remainingDependencies: Set[Dependency] = {
val rootDependencies0 = rootDependencies val rootDependencies0 = rootDependencies
.map(withDefaultScope) .map(withDefaultConfig)
.map(eraseVersion) .map(eraseVersion)
@tailrec @tailrec
@ -599,7 +605,7 @@ case class Resolution(
val modules = val modules =
(project.dependencies ++ profileDependencies) (project.dependencies ++ profileDependencies)
.collect{ .collect{
case dep if dep.scope == Scope.Import => dep.moduleVersion case ("import", dep) => dep.moduleVersion
} }
modules.toSet ++ project.parent modules.toSet ++ project.parent
@ -679,7 +685,7 @@ case class Resolution(
val deps = ( val deps = (
dependencies0 dependencies0
.collect { case dep if dep.scope == Scope.Import => .collect { case ("import", dep) =>
dep.moduleVersion dep.moduleVersion
} ++ } ++
project.parent project.parent
@ -693,16 +699,16 @@ case class Resolution(
profiles0.map(_.dependencyManagement) ++ profiles0.map(_.dependencyManagement) ++
projs.map(_.dependencyManagement) projs.map(_.dependencyManagement)
) )
).foldLeft(Map.empty[DepMgmt.Key, Dependency])(DepMgmt.addSeq) ).foldLeft(Map.empty[DepMgmt.Key, (String, Dependency)])(DepMgmt.addSeq)
val depsSet = deps.toSet val depsSet = deps.toSet
project.copy( project.copy(
dependencies = dependencies =
dependencies0 dependencies0
.filterNot(dep => .filterNot{case (config, dep) =>
dep.scope == Scope.Import && depsSet(dep.moduleVersion) config == "import" && depsSet(dep.moduleVersion)
) ++ } ++
project.parent project.parent
.filter(projectCache.contains) .filter(projectCache.contains)
.toSeq .toSeq
@ -716,7 +722,14 @@ case class Resolution(
} }
def minDependencies: Set[Dependency] = def minDependencies: Set[Dependency] =
Orders.minDependencies(dependencies) Orders.minDependencies(
dependencies,
dep =>
projectCache
.get(dep)
.map(_._2.configurations)
.getOrElse(Map.empty)
)
def artifacts: Seq[Artifact] = def artifacts: Seq[Artifact] =
for { for {

View File

@ -35,6 +35,12 @@ object MavenRepository {
.map(_.value) .map(_.value)
.filter(_.nonEmpty) .filter(_.nonEmpty)
val defaultConfigurations = Map(
"runtime" -> Seq("compile"),
"test" -> Seq("runtime")
)
} }
case class MavenRepository( case class MavenRepository(
@ -231,7 +237,7 @@ case class MavenRepository(
xml <- \/.fromEither(compatibility.xmlParse(str)) xml <- \/.fromEither(compatibility.xmlParse(str))
_ <- if (xml.label == "project") \/-(()) else -\/("Project definition not found") _ <- if (xml.label == "project") \/-(()) else -\/("Project definition not found")
proj <- Pom.project(xml) proj <- Pom.project(xml)
} yield proj): (String \/ Project) } yield proj.copy(configurations = defaultConfigurations)): (String \/ Project)
} }
} }
} }

View File

@ -43,16 +43,14 @@ object Pom {
private def readVersion(node: Node) = private def readVersion(node: Node) =
text(node, "version", "Version").getOrElse("").trim text(node, "version", "Version").getOrElse("").trim
private val defaultScope = Scope.Other("")
private val defaultType = "jar" private val defaultType = "jar"
private val defaultClassifier = "" private val defaultClassifier = ""
def dependency(node: Node): String \/ Dependency = { def dependency(node: Node): String \/ (String, Dependency) = {
for { for {
mod <- module(node) mod <- module(node)
version0 = readVersion(node) version0 = readVersion(node)
scopeOpt = text(node, "scope", "").toOption scopeOpt = text(node, "scope", "").toOption
.map(Parse.scope)
typeOpt = text(node, "type", "").toOption typeOpt = text(node, "type", "").toOption
classifierOpt = text(node, "classifier", "").toOption classifierOpt = text(node, "classifier", "").toOption
xmlExclusions = node.child xmlExclusions = node.child
@ -64,10 +62,10 @@ object Pom {
xmlExclusions.toList.traverseU(module(_)) xmlExclusions.toList.traverseU(module(_))
} }
optional = text(node, "optional", "").toOption.toSeq.contains("true") optional = text(node, "optional", "").toOption.toSeq.contains("true")
} yield Dependency( } yield scopeOpt.getOrElse("") -> Dependency(
mod, mod,
version0, version0,
scopeOpt getOrElse defaultScope, "",
Attributes(typeOpt getOrElse defaultType, classifierOpt getOrElse defaultClassifier), Attributes(typeOpt getOrElse defaultType, classifierOpt getOrElse defaultClassifier),
exclusions.map(mod => (mod.organization, mod.name)).toSet, exclusions.map(mod => (mod.organization, mod.name)).toSet,
optional optional
@ -191,6 +189,7 @@ object Pom {
deps, deps,
parentModuleOpt.map((_, parentVersionOpt.getOrElse(""))), parentModuleOpt.map((_, parentVersionOpt.getOrElse(""))),
depMgmts, depMgmts,
Map.empty,
properties.toMap, properties.toMap,
profiles, profiles,
None, None,

View File

@ -9,8 +9,8 @@ package object coursier {
def apply( def apply(
module: Module, module: Module,
version: String, version: String,
// Substituted by Resolver with its own default scope (compile) // Substituted by Resolver with its own default configuration (compile)
scope: Scope = Scope.Other(""), configuration: String = "",
attributes: Attributes = Attributes(), attributes: Attributes = Attributes(),
exclusions: Set[(String, String)] = Set.empty, exclusions: Set[(String, String)] = Set.empty,
optional: Boolean = false optional: Boolean = false
@ -18,7 +18,7 @@ package object coursier {
core.Dependency( core.Dependency(
module, module,
version, version,
scope, configuration,
attributes, attributes,
exclusions, exclusions,
optional optional
@ -48,8 +48,6 @@ package object coursier {
type ModuleVersion = (core.Module, String) type ModuleVersion = (core.Module, String)
type Scope = core.Scope
val Scope = core.Scope
type Repository = core.Repository type Repository = core.Repository
val Repository = core.Repository val Repository = core.Repository

View File

@ -44,7 +44,8 @@ object CentralTests extends TestSuite {
def resolutionCheck( def resolutionCheck(
module: Module, module: Module,
version: String, version: String,
extraRepo: Option[Repository] = None extraRepo: Option[Repository] = None,
configuration: String = ""
) = ) =
async { async {
val expected = val expected =
@ -54,7 +55,7 @@ object CentralTests extends TestSuite {
.split('\n') .split('\n')
.toSeq .toSeq
val dep = Dependency(module, version) val dep = Dependency(module, version, configuration = configuration)
val res = await(resolve(Set(dep), extraRepo = extraRepo)) val res = await(resolve(Set(dep), extraRepo = extraRepo))
val result = res val result = res
@ -138,6 +139,7 @@ object CentralTests extends TestSuite {
resolutionCheck( resolutionCheck(
Module("com.github.fommil", "java-logging"), Module("com.github.fommil", "java-logging"),
"1.2-SNAPSHOT", "1.2-SNAPSHOT",
configuration = "runtime",
extraRepo = Some(MavenRepository("https://oss.sonatype.org/content/repositories/public/")) extraRepo = Some(MavenRepository("https://oss.sonatype.org/content/repositories/public/"))
) )
} }

View File

@ -21,7 +21,7 @@ object PomParsingTests extends TestSuite {
</dependency> </dependency>
""" """
val expected = \/-(Dependency(Module("comp", "lib"), "2.1", attributes = Attributes(classifier = "extra"))) val expected = \/-("" -> Dependency(Module("comp", "lib"), "2.1", attributes = Attributes(classifier = "extra")))
val result = Pom.dependency(xmlParse(depNode).right.get) val result = Pom.dependency(xmlParse(depNode).right.get)
@ -90,7 +90,7 @@ object PomParsingTests extends TestSuite {
None, None,
Profile.Activation(Nil), Profile.Activation(Nil),
Seq( Seq(
Dependency(Module("comp", "lib"), "0.2")), "" -> Dependency(Module("comp", "lib"), "0.2")),
Nil, Nil,
Map.empty Map.empty
)) ))
@ -122,7 +122,7 @@ object PomParsingTests extends TestSuite {
Profile.Activation(Nil), Profile.Activation(Nil),
Nil, Nil,
Seq( Seq(
Dependency(Module("comp", "lib"), "0.2", scope = Scope.Test)), "test" -> Dependency(Module("comp", "lib"), "0.2")),
Map.empty Map.empty
)) ))

View File

@ -2,6 +2,7 @@ package coursier
package test package test
import coursier.core.Repository import coursier.core.Repository
import coursier.maven.MavenRepository
import utest._ import utest._
import scala.async.Async.{ async, await } import scala.async.Async.{ async, await }
@ -27,69 +28,68 @@ object ResolutionTests extends TestSuite {
Project(Module("acme", "config"), "1.3.0"), Project(Module("acme", "config"), "1.3.0"),
Project(Module("acme", "play"), "2.4.0", Seq( Project(Module("acme", "play"), "2.4.0", Seq(
Dependency(Module("acme", "play-json"), "2.4.0"))), "" -> Dependency(Module("acme", "play-json"), "2.4.0"))),
Project(Module("acme", "play-json"), "2.4.0"), Project(Module("acme", "play-json"), "2.4.0"),
Project(Module("acme", "play"), "2.4.1", Project(Module("acme", "play"), "2.4.1",
dependencies = Seq( dependencies = Seq(
Dependency(Module("acme", "play-json"), "${playJsonVersion}"), "" -> Dependency(Module("acme", "play-json"), "${playJsonVersion}"),
Dependency(Module("${project.groupId}", "${configName}"), "1.3.0")), "" -> Dependency(Module("${project.groupId}", "${configName}"), "1.3.0")),
properties = Map( properties = Map(
"playJsonVersion" -> "2.4.0", "playJsonVersion" -> "2.4.0",
"configName" -> "config")), "configName" -> "config")),
Project(Module("acme", "play-extra-no-config"), "2.4.1", Project(Module("acme", "play-extra-no-config"), "2.4.1",
Seq( Seq(
Dependency(Module("acme", "play"), "2.4.1", "" -> Dependency(Module("acme", "play"), "2.4.1",
exclusions = Set(("acme", "config"))))), exclusions = Set(("acme", "config"))))),
Project(Module("acme", "play-extra-no-config-no"), "2.4.1", Project(Module("acme", "play-extra-no-config-no"), "2.4.1",
Seq( Seq(
Dependency(Module("acme", "play"), "2.4.1", "" -> Dependency(Module("acme", "play"), "2.4.1",
exclusions = Set(("*", "config"))))), exclusions = Set(("*", "config"))))),
Project(Module("hudsucker", "mail"), "10.0", Project(Module("hudsucker", "mail"), "10.0",
Seq( Seq(
Dependency(Module("${project.groupId}", "test-util"), "${project.version}", "test" -> Dependency(Module("${project.groupId}", "test-util"), "${project.version}"))),
scope = Scope.Test))),
Project(Module("hudsucker", "test-util"), "10.0"), Project(Module("hudsucker", "test-util"), "10.0"),
Project(Module("se.ikea", "parent"), "18.0", Project(Module("se.ikea", "parent"), "18.0",
dependencyManagement = Seq( dependencyManagement = Seq(
Dependency(Module("acme", "play"), "2.4.0", "" -> Dependency(Module("acme", "play"), "2.4.0",
exclusions = Set(("acme", "play-json"))))), exclusions = Set(("acme", "play-json"))))),
Project(Module("se.ikea", "billy"), "18.0", Project(Module("se.ikea", "billy"), "18.0",
dependencies = Seq( dependencies = Seq(
Dependency(Module("acme", "play"), "")), "" -> Dependency(Module("acme", "play"), "")),
parent = Some(Module("se.ikea", "parent"), "18.0")), parent = Some(Module("se.ikea", "parent"), "18.0")),
Project(Module("org.gnome", "parent"), "7.0", Project(Module("org.gnome", "parent"), "7.0",
Seq( Seq(
Dependency(Module("org.gnu", "glib"), "13.4"))), "" -> Dependency(Module("org.gnu", "glib"), "13.4"))),
Project(Module("org.gnome", "panel-legacy"), "7.0", Project(Module("org.gnome", "panel-legacy"), "7.0",
dependencies = Seq( dependencies = Seq(
Dependency(Module("org.gnome", "desktop"), "${project.version}")), "" -> Dependency(Module("org.gnome", "desktop"), "${project.version}")),
parent = Some(Module("org.gnome", "parent"), "7.0")), parent = Some(Module("org.gnome", "parent"), "7.0")),
Project(Module("gov.nsa", "secure-pgp"), "10.0", Project(Module("gov.nsa", "secure-pgp"), "10.0",
Seq( Seq(
Dependency(Module("gov.nsa", "crypto"), "536.89"))), "" -> Dependency(Module("gov.nsa", "crypto"), "536.89"))),
Project(Module("com.mailapp", "mail-client"), "2.1", Project(Module("com.mailapp", "mail-client"), "2.1",
dependencies = Seq( dependencies = Seq(
Dependency(Module("gov.nsa", "secure-pgp"), "10.0", "" -> Dependency(Module("gov.nsa", "secure-pgp"), "10.0",
exclusions = Set(("*", "${crypto.name}")))), exclusions = Set(("*", "${crypto.name}")))),
properties = Map("crypto.name" -> "crypto", "dummy" -> "2")), properties = Map("crypto.name" -> "crypto", "dummy" -> "2")),
Project(Module("com.thoughtworks.paranamer", "paranamer-parent"), "2.6", Project(Module("com.thoughtworks.paranamer", "paranamer-parent"), "2.6",
dependencies = Seq( dependencies = Seq(
Dependency(Module("junit", "junit"), "")), "" -> Dependency(Module("junit", "junit"), "")),
dependencyManagement = Seq( dependencyManagement = Seq(
Dependency(Module("junit", "junit"), "4.11", scope = Scope.Test))), "test" -> Dependency(Module("junit", "junit"), "4.11"))),
Project(Module("com.thoughtworks.paranamer", "paranamer"), "2.6", Project(Module("com.thoughtworks.paranamer", "paranamer"), "2.6",
parent = Some(Module("com.thoughtworks.paranamer", "paranamer-parent"), "2.6")), parent = Some(Module("com.thoughtworks.paranamer", "paranamer-parent"), "2.6")),
@ -97,33 +97,33 @@ object ResolutionTests extends TestSuite {
Project(Module("com.github.dummy", "libb"), "0.3.3", Project(Module("com.github.dummy", "libb"), "0.3.3",
profiles = Seq( profiles = Seq(
Profile("default", activeByDefault = Some(true), dependencies = Seq( Profile("default", activeByDefault = Some(true), dependencies = Seq(
Dependency(Module("org.escalier", "librairie-standard"), "2.11.6"))))), "" -> Dependency(Module("org.escalier", "librairie-standard"), "2.11.6"))))),
Project(Module("com.github.dummy", "libb"), "0.4.2", Project(Module("com.github.dummy", "libb"), "0.4.2",
dependencies = Seq( dependencies = Seq(
Dependency(Module("org.scalaverification", "scala-verification"), "1.12.4")), "" -> Dependency(Module("org.scalaverification", "scala-verification"), "1.12.4")),
profiles = Seq( profiles = Seq(
Profile("default", activeByDefault = Some(true), dependencies = Seq( Profile("default", activeByDefault = Some(true), dependencies = Seq(
Dependency(Module("org.escalier", "librairie-standard"), "2.11.6"), "" -> Dependency(Module("org.escalier", "librairie-standard"), "2.11.6"),
Dependency(Module("org.scalaverification", "scala-verification"), "1.12.4", scope = Scope.Test))))), "test" -> Dependency(Module("org.scalaverification", "scala-verification"), "1.12.4"))))),
Project(Module("com.github.dummy", "libb"), "0.5.3", Project(Module("com.github.dummy", "libb"), "0.5.3",
properties = Map("special" -> "true"), properties = Map("special" -> "true"),
profiles = Seq( profiles = Seq(
Profile("default", activation = Profile.Activation(properties = Seq("special" -> None)), dependencies = Seq( Profile("default", activation = Profile.Activation(properties = Seq("special" -> None)), dependencies = Seq(
Dependency(Module("org.escalier", "librairie-standard"), "2.11.6"))))), "" -> Dependency(Module("org.escalier", "librairie-standard"), "2.11.6"))))),
Project(Module("com.github.dummy", "libb"), "0.5.4", Project(Module("com.github.dummy", "libb"), "0.5.4",
properties = Map("special" -> "true"), properties = Map("special" -> "true"),
profiles = Seq( profiles = Seq(
Profile("default", activation = Profile.Activation(properties = Seq("special" -> Some("true"))), dependencies = Seq( Profile("default", activation = Profile.Activation(properties = Seq("special" -> Some("true"))), dependencies = Seq(
Dependency(Module("org.escalier", "librairie-standard"), "2.11.6"))))), "" -> Dependency(Module("org.escalier", "librairie-standard"), "2.11.6"))))),
Project(Module("com.github.dummy", "libb"), "0.5.5", Project(Module("com.github.dummy", "libb"), "0.5.5",
properties = Map("special" -> "true"), properties = Map("special" -> "true"),
profiles = Seq( profiles = Seq(
Profile("default", activation = Profile.Activation(properties = Seq("special" -> Some("!false"))), dependencies = Seq( Profile("default", activation = Profile.Activation(properties = Seq("special" -> Some("!false"))), dependencies = Seq(
Dependency(Module("org.escalier", "librairie-standard"), "2.11.6"))))), "" -> Dependency(Module("org.escalier", "librairie-standard"), "2.11.6"))))),
Project(Module("com.github.dummy", "libb-parent"), "0.5.6", Project(Module("com.github.dummy", "libb-parent"), "0.5.6",
properties = Map("special" -> "true")), properties = Map("special" -> "true")),
@ -133,39 +133,39 @@ object ResolutionTests extends TestSuite {
properties = Map("special" -> "true"), properties = Map("special" -> "true"),
profiles = Seq( profiles = Seq(
Profile("default", activation = Profile.Activation(properties = Seq("special" -> Some("!false"))), dependencies = Seq( Profile("default", activation = Profile.Activation(properties = Seq("special" -> Some("!false"))), dependencies = Seq(
Dependency(Module("org.escalier", "librairie-standard"), "2.11.6"))))), "" -> Dependency(Module("org.escalier", "librairie-standard"), "2.11.6"))))),
Project(Module("an-org", "a-name"), "1.0"), Project(Module("an-org", "a-name"), "1.0"),
Project(Module("an-org", "a-name"), "1.2"), Project(Module("an-org", "a-name"), "1.2"),
Project(Module("an-org", "a-lib"), "1.0", Project(Module("an-org", "a-lib"), "1.0",
Seq(Dependency(Module("an-org", "a-name"), "1.0"))), Seq("" -> Dependency(Module("an-org", "a-name"), "1.0"))),
Project(Module("an-org", "a-lib"), "1.1"), Project(Module("an-org", "a-lib"), "1.1"),
Project(Module("an-org", "a-lib"), "1.2", Project(Module("an-org", "a-lib"), "1.2",
Seq(Dependency(Module("an-org", "a-name"), "1.2"))), Seq("" -> Dependency(Module("an-org", "a-name"), "1.2"))),
Project(Module("an-org", "another-lib"), "1.0", Project(Module("an-org", "another-lib"), "1.0",
Seq(Dependency(Module("an-org", "a-name"), "1.0"))), Seq("" -> Dependency(Module("an-org", "a-name"), "1.0"))),
// Must bring transitively an-org:a-name, as an optional dependency // Must bring transitively an-org:a-name, as an optional dependency
Project(Module("an-org", "an-app"), "1.0", Project(Module("an-org", "an-app"), "1.0",
Seq( Seq(
Dependency(Module("an-org", "a-lib"), "1.0", exclusions = Set(("an-org", "a-name"))), "" -> Dependency(Module("an-org", "a-lib"), "1.0", exclusions = Set(("an-org", "a-name"))),
Dependency(Module("an-org", "another-lib"), "1.0", optional = true))), "" -> Dependency(Module("an-org", "another-lib"), "1.0", optional = true))),
Project(Module("an-org", "an-app"), "1.1", Project(Module("an-org", "an-app"), "1.1",
Seq( Seq(
Dependency(Module("an-org", "a-lib"), "1.1"))), "" -> Dependency(Module("an-org", "a-lib"), "1.1"))),
Project(Module("an-org", "an-app"), "1.2", Project(Module("an-org", "an-app"), "1.2",
Seq( Seq(
Dependency(Module("an-org", "a-lib"), "1.2"))) "" -> Dependency(Module("an-org", "a-lib"), "1.2")))
) )
val projectsMap = projects.map(p => p.moduleVersion -> p).toMap val projectsMap = projects.map(p => p.moduleVersion -> p.copy(configurations = MavenRepository.defaultConfigurations)).toMap
val testRepository = new TestRepository(projectsMap) val testRepository = new TestRepository(projectsMap)
val repositories = Seq[Repository]( val repositories = Seq[Repository](
@ -308,8 +308,7 @@ object ResolutionTests extends TestSuite {
async { async {
val dep = Dependency(Module("hudsucker", "mail"), "10.0") val dep = Dependency(Module("hudsucker", "mail"), "10.0")
val res = await(resolve0( val res = await(resolve0(
Set(dep), Set(dep)
filter = Some(_.scope == Scope.Compile)
)).copy(filter = None) )).copy(filter = None)
val expected = Resolution( val expected = Resolution(
@ -331,8 +330,7 @@ object ResolutionTests extends TestSuite {
exclusions = Set(("acme", "play-json"))) exclusions = Set(("acme", "play-json")))
) )
val res = await(resolve0( val res = await(resolve0(
Set(dep), Set(dep)
filter = Some(_.scope == Scope.Compile)
)).copy(filter = None, projectCache = Map.empty) )).copy(filter = None, projectCache = Map.empty)
val expected = Resolution( val expected = Resolution(
@ -350,8 +348,7 @@ object ResolutionTests extends TestSuite {
Dependency(Module("org.gnu", "glib"), "13.4"), Dependency(Module("org.gnu", "glib"), "13.4"),
Dependency(Module("org.gnome", "desktop"), "7.0")) Dependency(Module("org.gnome", "desktop"), "7.0"))
val res = await(resolve0( val res = await(resolve0(
Set(dep), Set(dep)
filter = Some(_.scope == Scope.Compile)
)).copy(filter = None, projectCache = Map.empty, errorCache = Map.empty) )).copy(filter = None, projectCache = Map.empty, errorCache = Map.empty)
val expected = Resolution( val expected = Resolution(
@ -368,8 +365,7 @@ object ResolutionTests extends TestSuite {
val trDeps = Seq( val trDeps = Seq(
Dependency(Module("gov.nsa", "secure-pgp"), "10.0", exclusions = Set(("*", "crypto")))) Dependency(Module("gov.nsa", "secure-pgp"), "10.0", exclusions = Set(("*", "crypto"))))
val res = await(resolve0( val res = await(resolve0(
Set(dep), Set(dep)
filter = Some(_.scope == Scope.Compile)
)).copy(filter = None, projectCache = Map.empty, errorCache = Map.empty) )).copy(filter = None, projectCache = Map.empty, errorCache = Map.empty)
val expected = Resolution( val expected = Resolution(
@ -384,8 +380,7 @@ object ResolutionTests extends TestSuite {
async { async {
val dep = Dependency(Module("com.thoughtworks.paranamer", "paranamer"), "2.6") val dep = Dependency(Module("com.thoughtworks.paranamer", "paranamer"), "2.6")
val res = await(resolve0( val res = await(resolve0(
Set(dep), Set(dep)
filter = Some(_.scope == Scope.Compile)
)).copy(filter = None, projectCache = Map.empty, errorCache = Map.empty) )).copy(filter = None, projectCache = Map.empty, errorCache = Map.empty)
val expected = Resolution( val expected = Resolution(
@ -402,8 +397,7 @@ object ResolutionTests extends TestSuite {
val trDeps = Seq( val trDeps = Seq(
Dependency(Module("org.escalier", "librairie-standard"), "2.11.6")) Dependency(Module("org.escalier", "librairie-standard"), "2.11.6"))
val res = await(resolve0( val res = await(resolve0(
Set(dep), Set(dep)
filter = Some(_.scope == Scope.Compile)
)).copy(filter = None, projectCache = Map.empty, errorCache = Map.empty) )).copy(filter = None, projectCache = Map.empty, errorCache = Map.empty)
val expected = Resolution( val expected = Resolution(
@ -422,8 +416,7 @@ object ResolutionTests extends TestSuite {
val trDeps = Seq( val trDeps = Seq(
Dependency(Module("org.escalier", "librairie-standard"), "2.11.6")) Dependency(Module("org.escalier", "librairie-standard"), "2.11.6"))
val res = await(resolve0( val res = await(resolve0(
Set(dep), Set(dep)
filter = Some(_.scope == Scope.Compile)
)).copy(filter = None, projectCache = Map.empty, errorCache = Map.empty) )).copy(filter = None, projectCache = Map.empty, errorCache = Map.empty)
val expected = Resolution( val expected = Resolution(
@ -444,8 +437,7 @@ object ResolutionTests extends TestSuite {
val trDeps = Seq( val trDeps = Seq(
Dependency(Module("org.escalier", "librairie-standard"), "2.11.6")) Dependency(Module("org.escalier", "librairie-standard"), "2.11.6"))
val res = await(resolve0( val res = await(resolve0(
Set(dep), Set(dep)
filter = Some(_.scope == Scope.Compile)
)).copy(filter = None, projectCache = Map.empty, errorCache = Map.empty) )).copy(filter = None, projectCache = Map.empty, errorCache = Map.empty)
val expected = Resolution( val expected = Resolution(
@ -466,7 +458,7 @@ object ResolutionTests extends TestSuite {
Dependency(Module("an-org", "a-name"), "1.0", optional = true)) Dependency(Module("an-org", "a-name"), "1.0", optional = true))
val res = await(resolve0( val res = await(resolve0(
Set(dep), Set(dep),
filter = Some(_.scope == Scope.Compile) filter = Some(_ => true)
)).copy(filter = None, projectCache = Map.empty, errorCache = Map.empty) )).copy(filter = None, projectCache = Map.empty, errorCache = Map.empty)
val expected = Resolution( val expected = Resolution(
@ -489,7 +481,7 @@ object ResolutionTests extends TestSuite {
Dependency(Module("an-org", "a-name"), "1.0", optional = true)) Dependency(Module("an-org", "a-name"), "1.0", optional = true))
val res = await(resolve0( val res = await(resolve0(
deps, deps,
filter = Some(_.scope == Scope.Compile) filter = Some(_ => true)
)).copy(filter = None, projectCache = Map.empty, errorCache = Map.empty) )).copy(filter = None, projectCache = Map.empty, errorCache = Map.empty)
val expected = Resolution( val expected = Resolution(
@ -511,8 +503,7 @@ object ResolutionTests extends TestSuite {
val res = await(resolve0( val res = await(resolve0(
deps, deps,
forceVersions = depOverrides, forceVersions = depOverrides
filter = Some(_.scope == Scope.Compile)
)).copy(filter = None, projectCache = Map.empty, errorCache = Map.empty) )).copy(filter = None, projectCache = Map.empty, errorCache = Map.empty)
val expected = Resolution( val expected = Resolution(
@ -536,8 +527,7 @@ object ResolutionTests extends TestSuite {
val res = await(resolve0( val res = await(resolve0(
deps, deps,
forceVersions = depOverrides, forceVersions = depOverrides
filter = Some(_.scope == Scope.Compile)
)).copy(filter = None, projectCache = Map.empty, errorCache = Map.empty) )).copy(filter = None, projectCache = Map.empty, errorCache = Map.empty)
val expected = Resolution( val expected = Resolution(
@ -563,8 +553,7 @@ object ResolutionTests extends TestSuite {
val res = await(resolve0( val res = await(resolve0(
deps, deps,
forceVersions = depOverrides, forceVersions = depOverrides
filter = Some(_.scope == Scope.Compile)
)).copy(filter = None, projectCache = Map.empty, errorCache = Map.empty) )).copy(filter = None, projectCache = Map.empty, errorCache = Map.empty)
val expected = Resolution( val expected = Resolution(
@ -585,9 +574,9 @@ object ResolutionTests extends TestSuite {
'propertySubstitution{ 'propertySubstitution{
val res = val res =
core.Resolution.withProperties( core.Resolution.withProperties(
Seq(Dependency(Module("a-company", "a-name"), "${a.property}")), Seq("" -> Dependency(Module("a-company", "a-name"), "${a.property}")),
Map("a.property" -> "a-version")) Map("a.property" -> "a-version"))
val expected = Seq(Dependency(Module("a-company", "a-name"), "a-version")) val expected = Seq("" -> Dependency(Module("a-company", "a-name"), "a-version"))
assert(res == expected) assert(res == expected)
} }

View File

@ -3,7 +3,7 @@ package coursier
package object test { package object test {
implicit class DependencyOps(val underlying: Dependency) extends AnyVal { implicit class DependencyOps(val underlying: Dependency) extends AnyVal {
def withCompileScope: Dependency = underlying.copy(scope = Scope.Compile) def withCompileScope: Dependency = underlying.copy(configuration = "compile")
} }
object Profile { object Profile {
@ -16,8 +16,8 @@ package object test {
def apply(id: String, def apply(id: String,
activeByDefault: Option[Boolean] = None, activeByDefault: Option[Boolean] = None,
activation: Activation = Activation(), activation: Activation = Activation(),
dependencies: Seq[Dependency] = Nil, dependencies: Seq[(String, Dependency)] = Nil,
dependencyManagement: Seq[Dependency] = Nil, dependencyManagement: Seq[(String, Dependency)] = Nil,
properties: Map[String, String] = Map.empty) = properties: Map[String, String] = Map.empty) =
core.Profile(id, activeByDefault, activation, dependencies, dependencyManagement, properties) core.Profile(id, activeByDefault, activation, dependencies, dependencyManagement, properties)
} }
@ -25,13 +25,15 @@ package object test {
object Project { object Project {
def apply(module: Module, def apply(module: Module,
version: String, version: String,
dependencies: Seq[Dependency] = Seq.empty, dependencies: Seq[(String, Dependency)] = Seq.empty,
parent: Option[ModuleVersion] = None, parent: Option[ModuleVersion] = None,
dependencyManagement: Seq[Dependency] = Seq.empty, dependencyManagement: Seq[(String, Dependency)] = Seq.empty,
configurations: Map[String, Seq[String]] = Map.empty,
properties: Map[String, String] = Map.empty, properties: Map[String, String] = Map.empty,
profiles: Seq[Profile] = Seq.empty, profiles: Seq[Profile] = Seq.empty,
versions: Option[core.Versions] = None, versions: Option[core.Versions] = None,
snapshotVersioning: Option[core.SnapshotVersioning] = None): Project = snapshotVersioning: Option[core.SnapshotVersioning] = None
core.Project(module, version, dependencies, parent, dependencyManagement, properties, profiles, versions, snapshotVersioning) ): Project =
core.Project(module, version, dependencies, parent, dependencyManagement, configurations, properties, profiles, versions, snapshotVersioning)
} }
} }

View File

@ -17,8 +17,7 @@ import scala.scalajs.js
import js.Dynamic.{ global => g } import js.Dynamic.{ global => g }
case class ResolutionOptions( case class ResolutionOptions(
followOptional: Boolean = false, followOptional: Boolean = false
keepTest: Boolean = false
) )
case class State( case class State(
@ -66,7 +65,7 @@ class Backend($: BackendScope[Unit, State]) {
Seq( Seq(
dep.module.organization, dep.module.organization,
dep.module.name, dep.module.name,
dep.scope.name dep.configuration
).mkString(":") ).mkString(":")
for { for {
@ -176,8 +175,7 @@ class Backend($: BackendScope[Unit, State]) {
val res = coursier.Resolution( val res = coursier.Resolution(
s.modules.toSet, s.modules.toSet,
filter = Some(dep => filter = Some(dep =>
(s.options.followOptional || !dep.optional) && s.options.followOptional || !dep.optional
(s.options.keepTest || dep.scope != Scope.Test)
) )
) )
@ -338,14 +336,6 @@ class Backend($: BackendScope[Unit, State]) {
) )
) )
} }
def toggleTest(e: ReactEventI) = {
$.modState(s =>
s.copy(
options = s.options
.copy(keepTest = !s.options.keepTest)
)
)
}
} }
} }
@ -380,7 +370,7 @@ object App {
<.td(dep.module.name), <.td(dep.module.name),
<.td(finalVersionOpt.fold(dep.version)(finalVersion => s"$finalVersion (for ${dep.version})")), <.td(finalVersionOpt.fold(dep.version)(finalVersion => s"$finalVersion (for ${dep.version})")),
<.td(Seq[Seq[TagMod]]( <.td(Seq[Seq[TagMod]](
if (dep.scope == Scope.Compile) Seq() else Seq(infoLabel(dep.scope.name)), if (dep.configuration == "compile") Seq() else Seq(infoLabel(dep.configuration)),
if (dep.attributes.`type`.isEmpty || dep.attributes.`type` == "jar") Seq() else Seq(infoLabel(dep.attributes.`type`)), if (dep.attributes.`type`.isEmpty || dep.attributes.`type` == "jar") Seq() else Seq(infoLabel(dep.attributes.`type`)),
if (dep.attributes.classifier.isEmpty) Seq() else Seq(infoLabel(dep.attributes.classifier)), if (dep.attributes.classifier.isEmpty) Seq() else Seq(infoLabel(dep.attributes.classifier)),
Some(dep.exclusions).filter(_.nonEmpty).map(excls => infoPopOver("Exclusions", excls.toList.sorted.map{case (org, name) => s"$org:$name"}.mkString("; "))).toSeq, Some(dep.exclusions).filter(_.nonEmpty).map(excls => infoPopOver("Exclusions", excls.toList.sorted.map{case (org, name) => s"$org:$name"}.mkString("; "))).toSeq,
@ -683,15 +673,6 @@ object App {
"Follow optional dependencies" "Follow optional dependencies"
) )
) )
),
<.div(^.`class` := "checkbox",
<.label(
<.input(^.`type` := "checkbox",
^.onChange ==> backend.options.toggleTest,
if (options.keepTest) Seq(^.checked := "checked") else Seq(),
"Keep test dependencies"
)
)
) )
) )
} }