diff --git a/src/main/resources/graph.html b/src/main/resources/graph.html new file mode 100644 index 000000000..eae90cff0 --- /dev/null +++ b/src/main/resources/graph.html @@ -0,0 +1,126 @@ + + + + + +Dependency Graph + + + + + + + + + + + + + +

Dependencies

+ + + + + + + diff --git a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala index 0dcbb0d15..7356e97a9 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala @@ -33,6 +33,12 @@ trait DependencyGraphKeys { "Creates a dot file containing the dependency-graph for a project") val dependencyDotString = TaskKey[String]("dependency-dot-string", "Creates a String containing the dependency-graph for a project in dot format") + val dependencyBrowseGraphTarget = SettingKey[File]("dependency-browse-graph-target", + "The location dependency browse graph files should be put.") + val dependencyBrowseGraphHTML = TaskKey[URI]("dependency-browse-graph-html", + "Creates an HTML page that can be used to view the graph.") + val dependencyBrowseGraph = TaskKey[URI]("dependency-browse-graph", + "Opens an HTML page that can be used to view the graph.") val moduleGraph = TaskKey[ModuleGraph]("module-graph", "The dependency graph for a project") val asciiGraph = TaskKey[String]("dependency-graph-string", diff --git a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala index 29c8fc306..038c3282a 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala @@ -16,8 +16,6 @@ package net.virtualvoid.sbt.graph -import net.virtualvoid.sbt.graph.backend.{ IvyReport, SbtUpdateReport } -import net.virtualvoid.sbt.graph.util.IOUtil import sbt._ import Keys._ @@ -27,6 +25,10 @@ import sbt.complete.Parser import org.apache.ivy.core.resolve.ResolveOptions +import net.virtualvoid.sbt.graph.backend.{ IvyReport, SbtUpdateReport } +import net.virtualvoid.sbt.graph.rendering.DagreHTML +import net.virtualvoid.sbt.graph.util.IOUtil + object DependencyGraphSettings { import DependencyGraphKeys._ import ModuleGraphProtocol._ @@ -83,6 +85,13 @@ object DependencyGraphSettings { dependencyDotFile <<= target / "dependencies-%s.dot".format(config.toString), dependencyDotString <<= dependencyDotStringTask, dependencyDot <<= writeToFile(dependencyDotString, dependencyDotFile), + dependencyBrowseGraphTarget <<= target / "browse-dependency-graph", + dependencyBrowseGraphHTML <<= browseGraphHTMLTask, + dependencyBrowseGraph <<= (dependencyBrowseGraphHTML, streams).map { (uri, streams) ⇒ + streams.log.info("Opening in browser...") + java.awt.Desktop.getDesktop.browse(uri) + uri + }, dependencyDotHeader := """digraph "dependency-graph" { | graph[rankdir="LR"] | edge [ @@ -118,6 +127,13 @@ object DependencyGraphSettings { (graph, dotHead, nodeLabel) ⇒ rendering.DOT.dotGraph(graph, dotHead, nodeLabel) } + def browseGraphHTMLTask = + (dependencyDotString, dependencyBrowseGraphTarget, streams).map { (graph, target, streams) ⇒ + val link = DagreHTML.createLink(graph, target) + streams.log.info(s"HTML graph written to $link") + link + } + def writeToFile(dataTask: TaskKey[String], fileTask: SettingKey[File]) = (dataTask, fileTask, streams).map { (data, outFile, streams) ⇒ IOUtil.writeToFile(data, outFile) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/model.scala b/src/main/scala/net/virtualvoid/sbt/graph/model.scala index f4b51cfcb..e833d34ab 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/model.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/model.scala @@ -29,7 +29,8 @@ case class Module(id: ModuleId, evictedByVersion: Option[String] = None, error: Option[String] = None) { def hadError: Boolean = error.isDefined - def isUsed: Boolean = !evictedByVersion.isDefined + def isUsed: Boolean = !isEvicted + def isEvicted: Boolean = evictedByVersion.isDefined } case class ModuleGraph(nodes: Seq[Module], edges: Seq[Edge]) { diff --git a/src/main/scala/net/virtualvoid/sbt/graph/rendering/DagreHTML.scala b/src/main/scala/net/virtualvoid/sbt/graph/rendering/DagreHTML.scala new file mode 100644 index 000000000..3064ef502 --- /dev/null +++ b/src/main/scala/net/virtualvoid/sbt/graph/rendering/DagreHTML.scala @@ -0,0 +1,40 @@ +/* + * Copyright 2015 Johannes Rudolph + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.virtualvoid.sbt.graph +package rendering + +import java.io.File +import java.net.{ URLEncoder, URI } + +import net.virtualvoid.sbt.graph.util.IOUtil + +object DagreHTML { + def createLink(dotGraph: String, targetDirectory: File): URI = { + targetDirectory.mkdirs() + val graphHTML = new File(targetDirectory, "graph.html") + IOUtil.saveResource("graph.html", graphHTML) + IOUtil.writeToFile(dotGraph, new File(targetDirectory, "dependencies.dot")) + + val graphString = + URLEncoder.encode(dotGraph, "utf8") + .replaceAllLiterally("+", "%20") + + IOUtil.writeToFile(s"""data = "$graphString";""", new File(targetDirectory, "dependencies.dot.js")) + + new URI(graphHTML.toURI.toString) + } +}