cmd/go/internal/modcmd: add mod -graph

mod -graph dumps the requirement graph in text form,
for processing by other tools. For example, I wondered
why github.com/moby/buildkit was exploring a very
old version of Kubernetes:

    $ vgo mod -graph |
      digraph somepath github.com/moby/buildkit \
          k8s.io/kubernetes@v0.0.0-20150821172800-a412f6a67e3a
    github.com/moby/buildkit
    github.com/docker/docker@v0.0.0-20180531152204-71cd53e4a197
    github.com/containerd/containerd@v0.0.0-20180226221259-4ac4fd0b6a26
    k8s.io/kubernetes@v0.0.0-20180209063429-05944b1d2ca7
    k8s.io/heapster@v0.0.0-20160819112202-c2ac40f1adf8
    k8s.io/kubernetes@v0.0.0-20160809133706-301be4eeb561
    k8s.io/heapster@v0.0.0-20160517121052-9cb18ac0ceb1
    k8s.io/kubernetes@v0.0.0-20160513071043-4bb30e009782
    k8s.io/heapster@v0.0.0-20160405141354-de510e4bdcde
    k8s.io/kubernetes@v0.0.0-20160219000711-644d651c6907
    k8s.io/heapster@v0.0.0-20160126150510-0991ac528ea2
    k8s.io/kubernetes@v0.0.0-20151104234216-319baeec5ab5
    k8s.io/heapster@v0.0.0-20150824215340-0e1b65278181
    k8s.io/kubernetes@v0.0.0-20150821172800-a412f6a67e3a
    $

Change-Id: I202bfb9828e07e223eafce44f43c251cf24643b3
Reviewed-on: https://go-review.googlesource.com/120197
Reviewed-by: Bryan C. Mills <bcmills@google.com>
diff --git a/vendor/cmd/go/internal/modcmd/mod.go b/vendor/cmd/go/internal/modcmd/mod.go
index d120c27..b84aacf 100644
--- a/vendor/cmd/go/internal/modcmd/mod.go
+++ b/vendor/cmd/go/internal/modcmd/mod.go
@@ -6,14 +6,17 @@
 package modcmd
 
 import (
+	"bufio"
 	"encoding/json"
 	"fmt"
 	"os"
+	"sort"
 	"strings"
 
 	"cmd/go/internal/base"
 	"cmd/go/internal/modfile"
 	"cmd/go/internal/module"
+	"cmd/go/internal/par"
 	"cmd/go/internal/vgo"
 )
 
@@ -66,6 +69,11 @@
 rewrite the go.mod file. The only time this flag is needed is if no other
 flags are specified, as in 'go mod -fmt'.
 
+The -graph flag prints the module requirement graph (with replacements applied)
+in text form. Each line in the output has two space-separated fields: a module
+and one of its requirements. Each module is identified as a string of the form
+path@version, except for the main module, which has no @version suffix.
+
 The -json flag prints the go.mod file in JSON format corresponding to these
 Go types:
 
@@ -152,6 +160,7 @@
 
 	modFmt      = CmdMod.Flag.Bool("fmt", false, "")
 	modFix      = CmdMod.Flag.Bool("fix", false, "")
+	modGraph    = CmdMod.Flag.Bool("graph", false, "")
 	modJSON     = CmdMod.Flag.Bool("json", false, "")
 	modPackages = CmdMod.Flag.Bool("packages", false, "")
 	modSync     = CmdMod.Flag.Bool("sync", false, "")
@@ -198,6 +207,7 @@
 			*modJSON ||
 			*modFmt ||
 			*modFix ||
+			*modGraph ||
 			*modPackages ||
 			*modSync ||
 			len(modEdits) > 0
@@ -279,6 +289,10 @@
 		modPrintJSON()
 	}
 
+	if *modGraph {
+		modPrintGraph()
+	}
+
 	if *modPackages {
 		for _, pkg := range vgo.TargetPackages() {
 			fmt.Printf("%s\n", pkg)
@@ -450,3 +464,43 @@
 	data = append(data, '\n')
 	os.Stdout.Write(data)
 }
+
+// modPrintGraph prints the -graph output.
+func modPrintGraph() {
+	reqs := vgo.Reqs()
+
+	format := func(m module.Version) string {
+		if m.Version == "" {
+			return m.Path
+		}
+		return m.Path + "@" + m.Version
+	}
+
+	// Note: using par.Work only to manage work queue.
+	// No parallelism here, so no locking.
+	var out []string
+	var deps int // index in out where deps start
+	var work par.Work
+	work.Add(vgo.Target)
+	work.Do(1, func(item interface{}) {
+		m := item.(module.Version)
+		list, _ := reqs.Required(m)
+		for _, r := range list {
+			work.Add(r)
+			out = append(out, format(m)+" "+format(r)+"\n")
+		}
+		if m == vgo.Target {
+			deps = len(out)
+		}
+	})
+
+	sort.Slice(out[deps:], func(i, j int) bool {
+		return out[deps+j][0] < out[deps+j][0]
+	})
+
+	w := bufio.NewWriter(os.Stdout)
+	for _, line := range out {
+		w.WriteString(line)
+	}
+	w.Flush()
+}
diff --git a/vendor/cmd/go/internal/vgo/load.go b/vendor/cmd/go/internal/vgo/load.go
index 7fbfe1d..5a2fcf4 100644
--- a/vendor/cmd/go/internal/vgo/load.go
+++ b/vendor/cmd/go/internal/vgo/load.go
@@ -411,6 +411,11 @@
 	return r
 }
 
+// Reqs returns the module requirement graph.
+func Reqs() mvs.Reqs {
+	return newReqs()
+}
+
 func (r *mvsReqs) Required(mod module.Version) ([]module.Version, error) {
 	type cached struct {
 		list []module.Version