Merge pull request #37 from alexarchambault/develop

Last developments
This commit is contained in:
Alexandre Archambault 2015-06-20 16:18:19 +02:00
commit a84306c942
4 changed files with 43 additions and 18 deletions

View File

@ -12,7 +12,8 @@ import scalaz.{-\/, \/-}
case class Coursier(scope: List[String],
keepOptional: Boolean,
fetch: Boolean) extends App {
fetch: Boolean,
@ExtraName("N") maxIterations: Int) extends App {
val scopes0 =
if (scope.isEmpty) List(Scope.Compile, Scope.Runtime)
@ -85,9 +86,15 @@ case class Coursier(scope: List[String],
val res = resolve(
deps.toSet,
fetchFrom(repositories),
maxIterations = Some(maxIterations).filter(_ > 0),
filter = Some(dep => (keepOptional || !dep.optional) && scopes(dep.scope))
).run
if (!res.isDone) {
println(s"Maximum number of iteration reached!")
sys exit 1
}
def repr(dep: Dependency) =
s"${dep.module.organization}:${dep.module.name}:${dep.`type`}:${Some(dep.classifier).filter(_.nonEmpty).map(_+":").mkString}${dep.version}"

View File

@ -1,13 +1,15 @@
package coursier.core
/**
* Identify a "module".
* Identifies a "module".
*
* During resolution, all dependencies having the same module
* will be given the same version, if there are no version conflicts
* between them.
*
* Ivy attributes would land here, if support for Ivy is added.
* Using the same terminology as Ivy.
*
* Ivy attributes would land here, if support for it is added.
*/
case class Module(organization: String,
name: String) {

View File

@ -3,6 +3,7 @@ package coursier.core
import java.util.regex.Pattern.quote
import scala.annotation.tailrec
import scala.collection.mutable
import scalaz.concurrent.Task
import scalaz.{EitherT, \/-, \/, -\/}
@ -16,8 +17,8 @@ object Resolver {
* Look at `repositories` from the left, one-by-one, and stop at first success.
* Else, return all errors, in the same order.
*
* The `module` field of the returned `Project` in case of success may not be
* equal to `module`, in case the version of the latter is not a specific
* The `version` field of the returned `Project` in case of success may not be
* equal to the provided one, in case the latter is not a specific
* version (e.g. version interval). Which version get chosen depends on
* the repository implementation.
*/
@ -296,7 +297,7 @@ object Resolver {
else dep
/**
* Filters `deps` with `exclusions`.
* Filters `dependencies` with `exclusions`.
*/
def withExclusions(dependencies: Seq[Dependency],
exclusions: Set[(String, String)]): Seq[Dependency] = {
@ -378,6 +379,16 @@ object Resolver {
filter: Option[Dependency => Boolean],
profileActivation: Option[(String, Activation, Map[String, String]) => Boolean]) {
private val finalDependenciesCache = new mutable.HashMap[Dependency, Seq[Dependency]]()
private def finalDependencies0(dep: Dependency) = finalDependenciesCache.synchronized {
finalDependenciesCache.getOrElseUpdate(dep,
projectsCache.get(dep.moduleVersion) match {
case Some((_, proj)) => finalDependencies(dep, proj).filter(filter getOrElse defaultFilter)
case None => Nil
}
)
}
/**
* Transitive dependencies of the current dependencies, according to what there currently is in cache.
* No attempt is made to solve version conflicts here.
@ -385,14 +396,16 @@ object Resolver {
def transitiveDependencies =
for {
dep <- (dependencies -- conflicts).toList
(_, proj) <- projectsCache.get((dep.moduleVersion)).toSeq
trDep <- finalDependencies(dep, proj).filter(filter getOrElse defaultFilter)
trDep <- finalDependencies0(dep)
} yield trDep
/**
* The "next" dependency set, made of the current dependencies and their transitive dependencies,
* trying to solve version conflicts. Transitive dependencies are calculated with the current cache.
*
* May contain dependencies added in previous iterations, but no more required. These are filtered below, see
* @newDependencies.
*
* Returns a tuple made of the conflicting dependencies, and all the dependencies.
*/
def nextDependenciesAndConflicts = {
@ -403,8 +416,8 @@ object Resolver {
* The modules we miss some info about.
*/
def missingFromCache: Set[ModuleVersion] = {
val modules = dependencies.map(dep => (dep.moduleVersion))
val nextModules = nextDependenciesAndConflicts._2.map(dep => (dep.moduleVersion))
val modules = dependencies.map(_.moduleVersion)
val nextModules = nextDependenciesAndConflicts._2.map(_.moduleVersion)
(modules ++ nextModules)
.filterNot(mod => projectsCache.contains(mod) || errors.contains(mod))
@ -416,8 +429,8 @@ object Resolver {
*/
def isDone: Boolean = {
def isFixPoint = {
val (nextConflicts, nextDependencies) = nextDependenciesAndConflicts
dependencies == (nextDependencies ++ nextConflicts).toSet && conflicts == nextConflicts.toSet
val (nextConflicts, _) = nextDependenciesAndConflicts
dependencies == (newDependencies ++ nextConflicts) && conflicts == nextConflicts.toSet
}
missingFromCache.isEmpty && isFixPoint
@ -436,8 +449,7 @@ object Resolver {
val trDepsSeq =
for {
dep <- updatedDeps
(_, proj) <- projectsCache.get((dep.moduleVersion)).toList
trDep <- finalDependencies(dep, proj).filter(filter getOrElse defaultFilter)
trDep <- finalDependencies0(dep)
} yield key(trDep) -> (key(dep), trDep.exclusions)
val knownDeps = (updatedDeps ++ updatedConflicts).map(key).toSet
@ -531,7 +543,7 @@ object Resolver {
val modules =
(project.dependencies ++ profileDependencies)
.collect{ case dep if dep.scope == Scope.Import => (dep.moduleVersion) } ++
.collect{ case dep if dep.scope == Scope.Import => dep.moduleVersion } ++
project.parent
modules.toSet

View File

@ -4,11 +4,13 @@ package web
import coursier.core.{Resolver, Logger, Remote}
import japgolly.scalajs.react.vdom.{TagMod, Attr}
import japgolly.scalajs.react.vdom.Attrs.dangerouslySetInnerHtml
import japgolly.scalajs.react.{ReactKeyboardEventI, ReactEventI, ReactComponentB, BackendScope}
import japgolly.scalajs.react.{ReactEventI, ReactComponentB, BackendScope}
import japgolly.scalajs.react.vdom.prefix_<^._
import scala.scalajs.concurrent.JSExecutionContext.Implicits.queue
import org.scalajs.jquery.jQuery
import scala.concurrent.Future
import scala.scalajs.js
import js.Dynamic.{global => g}
@ -117,13 +119,15 @@ class Backend($: BackendScope[Unit, State]) {
}
val s = $.state
val task = coursier.resolve(
def task = coursier.resolve(
s.modules.toSet,
fetchFrom(s.repositories.map(_.copy(logger = Some(logger)))),
filter = Some(dep => (s.options.followOptional || !dep.optional) && (s.options.keepTest || dep.scope != Scope.Test))
)
task.runF.foreach { res: Resolution =>
// For reasons that are unclear to me, not delaying this when using the runNow execution context
// somehow discards the $.modState above. (Not a major problem as queue is used by default.)
Future(task)(scala.scalajs.concurrent.JSExecutionContext.Implicits.queue).flatMap(_.runF).foreach { res: Resolution =>
$.modState{ s => updateDepGraph(res); updateTree(res, "#deptree", reverse = s.reverseTree); s.copy(resolutionOpt = Some(res), resolving = false)}
g.$("#resResTab a:last").tab("show")
}