1
2
3
4
5 package modget
6
7 import (
8 "fmt"
9 "path/filepath"
10 "regexp"
11 "strings"
12 "sync"
13
14 "cmd/go/internal/base"
15 "cmd/go/internal/modload"
16 "cmd/go/internal/search"
17 "cmd/go/internal/str"
18
19 "golang.org/x/mod/module"
20 )
21
22
23
24 type query struct {
25
26 raw string
27
28
29 rawVersion string
30
31
32
33
34
35
36
37 pattern string
38
39
40
41
42
43
44 patternIsLocal bool
45
46
47
48
49 version string
50
51
52
53
54 matchWildcard func(path string) bool
55
56
57
58
59 canMatchWildcardInModule func(mPath string) bool
60
61
62
63
64 conflict *query
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83 candidates []pathSet
84 candidatesMu sync.Mutex
85
86
87
88 pathSeen sync.Map
89
90
91
92
93
94
95
96 resolved []module.Version
97
98
99
100 matchesPackages bool
101 }
102
103
104
105 type pathSet struct {
106
107
108
109
110
111
112
113 path string
114
115
116
117
118
119 pkgMods []module.Version
120
121
122
123
124
125
126
127
128
129 mod module.Version
130
131 err error
132 }
133
134
135 func errSet(err error) pathSet { return pathSet{err: err} }
136
137
138
139 func newQuery(raw string) (*query, error) {
140 pattern := raw
141 rawVers := ""
142 if i := strings.Index(raw, "@"); i >= 0 {
143 pattern, rawVers = raw[:i], raw[i+1:]
144 if strings.Contains(rawVers, "@") || rawVers == "" {
145 return nil, fmt.Errorf("invalid module version syntax %q", raw)
146 }
147 }
148
149
150
151 version := rawVers
152 if version == "" {
153 if getU.version == "" {
154 version = "upgrade"
155 } else {
156 version = getU.version
157 }
158 }
159
160 q := &query{
161 raw: raw,
162 rawVersion: rawVers,
163 pattern: pattern,
164 patternIsLocal: filepath.IsAbs(pattern) || search.IsRelativePath(pattern),
165 version: version,
166 }
167 if strings.Contains(q.pattern, "...") {
168 q.matchWildcard = search.MatchPattern(q.pattern)
169 q.canMatchWildcardInModule = search.TreeCanMatchPattern(q.pattern)
170 }
171 if err := q.validate(); err != nil {
172 return q, err
173 }
174 return q, nil
175 }
176
177
178 func (q *query) validate() error {
179 if q.patternIsLocal {
180 if q.rawVersion != "" {
181 return fmt.Errorf("can't request explicit version %q of path %q in main module", q.rawVersion, q.pattern)
182 }
183 return nil
184 }
185
186 if q.pattern == "all" {
187
188 if !modload.HasModRoot() {
189 return fmt.Errorf(`cannot match "all": %v`, modload.ErrNoModRoot)
190 }
191 if !versionOkForMainModule(q.version) {
192
193
194
195 return &modload.QueryUpgradesAllError{
196 MainModules: modload.MainModules.Versions(),
197 Query: q.version,
198 }
199 }
200 }
201
202 if search.IsMetaPackage(q.pattern) && q.pattern != "all" {
203 if q.pattern != q.raw {
204 return fmt.Errorf("can't request explicit version of standard-library pattern %q", q.pattern)
205 }
206 }
207
208 return nil
209 }
210
211
212 func (q *query) String() string { return q.raw }
213
214
215 func (q *query) ResolvedString(m module.Version) string {
216 if m.Path != q.pattern {
217 if m.Version != q.version {
218 return fmt.Sprintf("%v (matching %s@%s)", m, q.pattern, q.version)
219 }
220 return fmt.Sprintf("%v (matching %v)", m, q)
221 }
222 if m.Version != q.version {
223 return fmt.Sprintf("%s@%s (%s)", q.pattern, q.version, m.Version)
224 }
225 return q.String()
226 }
227
228
229 func (q *query) isWildcard() bool {
230 return q.matchWildcard != nil || (q.patternIsLocal && strings.Contains(q.pattern, "..."))
231 }
232
233
234 func (q *query) matchesPath(path string) bool {
235 if q.matchWildcard != nil {
236 return q.matchWildcard(path)
237 }
238 return path == q.pattern
239 }
240
241
242
243 func (q *query) canMatchInModule(mPath string) bool {
244 if q.canMatchWildcardInModule != nil {
245 return q.canMatchWildcardInModule(mPath)
246 }
247 return str.HasPathPrefix(q.pattern, mPath)
248 }
249
250
251
252
253
254
255
256
257
258
259 func (q *query) pathOnce(path string, f func() pathSet) {
260 if _, dup := q.pathSeen.LoadOrStore(path, nil); dup {
261 return
262 }
263
264 cs := f()
265
266 if len(cs.pkgMods) > 0 || cs.mod != (module.Version{}) || cs.err != nil {
267 cs.path = path
268 q.candidatesMu.Lock()
269 q.candidates = append(q.candidates, cs)
270 q.candidatesMu.Unlock()
271 }
272 }
273
274
275 func reportError(q *query, err error) {
276 errStr := err.Error()
277
278
279
280
281
282
283
284 patternRE := regexp.MustCompile("(?m)(?:[ \t(\"`]|^)" + regexp.QuoteMeta(q.pattern) + "(?:[ @:;)\"`]|$)")
285 if patternRE.MatchString(errStr) {
286 if q.rawVersion == "" {
287 base.Errorf("go: %s", errStr)
288 return
289 }
290
291 versionRE := regexp.MustCompile("(?m)(?:[ @(\"`]|^)" + regexp.QuoteMeta(q.version) + "(?:[ :;)\"`]|$)")
292 if versionRE.MatchString(errStr) {
293 base.Errorf("go: %s", errStr)
294 return
295 }
296 }
297
298 if qs := q.String(); qs != "" {
299 base.Errorf("go: %s: %s", qs, errStr)
300 } else {
301 base.Errorf("go: %s", errStr)
302 }
303 }
304
305 func reportConflict(pq *query, m module.Version, conflict versionReason) {
306 if pq.conflict != nil {
307
308
309 return
310 }
311 pq.conflict = conflict.reason
312
313 proposed := versionReason{
314 version: m.Version,
315 reason: pq,
316 }
317 if pq.isWildcard() && !conflict.reason.isWildcard() {
318
319 proposed, conflict = conflict, proposed
320 }
321 reportError(pq, &conflictError{
322 mPath: m.Path,
323 proposed: proposed,
324 conflict: conflict,
325 })
326 }
327
328 type conflictError struct {
329 mPath string
330 proposed versionReason
331 conflict versionReason
332 }
333
334 func (e *conflictError) Error() string {
335 argStr := func(q *query, v string) string {
336 if v != q.version {
337 return fmt.Sprintf("%s@%s (%s)", q.pattern, q.version, v)
338 }
339 return q.String()
340 }
341
342 pq := e.proposed.reason
343 rq := e.conflict.reason
344 modDetail := ""
345 if e.mPath != pq.pattern {
346 modDetail = fmt.Sprintf("for module %s, ", e.mPath)
347 }
348
349 return fmt.Sprintf("%s%s conflicts with %s",
350 modDetail,
351 argStr(pq, e.proposed.version),
352 argStr(rq, e.conflict.version))
353 }
354
355 func versionOkForMainModule(version string) bool {
356 return version == "upgrade" || version == "patch"
357 }
358
View as plain text