Merge pull request #136 from pcejrowski/master

Added dependencyBrowseTreeHTML and dependencyBrowseTree tasks
This commit is contained in:
Johannes Rudolph 2018-09-14 14:28:59 +02:00 committed by GitHub
commit 83d3e3a5df
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 123 additions and 8 deletions

View File

@ -21,6 +21,7 @@ the notes of version [0.8.2](https://github.com/jrudolph/sbt-dependency-graph/tr
## Main Tasks
* `dependencyBrowseTree`: Opens a browser window with a visualization of the dependency tree (courtesy of jstree).
* `dependencyTree`: Shows an ASCII tree representation of the project's dependencies
* `dependencyBrowseGraph`: Opens a browser window with a visualization of the dependency graph (courtesy of graphlib-dot + dagre-d3).
* `dependencyList`: Shows a flat list of all transitive dependencies on the sbt console (sorted by organization and name)

View File

@ -0,0 +1,49 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>dependencyBrowseTree</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.2.1/jstree.min.js"></script>
<script src="tree.data.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.2.1/themes/default/style.min.css"/>
<style>
#input-field {
display: inline;
}
#tree_div {
font-family: monospace
}
</style>
</head>
<body>
<h1>Dependencies</h1>
Search: <input type="search" id="input-field" value="">
<div id="tree_div" class="jstree-no-icons"></div>
<script>
$(function() {
$('#tree_div').jstree({
"plugins": ["search", "sort"],
"core": {
"data": tree_data
}
});
var to = false;
$('#input-field').keyup(function() {
if (to) {
clearTimeout(to);
}
to = setTimeout(function() {
var v = $('#input-field').val();
$('#tree_div').jstree(true).search(v);
}, 250);
});
});
</script>
</body>
</html>

View File

@ -49,6 +49,15 @@ trait DependencyGraphKeys {
val dependencyBrowseGraph = TaskKey[URI](
"dependency-browse-graph",
"Opens an HTML page that can be used to view the graph.")
val dependencyBrowseTreeTarget = SettingKey[File](
"dependency-browse-tree-target",
"The location dependency browse tree files should be put.")
val dependencyBrowseTreeHTML = TaskKey[URI](
"dependency-browse-tree-html",
"Creates an HTML page that can be used to view the dependency tree")
val dependencyBrowseTree = TaskKey[URI](
"dependency-browse-tree",
"Opens an HTML page that can be used to view the dependency tree")
val moduleGraph = TaskKey[ModuleGraph](
"module-graph",
"The dependency graph for a project")
@ -97,4 +106,4 @@ trait DependencyGraphKeys {
private[graph] val crossProjectId = SettingKey[ModuleID]("dependency-graph-cross-project-id")
}
object DependencyGraphKeys extends DependencyGraphKeys
object DependencyGraphKeys extends DependencyGraphKeys

View File

@ -22,7 +22,7 @@ import sbt._
import Keys._
import sbt.complete.Parser
import net.virtualvoid.sbt.graph.backend.{ IvyReport, SbtUpdateReport }
import net.virtualvoid.sbt.graph.rendering.{ AsciiGraph, DagreHTML }
import net.virtualvoid.sbt.graph.rendering.{ AsciiGraph, DagreHTML, TreeView }
import net.virtualvoid.sbt.graph.util.IOUtil
import internal.librarymanagement._
import librarymanagement._
@ -74,12 +74,10 @@ object DependencyGraphSettings {
dependencyDot := writeToFile(dependencyDotString, dependencyDotFile).value,
dependencyBrowseGraphTarget := { target.value / "browse-dependency-graph" },
dependencyBrowseGraphHTML := browseGraphHTMLTask.value,
dependencyBrowseGraph := {
val uri = dependencyBrowseGraphHTML.value
streams.value.log.info("Opening in browser...")
java.awt.Desktop.getDesktop.browse(uri)
uri
},
dependencyBrowseGraph := openBrowser(dependencyBrowseGraphHTML).value,
dependencyBrowseTreeTarget := { target.value / "browse-dependency-tree" },
dependencyBrowseTreeHTML := browseTreeHTMLTask.value,
dependencyBrowseTree := openBrowser(dependencyBrowseTreeHTML).value,
dependencyList := printFromGraph(rendering.FlatList.render(_, _.id.idString)).value,
dependencyStats := printFromGraph(rendering.Statistics.renderModuleStatsList).value,
dependencyDotHeader :=
@ -139,6 +137,14 @@ object DependencyGraphSettings {
link
}
def browseTreeHTMLTask =
Def.task {
val renderedTree = TreeView.createJson(moduleGraph.value)
val link = TreeView.createLink(renderedTree, target.value)
streams.value.log.info(s"HTML tree written to $link")
link
}
def writeToFile(dataTask: TaskKey[String], fileTask: SettingKey[File]) =
Def.task {
val outFile = fileTask.value
@ -156,6 +162,14 @@ object DependencyGraphSettings {
def printFromGraph(f: ModuleGraph String) =
Def.task { streams.value.log.info(f(moduleGraph.value)) }
def openBrowser(uriKey: TaskKey[URI]) =
Def.task {
val uri = uriKey.value
streams.value.log.info("Opening in browser...")
java.awt.Desktop.getDesktop.browse(uri)
uri
}
def showLicenseInfo(graph: ModuleGraph, streams: TaskStreams): Unit = {
val output =
graph.nodes.filter(_.isUsed).groupBy(_.license).toSeq.sortBy(_._1).map {

View File

@ -0,0 +1,42 @@
package net.virtualvoid.sbt.graph.rendering
import java.io.File
import java.net.URI
import net.virtualvoid.sbt.graph.util.IOUtil
import net.virtualvoid.sbt.graph.{ Module, ModuleGraph }
import scala.util.parsing.json.{ JSONArray, JSONObject }
object TreeView {
def createJson(graph: ModuleGraph): String = {
val trees = graph.roots
.map(module processSubtree(graph, module))
.toList
JSONArray(trees).toString
}
def createLink(graphJson: String, targetDirectory: File): URI = {
targetDirectory.mkdirs()
val graphHTML = new File(targetDirectory, "tree.html")
IOUtil.saveResource("tree.html", graphHTML)
IOUtil.writeToFile(graphJson, new File(targetDirectory, "tree.json"))
IOUtil.writeToFile(s"tree_data = $graphJson;", new File(targetDirectory, "tree.data.js"))
new URI(graphHTML.toURI.toString)
}
private def processSubtree(graph: ModuleGraph, module: Module): JSONObject = {
val children = graph.dependencyMap
.getOrElse(module.id, List())
.map(module processSubtree(graph, module))
.toList
moduleAsJson(module, children)
}
private def moduleAsJson(module: Module, children: List[JSONObject]): JSONObject = {
val eviction = module.evictedByVersion.map(version s" (evicted by $version)").getOrElse("")
val error = module.error.map(err s" (errors: $err)").getOrElse("")
val text = module.id.idString + eviction + error
JSONObject(Map("text" -> text, "children" -> JSONArray(children)))
}
}