@@ -37,6 +37,8 @@ The support commands are:
37
37
the set of nodes strongly connected to the specified one
38
38
focus <node>
39
39
the subgraph containing all directed paths that pass through the specified node
40
+ to dot
41
+ print the graph in Graphviz dot format (other formats may be supported in the future)
40
42
41
43
Input format:
42
44
@@ -81,6 +83,11 @@ Show which packages in x/tools depend, perhaps indirectly, on the callgraph pack
81
83
$ go list -f '{{.ImportPath}} {{join .Imports " "}}' -deps golang.org/x/tools/... |
82
84
digraph reverse golang.org/x/tools/go/callgraph
83
85
86
+ Visualize the package dependency graph of the current package:
87
+
88
+ $ go list -f '{{.ImportPath}} {{join .Imports " "}}' -deps |
89
+ digraph to dot | dot -Tpng -o x.png
90
+
84
91
Using a module graph produced by go mod, show all dependencies of the current module:
85
92
86
93
$ go mod graph | digraph forward $(go list -m)
@@ -137,6 +144,8 @@ The support commands are:
137
144
the set of nodes nodes strongly connected to the specified one
138
145
focus <node>
139
146
the subgraph containing all directed paths that pass through the specified node
147
+ to dot
148
+ print the graph in Graphviz dot format (other formats may be supported in the future)
140
149
` )
141
150
os .Exit (2 )
142
151
}
@@ -207,6 +216,14 @@ func (g graph) addEdges(from string, to ...string) {
207
216
}
208
217
}
209
218
219
+ func (g graph ) nodelist () nodelist {
220
+ nodes := make (nodeset )
221
+ for node := range g {
222
+ nodes [node ] = true
223
+ }
224
+ return nodes .sort ()
225
+ }
226
+
210
227
func (g graph ) reachableFrom (roots nodeset ) nodeset {
211
228
seen := make (nodeset )
212
229
var visit func (node string )
@@ -356,6 +373,20 @@ func (g graph) somepath(from, to string) error {
356
373
return nil
357
374
}
358
375
376
+ func (g graph ) toDot (w * bytes.Buffer ) {
377
+ fmt .Fprintln (w , "digraph {" )
378
+ for _ , src := range g .nodelist () {
379
+ for _ , dst := range g [src ].sort () {
380
+ // Dot's quoting rules appear to align with Go's for escString,
381
+ // which is the syntax of node IDs. Labels require significantly
382
+ // more quoting, but that appears not to be necessary if the node ID
383
+ // is implicitly used as the label.
384
+ fmt .Fprintf (w , "\t %q -> %q;\n " , src , dst )
385
+ }
386
+ }
387
+ fmt .Fprintln (w , "}" )
388
+ }
389
+
359
390
func parse (rd io.Reader ) (graph , error ) {
360
391
g := make (graph )
361
392
@@ -404,11 +435,7 @@ func digraph(cmd string, args []string) error {
404
435
if len (args ) != 0 {
405
436
return fmt .Errorf ("usage: digraph nodes" )
406
437
}
407
- nodes := make (nodeset )
408
- for node := range g {
409
- nodes [node ] = true
410
- }
411
- nodes .sort ().println ("\n " )
438
+ g .nodelist ().println ("\n " )
412
439
413
440
case "degree" :
414
441
if len (args ) != 0 {
@@ -563,6 +590,14 @@ func digraph(cmd string, args []string) error {
563
590
sort .Strings (edgesSorted )
564
591
fmt .Fprintln (stdout , strings .Join (edgesSorted , "\n " ))
565
592
593
+ case "to" :
594
+ if len (args ) != 1 || args [0 ] != "dot" {
595
+ return fmt .Errorf ("usage: digraph to dot" )
596
+ }
597
+ var b bytes.Buffer
598
+ g .toDot (& b )
599
+ stdout .Write (b .Bytes ())
600
+
566
601
default :
567
602
return fmt .Errorf ("no such command %q" , cmd )
568
603
}
0 commit comments