1
2
3
4
5 package modload
6
7 import (
8 "context"
9 "errors"
10 "fmt"
11 "os"
12 "runtime"
13 "strings"
14
15 "cmd/go/internal/base"
16 "cmd/go/internal/cfg"
17 "cmd/go/internal/modinfo"
18 "cmd/go/internal/search"
19
20 "golang.org/x/mod/module"
21 )
22
23 type ListMode int
24
25 const (
26 ListU ListMode = 1 << iota
27 ListRetracted
28 ListDeprecated
29 ListVersions
30 ListRetractedVersions
31 )
32
33
34
35
36
37 func ListModules(ctx context.Context, args []string, mode ListMode) ([]*modinfo.ModulePublic, error) {
38 rs, mods, err := listModules(ctx, LoadModFile(ctx), args, mode)
39
40 type token struct{}
41 sem := make(chan token, runtime.GOMAXPROCS(0))
42 if mode != 0 {
43 for _, m := range mods {
44 add := func(m *modinfo.ModulePublic) {
45 sem <- token{}
46 go func() {
47 if mode&ListU != 0 {
48 addUpdate(ctx, m)
49 }
50 if mode&ListVersions != 0 {
51 addVersions(ctx, m, mode&ListRetractedVersions != 0)
52 }
53 if mode&ListRetracted != 0 {
54 addRetraction(ctx, m)
55 }
56 if mode&ListDeprecated != 0 {
57 addDeprecation(ctx, m)
58 }
59 <-sem
60 }()
61 }
62
63 add(m)
64 if m.Replace != nil {
65 add(m.Replace)
66 }
67 }
68 }
69
70 for n := cap(sem); n > 0; n-- {
71 sem <- token{}
72 }
73
74 if err == nil {
75 requirements = rs
76 if !ExplicitWriteGoMod {
77 err = commitRequirements(ctx)
78 }
79 }
80 return mods, err
81 }
82
83 func listModules(ctx context.Context, rs *Requirements, args []string, mode ListMode) (_ *Requirements, mods []*modinfo.ModulePublic, mgErr error) {
84 if len(args) == 0 {
85 var ms []*modinfo.ModulePublic
86 for _, m := range MainModules.Versions() {
87 ms = append(ms, moduleInfo(ctx, rs, m, mode))
88 }
89 return rs, ms, nil
90 }
91
92 needFullGraph := false
93 for _, arg := range args {
94 if strings.Contains(arg, `\`) {
95 base.Fatalf("go: module paths never use backslash")
96 }
97 if search.IsRelativePath(arg) {
98 base.Fatalf("go: cannot use relative path %s to specify module", arg)
99 }
100 if arg == "all" || strings.Contains(arg, "...") {
101 needFullGraph = true
102 if !HasModRoot() {
103 base.Fatalf("go: cannot match %q: %v", arg, ErrNoModRoot)
104 }
105 continue
106 }
107 if i := strings.Index(arg, "@"); i >= 0 {
108 path := arg[:i]
109 vers := arg[i+1:]
110 if vers == "upgrade" || vers == "patch" {
111 if _, ok := rs.rootSelected(path); !ok || rs.pruning == unpruned {
112 needFullGraph = true
113 if !HasModRoot() {
114 base.Fatalf("go: cannot match %q: %v", arg, ErrNoModRoot)
115 }
116 }
117 }
118 continue
119 }
120 if _, ok := rs.rootSelected(arg); !ok || rs.pruning == unpruned {
121 needFullGraph = true
122 if mode&ListVersions == 0 && !HasModRoot() {
123 base.Fatalf("go: cannot match %q without -versions or an explicit version: %v", arg, ErrNoModRoot)
124 }
125 }
126 }
127
128 var mg *ModuleGraph
129 if needFullGraph {
130 rs, mg, mgErr = expandGraph(ctx, rs)
131 }
132
133 matchedModule := map[module.Version]bool{}
134 for _, arg := range args {
135 if i := strings.Index(arg, "@"); i >= 0 {
136 path := arg[:i]
137 vers := arg[i+1:]
138
139 var current string
140 if mg == nil {
141 current, _ = rs.rootSelected(path)
142 } else {
143 current = mg.Selected(path)
144 }
145 if current == "none" && mgErr != nil {
146 if vers == "upgrade" || vers == "patch" {
147
148
149
150 continue
151 }
152 }
153
154 allowed := CheckAllowed
155 if IsRevisionQuery(vers) || mode&ListRetracted != 0 {
156
157
158 allowed = nil
159 }
160 info, err := Query(ctx, path, vers, current, allowed)
161 if err != nil {
162 mods = append(mods, &modinfo.ModulePublic{
163 Path: path,
164 Version: vers,
165 Error: modinfoError(path, vers, err),
166 })
167 continue
168 }
169
170
171
172 var noRS *Requirements
173
174 mod := moduleInfo(ctx, noRS, module.Version{Path: path, Version: info.Version}, mode)
175 mods = append(mods, mod)
176 continue
177 }
178
179
180 var match func(string) bool
181 if arg == "all" {
182 match = func(string) bool { return true }
183 } else if strings.Contains(arg, "...") {
184 match = search.MatchPattern(arg)
185 } else {
186 var v string
187 if mg == nil {
188 var ok bool
189 v, ok = rs.rootSelected(arg)
190 if !ok {
191
192
193 panic(fmt.Sprintf("internal error: root requirement expected but not found for %v", arg))
194 }
195 } else {
196 v = mg.Selected(arg)
197 }
198 if v == "none" && mgErr != nil {
199
200 continue
201 }
202 if v != "none" {
203 mods = append(mods, moduleInfo(ctx, rs, module.Version{Path: arg, Version: v}, mode))
204 } else if cfg.BuildMod == "vendor" {
205
206
207
208 mods = append(mods, &modinfo.ModulePublic{
209 Path: arg,
210 Error: modinfoError(arg, "", errors.New("can't resolve module using the vendor directory\n\t(Use -mod=mod or -mod=readonly to bypass.)")),
211 })
212 } else if mode&ListVersions != 0 {
213
214
215
216 mods = append(mods, &modinfo.ModulePublic{Path: arg})
217 } else {
218 mods = append(mods, &modinfo.ModulePublic{
219 Path: arg,
220 Error: modinfoError(arg, "", errors.New("not a known dependency")),
221 })
222 }
223 continue
224 }
225
226 matched := false
227 for _, m := range mg.BuildList() {
228 if match(m.Path) {
229 matched = true
230 if !matchedModule[m] {
231 matchedModule[m] = true
232 mods = append(mods, moduleInfo(ctx, rs, m, mode))
233 }
234 }
235 }
236 if !matched {
237 fmt.Fprintf(os.Stderr, "warning: pattern %q matched no module dependencies\n", arg)
238 }
239 }
240
241 return rs, mods, mgErr
242 }
243
244
245
246 func modinfoError(path, vers string, err error) *modinfo.ModuleError {
247 var nerr *NoMatchingVersionError
248 var merr *module.ModuleError
249 if errors.As(err, &nerr) {
250
251
252 err = &module.ModuleError{Path: path, Err: err}
253 } else if !errors.As(err, &merr) {
254
255
256 err = &module.ModuleError{Path: path, Version: vers, Err: err}
257 }
258
259 return &modinfo.ModuleError{Err: err.Error()}
260 }
261
View as plain text