cmd/modgraphviz: make it a more idiomatic Go command
- Doc comment for command begins with "Name", not "The name command".
- Doc comment usage line is in a code block, not plain text.
- Drop GO111MODULE=on from usage text
(if people have a module, they have modules on).
- Doc comment text explains usage precisely, beyond usage line.
- Add references to what Graphviz is and also digraph tool.
- Turn off the date/time/file log annotations.
- Print command name as a log prefix.
- Don't print usage message using log.
- Check command-line argument count.
- Change Run(Reader, Writer) to convert(Reader) ([]byte, error)
to avoid unnecessary error checks on bytes.Buffer.Write
(which can't fail).
- io.Reader should be named r, not in.
- Use idiomatic bufio.Scanner loop, like in its example.
Change-Id: I74f1a9f58e2dada87eab483183a92eff9ff31cbf
Reviewed-on: https://go-review.googlesource.com/c/exp/+/183982
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
diff --git a/cmd/modgraphviz/main.go b/cmd/modgraphviz/main.go
index a6527d8..bf2f521 100644
--- a/cmd/modgraphviz/main.go
+++ b/cmd/modgraphviz/main.go
@@ -2,10 +2,23 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// The modgraphviz command translates the output for go mod graph into .dot
-// notation, which can then be parsed by `dot` into visual graphs.
+// Modgraphviz converts “go mod graph” output into Graphviz's DOT language,
+// for use with Graphviz visualization and analysis tools like dot, dotty, and sccmap.
//
-// Usage: GO111MODULE=on go mod graph | modgraphviz | dot -Tpng -o outfile.png
+// Usage:
+//
+// go mod graph | modgraphviz > graph.dot
+// go mod graph | modgraphviz | dot -Tpng -o graph.png
+//
+// Modgraphviz takes no options or arguments; it reads a graph in the format
+// generated by “go mod graph” on standard input and writes DOT language
+// on standard output.
+//
+// See http://www.graphviz.org/doc/info/lang.html for details of the DOT language
+// and http://www.graphviz.org/about/ for Graphviz itself.
+//
+// See also golang.org/x/tools/cmd/digraph for general queries and analysis
+// of “go mod graph” output.
package main
import (
@@ -19,50 +32,48 @@
"strings"
)
+func usage() {
+ fmt.Fprintf(os.Stderr, "Usage: go mod graph | modgraphviz | dot -Tpng -o graph.png\n")
+ os.Exit(2)
+}
+
func main() {
- flag.Usage = func() {
- log.Println("Usage: GO111MODULE=on go mod graph | modgraphviz | dot -Tpng -o outfile.png")
- }
+ log.SetFlags(0)
+ log.SetPrefix("modgraphviz: ")
+
+ flag.Usage = usage
flag.Parse()
+ if flag.NArg() != 0 {
+ usage()
+ }
- var out bytes.Buffer
-
- if err := Run(os.Stdin, &out); err != nil {
+ graph, err := convert(os.Stdin)
+ if err != nil {
log.Fatal(err)
}
-
- if _, err := out.WriteTo(os.Stdout); err != nil {
+ if _, err := os.Stdout.Write(graph); err != nil {
log.Fatal(err)
}
}
-func Run(in io.Reader, out io.Writer) error {
- if _, err := out.Write([]byte("digraph gomodgraph {\n")); err != nil {
- return err
- }
+// convert reads “go mod graph” output from r
+// and returns the equivalent DOT digraph.
+func convert(r io.Reader) ([]byte, error) {
+ var buf bytes.Buffer
+ fmt.Fprintf(&buf, "digraph gomodgraph {\n")
- r := bufio.NewScanner(in)
- for {
- if !r.Scan() {
- if r.Err() != nil {
- return r.Err()
- }
- break
- }
-
- parts := strings.Fields(r.Text())
+ scanner := bufio.NewScanner(r)
+ for scanner.Scan() {
+ parts := strings.Fields(scanner.Text())
if len(parts) != 2 {
continue
}
-
- if _, err := fmt.Fprintf(out, "\t%q -> %q\n", parts[0], parts[1]); err != nil {
- return err
- }
+ fmt.Fprintf(&buf, "\t%q -> %q\n", parts[0], parts[1])
+ }
+ if err := scanner.Err(); err != nil {
+ return nil, err
}
- if _, err := out.Write([]byte("}\n")); err != nil {
- return err
- }
-
- return nil
+ fmt.Fprintf(&buf, "}\n")
+ return buf.Bytes(), nil
}
diff --git a/cmd/modgraphviz/main_test.go b/cmd/modgraphviz/main_test.go
index 2f02978..8dfa65b 100644
--- a/cmd/modgraphviz/main_test.go
+++ b/cmd/modgraphviz/main_test.go
@@ -14,9 +14,8 @@
test.com/A test.com/B@v1.2.3
test.com/B test.com/C@v4.5.6
`))
- out := bytes.Buffer{}
-
- if err := Run(in, &out); err != nil {
+ graph, err := convert(in)
+ if err != nil {
t.Fatal(err)
}
@@ -25,7 +24,7 @@
"test.com/B" -> "test.com/C@v4.5.6"
}
`
- if out.String() != want {
- t.Fatalf("\ngot: %s\nwant: %s", out.String(), want)
+ if string(graph) != want {
+ t.Fatalf("\ngot: %s\nwant: %s", string(graph), want)
}
}