From 524ed3320b8077b34244d28b2b8022f3f2ba708d Mon Sep 17 00:00:00 2001 From: Alexandre Archambault Date: Thu, 18 Jun 2015 03:01:49 +0200 Subject: [PATCH] Change in model - version split off module - not trying to merge dependencies having the same module (by merging exclusions, optional flag, etc.) *needs tests and comments* (there were corner cases exclusions + optional were buggy if together) --- .../main/scala/coursier/cli/Coursier.scala | 16 +- .../src/main/scala/coursier/core/Remote.scala | 5 +- .../test/scala/coursier/test/JsTests.scala | 4 +- .../src/main/scala/coursier/core/Remote.scala | 12 +- .../main/scala/coursier/core/package.scala | 4 +- .../scala/coursier/core/Definitions.scala | 20 +- .../main/scala/coursier/core/Repository.scala | 2 +- .../main/scala/coursier/core/Resolver.scala | 95 ++++----- core/src/main/scala/coursier/core/Xml.scala | 24 ++- core/src/main/scala/coursier/package.scala | 24 ++- .../scala/coursier/test/CentralTests.scala | 12 +- .../scala/coursier/test/PomParsingTests.scala | 6 +- .../scala/coursier/test/ResolverTests.scala | 184 +++++++++--------- .../scala/coursier/test/TestRepository.scala | 6 +- web/src/main/scala/coursier/web/Backend.scala | 28 +-- 15 files changed, 223 insertions(+), 219 deletions(-) diff --git a/cli/src/main/scala/coursier/cli/Coursier.scala b/cli/src/main/scala/coursier/cli/Coursier.scala index 8f7b8ac22..2e14c1926 100644 --- a/cli/src/main/scala/coursier/cli/Coursier.scala +++ b/cli/src/main/scala/coursier/cli/Coursier.scala @@ -75,12 +75,12 @@ case class Coursier(scope: List[String], val modules = splitArtifacts.map{ case Seq(org, name, version) => - Module(org, name, version) + (Module(org, name), version) } - val deps = modules.map(mod => - Dependency(mod, scope = Scope.Runtime) - ) + val deps = modules.map{case (mod, ver) => + Dependency(mod, ver, scope = Scope.Runtime) + } val res = resolve( deps.toSet, @@ -89,7 +89,7 @@ case class Coursier(scope: List[String], ).run def repr(dep: Dependency) = - s"${dep.module.organization}:${dep.module.name}:${dep.`type`}:${Some(dep.classifier).filter(_.nonEmpty).map(_+":").mkString}${dep.module.version}" + s"${dep.module.organization}:${dep.module.name}:${dep.`type`}:${Some(dep.classifier).filter(_.nonEmpty).map(_+":").mkString}${dep.version}" val trDeps = res.dependencies.toList.sortBy(repr) @@ -100,11 +100,11 @@ case class Coursier(scope: List[String], println(s"${res.conflicts.size} conflict(s):\n ${res.conflicts.toList.map(repr).sorted.mkString(" \n")}") } - val errDeps = trDeps.filter(dep => res.errors.contains(dep.module)) + val errDeps = trDeps.filter(dep => res.errors.contains(dep.moduleVersion)) if (errDeps.nonEmpty) { println(s"${errDeps.size} error(s):") for (dep <- errDeps) { - println(s" ${dep.module}:\n ${res.errors(dep.module).mkString("\n").replace("\n", " \n")}") + println(s" ${dep.module}:\n ${res.errors(dep.moduleVersion).mkString("\n").replace("\n", " \n")}") } } @@ -113,7 +113,7 @@ case class Coursier(scope: List[String], val cachePolicy: CachePolicy = CachePolicy.Default - val m = res.dependencies.groupBy(dep => res.projectsCache.get(dep.module).map(_._1)) + val m = res.dependencies.groupBy(dep => res.projectsCache.get(dep.moduleVersion).map(_._1)) val (notFound, remaining0) = m.partition(_._1.isEmpty) if (notFound.nonEmpty) { val notFound0 = notFound.values.flatten.toList.map(repr).sorted diff --git a/core-js/src/main/scala/coursier/core/Remote.scala b/core-js/src/main/scala/coursier/core/Remote.scala index 6e0376334..e7b86ece7 100644 --- a/core-js/src/main/scala/coursier/core/Remote.scala +++ b/core-js/src/main/scala/coursier/core/Remote.scala @@ -73,13 +73,14 @@ trait Logger { case class Remote(base: String, logger: Option[Logger] = None) extends Repository { def find(module: Module, + version: String, cachePolicy: CachePolicy): EitherT[Task, String, Project] = { val relPath = module.organization.split('.').toSeq ++ Seq( module.name, - module.version, - s"${module.name}-${module.version}.pom" + version, + s"${module.name}-$version.pom" ) val url = base + relPath.mkString("/") diff --git a/core-js/src/test/scala/coursier/test/JsTests.scala b/core-js/src/test/scala/coursier/test/JsTests.scala index 30d8045d5..5888d9331 100644 --- a/core-js/src/test/scala/coursier/test/JsTests.scala +++ b/core-js/src/test/scala/coursier/test/JsTests.scala @@ -26,9 +26,9 @@ object JsTests extends TestSuite { 'getProj{ repository.mavenCentral - .find(Module("ch.qos.logback", "logback-classic", "1.1.3")) + .find(Module("ch.qos.logback", "logback-classic"), "1.1.3") .map{ proj => - assert(proj.parent == Some(Module("ch.qos.logback", "logback-parent", "1.1.3"))) + assert(proj.parent == Some(Module("ch.qos.logback", "logback-parent"), "1.1.3")) } .run .runF diff --git a/core-jvm/src/main/scala/coursier/core/Remote.scala b/core-jvm/src/main/scala/coursier/core/Remote.scala index 79c6c56c7..f1c610c71 100644 --- a/core-jvm/src/main/scala/coursier/core/Remote.scala +++ b/core-jvm/src/main/scala/coursier/core/Remote.scala @@ -20,6 +20,7 @@ case class ArtifactDownloader(root: String, cache: File, logger: Option[Artifact var bufferSize = 1024*1024 def artifact(module: Module, + version: String, classifier: String, `type`: String, cachePolicy: CachePolicy): EitherT[Task, String, File] = { @@ -27,8 +28,8 @@ case class ArtifactDownloader(root: String, cache: File, logger: Option[Artifact val relPath = module.organization.split('.').toSeq ++ Seq( module.name, - module.version, - s"${module.name}-${module.version}${Some(classifier).filter(_.nonEmpty).map("-"+_).mkString}.${`type`}" + version, + s"${module.name}-$version${Some(classifier).filter(_.nonEmpty).map("-"+_).mkString}.${`type`}" ) val file = (cache /: relPath)(new File(_, _)) @@ -93,7 +94,7 @@ case class ArtifactDownloader(root: String, cache: File, logger: Option[Artifact def artifact(dependency: Dependency, cachePolicy: CachePolicy = CachePolicy.Default): EitherT[Task, String, File] = - artifact(dependency.module, dependency.classifier, dependency.`type`, cachePolicy = cachePolicy) + artifact(dependency.module, dependency.version, dependency.classifier, dependency.`type`, cachePolicy = cachePolicy) } @@ -140,13 +141,14 @@ case class Remote(root: String, logger: Option[RemoteLogger] = None) extends Repository { def find(module: Module, + version: String, cachePolicy: CachePolicy): EitherT[Task, String, Project] = { val relPath = module.organization.split('.').toSeq ++ Seq( module.name, - module.version, - s"${module.name}-${module.version}.pom" + version, + s"${module.name}-$version.pom" ) def localFile = { diff --git a/core-jvm/src/main/scala/coursier/core/package.scala b/core-jvm/src/main/scala/coursier/core/package.scala index b4663e5dc..6191c782b 100644 --- a/core-jvm/src/main/scala/coursier/core/package.scala +++ b/core-jvm/src/main/scala/coursier/core/package.scala @@ -1,12 +1,14 @@ package coursier +import coursier.core.Resolver.ModuleVersion + import scalaz.EitherT import scalaz.concurrent.Task package object core { def resolution(dependencies: Set[Dependency], - fetch: Module => EitherT[Task, List[String], (Repository, Project)], + fetch: ModuleVersion => EitherT[Task, List[String], (Repository, Project)], filter: Option[Dependency => Boolean], profileActivation: Option[(String, Activation, Map[String, String]) => Boolean]): Stream[Resolution] = { diff --git a/core/src/main/scala/coursier/core/Definitions.scala b/core/src/main/scala/coursier/core/Definitions.scala index 2b1e1b7dd..223aa8d2d 100644 --- a/core/src/main/scala/coursier/core/Definitions.scala +++ b/core/src/main/scala/coursier/core/Definitions.scala @@ -1,32 +1,36 @@ package coursier.core case class Module(organization: String, - name: String, - version: String) { + name: String) { def trim: Module = copy( organization = organization.trim, - name = name.trim, - version = version.trim + name = name.trim ) - override def toString = s"$organization:$name:$version" + override def toString = s"$organization:$name" } sealed abstract class Scope(val name: String) case class Dependency(module: Module, + version: String, scope: Scope, `type`: String, classifier: String, exclusions: Set[(String, String)], - optional: Boolean) + optional: Boolean) { + def moduleVersion = (module, version) +} case class Project(module: Module, + version: String, dependencies: Seq[Dependency], - parent: Option[Module], + parent: Option[(Module, String)], dependencyManagement: Seq[Dependency], properties: Map[String, String], - profiles: Seq[Profile]) + profiles: Seq[Profile]) { + def moduleVersion = (module, version) +} object Scope { case object Compile extends Scope("compile") diff --git a/core/src/main/scala/coursier/core/Repository.scala b/core/src/main/scala/coursier/core/Repository.scala index 595c285db..52ca12a8f 100644 --- a/core/src/main/scala/coursier/core/Repository.scala +++ b/core/src/main/scala/coursier/core/Repository.scala @@ -4,7 +4,7 @@ import scalaz.{\/, EitherT} import scalaz.concurrent.Task trait Repository { - def find(module: Module, cachePolicy: CachePolicy = CachePolicy.Default): EitherT[Task, String, Project] + def find(module: Module, version: String, cachePolicy: CachePolicy = CachePolicy.Default): EitherT[Task, String, Project] def versions(organization: String, name: String, cachePolicy: CachePolicy = CachePolicy.Default): EitherT[Task, String, Versions] } diff --git a/core/src/main/scala/coursier/core/Resolver.scala b/core/src/main/scala/coursier/core/Resolver.scala index 651dfa89b..f19f7fcc9 100644 --- a/core/src/main/scala/coursier/core/Resolver.scala +++ b/core/src/main/scala/coursier/core/Resolver.scala @@ -8,6 +8,8 @@ import scalaz.{EitherT, \/-, \/, -\/} object Resolver { + type ModuleVersion = (Module, String) + /** * Try to find `module` among `repositories`. * @@ -20,9 +22,10 @@ object Resolver { * the repository implementation. */ def find(repositories: Seq[Repository], - module: Module): EitherT[Task, List[String], (Repository, Project)] = { + module: Module, + version: String): EitherT[Task, List[String], (Repository, Project)] = { - val lookups = repositories.map(repo => repo -> repo.find(module).run) + val lookups = repositories.map(repo => repo -> repo.find(module, version).run) val task = lookups.foldLeft(Task.now(-\/(Nil)): Task[List[String] \/ (Repository, Project)]) { case (acc, (repo, t)) => acc.flatMap { @@ -112,9 +115,9 @@ object Resolver { dep.copy( module = dep.module.copy( organization = substituteProps(dep.module.organization), - name = substituteProps(dep.module.name), - version = substituteProps(dep.module.version) + name = substituteProps(dep.module.name) ), + version = substituteProps(dep.version), `type` = substituteProps(dep.`type`), scope = Parse.scope(substituteProps(dep.scope.name)), exclusions = dep.exclusions @@ -153,42 +156,22 @@ object Resolver { def merge(dependencies: TraversableOnce[Dependency]): (Seq[Dependency], Seq[Dependency]) = { val m = dependencies .toList - .groupBy(dep => (dep.module.organization, dep.module.name)) + .groupBy(dep => dep.module) .mapValues{ deps => - if (deps.lengthCompare(1) == 0) List(\/-(deps.head)) + if (deps.lengthCompare(1) == 0) \/-(deps) else { - val scopeTypeClassifiers = (Set.empty[(Scope, String, String)] /: deps)((acc, dep) => acc + ((dep.scope, dep.`type`, dep.classifier))) - - val versions = deps.map(_.module.version).distinct + val versions = deps.map(_.version).distinct val versionOpt = mergeVersions(versions) - scopeTypeClassifiers.toList.flatMap{case (scope, type0, classifier) => - val scopeTypeClassifierDeps = - deps.filter(dep => - dep.scope == scope && dep.`type` == type0 && dep.classifier == classifier - ) - - def dep(version: String) = { - Dependency( - deps.head.module.copy(version = version), - scope, - type0, - classifier, - scopeTypeClassifierDeps.map(_.exclusions.toSet).reduce(exclusionsIntersect), - scopeTypeClassifierDeps.forall(_.optional) - ) - } - - versionOpt match { - case Some(version) => List(\/-(dep(version))) - case None => versions.map(version => -\/(dep(version))) - } + versionOpt match { + case Some(version) => \/-(deps.map(dep => dep.copy(version = version))) + case None => -\/(deps) } } } - val l = m.values.toList.flatten - (l.collect{case -\/(dep) => dep}, l.collect{case \/-(dep) => dep}) + val l = m.values.toList + (l.collect{case -\/(dep) => dep}.flatten, l.collect{case \/-(dep) => dep}.flatten) } /** @@ -223,8 +206,8 @@ object Resolver { var dep = dep0 for (mgmtDep <- m.get(dependencyManagementKey(dep0))) { - if (dep.module.version.isEmpty) - dep = dep.copy(module = dep.module.copy(version = mgmtDep.module.version)) + if (dep.version.isEmpty) + dep = dep.copy(version = mgmtDep.version) if (dep.scope.name.isEmpty) dep = dep.copy(scope = mgmtDep.scope) @@ -355,7 +338,7 @@ object Resolver { Map( "project.groupId" -> project.module.organization, "project.artifactId" -> project.module.name, - "project.version" -> project.module.version + "project.version" -> project.version ) ) @@ -390,8 +373,8 @@ object Resolver { case class Resolution(rootDependencies: Set[Dependency], dependencies: Set[Dependency], conflicts: Set[Dependency], - projectsCache: Map[Module, (Repository, Project)], - errors: Map[Module, Seq[String]], + projectsCache: Map[ModuleVersion, (Repository, Project)], + errors: Map[ModuleVersion, Seq[String]], filter: Option[Dependency => Boolean], profileActivation: Option[(String, Activation, Map[String, String]) => Boolean]) { @@ -402,7 +385,7 @@ object Resolver { def transitiveDependencies = for { dep <- (dependencies -- conflicts).toList - (_, proj) <- projectsCache.get(dep.module).toSeq + (_, proj) <- projectsCache.get((dep.moduleVersion)).toSeq trDep <- finalDependencies(dep, proj).filter(filter getOrElse defaultFilter) } yield trDep @@ -419,9 +402,9 @@ object Resolver { /** * The modules we miss some info about. */ - def missingFromCache: Set[Module] = { - val modules = dependencies.map(_.module) - val nextModules = nextDependenciesAndConflicts._2.map(_.module) + def missingFromCache: Set[ModuleVersion] = { + val modules = dependencies.map(dep => (dep.moduleVersion)) + val nextModules = nextDependenciesAndConflicts._2.map(dep => (dep.moduleVersion)) (modules ++ nextModules) .filterNot(mod => projectsCache.contains(mod) || errors.contains(mod)) @@ -453,7 +436,7 @@ object Resolver { val trDepsSeq = for { dep <- updatedDeps - (_, proj) <- projectsCache.get(dep.module).toList + (_, proj) <- projectsCache.get((dep.moduleVersion)).toList trDep <- finalDependencies(dep, proj).filter(filter getOrElse defaultFilter) } yield key(trDep) -> (key(dep), trDep.exclusions) @@ -526,7 +509,7 @@ object Resolver { /** * Do a new iteration, fetching the missing modules along the way. */ - def next(fetchModule: Module => EitherT[Task, List[String], (Repository, Project)]): Task[Resolution] = { + def next(fetchModule: ModuleVersion => EitherT[Task, List[String], (Repository, Project)]): Task[Resolution] = { val missing = missingFromCache if (missing.isEmpty) Task.now(nextNoMissingUnsafe()) else fetch(missing.toList, fetchModule).map(_.nextIfNoMissing()) @@ -535,7 +518,7 @@ object Resolver { /** * Required modules for the dependency management of `project`. */ - def dependencyManagementRequirements(project: Project): Set[Module] = { + def dependencyManagementRequirements(project: Project): Set[ModuleVersion] = { val approxProperties = project.parent .flatMap(projectsCache.get) @@ -548,7 +531,7 @@ object Resolver { val modules = (project.dependencies ++ profileDependencies) - .collect{ case dep if dep.scope == Scope.Import => dep.module } ++ + .collect{ case dep if dep.scope == Scope.Import => (dep.moduleVersion) } ++ project.parent modules.toSet @@ -562,12 +545,12 @@ object Resolver { * these modules should be added to the cache, and `dependencyManagementMissing` checked again * for new missing modules. */ - def dependencyManagementMissing(project: Project): Set[Module] = { + def dependencyManagementMissing(project: Project): Set[ModuleVersion] = { @tailrec - def helper(toCheck: Set[Module], - done: Set[Module], - missing: Set[Module]): Set[Module] = { + def helper(toCheck: Set[ModuleVersion], + done: Set[ModuleVersion], + missing: Set[ModuleVersion]): Set[ModuleVersion] = { if (toCheck.isEmpty) missing else if (toCheck.exists(done)) helper(toCheck -- done, done, missing) @@ -584,7 +567,7 @@ object Resolver { helper(Set.empty, done, missing ++ toCheck) } - helper(dependencyManagementRequirements(project), Set(project.module), Set.empty) + helper(dependencyManagementRequirements(project), Set(project.moduleVersion), Set.empty) } /** @@ -607,7 +590,7 @@ object Resolver { val deps = dependencies0 - .collect{ case dep if dep.scope == Scope.Import && projectsCache.contains(dep.module) => dep.module } ++ + .collect{ case dep if dep.scope == Scope.Import && projectsCache.contains(dep.moduleVersion) => dep.moduleVersion } ++ project.parent.filter(projectsCache.contains) val projs = deps.map(projectsCache(_)._2) @@ -619,7 +602,7 @@ object Resolver { project.copy( dependencies = dependencies0 - .filterNot(dep => dep.scope == Scope.Import && depsSet(dep.module)) ++ + .filterNot(dep => dep.scope == Scope.Import && depsSet(dep.moduleVersion)) ++ project.parent .filter(projectsCache.contains) .toSeq @@ -635,8 +618,8 @@ object Resolver { /** * Fetch `modules` with `fetchModules`, and add the resulting errors and projects to the cache. */ - def fetch(modules: Seq[Module], - fetchModule: Module => EitherT[Task, List[String], (Repository, Project)]): Task[Resolution] = { + def fetch(modules: Seq[ModuleVersion], + fetchModule: ModuleVersion => EitherT[Task, List[String], (Repository, Project)]): Task[Resolution] = { val lookups = modules.map(dep => fetchModule(dep).run.map(dep -> _)) val gatheredLookups = Task.gatherUnordered(lookups, exceptionCancels = true) @@ -654,7 +637,7 @@ object Resolver { current <- accTask updated <- current.fetch(current.dependencyManagementMissing(proj).toList, fetchModule) proj0 = updated.withDependencyManagement(proj) - } yield updated.copy(projectsCache = updated.projectsCache + (proj0.module -> (repo, proj0))) + } yield updated.copy(projectsCache = updated.projectsCache + (proj0.moduleVersion -> (repo, proj0))) } } } @@ -700,7 +683,7 @@ object Resolver { * */ def resolve(dependencies: Set[Dependency], - fetch: Module => EitherT[Task, List[String], (Repository, Project)], + fetch: ModuleVersion => EitherT[Task, List[String], (Repository, Project)], maxIterations: Option[Int], filter: Option[Dependency => Boolean], profileActivation: Option[(String, Activation, Map[String, String]) => Boolean]): Task[Resolution] = { diff --git a/core/src/main/scala/coursier/core/Xml.scala b/core/src/main/scala/coursier/core/Xml.scala index 70b3b3fcf..56cff7bfd 100644 --- a/core/src/main/scala/coursier/core/Xml.scala +++ b/core/src/main/scala/coursier/core/Xml.scala @@ -56,10 +56,12 @@ object Xml { else e } name <- text(node, "artifactId", "Name") - version = text(node, "version", "Version").getOrElse("") - } yield Module(organization, name, version).trim + } yield Module(organization, name).trim } + private def readVersion(node: Node) = + text(node, "version", "Version").getOrElse("").trim + private val defaultScope = Scope.Other("") private val defaultType = "jar" private val defaultClassifier = "" @@ -67,6 +69,7 @@ object Xml { def dependency(node: Node): String \/ Dependency = { for { mod <- module(node) + version0 = readVersion(node) scopeOpt = text(node, "scope", "").toOption .map(Parse.scope) typeOpt = text(node, "type", "").toOption @@ -82,6 +85,7 @@ object Xml { optional = text(node, "optional", "").toOption.toSeq.contains("true") } yield Dependency( mod, + version0, scopeOpt getOrElse defaultScope, typeOpt getOrElse defaultType, classifierOpt getOrElse defaultClassifier, @@ -150,12 +154,15 @@ object Xml { for { projModule <- module(pom, groupIdIsOptional = true) + projVersion = readVersion(pom) parentOpt = pom.child .find(_.label == "parent") parentModuleOpt <- parentOpt .map(module(_).map(Some(_))) .getOrElse(\/-(None)) + parentVersionOpt = parentOpt + .map(readVersion) xmlDeps = pom.child .find(_.label == "dependencies") @@ -173,12 +180,12 @@ object Xml { groupId <- Some(projModule.organization).filter(_.nonEmpty) .orElse(parentModuleOpt.map(_.organization).filter(_.nonEmpty)) .toRightDisjunction("No organization found") - version <- Some(projModule.version).filter(_.nonEmpty) - .orElse(parentModuleOpt.map(_.version).filter(_.nonEmpty)) + version <- Some(projVersion).filter(_.nonEmpty) + .orElse(parentVersionOpt.filter(_.nonEmpty)) .toRightDisjunction("No version found") - _ <- parentModuleOpt - .map(mod => if (mod.version.isEmpty) -\/("Parent version missing") else \/-(())) + _ <- parentVersionOpt + .map(v => if (v.isEmpty) -\/("Parent version missing") else \/-(())) .getOrElse(\/-(())) _ <- parentModuleOpt .map(mod => if (mod.organization.isEmpty) -\/("Parent organization missing") else \/-(())) @@ -197,9 +204,10 @@ object Xml { profiles <- xmlProfiles.toList.traverseU(profile) } yield Project( - projModule.copy(organization = groupId, version = version), + projModule.copy(organization = groupId), + version, deps, - parentModuleOpt, + parentModuleOpt.map((_, parentVersionOpt.getOrElse(""))), depMgmts, properties.toMap, profiles diff --git a/core/src/main/scala/coursier/package.scala b/core/src/main/scala/coursier/package.scala index 86394a5e7..0ac3d7d90 100644 --- a/core/src/main/scala/coursier/package.scala +++ b/core/src/main/scala/coursier/package.scala @@ -6,23 +6,25 @@ package object coursier { type Dependency = core.Dependency object Dependency { def apply(module: Module, + version: String, scope: Scope = Scope.Other(""), // Subsituted by Resolver with its own default scope (compile) `type`: String = "jar", classifier: String = "", exclusions: Set[(String, String)] = Set.empty, optional: Boolean = false): Dependency = - core.Dependency(module, scope, `type`, classifier, exclusions, optional) + core.Dependency(module, version, scope, `type`, classifier, exclusions, optional) } type Project = core.Project object Project { def apply(module: Module, + version: String, dependencies: Seq[Dependency] = Seq.empty, - parent: Option[Module] = None, + parent: Option[ModuleVersion] = None, dependencyManagement: Seq[Dependency] = Seq.empty, properties: Map[String, String] = Map.empty, profiles: Seq[Profile] = Seq.empty): Project = - core.Project(module, dependencies, parent, dependencyManagement, properties, profiles) + core.Project(module, version, dependencies, parent, dependencyManagement, properties, profiles) } type Profile = core.Profile @@ -44,17 +46,19 @@ package object coursier { type Module = core.Module object Module { - def apply(organization: String, name: String, version: String): Module = - core.Module(organization, name, version) + def apply(organization: String, name: String): Module = + core.Module(organization, name) } + type ModuleVersion = (core.Module, String) + type Scope = core.Scope val Scope: core.Scope.type = core.Scope type Repository = core.Repository - def fetchFrom(repositories: Seq[Repository]): Module => EitherT[Task, List[String], (Repository, Project)] = - core.Resolver.find(repositories, _) + def fetchFrom(repositories: Seq[Repository]): ModuleVersion => EitherT[Task, List[String], (Repository, Project)] = + modVersion => core.Resolver.find(repositories, modVersion._1, modVersion._2) type Resolution = core.Resolver.Resolution object Resolution { @@ -62,15 +66,15 @@ package object coursier { def apply(rootDependencies: Set[Dependency] = Set.empty, dependencies: Set[Dependency] = Set.empty, conflicts: Set[Dependency] = Set.empty, - projectsCache: Map[Module, (Repository, Project)] = Map.empty, - errors: Map[Module, Seq[String]] = Map.empty, + projectsCache: Map[ModuleVersion, (Repository, Project)] = Map.empty, + errors: Map[ModuleVersion, Seq[String]] = Map.empty, filter: Option[Dependency => Boolean] = None, profileActivation: Option[(String, Profile.Activation, Map[String, String]) => Boolean] = None): Resolution = core.Resolver.Resolution(rootDependencies, dependencies, conflicts, projectsCache, errors, filter, profileActivation) } def resolve(dependencies: Set[Dependency], - fetch: Module => EitherT[Task, List[String], (Repository, Project)], + fetch: ModuleVersion => EitherT[Task, List[String], (Repository, Project)], maxIterations: Option[Int] = Some(200), filter: Option[Dependency => Boolean] = None, profileActivation: Option[(String, Profile.Activation, Map[String, String]) => Boolean] = None): Task[Resolution] = { diff --git a/core/src/test/scala/coursier/test/CentralTests.scala b/core/src/test/scala/coursier/test/CentralTests.scala index 6699d2f0d..bfd0abe9e 100644 --- a/core/src/test/scala/coursier/test/CentralTests.scala +++ b/core/src/test/scala/coursier/test/CentralTests.scala @@ -15,7 +15,7 @@ object CentralTests extends TestSuite { val tests = TestSuite { 'logback{ async { - val dep = Dependency(Module("ch.qos.logback", "logback-classic", "1.1.3")) + val dep = Dependency(Module("ch.qos.logback", "logback-classic"), "1.1.3") val res0 = await(resolve(Set(dep), fetchFrom(repositories)) .runF) @@ -28,8 +28,8 @@ object CentralTests extends TestSuite { rootDependencies = Set(dep.withCompileScope), dependencies = Set( dep.withCompileScope, - Dependency(Module("ch.qos.logback", "logback-core", "1.1.3")).withCompileScope, - Dependency(Module("org.slf4j", "slf4j-api", "1.7.7")).withCompileScope + Dependency(Module("ch.qos.logback", "logback-core"), "1.1.3").withCompileScope, + Dependency(Module("org.slf4j", "slf4j-api"), "1.7.7").withCompileScope ) ) @@ -38,7 +38,7 @@ object CentralTests extends TestSuite { } 'asm{ async { - val dep = Dependency(Module("org.ow2.asm", "asm-commons", "5.0.2")) + val dep = Dependency(Module("org.ow2.asm", "asm-commons"), "5.0.2") val res0 = await(resolve(Set(dep), fetchFrom(repositories)) .runF) @@ -51,8 +51,8 @@ object CentralTests extends TestSuite { rootDependencies = Set(dep.withCompileScope), dependencies = Set( dep.withCompileScope, - Dependency(Module("org.ow2.asm", "asm-tree", "5.0.2")).withCompileScope, - Dependency(Module("org.ow2.asm", "asm", "5.0.2")).withCompileScope + Dependency(Module("org.ow2.asm", "asm-tree"), "5.0.2").withCompileScope, + Dependency(Module("org.ow2.asm", "asm"), "5.0.2").withCompileScope ) ) diff --git a/core/src/test/scala/coursier/test/PomParsingTests.scala b/core/src/test/scala/coursier/test/PomParsingTests.scala index 1582fdf1d..733e42f61 100644 --- a/core/src/test/scala/coursier/test/PomParsingTests.scala +++ b/core/src/test/scala/coursier/test/PomParsingTests.scala @@ -21,7 +21,7 @@ object PomParsingTests extends TestSuite { """ - val expected = \/-(Dependency(Module("comp", "lib", "2.1"), classifier = "extra")) + val expected = \/-(Dependency(Module("comp", "lib"), "2.1", classifier = "extra")) val result = Xml.dependency(xmlParse(depNode).right.get) @@ -75,7 +75,7 @@ object PomParsingTests extends TestSuite { None, Activation(Nil), Seq( - Dependency(Module("comp", "lib", "0.2"))), + Dependency(Module("comp", "lib"), "0.2")), Nil, Map.empty )) @@ -107,7 +107,7 @@ object PomParsingTests extends TestSuite { Activation(Nil), Nil, Seq( - Dependency(Module("comp", "lib", "0.2"), scope = Scope.Test)), + Dependency(Module("comp", "lib"), "0.2", scope = Scope.Test)), Map.empty )) diff --git a/core/src/test/scala/coursier/test/ResolverTests.scala b/core/src/test/scala/coursier/test/ResolverTests.scala index 9b6baf37c..a4ea2a752 100644 --- a/core/src/test/scala/coursier/test/ResolverTests.scala +++ b/core/src/test/scala/coursier/test/ResolverTests.scala @@ -10,137 +10,137 @@ import coursier.test.compatibility._ object ResolverTests extends TestSuite { implicit class ProjectOps(val p: Project) extends AnyVal { - def kv: (Module, (Repository, Project)) = p.module -> (testRepository, p) + def kv: (ModuleVersion, (Repository, Project)) = p.moduleVersion -> (testRepository, p) } val projects = Seq( - Project(Module("acme", "config", "1.3.0")), + Project(Module("acme", "config"), "1.3.0"), - Project(Module("acme", "play", "2.4.0"), Seq( - Dependency(Module("acme", "play-json", "2.4.0")))), + Project(Module("acme", "play"), "2.4.0", Seq( + 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", Seq( - Dependency(Module("acme", "play-json", "${playJsonVersion}")), - Dependency(Module("${project.groupId}", "${configName}", "1.3.0"))), + Dependency(Module("acme", "play-json"), "${playJsonVersion}"), + Dependency(Module("${project.groupId}", "${configName}"), "1.3.0")), properties = Map( "playJsonVersion" -> "2.4.0", "configName" -> "config")), - Project(Module("acme", "play-extra-no-config", "2.4.1"), + Project(Module("acme", "play-extra-no-config"), "2.4.1", Seq( - Dependency(Module("acme", "play", "2.4.1"), + Dependency(Module("acme", "play"), "2.4.1", 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( - Dependency(Module("acme", "play", "2.4.1"), + Dependency(Module("acme", "play"), "2.4.1", exclusions = Set(("*", "config"))))), - Project(Module("hudsucker", "mail", "10.0"), + Project(Module("hudsucker", "mail"), "10.0", Seq( - Dependency(Module("${project.groupId}", "test-util", "${project.version}"), + 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( - Dependency(Module("acme", "play", "2.4.0"), + Dependency(Module("acme", "play"), "2.4.0", exclusions = Set(("acme", "play-json"))))), - Project(Module("se.ikea", "billy", "18.0"), + Project(Module("se.ikea", "billy"), "18.0", 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( - 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", Seq( - Dependency(Module("org.gnome", "desktop", "${project.version}"))), - parent = Some(Module("org.gnome", "parent", "7.0"))), + Dependency(Module("org.gnome", "desktop"), "${project.version}")), + 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( - 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", Seq( - Dependency(Module("gov.nsa", "secure-pgp", "10.0"), + Dependency(Module("gov.nsa", "secure-pgp"), "10.0", exclusions = Set(("*", "${crypto.name}")))), 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", Seq( - Dependency(Module("junit", "junit", ""))), + Dependency(Module("junit", "junit"), "")), dependencyManagement = Seq( - Dependency(Module("junit", "junit", "4.11"), scope = Scope.Test))), + Dependency(Module("junit", "junit"), "4.11", scope = Scope.Test))), - Project(Module("com.thoughtworks.paranamer", "paranamer", "2.6"), - parent = Some(Module("com.thoughtworks.paranamer", "paranamer-parent", "2.6"))), + Project(Module("com.thoughtworks.paranamer", "paranamer"), "2.6", + parent = Some(Module("com.thoughtworks.paranamer", "paranamer-parent"), "2.6")), - Project(Module("com.github.dummy", "libb", "0.3.3"), + Project(Module("com.github.dummy", "libb"), "0.3.3", profiles = 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", Seq( - Dependency(Module("org.scalaverification", "scala-verification", "1.12.4")) + Dependency(Module("org.scalaverification", "scala-verification"), "1.12.4") ), profiles = Seq( Profile("default", activeByDefault = Some(true), dependencies = Seq( - Dependency(Module("org.escalier", "librairie-standard", "2.11.6")), - Dependency(Module("org.scalaverification", "scala-verification", "1.12.4"), scope = Scope.Test) + Dependency(Module("org.escalier", "librairie-standard"), "2.11.6"), + Dependency(Module("org.scalaverification", "scala-verification"), "1.12.4", scope = Scope.Test) )) )), - Project(Module("com.github.dummy", "libb", "0.5.3"), + Project(Module("com.github.dummy", "libb"), "0.5.3", properties = Map("special" -> "true"), profiles = 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"), profiles = 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"), profiles = 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")), - Project(Module("com.github.dummy", "libb", "0.5.6"), - parent = Some(Module("com.github.dummy", "libb-parent", "0.5.6")), + Project(Module("com.github.dummy", "libb"), "0.5.6", + parent = Some(Module("com.github.dummy", "libb-parent"), "0.5.6"), properties = Map("special" -> "true"), profiles = 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") )) )) ) - val projectsMap = projects.map(p => p.module -> p).toMap + val projectsMap = projects.map(p => p.moduleVersion -> p).toMap val testRepository: Repository = new TestRepository(projectsMap) val repositories = Seq[Repository]( @@ -161,7 +161,7 @@ object ResolverTests extends TestSuite { } 'notFound{ async { - val dep = Dependency(Module("acme", "playy", "2.4.0")) + val dep = Dependency(Module("acme", "playy"), "2.4.0") val res = await(resolve( Set(dep), fetchFrom(repositories) @@ -170,7 +170,7 @@ object ResolverTests extends TestSuite { val expected = Resolution( rootDependencies = Set(dep.withCompileScope), dependencies = Set(dep.withCompileScope), - errors = Map(dep.module -> Seq("Not found")) + errors = Map(dep.moduleVersion -> Seq("Not found")) ) assert(res == expected) @@ -178,7 +178,7 @@ object ResolverTests extends TestSuite { } 'single{ async { - val dep = Dependency(Module("acme", "config", "1.3.0")) + val dep = Dependency(Module("acme", "config"), "1.3.0") val res = await(resolve( Set(dep), fetchFrom(repositories) @@ -187,7 +187,7 @@ object ResolverTests extends TestSuite { val expected = Resolution( rootDependencies = Set(dep.withCompileScope), dependencies = Set(dep.withCompileScope), - projectsCache = Map(dep.module -> (testRepository, projectsMap(dep.module))) + projectsCache = Map(dep.moduleVersion -> (testRepository, projectsMap(dep.moduleVersion))) ) assert(res == expected) @@ -195,8 +195,8 @@ object ResolverTests extends TestSuite { } 'oneTransitiveDependency{ async { - val dep = Dependency(Module("acme", "play", "2.4.0")) - val trDep = Dependency(Module("acme", "play-json", "2.4.0")) + val dep = Dependency(Module("acme", "play"), "2.4.0") + val trDep = Dependency(Module("acme", "play-json"), "2.4.0") val res = await(resolve( Set(dep), fetchFrom(repositories) @@ -206,8 +206,8 @@ object ResolverTests extends TestSuite { rootDependencies = Set(dep.withCompileScope), dependencies = Set(dep.withCompileScope, trDep.withCompileScope), projectsCache = Map( - projectsMap(dep.module).kv, - projectsMap(trDep.module).kv + projectsMap(dep.moduleVersion).kv, + projectsMap(trDep.moduleVersion).kv ) ) @@ -216,10 +216,10 @@ object ResolverTests extends TestSuite { } 'twoTransitiveDependencyWithProps{ async { - val dep = Dependency(Module("acme", "play", "2.4.1")) + val dep = Dependency(Module("acme", "play"), "2.4.1") val trDeps = Seq( - Dependency(Module("acme", "play-json", "2.4.0")), - Dependency(Module("acme", "config", "1.3.0")) + Dependency(Module("acme", "play-json"), "2.4.0"), + Dependency(Module("acme", "config"), "1.3.0") ) val res = await(resolve( Set(dep), @@ -230,8 +230,8 @@ object ResolverTests extends TestSuite { rootDependencies = Set(dep.withCompileScope), dependencies = Set(dep.withCompileScope) ++ trDeps.map(_.withCompileScope), projectsCache = Map( - projectsMap(dep.module).kv - ) ++ trDeps.map(trDep => projectsMap(trDep.module).kv) + projectsMap(dep.moduleVersion).kv + ) ++ trDeps.map(trDep => projectsMap(trDep.moduleVersion).kv) ) assert(res == expected) @@ -239,11 +239,11 @@ object ResolverTests extends TestSuite { } 'exclude{ async { - val dep = Dependency(Module("acme", "play-extra-no-config", "2.4.1")) + val dep = Dependency(Module("acme", "play-extra-no-config"), "2.4.1") val trDeps = Seq( - Dependency(Module("acme", "play", "2.4.1"), + Dependency(Module("acme", "play"), "2.4.1", exclusions = Set(("acme", "config"))), - Dependency(Module("acme", "play-json", "2.4.0"), + Dependency(Module("acme", "play-json"), "2.4.0", exclusions = Set(("acme", "config"))) ) val res = await(resolve( @@ -255,8 +255,8 @@ object ResolverTests extends TestSuite { rootDependencies = Set(dep.withCompileScope), dependencies = Set(dep.withCompileScope) ++ trDeps.map(_.withCompileScope), projectsCache = Map( - projectsMap(dep.module).kv - ) ++ trDeps.map(trDep => projectsMap(trDep.module).kv) + projectsMap(dep.moduleVersion).kv + ) ++ trDeps.map(trDep => projectsMap(trDep.moduleVersion).kv) ) assert(res == expected) @@ -264,11 +264,11 @@ object ResolverTests extends TestSuite { } 'excludeOrgWildcard{ async { - val dep = Dependency(Module("acme", "play-extra-no-config-no", "2.4.1")) + val dep = Dependency(Module("acme", "play-extra-no-config-no"), "2.4.1") val trDeps = Seq( - Dependency(Module("acme", "play", "2.4.1"), + Dependency(Module("acme", "play"), "2.4.1", exclusions = Set(("*", "config"))), - Dependency(Module("acme", "play-json", "2.4.0"), + Dependency(Module("acme", "play-json"), "2.4.0", exclusions = Set(("*", "config"))) ) val res = await(resolve( @@ -280,8 +280,8 @@ object ResolverTests extends TestSuite { rootDependencies = Set(dep.withCompileScope), dependencies = Set(dep.withCompileScope) ++ trDeps.map(_.withCompileScope), projectsCache = Map( - projectsMap(dep.module).kv - ) ++ trDeps.map(trDep => projectsMap(trDep.module).kv) + projectsMap(dep.moduleVersion).kv + ) ++ trDeps.map(trDep => projectsMap(trDep.moduleVersion).kv) ) assert(res == expected) @@ -289,7 +289,7 @@ object ResolverTests extends TestSuite { } 'filter{ async { - val dep = Dependency(Module("hudsucker", "mail", "10.0")) + val dep = Dependency(Module("hudsucker", "mail"), "10.0") val res = await(resolve( Set(dep), fetchFrom(repositories), @@ -300,7 +300,7 @@ object ResolverTests extends TestSuite { rootDependencies = Set(dep.withCompileScope), dependencies = Set(dep.withCompileScope), projectsCache = Map( - projectsMap(dep.module).kv + projectsMap(dep.moduleVersion).kv ) ) @@ -309,9 +309,9 @@ object ResolverTests extends TestSuite { } 'parentDepMgmt{ async { - val dep = Dependency(Module("se.ikea", "billy", "18.0")) + val dep = Dependency(Module("se.ikea", "billy"), "18.0") val trDeps = Seq( - Dependency(Module("acme", "play", "2.4.0"), + Dependency(Module("acme", "play"), "2.4.0", exclusions = Set(("acme", "play-json"))) ) val res = await(resolve( @@ -330,10 +330,10 @@ object ResolverTests extends TestSuite { } 'parentDependencies{ async { - val dep = Dependency(Module("org.gnome", "panel-legacy", "7.0")) + val dep = Dependency(Module("org.gnome", "panel-legacy"), "7.0") val trDeps = Seq( - Dependency(Module("org.gnu", "glib", "13.4")), - Dependency(Module("org.gnome", "desktop", "7.0"))) + Dependency(Module("org.gnu", "glib"), "13.4"), + Dependency(Module("org.gnome", "desktop"), "7.0")) val res = await(resolve( Set(dep), fetchFrom(repositories), @@ -350,9 +350,9 @@ object ResolverTests extends TestSuite { } 'propertiesInExclusions{ async { - val dep = Dependency(Module("com.mailapp", "mail-client", "2.1")) + val dep = Dependency(Module("com.mailapp", "mail-client"), "2.1") 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(resolve( Set(dep), fetchFrom(repositories), @@ -369,7 +369,7 @@ object ResolverTests extends TestSuite { } 'depMgmtInParentDeps{ async { - val dep = Dependency(Module("com.thoughtworks.paranamer", "paranamer", "2.6")) + val dep = Dependency(Module("com.thoughtworks.paranamer", "paranamer"), "2.6") val res = await(resolve( Set(dep), fetchFrom(repositories), @@ -386,9 +386,9 @@ object ResolverTests extends TestSuite { } 'depsFromDefaultProfile{ async { - val dep = Dependency(Module("com.github.dummy", "libb", "0.3.3")) + val dep = Dependency(Module("com.github.dummy", "libb"), "0.3.3") val trDeps = Seq( - Dependency(Module("org.escalier", "librairie-standard", "2.11.6"))) + Dependency(Module("org.escalier", "librairie-standard"), "2.11.6")) val res = await(resolve( Set(dep), fetchFrom(repositories), @@ -407,9 +407,9 @@ object ResolverTests extends TestSuite { val f = for (version <- Seq("0.5.3", "0.5.4", "0.5.5", "0.5.6")) yield { async { - val dep = Dependency(Module("com.github.dummy", "libb", version)) + val dep = Dependency(Module("com.github.dummy", "libb"), version) val trDeps = Seq( - Dependency(Module("org.escalier", "librairie-standard", "2.11.6"))) + Dependency(Module("org.escalier", "librairie-standard"), "2.11.6")) val res = await(resolve( Set(dep), fetchFrom(repositories), @@ -430,9 +430,9 @@ object ResolverTests extends TestSuite { 'depsScopeOverrideFromProfile{ async { // Like com.google.inject:guice:3.0 with org.sonatype.sisu.inject:cglib - val dep = Dependency(Module("com.github.dummy", "libb", "0.4.2")) + val dep = Dependency(Module("com.github.dummy", "libb"), "0.4.2") val trDeps = Seq( - Dependency(Module("org.escalier", "librairie-standard", "2.11.6"))) + Dependency(Module("org.escalier", "librairie-standard"), "2.11.6")) val res = await(resolve( Set(dep), fetchFrom(repositories), @@ -452,9 +452,9 @@ object ResolverTests extends TestSuite { 'propertySubstitution{ val res = Resolver.withProperties( - Seq(Dependency(Module("a-company", "a-name", "${a.property}"))), + Seq(Dependency(Module("a-company", "a-name"), "${a.property}")), 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) } diff --git a/core/src/test/scala/coursier/test/TestRepository.scala b/core/src/test/scala/coursier/test/TestRepository.scala index b79e638ac..b70077b34 100644 --- a/core/src/test/scala/coursier/test/TestRepository.scala +++ b/core/src/test/scala/coursier/test/TestRepository.scala @@ -7,10 +7,10 @@ import scalaz.{-\/, \/, EitherT} import scalaz.concurrent.Task import scalaz.Scalaz._ -class TestRepository(projects: Map[Module, Project]) extends Repository { - def find(module: Module, cachePolicy: CachePolicy) = +class TestRepository(projects: Map[(Module, String), Project]) extends Repository { + def find(module: Module, version: String, cachePolicy: CachePolicy) = EitherT(Task.now( - projects.get(module).toRightDisjunction("Not found") + projects.get((module, version)).toRightDisjunction("Not found") )) def versions(organization: String, name: String, cachePolicy: CachePolicy) = EitherT(Task.now[String \/ Versions]( diff --git a/web/src/main/scala/coursier/web/Backend.scala b/web/src/main/scala/coursier/web/Backend.scala index 975799fc9..c1b0ad081 100644 --- a/web/src/main/scala/coursier/web/Backend.scala +++ b/web/src/main/scala/coursier/web/Backend.scala @@ -69,7 +69,7 @@ class Backend($: BackendScope[Unit, State]) { def updateTree(resolution: Resolution, target: String, reverse: Boolean) = { def depsOf(dep: Dependency) = - resolution.projectsCache.get(dep.module).toSeq.flatMap(t => Resolver.finalDependencies(dep, t._2).filter(resolution.filter getOrElse Resolver.defaultFilter)) + resolution.projectsCache.get(dep.moduleVersion).toSeq.flatMap(t => Resolver.finalDependencies(dep, t._2).filter(resolution.filter getOrElse Resolver.defaultFilter)) lazy val reverseDeps = { var m = Map.empty[Module, Seq[Dependency]] @@ -169,7 +169,7 @@ class Backend($: BackendScope[Unit, State]) { def addModule(e: ReactEventI) = { e.preventDefault() $.modState{ state => - val modules = state.modules :+ Dependency(Module("", "", "")) + val modules = state.modules :+ Dependency(Module("", ""), "") println(s"Modules:\n${modules.mkString("\n")}") state.copy(modules = modules, editModuleIdx = modules.length - 1) } @@ -211,26 +211,26 @@ object App { def depItem(dep: Dependency) = <.tr( - ^.`class` := (if (res.errors.contains(dep.module)) "danger" else ""), + ^.`class` := (if (res.errors.contains(dep.moduleVersion)) "danger" else ""), <.td(dep.module.organization), <.td(dep.module.name), - <.td(dep.module.version), + <.td(dep.version), <.td(Seq[Seq[TagMod]]( if (dep.scope == Scope.Compile) Seq() else Seq(infoLabel(dep.scope.name)), if (dep.`type`.isEmpty || dep.`type` == "jar") Seq() else Seq(infoLabel(dep.`type`)), if (dep.classifier.isEmpty) Seq() else Seq(infoLabel(dep.classifier)), if (dep.optional) Seq(infoLabel("optional")) else Seq(), - res.errors.get(dep.module).map(errs => errorLabel("Error", errs.mkString("; "))).toSeq + res.errors.get(dep.moduleVersion).map(errs => errorLabel("Error", errs.mkString("; "))).toSeq )), <.td(Seq[Seq[TagMod]]( - res.projectsCache.get(dep.module) match { + res.projectsCache.get(dep.moduleVersion) match { case Some((repo: Remote, _)) => // FIXME Maven specific, generalize if/when adding support for Ivy val relPath = dep.module.organization.split('.').toSeq ++ Seq( dep.module.name, - dep.module.version, - s"${dep.module.name}-${dep.module.version}" + dep.version, + s"${dep.module.name}-${dep.version}" ) Seq( @@ -274,9 +274,9 @@ object App { def remove = apply("remove") } - val moduleEditModal = ReactComponentB[(Module, Int, Backend)]("EditModule") + val moduleEditModal = ReactComponentB[((Module, String), Int, Backend)]("EditModule") .render{ P => - val (module, moduleIdx, backend) = P + val ((module, version), moduleIdx, backend) = P <.div(^.`class` := "modal fade", ^.id := "moduleEdit", ^.role := "dialog", ^.aria.labelledby := "moduleEditTitle", <.div(^.`class` := "modal-dialog", <.div(^.`class` := "modal-content", <.div(^.`class` := "modal-header", @@ -304,8 +304,8 @@ object App { <.div(^.`class` := "form-group", <.label(^.`for` := "inputVersion", "Version"), <.input(^.`class` := "form-control", ^.id := "inputVersion", ^.placeholder := "Version", - ^.onChange ==> backend.updateModule(moduleIdx, (dep, value) => dep.copy(module = dep.module.copy(version = value))), - ^.value := module.version + ^.onChange ==> backend.updateModule(moduleIdx, (dep, value) => dep.copy(version = value)), + ^.value := version ) ), <.div(^.`class` := "modal-footer", @@ -326,7 +326,7 @@ object App { <.tr( <.td(dep.module.organization), <.td(dep.module.name), - <.td(dep.module.version), + <.td(dep.version), <.td( <.a(Attr("data-toggle") := "modal", Attr("data-target") := "#moduleEdit", ^.`class` := "icon-action", ^.onClick ==> backend.editModule(idx), @@ -363,7 +363,7 @@ object App { deps.zipWithIndex.map((depItem _).tupled) ) ), - moduleEditModal((deps.lift(editModuleIdx).fold(Module("", "", ""))(_.module), editModuleIdx, backend)) + moduleEditModal((deps.lift(editModuleIdx).fold((Module("", ""), ""))(_.moduleVersion), editModuleIdx, backend)) ) } .build