mirror of https://github.com/sbt/sbt.git
Some visual improvements
+ Display nodes as groupId:artifact:version + Provide tasks for printing ascii representations of the dependency graphs for the various configurations: compile, test, runtime, optional, provided
This commit is contained in:
parent
70462d7a62
commit
f69915cb8c
|
|
@ -4,7 +4,7 @@ name := "sbt-dependency-graph"
|
|||
|
||||
organization := "net.virtual-void"
|
||||
|
||||
version := "0.5.2"
|
||||
version := "0.5.3-SNAPSHOT"
|
||||
|
||||
homepage := Some(url("http://github.com/jrudolph/sbt-dependency-graph"))
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
sbt.version=0.12.0-Beta2
|
||||
52
src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala
Normal file → Executable file
52
src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala
Normal file → Executable file
|
|
@ -18,24 +18,54 @@ package net.virtualvoid.sbt.graph
|
|||
|
||||
import xml.parsing.ConstructingParser
|
||||
import java.io.File
|
||||
import xml.{XML, Node}
|
||||
import collection.mutable.HashMap
|
||||
import collection.mutable.MultiMap
|
||||
import collection.mutable.{Set => MSet}
|
||||
import sbt.Graph
|
||||
import xml.{Document, XML, Node}
|
||||
|
||||
object IvyGraphMLDependencies extends App {
|
||||
case class Module(organisation: String, name: String, version: String) {
|
||||
def id: String = organisation+"."+name+"-"+version
|
||||
def id: String = organisation+":"+name+":"+version
|
||||
}
|
||||
def transform(ivyReportFile: String, outputFile: String) {
|
||||
val doc = ConstructingParser.fromSource(io.Source.fromFile(ivyReportFile), false).document
|
||||
|
||||
case class ModuleGraph(nodes: Seq[Module], edges: Seq[(Module, Module)])
|
||||
|
||||
def buildGraph(doc: Document): ModuleGraph = {
|
||||
val edges = for {
|
||||
mod <- doc \ "dependencies" \ "module"
|
||||
caller <- mod \ "revision" \ "caller"
|
||||
callerModule = nodeFromElement(caller, caller.attribute("callerrev").get.text)
|
||||
depModule = nodeFromElement(mod, caller.attribute("rev").get.text)
|
||||
} yield (callerModule, depModule)
|
||||
mod <- doc \ "dependencies" \ "module"
|
||||
caller <- mod \ "revision" \ "caller"
|
||||
callerModule = nodeFromElement(caller, caller.attribute("callerrev").get.text)
|
||||
depModule = nodeFromElement(mod, caller.attribute("rev").get.text)
|
||||
} yield (callerModule, depModule)
|
||||
|
||||
val nodes = edges.flatMap(e => Seq(e._1, e._2)).distinct
|
||||
|
||||
ModuleGraph(nodes, edges)
|
||||
}
|
||||
|
||||
|
||||
def ascii(ivyReportFile: String): String = {
|
||||
val doc = buildDoc(ivyReportFile)
|
||||
val graph = buildGraph(doc)
|
||||
import graph._
|
||||
val deps = {
|
||||
val m = new HashMap[Module, MSet[Module]] with MultiMap[Module, Module]
|
||||
edges.foreach { case (from, to) => m.addBinding(from, to) }
|
||||
m.toMap.mapValues(_.toSeq.sortBy(_.id))
|
||||
}
|
||||
// there should only be one root node (the project itself)
|
||||
val roots = nodes.filter(n => !edges.exists(_._2 == n)).sortBy(_.id)
|
||||
roots.map(root =>
|
||||
Graph.toAscii[Module](root, node => deps.getOrElse(node, Seq.empty[Module]), _.id)
|
||||
).mkString("\n")
|
||||
}
|
||||
|
||||
def transform(ivyReportFile: String, outputFile: String) {
|
||||
val doc = buildDoc(ivyReportFile)
|
||||
val graph = buildGraph(doc)
|
||||
import graph._
|
||||
|
||||
val nodesXml =
|
||||
for (n <- nodes)
|
||||
yield
|
||||
|
|
@ -63,9 +93,11 @@ object IvyGraphMLDependencies extends App {
|
|||
|
||||
XML.save(outputFile, xml)
|
||||
}
|
||||
def nodeFromElement(element: Node, version: String): Module =
|
||||
private def nodeFromElement(element: Node, version: String): Module =
|
||||
Module(element.attribute("organisation").get.text, element.attribute("name").get.text, version)
|
||||
|
||||
private def buildDoc(ivyReportFile: String) = ConstructingParser.fromSource(io.Source.fromFile(ivyReportFile), false).document
|
||||
|
||||
def die(msg: String): Nothing = {
|
||||
println(msg)
|
||||
sys.exit(1)
|
||||
|
|
|
|||
|
|
@ -22,6 +22,10 @@ import Keys._
|
|||
object Plugin extends sbt.Plugin {
|
||||
val dependencyGraphTask = TaskKey[File]("dependency-graph",
|
||||
"Creates a graphml file containing the dependency-graph for a project")
|
||||
val asciiGraph = TaskKey[String]("ascii-graph",
|
||||
"Returns a string containing the ascii representation of the dependency graph for a project")
|
||||
val printAsciiGraph = TaskKey[Unit]("print-ascii-graph",
|
||||
"Prints the ascii graph to the console")
|
||||
val ivyReportF = SettingKey[String => File]("ivy-report-function",
|
||||
"A function which returns the file containing the ivy report from the ivy cache for a given configuration")
|
||||
val ivyReport = InputKey[File]("ivy-report",
|
||||
|
|
@ -40,6 +44,19 @@ object Plugin extends sbt.Plugin {
|
|||
report(args(0))
|
||||
}
|
||||
},
|
||||
|
||||
asciiGraph in Compile <<= asciiGraphTask(Compile),
|
||||
asciiGraph in Test <<= asciiGraphTask(Test),
|
||||
asciiGraph in Runtime <<= asciiGraphTask(Runtime),
|
||||
asciiGraph in Provided <<= asciiGraphTask(Provided),
|
||||
asciiGraph in Optional <<= asciiGraphTask(Optional),
|
||||
|
||||
printAsciiGraph in Compile <<= printAsciiGraphTask(Compile),
|
||||
printAsciiGraph in Test <<= printAsciiGraphTask(Test),
|
||||
printAsciiGraph in Runtime <<= printAsciiGraphTask(Runtime),
|
||||
printAsciiGraph in Provided <<= printAsciiGraphTask(Provided),
|
||||
printAsciiGraph in Optional <<= printAsciiGraphTask(Optional),
|
||||
|
||||
dependencyGraphTask <<= (ivyReportF, target, streams) map { (report, target, streams) =>
|
||||
val resultFile = target / "dependencies.graphml"
|
||||
IvyGraphMLDependencies.transform(report("compile").getAbsolutePath, resultFile.getAbsolutePath)
|
||||
|
|
@ -48,11 +65,19 @@ object Plugin extends sbt.Plugin {
|
|||
} dependsOn(deliverLocal)
|
||||
)
|
||||
|
||||
def asciiGraphTask(conf: Configuration) = (ivyReportF in conf) map { (report) =>
|
||||
IvyGraphMLDependencies.ascii(report(conf.name).getAbsolutePath)
|
||||
} dependsOn(deliverLocal)
|
||||
|
||||
def printAsciiGraphTask(conf: Configuration) = (asciiGraph in conf, streams in conf) map { (graph, streams) =>
|
||||
streams.log.info(graph)
|
||||
}
|
||||
|
||||
def crossName(moduleId: ModuleID, scalaVersion: String) =
|
||||
moduleId.name + (
|
||||
if (moduleId.crossVersion)
|
||||
"_"+scalaVersion
|
||||
else
|
||||
""
|
||||
moduleId.crossVersion match {
|
||||
case CrossVersion.Disabled => ""
|
||||
case _ => "_"+scalaVersion
|
||||
}
|
||||
)
|
||||
}
|
||||
Loading…
Reference in New Issue