]>
Commit | Line | Data |
---|---|---|
dd931d9b ILT |
1 | // Copyright 2018 The Go Authors. All rights reserved. |
2 | // Use of this source code is governed by a BSD-style | |
3 | // license that can be found in the LICENSE file. | |
4 | ||
5 | // go mod graph | |
6 | ||
7 | package modcmd | |
8 | ||
9 | import ( | |
10 | "bufio" | |
11 | "os" | |
12 | "sort" | |
13 | ||
14 | "cmd/go/internal/base" | |
5a8ea165 | 15 | "cmd/go/internal/cfg" |
dd931d9b | 16 | "cmd/go/internal/modload" |
dd931d9b | 17 | "cmd/go/internal/par" |
5a8ea165 ILT |
18 | "cmd/go/internal/work" |
19 | ||
20 | "golang.org/x/mod/module" | |
dd931d9b ILT |
21 | ) |
22 | ||
23 | var cmdGraph = &base.Command{ | |
24 | UsageLine: "go mod graph", | |
25 | Short: "print module requirement graph", | |
26 | Long: ` | |
27 | Graph prints the module requirement graph (with replacements applied) | |
28 | in text form. Each line in the output has two space-separated fields: a module | |
29 | and one of its requirements. Each module is identified as a string of the form | |
30 | path@version, except for the main module, which has no @version suffix. | |
31 | `, | |
32 | Run: runGraph, | |
33 | } | |
34 | ||
5a8ea165 ILT |
35 | func init() { |
36 | work.AddModCommonFlags(cmdGraph) | |
37 | } | |
38 | ||
dd931d9b ILT |
39 | func runGraph(cmd *base.Command, args []string) { |
40 | if len(args) > 0 { | |
41 | base.Fatalf("go mod graph: graph takes no arguments") | |
42 | } | |
aa8901e9 ILT |
43 | // Checks go mod expected behavior |
44 | if !modload.Enabled() { | |
45 | if cfg.Getenv("GO111MODULE") == "off" { | |
46 | base.Fatalf("go: modules disabled by GO111MODULE=off; see 'go help modules'") | |
47 | } else { | |
48 | base.Fatalf("go: cannot find main module; see 'go help modules'") | |
49 | } | |
50 | } | |
dd931d9b ILT |
51 | modload.LoadBuildList() |
52 | ||
53 | reqs := modload.MinReqs() | |
54 | format := func(m module.Version) string { | |
55 | if m.Version == "" { | |
56 | return m.Path | |
57 | } | |
58 | return m.Path + "@" + m.Version | |
59 | } | |
60 | ||
61 | // Note: using par.Work only to manage work queue. | |
62 | // No parallelism here, so no locking. | |
63 | var out []string | |
64 | var deps int // index in out where deps start | |
65 | var work par.Work | |
66 | work.Add(modload.Target) | |
67 | work.Do(1, func(item interface{}) { | |
68 | m := item.(module.Version) | |
69 | list, _ := reqs.Required(m) | |
70 | for _, r := range list { | |
71 | work.Add(r) | |
72 | out = append(out, format(m)+" "+format(r)+"\n") | |
73 | } | |
74 | if m == modload.Target { | |
75 | deps = len(out) | |
76 | } | |
77 | }) | |
78 | ||
79 | sort.Slice(out[deps:], func(i, j int) bool { | |
80 | return out[deps+i][0] < out[deps+j][0] | |
81 | }) | |
82 | ||
83 | w := bufio.NewWriter(os.Stdout) | |
84 | for _, line := range out { | |
85 | w.WriteString(line) | |
86 | } | |
87 | w.Flush() | |
88 | } |