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)
 	}
 }