1
2
3
4
5
6
7 package modcmd
8
9 import (
10 "bufio"
11 "context"
12 "os"
13
14 "cmd/go/internal/base"
15 "cmd/go/internal/modload"
16
17 "golang.org/x/mod/module"
18 )
19
20 var cmdGraph = &base.Command{
21 UsageLine: "go mod graph [-go=version]",
22 Short: "print module requirement graph",
23 Long: `
24 Graph prints the module requirement graph (with replacements applied)
25 in text form. Each line in the output has two space-separated fields: a module
26 and one of its requirements. Each module is identified as a string of the form
27 path@version, except for the main module, which has no @version suffix.
28
29 The -go flag causes graph to report the module graph as loaded by the
30 given Go version, instead of the version indicated by the 'go' directive
31 in the go.mod file.
32
33 See https://golang.org/ref/mod#go-mod-graph for more about 'go mod graph'.
34 `,
35 Run: runGraph,
36 }
37
38 var (
39 graphGo goVersionFlag
40 )
41
42 func init() {
43 cmdGraph.Flag.Var(&graphGo, "go", "")
44 base.AddModCommonFlags(&cmdGraph.Flag)
45 }
46
47 func runGraph(ctx context.Context, cmd *base.Command, args []string) {
48 modload.InitWorkfile()
49
50 if len(args) > 0 {
51 base.Fatalf("go: 'go mod graph' accepts no arguments")
52 }
53 modload.ForceUseModules = true
54 modload.RootMode = modload.NeedRoot
55 mg := modload.LoadModGraph(ctx, graphGo.String())
56
57 w := bufio.NewWriter(os.Stdout)
58 defer w.Flush()
59
60 format := func(m module.Version) {
61 w.WriteString(m.Path)
62 if m.Version != "" {
63 w.WriteString("@")
64 w.WriteString(m.Version)
65 }
66 }
67
68 mg.WalkBreadthFirst(func(m module.Version) {
69 reqs, _ := mg.RequiredBy(m)
70 for _, r := range reqs {
71 format(m)
72 w.WriteByte(' ')
73 format(r)
74 w.WriteByte('\n')
75 }
76 })
77 }
78
View as plain text