Add support for attributes

This commit is contained in:
Alexandre Archambault 2015-12-30 01:34:37 +01:00
parent a3188a9b8a
commit f52e2ecca4
10 changed files with 69 additions and 29 deletions

View File

@ -158,8 +158,22 @@ class Helper(
} }
val moduleVersions = splitDependencies.map{ val moduleVersions = splitDependencies.map{
case Seq(org, name, version) => case Seq(org, namePart, version) =>
(Module(org, name), version) val p = namePart.split(';')
val name = p.head
val splitAttributes = p.tail.map(_.split("=", 2).toSeq).toSeq
val malformedAttributes = splitAttributes.filter(_.length != 2)
if (malformedAttributes.nonEmpty) {
// FIXME Get these for all dependencies at once
Console.err.println(s"Malformed attributes in ${splitDependencies.mkString(":")}")
// :(
sys.exit(255)
}
val attributes = splitAttributes.collect {
case Seq(k, v) => k -> v
}
println(s"-> $org:$name:$attributes")
(Module(org, name, attributes.toMap), version)
} }
val deps = moduleVersions.map{case (mod, ver) => val deps = moduleVersions.map{case (mod, ver) =>

View File

@ -51,7 +51,7 @@ package object compatibility {
.map(l => List.tabulate(l.length)(l.item).map(fromNode)) .map(l => List.tabulate(l.length)(l.item).map(fromNode))
.getOrElse(Nil) .getOrElse(Nil)
def attributes: Seq[(String, String)] = ??? def attributes = ???
// `exists` instead of `contains`, for scala 2.10 // `exists` instead of `contains`, for scala 2.10
def isText = def isText =

View File

@ -2,7 +2,7 @@ package coursier.core
import coursier.util.Xml import coursier.util.Xml
import scala.xml.{ MetaData, Null } import scala.xml.{ Attribute, MetaData, Null }
package object compatibility { package object compatibility {
@ -19,14 +19,20 @@ package object compatibility {
def fromNode(node: scala.xml.Node): Xml.Node = def fromNode(node: scala.xml.Node): Xml.Node =
new Xml.Node { new Xml.Node {
lazy val attributes = { lazy val attributes = {
def helper(m: MetaData): Stream[(String, String)] = def helper(m: MetaData): Stream[(String, String, String)] =
m match { m match {
case Null => Stream.empty case Null => Stream.empty
case attr => case attr =>
val pre = attr match {
case a: Attribute => Option(node.getNamespace(a.pre)).getOrElse("")
case _ => ""
}
val value = attr.value.collect { val value = attr.value.collect {
case scala.xml.Text(t) => t case scala.xml.Text(t) => t
}.mkString("") }.mkString("")
(attr.key -> value) #:: helper(m.next)
(pre, attr.key, value) #:: helper(m.next)
} }
helper(node.attributes).toVector helper(node.attributes).toVector

View File

@ -8,12 +8,11 @@ package coursier.core
* between them. * between them.
* *
* Using the same terminology as Ivy. * Using the same terminology as Ivy.
*
* Ivy attributes would land here, if support for it is added.
*/ */
case class Module( case class Module(
organization: String, organization: String,
name: String name: String,
attributes: Map[String, String]
) { ) {
def trim: Module = copy( def trim: Module = copy(
@ -21,7 +20,14 @@ case class Module(
name = name.trim name = name.trim
) )
override def toString = s"$organization:$name" private def attributesStr = attributes.toSeq
.sortBy { case (k, _) => k }
.map { case (k, v) => s"$k=$v" }
.mkString(";")
override def toString =
s"$organization:$name" +
(if (attributes.nonEmpty) s";$attributesStr" else "")
} }
/** /**

View File

@ -145,23 +145,22 @@ case class IvyRepository(
// list of variables that should be supported. // list of variables that should be supported.
// Some are missing (branch, conf, originalName). // Some are missing (branch, conf, originalName).
private def variables( private def variables(
org: String, module: Module,
name: String,
version: String, version: String,
`type`: String, `type`: String,
artifact: String, artifact: String,
ext: String ext: String
) = ) =
Map( Map(
"organization" -> org, "organization" -> module.organization,
"organisation" -> org, "organisation" -> module.organization,
"orgPath" -> org.replace('.', '/'), "orgPath" -> module.organization.replace('.', '/'),
"module" -> name, "module" -> module.name,
"revision" -> version, "revision" -> version,
"type" -> `type`, "type" -> `type`,
"artifact" -> artifact, "artifact" -> artifact,
"ext" -> ext "ext" -> ext
) ) ++ module.attributes
val source: Artifact.Source = new Artifact.Source { val source: Artifact.Source = new Artifact.Source {
@ -191,8 +190,7 @@ case class IvyRepository(
val retainedWithUrl = retained.flatMap { p => val retainedWithUrl = retained.flatMap { p =>
substitute(variables( substitute(variables(
dependency.module.organization, dependency.module,
dependency.module.name,
dependency.version, dependency.version,
p.`type`, p.`type`,
p.name, p.name,
@ -225,7 +223,9 @@ case class IvyRepository(
val eitherArtifact: String \/ Artifact = val eitherArtifact: String \/ Artifact =
for { for {
url <- substitute(variables(module.organization, module.name, version, "ivy", "ivy", "xml")) url <- substitute(
variables(module, version, "ivy", "ivy", "xml")
)
} yield } yield
Artifact( Artifact(
url, url,

View File

@ -7,12 +7,15 @@ import scalaz.{ Node => _, _ }, Scalaz._
object IvyXml { object IvyXml {
val attributesNamespace = "http://ant.apache.org/ivy/extra"
private def info(node: Node): String \/ (Module, String) = private def info(node: Node): String \/ (Module, String) =
for { for {
org <- node.attribute("organisation") org <- node.attribute("organisation")
name <- node.attribute("module") name <- node.attribute("module")
version <- node.attribute("revision") version <- node.attribute("revision")
} yield (Module(org, name), version) attr = node.attributesFromNamespace(attributesNamespace)
} yield (Module(org, name, attr.toMap), version)
// FIXME Errors are ignored here // FIXME Errors are ignored here
private def configurations(node: Node): Seq[(String, Seq[String])] = private def configurations(node: Node): Seq[(String, Seq[String])] =
@ -53,8 +56,9 @@ object IvyXml {
(fromConf, toConf) <- rawConf.split(',').toSeq.map(_.split("->", 2)).collect { (fromConf, toConf) <- rawConf.split(',').toSeq.map(_.split("->", 2)).collect {
case Array(from, to) => from -> to case Array(from, to) => from -> to
} }
attr = node.attributesFromNamespace(attributesNamespace)
} yield fromConf -> Dependency( } yield fromConf -> Dependency(
Module(org, name), Module(org, name, attr.toMap),
version, version,
toConf, toConf,
allConfsExcludes ++ excludes.getOrElse(fromConf, Set.empty), allConfsExcludes ++ excludes.getOrElse(fromConf, Set.empty),

View File

@ -22,7 +22,7 @@ object Pom {
else e else e
} }
name <- text(node, "artifactId", "Name") name <- text(node, "artifactId", "Name")
} yield Module(organization, name).trim } yield Module(organization, name, Map.empty).trim
} }
private def readVersion(node: Node) = private def readVersion(node: Node) =
@ -307,7 +307,7 @@ object Pom {
.toList .toList
.traverseU(snapshotVersion) .traverseU(snapshotVersion)
} yield SnapshotVersioning( } yield SnapshotVersioning(
Module(organization, name), Module(organization, name, Map.empty),
version, version,
latest, latest,
release, release,

View File

@ -42,8 +42,8 @@ package object coursier {
type Module = core.Module type Module = core.Module
object Module { object Module {
def apply(organization: String, name: String): Module = def apply(organization: String, name: String, attributes: Map[String, String] = Map.empty): Module =
core.Module(organization, name) core.Module(organization, name, attributes)
} }
type ModuleVersion = (core.Module, String) type ModuleVersion = (core.Module, String)

View File

@ -7,13 +7,20 @@ object Xml {
/** A representation of an XML node/document, with different implementations on JVM and JS */ /** A representation of an XML node/document, with different implementations on JVM and JS */
trait Node { trait Node {
def label: String def label: String
def attributes: Seq[(String, String)] /** Namespace / key / value */
def attributes: Seq[(String, String, String)]
def children: Seq[Node] def children: Seq[Node]
def isText: Boolean def isText: Boolean
def textContent: String def textContent: String
def isElement: Boolean def isElement: Boolean
lazy val attributesMap = attributes.toMap def attributesFromNamespace(namespace: String): Seq[(String, String)] =
attributes.collect {
case (`namespace`, k, v) =>
k -> v
}
lazy val attributesMap = attributes.map { case (_, k, v) => k -> v }.toMap
def attribute(name: String): String \/ String = def attribute(name: String): String \/ String =
attributesMap.get(name) match { attributesMap.get(name) match {
case None => -\/(s"Missing attribute $name") case None => -\/(s"Missing attribute $name")

View File

@ -406,7 +406,10 @@ object App {
} }
val sortedDeps = res.minDependencies.toList val sortedDeps = res.minDependencies.toList
.sortBy(dep => coursier.core.Module.unapply(dep.module).get) .sortBy { dep =>
val (org, name, _) = coursier.core.Module.unapply(dep.module).get
(org, name)
}
<.table(^.`class` := "table", <.table(^.`class` := "table",
<.thead( <.thead(