diff --git a/README.md b/README.md
index 0cf0b42..a045e3b 100644
--- a/README.md
+++ b/README.md
@@ -36,4 +36,9 @@ at `localhost:18080`.
This tool is a rewrite from scratch of a tool I wrote while at Google
for exploring the dependency graphs used by the Blaze build system.
The basic design could be easily be generalized to support any kind of
-dependency graph, independent of language or domain.
+dependency graph, independent of language or domain, or turned into a
+secure multi-user web service that operates on graph data uploaded from
+the client program that generates it.
+
+You can probably tell that web UIs are not my expertise.
+PRs that provide cosmetic improvements are most welcome!
diff --git a/code.js b/code.js
index c3eb126..333b4de 100644
--- a/code.js
+++ b/code.js
@@ -5,8 +5,6 @@ var broken = null // array of 2-arrays of int, the node ids of broken edges.
function onLoad() {
// Grab data from server: package graph, "directory" tree, broken edges.
- // TODO(adonovan): opt: put JSON data in the /index.html page?
- // There's no need for a second HTTP request.
jQuery.ajax({url: "/data", success: onData})
}
@@ -76,10 +74,9 @@ function onData(data) {
function selectPkg(json) {
if (json.Package < 0) {
// Non-package "directory" node: clear the fields.
- $('#json').text("")
$('#pkgname').text("none")
$('#doc').text("")
- $('#imports').text("")
+ $('#imports').html("")
$('#path').text("")
return
}
@@ -87,25 +84,34 @@ function selectPkg(json) {
// A package node was selected.
var pkg = packages[json.Package]
- // Show JSON, for debugging.
- $('#json').html("" + JSON.stringify(json) + "
")
-
// Show selected package.
$('#pkgname').text(pkg.PkgPath)
- // Set link to package documentation.
- $('#doc').html("doc")
-
- // TODO(adonovan): display imports as a set of links,
- // with as ImportPath text and "select dir tree node" as action.
- $('#imports').text(json.Imports.join(" "))
+ // Set link to Go package documentation.
+ $('#doc').html("")
+
+ // Show imports in a drop-down menu.
+ // Selecting an import acts like clicking on that package in the tree.
+ var imports = $('#imports')
+ imports.html("")
+ var option = document.createElement("option")
+ option.textContent = "..."
+ option.value = "-1"
+ imports.append(option)
+ for (var i in json.Imports) {
+ var imp = json.Imports[i]
+ option = document.createElement("option")
+ option.textContent = packages[imp].PkgPath
+ option.value = "" + imp // package index, used by onSelectImport
+ imports.append(option)
+ }
// Show "break edges" buttons.
var html = ""
var path = [].concat(json.Path).reverse() // from root to selected package
for (var i in path) {
var p = packages[path[i]]
- if (i >= 0) {
+ if (i > 0) {
html += " "
+ " "
+ "⟶ "
@@ -124,3 +130,11 @@ function unbreak(i, j) {
// Must reload the page since the graph has changed.
document.location = "/unbreak?from=" + i + "&to=" + j
}
+
+// onSelectImport is called by the imports dropdown.
+function onSelectImport(sel) {
+ if (sel.value >= 0) {
+ // Simulate a click on a tree node corresponding to the selected import.
+ $('#tree').jstree('select_node', 'node' + sel.value);
+ }
+}
diff --git a/go.mod b/go.mod
index d22436d..57e26d6 100644
--- a/go.mod
+++ b/go.mod
@@ -3,7 +3,6 @@ module github.com/adonovan/spaghetti
go 1.16
require (
- github.com/google/renameio v0.1.0 // indirect
- golang.org/x/tools v0.1.1-0.20210319172145-bda8f5cee399 // indirect
+ golang.org/x/tools v0.1.1-0.20210319172145-bda8f5cee399
golang.org/x/tools/gopls v0.6.9 // indirect
)
diff --git a/go.sum b/go.sum
index 725b9c6..21a462b 100644
--- a/go.sum
+++ b/go.sum
@@ -5,7 +5,6 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/safehtml v0.0.2/go.mod h1:L4KWwDsUJdECRAEpZoBn3O64bQaywRscowZjJAzjHnU=
github.com/jba/templatecheck v0.5.0/go.mod h1:/1k7EajoSErFI9GLHAsiIJEaNLt3ALKNw2TV7z2SYv4=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
@@ -26,7 +25,6 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1 h1:Kvvh58BN8Y9/lBi7hTekvtMpm07eUZ0ck5pRHpsMWrY=
@@ -40,7 +38,6 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4 h1:myAQVi0cGEoqQVR5POX+8RR2mrocKqNN1hmeMqhX27k=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -49,7 +46,6 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20210101214203-2dba1e4ea05c/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.1-0.20210319172145-bda8f5cee399 h1:O5bm8buX/OaamnfcBrkjn0SPUIU30jFmaS8lP+ikkxs=
golang.org/x/tools v0.1.1-0.20210319172145-bda8f5cee399/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU=
diff --git a/index.html b/index.html
index b9271e8..e8e18ad 100644
--- a/index.html
+++ b/index.html
@@ -1,7 +1,7 @@
This tool displays the complete dependencies of these initial packages:
...
- Click on a package in the tree view to display information about - it, including a path by which it is reached from one of the - initial packages. Use the break button to remove an - edge from the graph, so that you can assess what edges need to be - broken to remove an unwanted dependency. + Click on a package in the tree view to display information about it, + including a path by which it is reached from one of the initial packages. + + Use the break button to remove an edge from the graph, so + that you can assess what edges need to be broken to eliminate an + unwanted dependency.
+
@@ -45,26 +47,25 @@
- [...]
-
ⓘThis list shows the packages
directly imported by the selected package
-
- ...
+
+
- ⓘThis section
- displays an arbitrary path from one of the initial packages to
- the selected package. Click the break button so see how
- your dependencies would change if you were to remove a single
- edge. Click break all to remove all inbound edges to a
+ ⓘ
+ This section displays an arbitrary path from one of the
+ initial packages to the selected package. Click
+ the break button so see how your dependencies would
+ change if you were to remove a single edge.
+
+ Click break all to remove all inbound edges to a
package, removing it from the graph. This may be useful for
removing distracting packages that you don't plan to
- eliminate.
+ eliminate.
+
The bold nodes are dominators: nodes that are found on
every path to the selected node. One way to break a dependency
on a package is to break all dependencies on any of its dominators.
diff --git a/spaghetti.go b/spaghetti.go
index 26dd9f9..4785358 100644
--- a/spaghetti.go
+++ b/spaghetti.go
@@ -101,7 +101,7 @@ func main() {
http.Handle("/", http.FileServer(http.FS(content)))
const addr = "localhost:18080"
- log.Printf("Listening on %s...", addr)
+ log.Printf("listening on http://%s", addr)
if err := http.ListenAndServe(addr, nil); err != nil {
log.Fatal(err)
}
@@ -256,7 +256,7 @@ func onData(w http.ResponseWriter, req *http.Request) {
// Any additional fields will be accessible
// in the jstree node's .original field.
Package int // -1 for non-package nodes
- Imports []string
+ Imports []int
Dominators []int // path through dom tree, from package to root inclusive
Path []int // path through package graph, from package to root inclusive
}
@@ -306,9 +306,9 @@ func onData(w http.ResponseWriter, req *http.Request) {
// item.State = { 'opened' : true, 'selected' : true }
item.Package = e.node.index
- item.Imports = []string{} // avoid JSON null
+ item.Imports = []int{} // avoid JSON null
for _, imp := range e.node.imports {
- item.Imports = append(item.Imports, imp.Package.ID)
+ item.Imports = append(item.Imports, imp.index)
}
for n := e.node; n != nil; n = n.Idom() {
item.Dominators = append(item.Dominators, n.index)
diff --git a/style.css b/style.css
index 4cfc81d..7f26294 100644
--- a/style.css
+++ b/style.css
@@ -1,9 +1,9 @@
-body { margin: 1em; font-family: "Minion Pro", serif; }
+body { margin: 1em; font-family: "Minion Pro", serif; max-width: 1024px; }
h1, h2, h3, h4, .jstree-default { font-family: Lato; }
code, pre { font-family: Consolas, monospace; }
code.dom { font-weight: bold; }
-button { font-size: 50%; }
-pre#imports { font-size: 50%; max-height: 3em; overflow: scroll; }
+button { font-size: 90%; }
+pre#initial { margin-left: 1em; }
/* the ⓘ symbol */
.tooltip {