mirror of https://github.com/sbt/sbt.git
enable Scalariform auto-formatting
This commit is contained in:
parent
0c3cf98a89
commit
0c4bc73a64
|
|
@ -24,3 +24,5 @@ sbt.CrossBuilding.latestCompatibleVersionMapper ~= {
|
|||
case x => original(x)
|
||||
}
|
||||
}
|
||||
|
||||
ScalariformSupport.formatSettings
|
||||
|
|
@ -25,7 +25,7 @@ trait DependencyGraphKeys {
|
|||
"Creates a graphml file containing the dependency-graph for a project")
|
||||
val dependencyDotFile = SettingKey[File]("dependency-dot-file",
|
||||
"The location the dot file should be generated at")
|
||||
val dependencyDotNodeLabel = SettingKey[(String,String,String) => String]("dependency-dot-node-label",
|
||||
val dependencyDotNodeLabel = SettingKey[(String, String, String) ⇒ String]("dependency-dot-node-label",
|
||||
"Returns a formated string of a dependency. Takes organisation, name and version as parameters")
|
||||
val dependencyDotHeader = SettingKey[String]("dependency-dot-header",
|
||||
"The header of the dot file. (e.g. to set your preferred node shapes)")
|
||||
|
|
@ -41,14 +41,13 @@ trait DependencyGraphKeys {
|
|||
"Returns a string containing an ascii tree representation of the dependency graph for a project")
|
||||
val dependencyTree = TaskKey[Unit]("dependency-tree",
|
||||
"Prints the ascii tree to the console")
|
||||
val ivyReportFunction = TaskKey[String => File]("ivy-report-function",
|
||||
val ivyReportFunction = TaskKey[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 = TaskKey[File]("ivy-report",
|
||||
"A task which returns the location of the ivy report file for a given configuration (default `compile`).")
|
||||
val ignoreMissingUpdate = Keys.update in ivyReport
|
||||
val filterScalaLibrary = SettingKey[Boolean]("filter-scala-library",
|
||||
"Specifies if scala dependency should be filtered in dependency-* output"
|
||||
)
|
||||
"Specifies if scala dependency should be filtered in dependency-* output")
|
||||
|
||||
val licenseInfo = TaskKey[Unit]("dependency-license-info",
|
||||
"Aggregates and shows information about the licenses of dependencies")
|
||||
|
|
|
|||
|
|
@ -31,29 +31,28 @@ object DependencyGraphSettings {
|
|||
import ModuleGraphProtocol._
|
||||
|
||||
def graphSettings = Seq(
|
||||
ivyReportFunction <<= (sbtVersion, target, projectID, ivyModule, appConfiguration, streams) map { (sbtV, target, projectID, ivyModule, config, streams) =>
|
||||
ivyReportFunction <<= (sbtVersion, target, projectID, ivyModule, appConfiguration, streams) map { (sbtV, target, projectID, ivyModule, config, streams) ⇒
|
||||
sbtV match {
|
||||
case Version(0, min, fix, _) if min > 12 || (min == 12 && fix >= 3) =>
|
||||
(c: String) => file("%s/resolution-cache/reports/%s-%s-%s.xml".format(target, projectID.organization, crossName(ivyModule), c))
|
||||
case Version(0, min, fix, _) if min == 12 && fix >= 1 && fix < 3 =>
|
||||
ivyModule.withModule(streams.log) { (i, moduleDesc, _) =>
|
||||
case Version(0, min, fix, _) if min > 12 || (min == 12 && fix >= 3) ⇒
|
||||
(c: String) ⇒ file("%s/resolution-cache/reports/%s-%s-%s.xml".format(target, projectID.organization, crossName(ivyModule), c))
|
||||
case Version(0, min, fix, _) if min == 12 && fix >= 1 && fix < 3 ⇒
|
||||
ivyModule.withModule(streams.log) { (i, moduleDesc, _) ⇒
|
||||
val id = ResolveOptions.getDefaultResolveId(moduleDesc)
|
||||
(c: String) => file("%s/resolution-cache/reports/%s/%s-resolved.xml" format (target, id,c))
|
||||
(c: String) ⇒ file("%s/resolution-cache/reports/%s/%s-resolved.xml" format (target, id, c))
|
||||
}
|
||||
case _ =>
|
||||
case _ ⇒
|
||||
val home = config.provider.scalaProvider.launcher.ivyHome
|
||||
(c: String) => file("%s/cache/%s-%s-%s.xml" format (home, projectID.organization, crossName(ivyModule), c))
|
||||
(c: String) ⇒ file("%s/cache/%s-%s-%s.xml" format (home, projectID.organization, crossName(ivyModule), c))
|
||||
}
|
||||
},
|
||||
updateConfiguration in ignoreMissingUpdate <<= updateConfiguration(config => new UpdateConfiguration(config.retrieve, true, config.logging)),
|
||||
updateConfiguration in ignoreMissingUpdate <<= updateConfiguration(config ⇒ new UpdateConfiguration(config.retrieve, true, config.logging)),
|
||||
ignoreMissingUpdateT,
|
||||
filterScalaLibrary in Global := true
|
||||
) ++ Seq(Compile, Test, Runtime, Provided, Optional).flatMap(ivyReportForConfig)
|
||||
filterScalaLibrary in Global := true) ++ Seq(Compile, Test, Runtime, Provided, Optional).flatMap(ivyReportForConfig)
|
||||
|
||||
def ivyReportForConfig(config: Configuration) = inConfig(config)(Seq(
|
||||
ivyReport <<= ivyReportFunction map (_(config.toString)) dependsOn(ignoreMissingUpdate),
|
||||
ivyReport <<= ivyReportFunction map (_(config.toString)) dependsOn (ignoreMissingUpdate),
|
||||
moduleGraph <<= ivyReport map (absoluteReportPath.andThen(frontend.IvyReport.fromReportFile)),
|
||||
moduleGraph <<= (scalaVersion, moduleGraph, filterScalaLibrary) map { (scalaV, graph, filter) =>
|
||||
moduleGraph <<= (scalaVersion, moduleGraph, filterScalaLibrary) map { (scalaV, graph, filter) ⇒
|
||||
if (filter)
|
||||
GraphTransformations.ignoreScalaLibrary(scalaV, graph)
|
||||
else
|
||||
|
|
@ -61,8 +60,8 @@ object DependencyGraphSettings {
|
|||
},
|
||||
moduleGraphStore <<= moduleGraph storeAs moduleGraphStore triggeredBy moduleGraph,
|
||||
asciiGraph <<= moduleGraph map rendering.AsciiGraph.asciiGraph,
|
||||
dependencyGraph <<= InputTask(shouldForceParser) { force =>
|
||||
(force, moduleGraph, streams) map { (force, graph, streams) =>
|
||||
dependencyGraph <<= InputTask(shouldForceParser) { force ⇒
|
||||
(force, moduleGraph, streams) map { (force, graph, streams) ⇒
|
||||
if (force || graph.nodes.size < 15) {
|
||||
streams.log.info(rendering.AsciiGraph.asciiGraph(graph))
|
||||
streams.log.info("\n\n")
|
||||
|
|
@ -91,35 +90,34 @@ object DependencyGraphSettings {
|
|||
| edge [
|
||||
| arrowtail="none"
|
||||
| ]""".stripMargin,
|
||||
dependencyDotNodeLabel := { (organisation: String, name: String, version: String) =>
|
||||
dependencyDotNodeLabel := { (organisation: String, name: String, version: String) ⇒
|
||||
"""<%s<BR/><B>%s</B><BR/>%s>""".format(organisation, name, version)
|
||||
},
|
||||
whatDependsOn <<= InputTask(artifactIdParser) { module =>
|
||||
(module, streams, moduleGraph) map { (module, streams, graph) =>
|
||||
whatDependsOn <<= InputTask(artifactIdParser) { module ⇒
|
||||
(module, streams, moduleGraph) map { (module, streams, graph) ⇒
|
||||
streams.log.info(rendering.AsciiTree.asciiTree(GraphTransformations.reverseGraphStartingAt(graph, module)))
|
||||
}
|
||||
},
|
||||
licenseInfo <<= (moduleGraph, streams) map showLicenseInfo
|
||||
))
|
||||
licenseInfo <<= (moduleGraph, streams) map showLicenseInfo))
|
||||
|
||||
def printAsciiGraphTask =
|
||||
(streams, asciiGraph) map (_.log.info(_))
|
||||
|
||||
def dependencyGraphMLTask =
|
||||
(moduleGraph, dependencyGraphMLFile, streams) map { (graph, resultFile, streams) =>
|
||||
(moduleGraph, dependencyGraphMLFile, streams) map { (graph, resultFile, streams) ⇒
|
||||
rendering.GraphML.saveAsGraphML(graph, resultFile.getAbsolutePath)
|
||||
streams.log.info("Wrote dependency graph to '%s'" format resultFile)
|
||||
resultFile
|
||||
}
|
||||
def dependencyDotTask =
|
||||
(moduleGraph, dependencyDotHeader, dependencyDotNodeLabel, dependencyDotFile, streams).map {
|
||||
(graph, dotHead, nodeLabel, outFile, streams) =>
|
||||
(graph, dotHead, nodeLabel, outFile, streams) ⇒
|
||||
|
||||
val resultFile = rendering.DOT.saveAsDot(graph, dotHead, nodeLabel, outFile)
|
||||
streams.log.info("Wrote dependency graph to '%s'" format resultFile)
|
||||
resultFile
|
||||
}
|
||||
def absoluteReportPath = (file: File) => file.getAbsolutePath
|
||||
def absoluteReportPath = (file: File) ⇒ file.getAbsolutePath
|
||||
|
||||
def print(key: TaskKey[String]) =
|
||||
(streams, key) map (_.log.info(_))
|
||||
|
|
@ -127,38 +125,40 @@ object DependencyGraphSettings {
|
|||
def showLicenseInfo(graph: ModuleGraph, streams: TaskStreams) {
|
||||
val output =
|
||||
graph.nodes.filter(_.isUsed).groupBy(_.license).toSeq.sortBy(_._1).map {
|
||||
case (license, modules) =>
|
||||
license.getOrElse("No license specified")+"\n"+
|
||||
case (license, modules) ⇒
|
||||
license.getOrElse("No license specified") + "\n" +
|
||||
modules.map(_.id.idString formatted "\t %s").mkString("\n")
|
||||
}.mkString("\n\n")
|
||||
streams.log.info(output)
|
||||
}
|
||||
|
||||
import Project._
|
||||
val shouldForceParser: State => Parser[Boolean] = { (state: State) =>
|
||||
val shouldForceParser: State ⇒ Parser[Boolean] = { (state: State) ⇒
|
||||
import sbt.complete.DefaultParsers._
|
||||
|
||||
(Space ~> token("--force")).?.map(_.isDefined)
|
||||
}
|
||||
|
||||
val artifactIdParser: Initialize[State => Parser[ModuleId]] =
|
||||
resolvedScoped { ctx => (state: State) =>
|
||||
val graph = loadFromContext(moduleGraphStore, ctx, state) getOrElse ModuleGraph(Nil, Nil)
|
||||
val artifactIdParser: Initialize[State ⇒ Parser[ModuleId]] =
|
||||
resolvedScoped { ctx ⇒
|
||||
(state: State) ⇒
|
||||
val graph = loadFromContext(moduleGraphStore, ctx, state) getOrElse ModuleGraph(Nil, Nil)
|
||||
|
||||
import sbt.complete.DefaultParsers._
|
||||
def moduleFrom(modules: Seq[ModuleId]) =
|
||||
modules.map { m =>
|
||||
(token(m.name) ~ Space ~ token(m.version)).map(_ => m)
|
||||
}.reduce(_ | _)
|
||||
import sbt.complete.DefaultParsers._
|
||||
def moduleFrom(modules: Seq[ModuleId]) =
|
||||
modules.map { m ⇒
|
||||
(token(m.name) ~ Space ~ token(m.version)).map(_ ⇒ m)
|
||||
}.reduce(_ | _)
|
||||
|
||||
graph.nodes.map(_.id).groupBy(_.organisation).map {
|
||||
case (org, modules) =>
|
||||
Space ~ token(org) ~ Space ~> moduleFrom(modules)
|
||||
}.reduceOption(_ | _).getOrElse {
|
||||
(Space ~> token(StringBasic, "organization") ~ Space ~ token(StringBasic, "module") ~ Space ~ token(StringBasic, "version") ).map { case ((((org, _), mod), _), version) =>
|
||||
ModuleId(org, mod, version)
|
||||
graph.nodes.map(_.id).groupBy(_.organisation).map {
|
||||
case (org, modules) ⇒
|
||||
Space ~ token(org) ~ Space ~> moduleFrom(modules)
|
||||
}.reduceOption(_ | _).getOrElse {
|
||||
(Space ~> token(StringBasic, "organization") ~ Space ~ token(StringBasic, "module") ~ Space ~ token(StringBasic, "version")).map {
|
||||
case ((((org, _), mod), _), version) ⇒
|
||||
ModuleId(org, mod, version)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This is to support 0.13.8's InlineConfigurationWithExcludes while not forcing 0.13.8
|
||||
|
|
@ -167,17 +167,17 @@ object DependencyGraphSettings {
|
|||
}
|
||||
def crossName(ivyModule: IvySbt#Module) =
|
||||
ivyModule.moduleSettings match {
|
||||
case ic: InlineConfiguration => ic.module.name
|
||||
case hm: HasModule if hm.getClass.getName == "sbt.InlineConfigurationWithExcludes" => hm.module.name
|
||||
case _ =>
|
||||
case ic: InlineConfiguration ⇒ ic.module.name
|
||||
case hm: HasModule if hm.getClass.getName == "sbt.InlineConfigurationWithExcludes" ⇒ hm.module.name
|
||||
case _ ⇒
|
||||
throw new IllegalStateException("sbt-dependency-graph plugin currently only supports InlineConfiguration of ivy settings (the default in sbt)")
|
||||
}
|
||||
|
||||
val VersionPattern = """(\d+)\.(\d+)\.(\d+)(?:-(.*))?""".r
|
||||
object Version {
|
||||
def unapply(str: String): Option[(Int, Int, Int, Option[String])] = str match {
|
||||
case VersionPattern(major, minor, fix, appendix) => Some((major.toInt, minor.toInt, fix.toInt, Option(appendix)))
|
||||
case _ => None
|
||||
case VersionPattern(major, minor, fix, appendix) ⇒ Some((major.toInt, minor.toInt, fix.toInt, Option(appendix)))
|
||||
case _ ⇒ None
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -195,17 +195,17 @@ object DependencyGraphSettings {
|
|||
// Only substitute unmanaged jars for managed jars when the major.minor parts of the versions the same for:
|
||||
// the resolved Scala version and the scalaHome version: compatible (weakly- no qualifier checked)
|
||||
// the resolved Scala version and the declared scalaVersion: assume the user intended scalaHome to override anything with scalaVersion
|
||||
def subUnmanaged(subVersion: String, jars: Seq[File]) = (sv: String) =>
|
||||
def subUnmanaged(subVersion: String, jars: Seq[File]) = (sv: String) ⇒
|
||||
(partialVersion(sv), partialVersion(subVersion), partialVersion(scalaVersion.value)) match {
|
||||
case (Some(res), Some(sh), _) if res == sh => jars
|
||||
case (Some(res), _, Some(decl)) if res == decl => jars
|
||||
case _ => Nil
|
||||
case (Some(res), Some(sh), _) if res == sh ⇒ jars
|
||||
case (Some(res), _, Some(decl)) if res == decl ⇒ jars
|
||||
case _ ⇒ Nil
|
||||
}
|
||||
val subScalaJars: String => Seq[File] = SbtAccess.unmanagedScalaInstanceOnly.value match {
|
||||
case Some(si) => subUnmanaged(si.version, si.jars)
|
||||
case None => sv => if(scalaProvider.version == sv) scalaProvider.jars else Nil
|
||||
val subScalaJars: String ⇒ Seq[File] = SbtAccess.unmanagedScalaInstanceOnly.value match {
|
||||
case Some(si) ⇒ subUnmanaged(si.version, si.jars)
|
||||
case None ⇒ sv ⇒ if (scalaProvider.version == sv) scalaProvider.jars else Nil
|
||||
}
|
||||
val transform: UpdateReport => UpdateReport = r => Classpaths.substituteScalaFiles(scalaOrganization.value, r)(subScalaJars)
|
||||
val transform: UpdateReport ⇒ UpdateReport = r ⇒ Classpaths.substituteScalaFiles(scalaOrganization.value, r)(subScalaJars)
|
||||
|
||||
val show = Reference.display(thisProjectRef.value)
|
||||
Classpaths.cachedUpdate(s.cacheDirectory, show, ivyModule.value, (updateConfiguration in ignoreMissingUpdate).value, transform, skip = (skip in update).value, force = isRoot, depsUpdated = depsUpdated, log = s.log)
|
||||
|
|
|
|||
|
|
@ -25,15 +25,15 @@ object GraphTransformations {
|
|||
Nil
|
||||
else
|
||||
deps.get(module) match {
|
||||
case Some(deps) =>
|
||||
deps.flatMap { to =>
|
||||
case Some(deps) ⇒
|
||||
deps.flatMap { to ⇒
|
||||
(module, to.id) +: visit(to.id, visited + module)
|
||||
}
|
||||
case None => Nil
|
||||
case None ⇒ Nil
|
||||
}
|
||||
|
||||
val edges = visit(root, Set.empty)
|
||||
val nodes = edges.foldLeft(Set.empty[ModuleId])((set, edge) => set + edge._1 + edge._2).map(graph.module)
|
||||
val nodes = edges.foldLeft(Set.empty[ModuleId])((set, edge) ⇒ set + edge._1 + edge._2).map(graph.module)
|
||||
ModuleGraph(nodes.toSeq, edges)
|
||||
}
|
||||
|
||||
|
|
@ -52,7 +52,7 @@ object GraphTransformations {
|
|||
}
|
||||
|
||||
val newNodes = graph.nodes.map(addScalaLibraryAnnotation).filterNot(isScalaLibrary)
|
||||
val newEdges = graph.edges.filterNot(e => isScalaLibraryId(e._2))
|
||||
val newEdges = graph.edges.filterNot(e ⇒ isScalaLibraryId(e._2))
|
||||
ModuleGraph(newNodes, newEdges)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ object Main extends App {
|
|||
def usage: String =
|
||||
"Usage: <ivy-report-file> <output-file>"
|
||||
|
||||
val reportFile = args.lift(0).filter(f => new File(f).exists).getOrElse(die(usage))
|
||||
val reportFile = args.lift(0).filter(f ⇒ new File(f).exists).getOrElse(die(usage))
|
||||
val outputFile = args.lift(1).getOrElse(die(usage))
|
||||
val graph = frontend.IvyReport.fromReportFile(reportFile)
|
||||
rendering.GraphML.saveAsGraphML(graph, outputFile)
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ package net.virtualvoid.sbt.graph.frontend
|
|||
|
||||
import net.virtualvoid.sbt.graph._
|
||||
|
||||
import scala.xml.{NodeSeq, Document, Node}
|
||||
import scala.xml.{ NodeSeq, Document, Node }
|
||||
import scala.xml.parsing.ConstructingParser
|
||||
|
||||
object IvyReport {
|
||||
|
|
@ -28,16 +28,16 @@ object IvyReport {
|
|||
def fromReportXML(doc: Document): ModuleGraph = {
|
||||
def edgesForModule(id: ModuleId, revision: NodeSeq): Seq[Edge] =
|
||||
for {
|
||||
caller <- revision \ "caller"
|
||||
caller ← revision \ "caller"
|
||||
callerModule = moduleIdFromElement(caller, caller.attribute("callerrev").get.text)
|
||||
} yield (moduleIdFromElement(caller, caller.attribute("callerrev").get.text), id)
|
||||
|
||||
val moduleEdges: Seq[(Module, Seq[Edge])] = for {
|
||||
mod <- doc \ "dependencies" \ "module"
|
||||
revision <- mod \ "revision"
|
||||
rev = revision.attribute("name").get.text
|
||||
moduleId = moduleIdFromElement(mod, rev)
|
||||
module = Module(moduleId,
|
||||
mod ← doc \ "dependencies" \ "module"
|
||||
revision ← mod \ "revision"
|
||||
rev = revision.attribute("name").get.text
|
||||
moduleId = moduleIdFromElement(mod, rev)
|
||||
module = Module(moduleId,
|
||||
(revision \ "license").headOption.flatMap(_.attribute("name")).map(_.text),
|
||||
evictedByVersion = (revision \ "evicted-by").headOption.flatMap(_.attribute("rev").map(_.text)),
|
||||
error = revision.attribute("error").map(_.text))
|
||||
|
|
@ -47,7 +47,7 @@ object IvyReport {
|
|||
|
||||
val info = (doc \ "info").head
|
||||
def infoAttr(name: String): String =
|
||||
info.attribute(name).getOrElse(throw new IllegalArgumentException("Missing attribute "+name)).text
|
||||
info.attribute(name).getOrElse(throw new IllegalArgumentException("Missing attribute " + name)).text
|
||||
val rootModule = Module(ModuleId(infoAttr("organisation"), infoAttr("module"), infoAttr("revision")))
|
||||
|
||||
ModuleGraph(rootModule +: nodes, edges.flatten)
|
||||
|
|
|
|||
|
|
@ -16,12 +16,12 @@
|
|||
|
||||
package net.virtualvoid.sbt.graph
|
||||
|
||||
import scala.collection.mutable.{MultiMap, HashMap, Set}
|
||||
import scala.collection.mutable.{ MultiMap, HashMap, Set }
|
||||
|
||||
case class ModuleId(organisation: String,
|
||||
name: String,
|
||||
version: String) {
|
||||
def idString: String = organisation+":"+name+":"+version
|
||||
def idString: String = organisation + ":" + name + ":" + version
|
||||
}
|
||||
case class Module(id: ModuleId,
|
||||
license: Option[String] = None,
|
||||
|
|
@ -34,7 +34,7 @@ case class Module(id: ModuleId,
|
|||
|
||||
case class ModuleGraph(nodes: Seq[Module], edges: Seq[Edge]) {
|
||||
lazy val modules: Map[ModuleId, Module] =
|
||||
nodes.map(n => (n.id, n)).toMap
|
||||
nodes.map(n ⇒ (n.id, n)).toMap
|
||||
|
||||
def module(id: ModuleId): Module = modules(id)
|
||||
|
||||
|
|
@ -42,11 +42,11 @@ case class ModuleGraph(nodes: Seq[Module], edges: Seq[Edge]) {
|
|||
createMap(identity)
|
||||
|
||||
lazy val reverseDependencyMap: Map[ModuleId, Seq[Module]] =
|
||||
createMap { case (a, b) => (b, a) }
|
||||
createMap { case (a, b) ⇒ (b, a) }
|
||||
|
||||
def createMap(bindingFor: ((ModuleId, ModuleId)) => (ModuleId, ModuleId)): Map[ModuleId, Seq[Module]] = {
|
||||
def createMap(bindingFor: ((ModuleId, ModuleId)) ⇒ (ModuleId, ModuleId)): Map[ModuleId, Seq[Module]] = {
|
||||
val m = new HashMap[ModuleId, Set[Module]] with MultiMap[ModuleId, Module]
|
||||
edges.foreach { entry =>
|
||||
edges.foreach { entry ⇒
|
||||
val (f, t) = bindingFor(entry)
|
||||
m.addBinding(f, module(t))
|
||||
}
|
||||
|
|
@ -54,7 +54,7 @@ case class ModuleGraph(nodes: Seq[Module], edges: Seq[Edge]) {
|
|||
}
|
||||
}
|
||||
|
||||
import sbinary.{Format, DefaultProtocol}
|
||||
import sbinary.{ Format, DefaultProtocol }
|
||||
object ModuleGraphProtocol extends DefaultProtocol {
|
||||
implicit def seqFormat[T: Format]: Format[Seq[T]] = wrap[Seq[T], List[T]](_.toList, _.toSeq)
|
||||
implicit val ModuleIdFormat: Format[ModuleId] = asProduct3(ModuleId)(ModuleId.unapply(_).get)
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ object AsciiGraph {
|
|||
module.id.name + module.extraInfo + "\n" +
|
||||
module.id.organisation + "\n" +
|
||||
module.id.version +
|
||||
module.error.map("\nerror: "+_).getOrElse("") +
|
||||
module.error.map("\nerror: " + _).getOrElse("") +
|
||||
module.evictedByVersion.map(_ formatted "\nevicted by: %s").getOrElse("")
|
||||
|
||||
val vertices = moduleGraph.nodes.map(renderVertex).toList
|
||||
|
|
|
|||
|
|
@ -25,15 +25,15 @@ object AsciiTree {
|
|||
val deps = graph.dependencyMap
|
||||
|
||||
// there should only be one root node (the project itself)
|
||||
val roots = graph.nodes.filter(n => !graph.edges.exists(_._2 == n.id)).sortBy(_.id.idString)
|
||||
roots.map { root =>
|
||||
AsciiTreeLayout.toAscii[Module](root, node => deps.getOrElse(node.id, Seq.empty[Module]), displayModule)
|
||||
val roots = graph.nodes.filter(n ⇒ !graph.edges.exists(_._2 == n.id)).sortBy(_.id.idString)
|
||||
roots.map { root ⇒
|
||||
AsciiTreeLayout.toAscii[Module](root, node ⇒ deps.getOrElse(node.id, Seq.empty[Module]), displayModule)
|
||||
}.mkString("\n")
|
||||
}
|
||||
|
||||
def displayModule(module: Module): String =
|
||||
red(module.id.idString +
|
||||
module.extraInfo +
|
||||
module.error.map(" (error: "+_+")").getOrElse("") +
|
||||
module.error.map(" (error: " + _ + ")").getOrElse("") +
|
||||
module.evictedByVersion.map(_ formatted " (evicted by: %s)").getOrElse(""), module.hadError)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,19 +23,17 @@ import net.virtualvoid.sbt.graph.ModuleGraph
|
|||
object DOT {
|
||||
def saveAsDot(graph: ModuleGraph,
|
||||
dotHead: String,
|
||||
nodeFormation: (String, String, String) => String,
|
||||
nodeFormation: (String, String, String) ⇒ String,
|
||||
outputFile: File): File = {
|
||||
val nodes = {
|
||||
for (n <- graph.nodes)
|
||||
yield
|
||||
""" "%s"[label=%s]""".format(n.id.idString,
|
||||
nodeFormation(n.id.organisation, n.id.name, n.id.version))
|
||||
for (n ← graph.nodes)
|
||||
yield """ "%s"[label=%s]""".format(n.id.idString,
|
||||
nodeFormation(n.id.organisation, n.id.name, n.id.version))
|
||||
}.mkString("\n")
|
||||
|
||||
val edges = {
|
||||
for ( e <- graph.edges)
|
||||
yield
|
||||
""" "%s" -> "%s"""".format(e._1.idString, e._2.idString)
|
||||
for (e ← graph.edges)
|
||||
yield """ "%s" -> "%s"""".format(e._1.idString, e._2.idString)
|
||||
}.mkString("\n")
|
||||
|
||||
val dot = "%s\n%s\n%s\n}".format(dotHead, nodes, edges)
|
||||
|
|
|
|||
|
|
@ -23,27 +23,23 @@ import scala.xml.XML
|
|||
object GraphML {
|
||||
def saveAsGraphML(graph: ModuleGraph, outputFile: String) {
|
||||
val nodesXml =
|
||||
for (n <- graph.nodes)
|
||||
yield
|
||||
<node id={n.id.idString}><data key="d0">
|
||||
<y:ShapeNode>
|
||||
<y:NodeLabel>{n.id.idString}</y:NodeLabel>
|
||||
</y:ShapeNode>
|
||||
</data></node>
|
||||
for (n ← graph.nodes)
|
||||
yield <node id={ n.id.idString }><data key="d0">
|
||||
<y:ShapeNode>
|
||||
<y:NodeLabel>{ n.id.idString }</y:NodeLabel>
|
||||
</y:ShapeNode>
|
||||
</data></node>
|
||||
|
||||
val edgesXml =
|
||||
for (e <- graph.edges)
|
||||
yield <edge source={e._1.idString} target={e._2.idString} />
|
||||
for (e ← graph.edges)
|
||||
yield <edge source={ e._1.idString } target={ e._2.idString }/>
|
||||
|
||||
val xml =
|
||||
<graphml xmlns="http://graphml.graphdrawing.org/xmlns"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:y="http://www.yworks.com/xml/graphml"
|
||||
xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
|
||||
<graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:y="http://www.yworks.com/xml/graphml" xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
|
||||
<key for="node" id="d0" yfiles.type="nodegraphics"/>
|
||||
<graph id="Graph" edgedefault="undirected">
|
||||
{nodesXml}
|
||||
{edgesXml}
|
||||
{ nodesXml }
|
||||
{ edgesXml }
|
||||
</graph>
|
||||
</graphml>
|
||||
|
||||
|
|
|
|||
|
|
@ -6,50 +6,50 @@
|
|||
package net.virtualvoid.sbt.graph.util
|
||||
|
||||
object AsciiTreeLayout {
|
||||
// [info] foo
|
||||
// [info] +-bar
|
||||
// [info] | +-baz
|
||||
// [info] |
|
||||
// [info] +-quux
|
||||
def toAscii[A](top: A,
|
||||
children: A => Seq[A],
|
||||
display: A => String,
|
||||
// [info] foo
|
||||
// [info] +-bar
|
||||
// [info] | +-baz
|
||||
// [info] |
|
||||
// [info] +-quux
|
||||
def toAscii[A](top: A,
|
||||
children: A ⇒ Seq[A],
|
||||
display: A ⇒ String,
|
||||
maxColumn: Int = defaultColumnSize): String = {
|
||||
val twoSpaces = " " + " " // prevent accidentally being converted into a tab
|
||||
def limitLine(s: String): String =
|
||||
if (s.length > maxColumn) s.slice(0, maxColumn - 2) + ".."
|
||||
else s
|
||||
def insertBar(s: String, at: Int): String =
|
||||
val twoSpaces = " " + " " // prevent accidentally being converted into a tab
|
||||
def limitLine(s: String): String =
|
||||
if (s.length > maxColumn) s.slice(0, maxColumn - 2) + ".."
|
||||
else s
|
||||
def insertBar(s: String, at: Int): String =
|
||||
if (at < s.length)
|
||||
s.slice(0, at) +
|
||||
(s(at).toString match {
|
||||
case " " => "|"
|
||||
case x => x
|
||||
}) +
|
||||
s.slice(at + 1, s.length)
|
||||
(s(at).toString match {
|
||||
case " " ⇒ "|"
|
||||
case x ⇒ x
|
||||
}) +
|
||||
s.slice(at + 1, s.length)
|
||||
else s
|
||||
def toAsciiLines(node: A, level: Int, parents: Set[A]): Vector[String] =
|
||||
if (parents contains node) // cycle
|
||||
Vector(limitLine((twoSpaces * level) + "#-" + display(node)))
|
||||
else {
|
||||
val line = limitLine((twoSpaces * level) + (if (level == 0) "" else "+-") + display(node))
|
||||
val cs = Vector(children(node): _*)
|
||||
val childLines = cs map {
|
||||
toAsciiLines(_, level + 1, parents + node)
|
||||
}
|
||||
val withBar = childLines.zipWithIndex flatMap {
|
||||
case (lines, pos) if pos < (cs.size - 1) => lines map {
|
||||
insertBar(_, 2 * (level + 1))
|
||||
}
|
||||
case (lines, pos) =>
|
||||
if (lines.last.trim != "") lines ++ Vector(twoSpaces * (level + 1))
|
||||
else lines
|
||||
}
|
||||
line +: withBar
|
||||
}
|
||||
def toAsciiLines(node: A, level: Int, parents: Set[A]): Vector[String] =
|
||||
if (parents contains node) // cycle
|
||||
Vector(limitLine((twoSpaces * level) + "#-" + display(node)))
|
||||
else {
|
||||
val line = limitLine((twoSpaces * level) + (if (level == 0) "" else "+-") + display(node))
|
||||
val cs = Vector(children(node): _*)
|
||||
val childLines = cs map {
|
||||
toAsciiLines(_, level + 1, parents + node)
|
||||
}
|
||||
val withBar = childLines.zipWithIndex flatMap {
|
||||
case (lines, pos) if pos < (cs.size - 1) ⇒ lines map {
|
||||
insertBar(_, 2 * (level + 1))
|
||||
}
|
||||
case (lines, pos) ⇒
|
||||
if (lines.last.trim != "") lines ++ Vector(twoSpaces * (level + 1))
|
||||
else lines
|
||||
}
|
||||
line +: withBar
|
||||
}
|
||||
|
||||
toAsciiLines(top, 0, Set.empty).mkString("\n")
|
||||
}
|
||||
toAsciiLines(top, 0, Set.empty).mkString("\n")
|
||||
}
|
||||
|
||||
def defaultColumnSize: Int = {
|
||||
val termWidth = sbt.SbtAccess.getTerminalWidth
|
||||
|
|
|
|||
|
|
@ -8,12 +8,12 @@ class AsciiTreeLayoutSpecs extends Specification {
|
|||
case class Leaf(i: Int) extends Tree
|
||||
|
||||
def children(t: Tree): Seq[Tree] = t match {
|
||||
case Branch(left, right) => Seq(left, right)
|
||||
case _: Leaf => Nil
|
||||
case Branch(left, right) ⇒ Seq(left, right)
|
||||
case _: Leaf ⇒ Nil
|
||||
}
|
||||
def display(t: Tree): String = t match {
|
||||
case Branch(left, right) => "Branch"
|
||||
case Leaf(value) => value.toString * value
|
||||
case Branch(left, right) ⇒ "Branch"
|
||||
case Leaf(value) ⇒ value.toString * value
|
||||
}
|
||||
|
||||
"Graph" should {
|
||||
|
|
@ -66,29 +66,29 @@ class AsciiTreeLayoutSpecs extends Specification {
|
|||
}
|
||||
"cut off cycles" in {
|
||||
AsciiTreeLayout.toAscii[Int](1, Map(
|
||||
1 -> Seq(2,3,4),
|
||||
2 -> Seq(4,5),
|
||||
1 -> Seq(2, 3, 4),
|
||||
2 -> Seq(4, 5),
|
||||
3 -> Seq(),
|
||||
4 -> Seq(3),
|
||||
5 -> Seq(1,4,6,7),
|
||||
5 -> Seq(1, 4, 6, 7),
|
||||
6 -> Seq(),
|
||||
7 -> Seq()), _.toString).trim ===
|
||||
"""1
|
||||
| +-2
|
||||
| | +-4
|
||||
| | | +-3
|
||||
| | |\u0020
|
||||
| | +-5
|
||||
| | #-1
|
||||
| | +-4
|
||||
| | | +-3
|
||||
| | |\u0020
|
||||
| | +-6
|
||||
| | +-7
|
||||
| |\u0020\u0020\u0020
|
||||
| +-3
|
||||
| +-4
|
||||
| +-3""".stripMargin.trim
|
||||
"""1
|
||||
| +-2
|
||||
| | +-4
|
||||
| | | +-3
|
||||
| | |\u0020
|
||||
| | +-5
|
||||
| | #-1
|
||||
| | +-4
|
||||
| | | +-3
|
||||
| | |\u0020
|
||||
| | +-6
|
||||
| | +-7
|
||||
| |\u0020\u0020\u0020
|
||||
| +-3
|
||||
| +-4
|
||||
| +-3""".stripMargin.trim
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue