Merge pull request #26 from alexarchambault/develop

Develop
This commit is contained in:
Alexandre Archambault 2015-06-18 01:00:33 +02:00
commit 92e60d2b26
10 changed files with 183 additions and 46 deletions

View File

@ -91,9 +91,22 @@ case class Coursier(scope: List[String],
def repr(dep: Dependency) =
s"${dep.module.organization}:${dep.module.name}:${dep.`type`}:${Some(dep.classifier).filter(_.nonEmpty).map(_+":").mkString}${dep.module.version}"
val trDeps = res.dependencies.toList.map(repr).sorted
val trDeps = res.dependencies.toList.sortBy(repr)
println("\n" + trDeps.mkString("\n"))
println("\n" + trDeps.map(repr).mkString("\n"))
if (res.conflicts.nonEmpty) {
// Needs test
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))
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")}")
}
}
if (fetch) {
println()

View File

@ -91,7 +91,7 @@ case class Remote(base: String, logger: Option[Logger] = None) extends Repositor
for {
xml <- \/.fromEither(eitherXml)
_ = logger.foreach(_.other(url, "is XML"))
_ <- if (xml.label == "project") \/-(()) else -\/("Project definition not found")
_ <- if (xml.label == "project") \/-(()) else -\/(s"Project definition not found (got '${xml.label}')")
_ = logger.foreach(_.other(url, "project definition found"))
proj <- Xml.project(xml)
_ = logger.foreach(_.other(url, "project definition ok"))

View File

@ -30,6 +30,20 @@ package object compatibility {
js.Dynamic.newInstance(defn)()
}
lazy val XMLSerializer = {
import js.Dynamic.{global => g}
import js.DynamicImplicits._
val defn =
if (js.isUndefined(g.XMLSerializer)) g.require("xmldom").XMLSerializer
else g.XMLSerializer
js.Dynamic.newInstance(defn)()
}
// Can't find these from node
val ELEMENT_NODE = 1 // org.scalajs.dom.raw.Node.ELEMENT_NODE
val TEXT_NODE = 3 // org.scalajs.dom.raw.Node.TEXT_NODE
def fromNode(node: org.scalajs.dom.raw.Node): Xml.Node = {
val node0 = node.asInstanceOf[js.Dynamic]
@ -43,15 +57,19 @@ package object compatibility {
.map(l => List.tabulate(l.length)(l.item).map(fromNode))
.getOrElse(Nil)
// `exists` instead of `contains`, for scala 2.10
def isText =
option[Int](node0.nodeType)
.exists(_ == 3) //org.scalajs.dom.raw.Node.TEXT_NODE
.exists(_ == TEXT_NODE)
def textContent =
option(node0.textContent)
.getOrElse("")
def isElement =
option[Int](node0.nodeType)
.exists(_ == 1) // org.scalajs.dom.raw.Node.ELEMENT_NODE
.exists(_ == ELEMENT_NODE)
override def toString =
XMLSerializer.serializeToString(node).asInstanceOf[String]
}
}
@ -59,10 +77,18 @@ package object compatibility {
def xmlParse(s: String): Either[String, Xml.Node] = {
val doc = {
if (s.isEmpty) None
else
dynOption(DOMParser.parseFromString(s, "text/xml"))
.flatMap(t => dynOption(t.childNodes))
.flatMap(l => l.asInstanceOf[js.Array[js.Dynamic]].headOption.flatMap(option[org.scalajs.dom.raw.Node]))
else {
for {
xmlDoc <- dynOption(DOMParser.parseFromString(s, "text/xml"))
rootNodes <- dynOption(xmlDoc.childNodes)
// From node, rootNodes.head is sometimes just a comment instead of the main root node
// (tested with org.ow2.asm:asm-commons in CentralTests)
rootNode <- rootNodes.asInstanceOf[js.Array[js.Dynamic]]
.flatMap(option[org.scalajs.dom.raw.Node])
.dropWhile(_.nodeType != ELEMENT_NODE)
.headOption
} yield rootNode
}
}
Right(doc.fold(Xml.Node.empty)(fromNode))

View File

@ -17,10 +17,7 @@ package object compatibility {
def label = node.label
def child = node.child.map(fromNode)
def isText = node match { case _: scala.xml.Text => true; case _ => false }
def textContent = node match {
case t: scala.xml.Text => t.data
case _ => throw new NoSuchElementException("text of non text node")
}
def textContent = node.text
def isElement = node match { case _: scala.xml.Elem => true; case _ => false }
}

View File

@ -350,21 +350,22 @@ object Resolver {
// Here, we're substituting properties also in dependencies that come from parents
// or dependency management. This may not be the right thing to do.
val properties = mergeProperties(
project.properties,
Map(
"project.groupId" -> project.module.organization,
"project.artifactId" -> project.module.name,
"project.version" -> project.module.version
)
)
val deps =
withExclusions(
withProperties(
depsWithDependencyManagement(
project.dependencies,
project.dependencyManagement
),
mergeProperties(
project.properties,
Map(
"project.groupId" -> project.module.organization,
"project.artifactId" -> project.module.name,
"project.version" -> project.module.version
)
)
depsWithDependencyManagement(
// important: properties have to be applied to both, so that dep mgmt can be matched properly
// See the added test with org.ow2.asm:asm-commons:5.0.2
withProperties(project.dependencies, properties),
withProperties(project.dependencyManagement, properties)
),
from.exclusions
)

View File

@ -41,12 +41,10 @@ object Xml {
.toRightDisjunction(s"$description not found")
}
private def property(elem: Node): String \/ (String, String) = {
elem.child match {
case Seq() => \/-(elem.label -> "")
case Seq(Text(t)) => \/-(elem.label -> t)
case _ => -\/(s"Can't parse property $elem")
}
def property(elem: Node): String \/ (String, String) = {
// Not matching with Text, which fails on scala-js if the property value has xml comments
if (elem.isElement) \/-(elem.label -> elem.textContent)
else -\/(s"Can't parse property $elem")
}
// TODO Allow no version in some contexts

View File

@ -21,8 +21,7 @@ object CentralTests extends TestSuite {
.runF)
val res = res0.copy(
projectsCache = Map.empty, errors = Map.empty, // No validating these here
dependencies = res0.dependencies.filter(dep => dep.scope == Scope.Compile && !dep.optional)
projectsCache = Map.empty, errors = Map.empty // No validating these here
)
val expected = Resolution(
@ -34,6 +33,29 @@ object CentralTests extends TestSuite {
)
)
assert(res == expected)
}
}
'asm{
async {
val dep = Dependency(Module("org.ow2.asm", "asm-commons", "5.0.2"))
val res0 =
await(resolve(Set(dep), fetchFrom(repositories))
.runF)
val res = res0.copy(
projectsCache = Map.empty, errors = Map.empty // No validating these here
)
val expected = Resolution(
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
)
)
assert(res == expected)
}
}

View File

@ -138,6 +138,62 @@ object PomParsingTests extends TestSuite {
assert(result == expected)
}
'beFineWithCommentsInProperties{
import scalaz._, Scalaz._
val properties =
"""
| <properties>
| <maven.compile.source>1.6</maven.compile.source>
| <maven.compile.target>1.6</maven.compile.target>
| <commons.componentid>io</commons.componentid>
| <commons.rc.version>RC1</commons.rc.version>
| <commons.release.version>2.4</commons.release.version>
| <commons.release.desc>(requires JDK 1.6+)</commons.release.desc>
| <commons.release.2.version>2.2</commons.release.2.version>
| <commons.release.2.desc>(requires JDK 1.5+)</commons.release.2.desc>
| <commons.jira.id>IO</commons.jira.id>
| <commons.jira.pid>12310477</commons.jira.pid>
| <commons.osgi.export>
| <!-- Explicit list of packages from IO 1.4 -->
| org.apache.commons.io;
| org.apache.commons.io.comparator;
| org.apache.commons.io.filefilter;
| org.apache.commons.io.input;
| org.apache.commons.io.output;version=1.4.9999;-noimport:=true,
| <!-- Same list plus * for new packages -->
| org.apache.commons.io;
| org.apache.commons.io.comparator;
| org.apache.commons.io.filefilter;
| org.apache.commons.io.input;
| org.apache.commons.io.output;
| org.apache.commons.io.*;version=${project.version};-noimport:=true
| </commons.osgi.export>
| </properties>
|
""".stripMargin
val parsed = core.compatibility.xmlParse(properties)
assert(parsed.isRight)
val node = parsed.right.get
assert(node.label == "properties")
val children = node.child.collect{case elem if elem.isElement => elem}
val props0 = children.toList.traverseU(Xml.property)
assert(props0.isRight)
val props = props0.getOrElse(???).toMap
assert(props.contains("commons.release.2.desc"))
assert(props.contains("commons.osgi.export"))
assert(props("commons.rc.version") == "RC1")
assert(props("commons.release.2.desc") == "(requires JDK 1.5+)")
assert(props("commons.osgi.export").contains("org.apache.commons.io.filefilter;"))
assert(props("commons.osgi.export").contains("org.apache.commons.io.input;"))
}
}
}

View File

@ -27,6 +27,10 @@
.customButton {
margin: 5px;
}
.popover {
max-width: 400px;
}
</style>
</head>

View File

@ -175,6 +175,10 @@ class Backend($: BackendScope[Unit, State]) {
}
}
def enablePopover(e: ReactEventI) = {
g.$("[data-toggle='popover']").popover()
}
object options {
def toggleOptional(e: ReactEventI) = {
$.modState(s => s.copy(options = s.options.copy(followOptional = !s.options.followOptional)))
@ -189,8 +193,22 @@ object App {
lazy val arbor = g.arbor
val resultDependencies = ReactComponentB[Resolution]("Result")
.render{ res =>
val resultDependencies = ReactComponentB[(Resolution, Backend)]("Result")
.render{ T =>
val (res, backend) = T
def infoLabel(label: String) =
<.span(^.`class` := "label label-info", label)
def errorLabel(label: String, desc: String) =
<.button(^.`type` := "button", ^.`class` := "btn btn-xs btn-danger",
Attr("data-trigger") := "focus",
Attr("data-toggle") := "popover", Attr("data-placement") := "bottom",
Attr("data-content") := desc,
^.onClick ==> backend.enablePopover,
^.onMouseOver ==> backend.enablePopover,
label
)
def depItem(dep: Dependency) =
<.tr(
^.`class` := (if (res.errors.contains(dep.module)) "danger" else ""),
@ -198,10 +216,11 @@ object App {
<.td(dep.module.name),
<.td(dep.module.version),
<.td(Seq[Seq[TagMod]](
if (dep.scope == Scope.Compile) Seq() else Seq(<.span(^.`class` := "label label-info", dep.scope.name)),
if (dep.`type`.isEmpty || dep.`type` == "jar") Seq() else Seq(<.span(^.`class` := "label label-info", dep.`type`)),
if (dep.classifier.isEmpty) Seq() else Seq(<.span(^.`class` := "label label-info", dep.classifier)),
if (dep.optional) Seq(<.span(^.`class` := "label label-info", dep.classifier)) else Seq()
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
)),
<.td(Seq[Seq[TagMod]](
res.projectsCache.get(dep.module) match {
@ -244,7 +263,6 @@ object App {
<.tbody(
sortedDeps.map(depItem)
)
// <.div(dangerouslySetInnerHtml("<script>$(function () { $('[data-toggle=\"popover\"]').popover() })</script>"))
)
}
.build
@ -406,21 +424,23 @@ object App {
}
.build
val resolution = ReactComponentB[Option[Resolution]]("Resolution")
.render(resOpt =>
val resolution = ReactComponentB[(Option[Resolution], Backend)]("Resolution")
.render{ T =>
val (resOpt, backend) = T
resOpt match {
case Some(res) =>
<.div(
<.div(^.`class` := "page-header",
<.h1("Resolution")
),
resultDependencies(res)
resultDependencies((res, backend))
)
case None =>
<.div()
}
)
}
.build
val initialState = State(Nil, Seq(coursier.repository.mavenCentral), ResolutionOptions(), None, -1, resolving = false, reverseTree = false, log = Nil)
@ -494,7 +514,7 @@ object App {
),
<.div(^.`class` := "tab-content",
<.div(^.role := "tabpanel", ^.`class` := "tab-pane", ^.id := "resolution",
resolution(S.resolutionOpt)
resolution((S.resolutionOpt, B))
),
<.div(^.role := "tabpanel", ^.`class` := "tab-pane", ^.id := "log",
<.button(^.`type` := "button", ^.`class` := "btn btn-default",