diff --git a/cli/src/main/scala-2.11/coursier/cli/Coursier.scala b/cli/src/main/scala-2.11/coursier/cli/Coursier.scala index b6a3204ea..9f3742861 100644 --- a/cli/src/main/scala-2.11/coursier/cli/Coursier.scala +++ b/cli/src/main/scala-2.11/coursier/cli/Coursier.scala @@ -41,6 +41,10 @@ case class CommonOptions( @Value("organization:name:forcedVersion") @Short("V") forceVersion: List[String], + @Help("Exclude module") + @Value("organization:name") + @Short("E") + exclude: List[String], @Help("Maximum number of parallel downloads (default: 6)") @Short("n") parallel: Int = 6, diff --git a/cli/src/main/scala-2.11/coursier/cli/Helper.scala b/cli/src/main/scala-2.11/coursier/cli/Helper.scala index 1305f382e..f39dcc2db 100644 --- a/cli/src/main/scala-2.11/coursier/cli/Helper.scala +++ b/cli/src/main/scala-2.11/coursier/cli/Helper.scala @@ -115,11 +115,6 @@ class Helper( s"Cannot parse dependencies:\n" + modVerErrors.map(" "+_).mkString("\n") } - val dependencies = moduleVersions.map { - case (module, version) => - Dependency(module, version, configuration = "default(compile)") - } - val (forceVersionErrors, forceVersions0) = Parse.moduleVersions(forceVersion) @@ -138,6 +133,38 @@ class Helper( grouped.map { case (mod, versions) => mod -> versions.last } } + val (excludeErrors, excludes0) = Parse.modules(exclude) + + prematureExitIf(excludeErrors.nonEmpty) { + s"Cannot parse excluded modules:\n" + + excludeErrors + .map(" " + _) + .mkString("\n") + } + + val (excludesNoAttr, excludesWithAttr) = excludes0.partition(_.attributes.isEmpty) + + prematureExitIf(excludesWithAttr.nonEmpty) { + s"Excluded modules with attributes not supported:\n" + + excludesWithAttr + .map(" " + _) + .mkString("\n") + } + + val excludes = excludesNoAttr.map { mod => + (mod.organization, mod.name) + }.toSet + + val dependencies = moduleVersions.map { + case (module, version) => + Dependency( + module, + version, + configuration = "default(compile)", + exclusions = excludes + ) + } + val startRes = Resolution( dependencies.toSet, forceVersions = forceVersions, diff --git a/core/shared/src/main/scala/coursier/util/Parse.scala b/core/shared/src/main/scala/coursier/util/Parse.scala index 07ec95fc5..0f0c03b76 100644 --- a/core/shared/src/main/scala/coursier/util/Parse.scala +++ b/core/shared/src/main/scala/coursier/util/Parse.scala @@ -8,6 +8,58 @@ import scala.collection.mutable.ArrayBuffer object Parse { + /** + * Parses a module like + * org:name + * possibly with attributes, like + * org:name;attr1=val1;attr2=val2 + */ + def module(s: String): Either[String, Module] = { + + val parts = s.split(":", 2) + + parts match { + case Array(org, rawName) => + val splitName = rawName.split(';') + + if (splitName.tail.exists(!_.contains("="))) + Left(s"malformed attribute(s) in $s") + else { + val name = splitName.head + val attributes = splitName.tail.map(_.split("=", 2)).map { + case Array(key, value) => key -> value + }.toMap + + Right(Module(org, name, attributes)) + } + + case _ => + Left(s"malformed module: $s") + } + } + + private def valuesAndErrors[L, R](f: String => Either[L, R], l: Seq[String]): (Seq[L], Seq[R]) = { + + val errors = new ArrayBuffer[L] + val values = new ArrayBuffer[R] + + for (elem <- l) + f(elem) match { + case Left(err) => errors += err + case Right(modVer) => values += modVer + } + + (errors.toSeq, values.toSeq) + } + + /** + * Parses a sequence of coordinates. + * + * @return Sequence of errors, and sequence of modules/versions + */ + def modules(l: Seq[String]): (Seq[String], Seq[Module]) = + valuesAndErrors(module, l) + /** * Parses coordinates like * org:name:version @@ -20,18 +72,9 @@ object Parse { parts match { case Array(org, rawName, version) => - val splitName = rawName.split(';') - - if (splitName.tail.exists(!_.contains("="))) - Left(s"Malformed attribute in $s") - else { - val name = splitName.head - val attributes = splitName.tail.map(_.split("=", 2)).map { - case Array(key, value) => key -> value - }.toMap - - Right((Module(org, name, attributes), version)) - } + module(s"$org:$rawName") + .right + .map((_, version)) case _ => Left(s"Malformed coordinates: $s") @@ -43,19 +86,8 @@ object Parse { * * @return Sequence of errors, and sequence of modules/versions */ - def moduleVersions(l: Seq[String]): (Seq[String], Seq[(Module, String)]) = { - - val errors = new ArrayBuffer[String] - val moduleVersions = new ArrayBuffer[(Module, String)] - - for (elem <- l) - moduleVersion(elem) match { - case Left(err) => errors += err - case Right(modVer) => moduleVersions += modVer - } - - (errors.toSeq, moduleVersions.toSeq) - } + def moduleVersions(l: Seq[String]): (Seq[String], Seq[(Module, String)]) = + valuesAndErrors(moduleVersion, l) def repository(s: String): Repository = if (s == "central")