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 commitRequirements(ctx, modFileGoVersion(), rs)
76 }
77 return mods, err
78 }
79
80 func listModules(ctx context.Context, rs *Requirements, args []string, mode ListMode) (_ *Requirements, mods []*modinfo.ModulePublic, mgErr error) {
81 if len(args) == 0 {
82 return rs, []*modinfo.ModulePublic{moduleInfo(ctx, rs, Target, mode)}, nil
83 }
84
85 needFullGraph := false
86 for _, arg := range args {
87 if strings.Contains(arg, `\`) {
88 base.Fatalf("go: module paths never use backslash")
89 }
90 if search.IsRelativePath(arg) {
91 base.Fatalf("go: cannot use relative path %s to specify module", arg)
92 }
93 if arg == "all" || strings.Contains(arg, "...") {
94 needFullGraph = true
95 if !HasModRoot() {
96 base.Fatalf("go: cannot match %q: %v", arg, ErrNoModRoot)
97 }
98 continue
99 }
100 if i := strings.Index(arg, "@"); i >= 0 {
101 path := arg[:i]
102 vers := arg[i+1:]
103 if vers == "upgrade" || vers == "patch" {
104 if _, ok := rs.rootSelected(path); !ok || rs.depth == eager {
105 needFullGraph = true
106 if !HasModRoot() {
107 base.Fatalf("go: cannot match %q: %v", arg, ErrNoModRoot)
108 }
109 }
110 }
111 continue
112 }
113 if _, ok := rs.rootSelected(arg); !ok || rs.depth == eager {
114 needFullGraph = true
115 if mode&ListVersions == 0 && !HasModRoot() {
116 base.Fatalf("go: cannot match %q without -versions or an explicit version: %v", arg, ErrNoModRoot)
117 }
118 }
119 }
120
121 var mg *ModuleGraph
122 if needFullGraph {
123 rs, mg, mgErr = expandGraph(ctx, rs)
124 }
125
126 matchedModule := map[module.Version]bool{}
127 for _, arg := range args {
128 if i := strings.Index(arg, "@"); i >= 0 {
129 path := arg[:i]
130 vers := arg[i+1:]
131
132 var current string
133 if mg == nil {
134 current, _ = rs.rootSelected(path)
135 } else {
136 current = mg.Selected(path)
137 }
138 if current == "none" && mgErr != nil {
139 if vers == "upgrade" || vers == "patch" {
140
141
142
143 continue
144 }
145 }
146
147 allowed := CheckAllowed
148 if IsRevisionQuery(vers) || mode&ListRetracted != 0 {
149
150
151 allowed = nil
152 }
153 info, err := Query(ctx, path, vers, current, allowed)
154 if err != nil {
155 mods = append(mods, &modinfo.ModulePublic{
156 Path: path,
157 Version: vers,
158 Error: modinfoError(path, vers, err),
159 })
160 continue
161 }
162
163
164
165 var noRS *Requirements
166
167 mod := moduleInfo(ctx, noRS, module.Version{Path: path, Version: info.Version}, mode)
168 mods = append(mods, mod)
169 continue
170 }
171
172
173 var match func(string) bool
174 if arg == "all" {
175 match = func(string) bool { return true }
176 } else if strings.Contains(arg, "...") {
177 match = search.MatchPattern(arg)
178 } else {
179 var v string
180 if mg == nil {
181 var ok bool
182 v, ok = rs.rootSelected(arg)
183 if !ok {
184
185
186 panic(fmt.Sprintf("internal error: root requirement expected but not found for %v", arg))
187 }
188 } else {
189 v = mg.Selected(arg)
190 }
191 if v == "none" && mgErr != nil {
192
193 continue
194 }
195 if v != "none" {
196 mods = append(mods, moduleInfo(ctx, rs, module.Version{Path: arg, Version: v}, mode))
197 } else if cfg.BuildMod == "vendor" {
198
199
200
201 mods = append(mods, &modinfo.ModulePublic{
202 Path: arg,
203 Error: modinfoError(arg, "", errors.New("can't resolve module using the vendor directory\n\t(Use -mod=mod or -mod=readonly to bypass.)")),
204 })
205 } else if mode&ListVersions != 0 {
206
207
208
209 mods = append(mods, &modinfo.ModulePublic{Path: arg})
210 } else {
211 mods = append(mods, &modinfo.ModulePublic{
212 Path: arg,
213 Error: modinfoError(arg, "", errors.New("not a known dependency")),
214 })
215 }
216 continue
217 }
218
219 matched := false
220 for _, m := range mg.BuildList() {
221 if match(m.Path) {
222 matched = true
223 if !matchedModule[m] {
224 matchedModule[m] = true
225 mods = append(mods, moduleInfo(ctx, rs, m, mode))
226 }
227 }
228 }
229 if !matched {
230 fmt.Fprintf(os.Stderr, "warning: pattern %q matched no module dependencies\n", arg)
231 }
232 }
233
234 return rs, mods, mgErr
235 }
236
237
238
239 func modinfoError(path, vers string, err error) *modinfo.ModuleError {
240 var nerr *NoMatchingVersionError
241 var merr *module.ModuleError
242 if errors.As(err, &nerr) {
243
244
245 err = &module.ModuleError{Path: path, Err: err}
246 } else if !errors.As(err, &merr) {
247
248
249 err = &module.ModuleError{Path: path, Version: vers, Err: err}
250 }
251
252 return &modinfo.ModuleError{Err: err.Error()}
253 }
254
View as plain text