From d1e502b8f3a7b9a01eda0cfef78e15e7f0cd5dad Mon Sep 17 00:00:00 2001 From: Alexandre Archambault Date: Wed, 30 Dec 2015 01:34:39 +0100 Subject: [PATCH] Move things around --- .../main/scala/coursier/CoursierPlugin.scala | 254 +----------------- plugin/src/main/scala/coursier/Tasks.scala | 245 +++++++++++++++++ 2 files changed, 250 insertions(+), 249 deletions(-) diff --git a/plugin/src/main/scala/coursier/CoursierPlugin.scala b/plugin/src/main/scala/coursier/CoursierPlugin.scala index 3d85bbfc6..97ac8caff 100644 --- a/plugin/src/main/scala/coursier/CoursierPlugin.scala +++ b/plugin/src/main/scala/coursier/CoursierPlugin.scala @@ -1,29 +1,16 @@ package coursier -import java.io.{ File, OutputStreamWriter } +import java.io.File -import coursier.cli.TermDisplay -import coursier.ivy.IvyRepository -import sbt.{ MavenRepository => _, _ } +import sbt._ import sbt.Keys._ -import scalaz.{ -\/, \/- } -import scalaz.concurrent.Task - object CoursierPlugin extends AutoPlugin { - private def grouped[K, V](map: Seq[(K, V)]): Map[K, Seq[V]] = - map.groupBy { case (k, _) => k }.map { - case (k, l) => - k -> l.map { case (_, v) => v } - } - override def trigger = allRequirements override def requires = sbt.plugins.IvyPlugin - private def errPrintln(s: String): Unit = scala.Console.err.println(s) - object autoImport { val coursierParallelDownloads = Keys.coursierParallelDownloads val coursierMaxIterations = Keys.coursierMaxIterations @@ -40,237 +27,6 @@ object CoursierPlugin extends AutoPlugin { import autoImport._ - private val ivyProperties = Map( - "ivy.home" -> s"${sys.props("user.home")}/.ivy2" - ) ++ sys.props - - private def createLogger() = Some { - new TermDisplay( - new OutputStreamWriter(System.err), - fallbackMode = sys.env.get("COURSIER_NO_TERM").nonEmpty - ) - } - - - private def updateTask(withClassifiers: Boolean, sbtClassifiers: Boolean = false) = Def.task { - - // let's update only one module at once, for a better output - // Downloads are already parallel, no need to parallelize further anyway - synchronized { - - lazy val cm = coursierSbtClassifiersModule.value - - val currentProject = - if (sbtClassifiers) { - FromSbt.project( - cm.id, - cm.modules, - cm.configurations.map(cfg => cfg.name -> cfg.extendsConfigs.map(_.name)).toMap, - scalaVersion.value, - scalaBinaryVersion.value - ) - } else { - val (p, _) = coursierProject.value - p - } - - val projects = coursierProjects.value - - val parallelDownloads = coursierParallelDownloads.value - val checksums = coursierChecksums.value - val maxIterations = coursierMaxIterations.value - val cachePolicy = coursierCachePolicy.value - val cacheDir = coursierCache.value - - val resolvers = coursierResolvers.value - - val verbosity = coursierVerbosity.value - - - val startRes = Resolution( - currentProject.dependencies.map { case (_, dep) => dep }.toSet, - filter = Some(dep => !dep.optional), - forceVersions = projects.map { case (proj, _) => proj.moduleVersion }.toMap - ) - - if (verbosity >= 1) { - println("InterProjectRepository") - for ((p, _) <- projects) - println(s" ${p.module}:${p.version}") - } - - val globalPluginsRepo = IvyRepository( - new File(sys.props("user.home") + "/.sbt/0.13/plugins/target/resolution-cache/").toURI.toString + - "[organization]/[module](/scala_[scalaVersion])(/sbt_[sbtVersion])/[revision]/resolved.xml.[ext]", - withChecksums = false, - withSignatures = false, - withArtifacts = false - ) - - val interProjectRepo = InterProjectRepository(projects) - val repositories = Seq(globalPluginsRepo, interProjectRepo) ++ resolvers.flatMap(FromSbt.repository(_, ivyProperties)) - - val files = Files( - Seq("http://" -> new File(cacheDir, "http"), "https://" -> new File(cacheDir, "https")), - () => ???, - concurrentDownloadCount = parallelDownloads - ) - - val logger = createLogger() - logger.foreach(_.init()) - val fetch = coursier.Fetch( - repositories, - files.fetch(checksums = checksums, logger = logger)(cachePolicy = CachePolicy.LocalOnly), - files.fetch(checksums = checksums, logger = logger)(cachePolicy = cachePolicy) - ) - - def depsRepr = currentProject.dependencies.map { case (config, dep) => - s"${dep.module}:${dep.version}:$config->${dep.configuration}" - }.sorted - - if (verbosity >= 0) - errPrintln(s"Resolving ${currentProject.module.organization}:${currentProject.module.name}:${currentProject.version}") - if (verbosity >= 1) - for (depRepr <- depsRepr) - errPrintln(s" $depRepr") - - val res = startRes - .process - .run(fetch, maxIterations) - .attemptRun - .leftMap(ex => throw new Exception(s"Exception during resolution", ex)) - .merge - - if (!res.isDone) - throw new Exception(s"Maximum number of iteration reached!") - - if (verbosity >= 0) - errPrintln("Resolution done") - - def repr(dep: Dependency) = { - // dep.version can be an interval, whereas the one from project can't - val version = res - .projectCache - .get(dep.moduleVersion) - .map(_._2.version) - .getOrElse(dep.version) - val extra = - if (version == dep.version) "" - else s" ($version for ${dep.version})" - - ( - Seq( - dep.module.organization, - dep.module.name, - dep.attributes.`type` - ) ++ - Some(dep.attributes.classifier) - .filter(_.nonEmpty) - .toSeq ++ - Seq( - version - ) - ).mkString(":") + extra - } - - if (res.conflicts.nonEmpty) { - // Needs test - println(s"${res.conflicts.size} conflict(s):\n ${res.conflicts.toList.map(repr).sorted.mkString(" \n")}") - } - - val errors = res.errors - - if (errors.nonEmpty) { - println(s"\n${errors.size} error(s):") - for ((dep, errs) <- errors) { - println(s" ${dep.module}:${dep.version}:\n${errs.map(" " + _.replace("\n", " \n")).mkString("\n")}") - } - } - - val classifiers = - if (withClassifiers) - Some { - if (sbtClassifiers) - cm.classifiers - else - transitiveClassifiers.value - } - else - None - - val allArtifacts = - classifiers match { - case None => res.artifacts - case Some(cl) => res.classifiersArtifacts(cl) - } - - val artifactFileOrErrorTasks = allArtifacts.toVector.map { a => - files.file(a, checksums = checksums, logger = logger)(cachePolicy = cachePolicy).run.map((a, _)) - } - - if (verbosity >= 0) - errPrintln(s"Fetching artifacts") - - val artifactFilesOrErrors = Task.gatherUnordered(artifactFileOrErrorTasks).attemptRun match { - case -\/(ex) => - throw new Exception(s"Error while downloading / verifying artifacts", ex) - case \/-(l) => - l.toMap - } - - if (verbosity >= 0) - errPrintln(s"Fetching artifacts: done") - - val configs = { - val configs0 = ivyConfigurations.value.map { config => - config.name -> config.extendsConfigs.map(_.name) - }.toMap - - def allExtends(c: String) = { - // possibly bad complexity - def helper(current: Set[String]): Set[String] = { - val newSet = current ++ current.flatMap(configs0.getOrElse(_, Nil)) - if ((newSet -- current).nonEmpty) - helper(newSet) - else - newSet - } - - helper(Set(c)) - } - - configs0.map { - case (config, _) => - config -> allExtends(config) - } - } - - def artifactFileOpt(artifact: Artifact) = { - val fileOrError = artifactFilesOrErrors.getOrElse(artifact, -\/("Not downloaded")) - - fileOrError match { - case \/-(file) => - if (file.toString.contains("file:/")) - throw new Exception(s"Wrong path: $file") - Some(file) - case -\/(err) => - errPrintln(s"${artifact.url}: $err") - None - } - } - - val depsByConfig = grouped(currentProject.dependencies) - - ToSbt.updateReport( - depsByConfig, - res, - configs, - classifiers, - artifactFileOpt - ) - } - } - override lazy val projectSettings = Seq( coursierParallelDownloads := 6, coursierMaxIterations := 50, @@ -279,9 +35,9 @@ object CoursierPlugin extends AutoPlugin { coursierVerbosity := 1, coursierResolvers <<= Tasks.coursierResolversTask, coursierCache := new File(sys.props("user.home") + "/.coursier/sbt"), - update <<= updateTask(withClassifiers = false), - updateClassifiers <<= updateTask(withClassifiers = true), - updateSbtClassifiers in Defaults.TaskGlobal <<= updateTask(withClassifiers = true, sbtClassifiers = true), + update <<= Tasks.updateTask(withClassifiers = false), + updateClassifiers <<= Tasks.updateTask(withClassifiers = true), + updateSbtClassifiers in Defaults.TaskGlobal <<= Tasks.updateTask(withClassifiers = true, sbtClassifiers = true), coursierProject <<= Tasks.coursierProjectTask, coursierProjects <<= Tasks.coursierProjectsTask, coursierSbtClassifiersModule <<= classifiersModule in updateSbtClassifiers diff --git a/plugin/src/main/scala/coursier/Tasks.scala b/plugin/src/main/scala/coursier/Tasks.scala index 130af086b..223909724 100644 --- a/plugin/src/main/scala/coursier/Tasks.scala +++ b/plugin/src/main/scala/coursier/Tasks.scala @@ -1,10 +1,17 @@ package coursier +import java.io.{OutputStreamWriter, File} + +import coursier.cli.TermDisplay +import coursier.ivy.IvyRepository import sbt.{Classpaths, Resolver, Def} import Structure._ import Keys._ import sbt.Keys._ +import scalaz.{\/-, -\/} +import scalaz.concurrent.Task + object Tasks { def coursierResolversTask: Def.Initialize[sbt.Task[Seq[Resolver]]] = Def.task { @@ -66,4 +73,242 @@ object Tasks { coursierProject.forAllProjects(state, projects).map(_.values.toVector) } + def updateTask(withClassifiers: Boolean, sbtClassifiers: Boolean = false) = Def.task { + + def errPrintln(s: String): Unit = scala.Console.err.println(s) + + def grouped[K, V](map: Seq[(K, V)]): Map[K, Seq[V]] = + map.groupBy { case (k, _) => k }.map { + case (k, l) => + k -> l.map { case (_, v) => v } + } + + val ivyProperties = Map( + "ivy.home" -> s"${sys.props("user.home")}/.ivy2" + ) ++ sys.props + + def createLogger() = Some { + new TermDisplay( + new OutputStreamWriter(System.err), + fallbackMode = sys.env.get("COURSIER_NO_TERM").nonEmpty + ) + } + + // let's update only one module at once, for a better output + // Downloads are already parallel, no need to parallelize further anyway + synchronized { + + lazy val cm = coursierSbtClassifiersModule.value + + val currentProject = + if (sbtClassifiers) + FromSbt.project( + cm.id, + cm.modules, + cm.configurations.map(cfg => cfg.name -> cfg.extendsConfigs.map(_.name)).toMap, + scalaVersion.value, + scalaBinaryVersion.value + ) + else { + val (p, _) = coursierProject.value + p + } + + val projects = coursierProjects.value + + val parallelDownloads = coursierParallelDownloads.value + val checksums = coursierChecksums.value + val maxIterations = coursierMaxIterations.value + val cachePolicy = coursierCachePolicy.value + val cacheDir = coursierCache.value + + val resolvers = coursierResolvers.value + + val verbosity = coursierVerbosity.value + + + val startRes = Resolution( + currentProject.dependencies.map { case (_, dep) => dep }.toSet, + filter = Some(dep => !dep.optional), + forceVersions = projects.map { case (proj, _) => proj.moduleVersion }.toMap + ) + + if (verbosity >= 1) { + println("InterProjectRepository") + for ((p, _) <- projects) + println(s" ${p.module}:${p.version}") + } + + val globalPluginsRepo = IvyRepository( + new File(sys.props("user.home") + "/.sbt/0.13/plugins/target/resolution-cache/").toURI.toString + + "[organization]/[module](/scala_[scalaVersion])(/sbt_[sbtVersion])/[revision]/resolved.xml.[ext]", + withChecksums = false, + withSignatures = false, + withArtifacts = false + ) + + val interProjectRepo = InterProjectRepository(projects) + val repositories = Seq(globalPluginsRepo, interProjectRepo) ++ resolvers.flatMap(FromSbt.repository(_, ivyProperties)) + + val files = Files( + Seq("http://" -> new File(cacheDir, "http"), "https://" -> new File(cacheDir, "https")), + () => ???, + concurrentDownloadCount = parallelDownloads + ) + + val logger = createLogger() + logger.foreach(_.init()) + val fetch = coursier.Fetch( + repositories, + files.fetch(checksums = checksums, logger = logger)(cachePolicy = CachePolicy.LocalOnly), + files.fetch(checksums = checksums, logger = logger)(cachePolicy = cachePolicy) + ) + + def depsRepr = currentProject.dependencies.map { case (config, dep) => + s"${dep.module}:${dep.version}:$config->${dep.configuration}" + }.sorted + + if (verbosity >= 0) + errPrintln(s"Resolving ${currentProject.module.organization}:${currentProject.module.name}:${currentProject.version}") + if (verbosity >= 1) + for (depRepr <- depsRepr) + errPrintln(s" $depRepr") + + val res = startRes + .process + .run(fetch, maxIterations) + .attemptRun + .leftMap(ex => throw new Exception(s"Exception during resolution", ex)) + .merge + + if (!res.isDone) + throw new Exception(s"Maximum number of iteration reached!") + + if (verbosity >= 0) + errPrintln("Resolution done") + + def repr(dep: Dependency) = { + // dep.version can be an interval, whereas the one from project can't + val version = res + .projectCache + .get(dep.moduleVersion) + .map(_._2.version) + .getOrElse(dep.version) + val extra = + if (version == dep.version) "" + else s" ($version for ${dep.version})" + + ( + Seq( + dep.module.organization, + dep.module.name, + dep.attributes.`type` + ) ++ + Some(dep.attributes.classifier) + .filter(_.nonEmpty) + .toSeq ++ + Seq( + version + ) + ).mkString(":") + extra + } + + if (res.conflicts.nonEmpty) { + // Needs test + println(s"${res.conflicts.size} conflict(s):\n ${res.conflicts.toList.map(repr).sorted.mkString(" \n")}") + } + + val errors = res.errors + + if (errors.nonEmpty) { + println(s"\n${errors.size} error(s):") + for ((dep, errs) <- errors) { + println(s" ${dep.module}:${dep.version}:\n${errs.map(" " + _.replace("\n", " \n")).mkString("\n")}") + } + } + + val classifiers = + if (withClassifiers) + Some { + if (sbtClassifiers) + cm.classifiers + else + transitiveClassifiers.value + } + else + None + + val allArtifacts = + classifiers match { + case None => res.artifacts + case Some(cl) => res.classifiersArtifacts(cl) + } + + val artifactFileOrErrorTasks = allArtifacts.toVector.map { a => + files.file(a, checksums = checksums, logger = logger)(cachePolicy = cachePolicy).run.map((a, _)) + } + + if (verbosity >= 0) + errPrintln(s"Fetching artifacts") + + val artifactFilesOrErrors = Task.gatherUnordered(artifactFileOrErrorTasks).attemptRun match { + case -\/(ex) => + throw new Exception(s"Error while downloading / verifying artifacts", ex) + case \/-(l) => + l.toMap + } + + if (verbosity >= 0) + errPrintln(s"Fetching artifacts: done") + + val configs = { + val configs0 = ivyConfigurations.value.map { config => + config.name -> config.extendsConfigs.map(_.name) + }.toMap + + def allExtends(c: String) = { + // possibly bad complexity + def helper(current: Set[String]): Set[String] = { + val newSet = current ++ current.flatMap(configs0.getOrElse(_, Nil)) + if ((newSet -- current).nonEmpty) + helper(newSet) + else + newSet + } + + helper(Set(c)) + } + + configs0.map { + case (config, _) => + config -> allExtends(config) + } + } + + def artifactFileOpt(artifact: Artifact) = { + val fileOrError = artifactFilesOrErrors.getOrElse(artifact, -\/("Not downloaded")) + + fileOrError match { + case \/-(file) => + if (file.toString.contains("file:/")) + throw new Exception(s"Wrong path: $file") + Some(file) + case -\/(err) => + errPrintln(s"${artifact.url}: $err") + None + } + } + + val depsByConfig = grouped(currentProject.dependencies) + + ToSbt.updateReport( + depsByConfig, + res, + configs, + classifiers, + artifactFileOpt + ) + } + } + }