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