Source file src/pkg/cmd/go/internal/mvs/mvs.go
1
2
3
4
5
6
7 package mvs
8
9 import (
10 "fmt"
11 "sort"
12 "strings"
13 "sync"
14 "sync/atomic"
15
16 "cmd/go/internal/module"
17 "cmd/go/internal/par"
18 )
19
20
21
22
23
24
25
26
27
28
29
30 type Reqs interface {
31
32
33 Required(m module.Version) ([]module.Version, error)
34
35
36
37
38
39
40
41
42
43 Max(v1, v2 string) string
44
45
46
47
48
49
50
51
52
53
54
55
56 Upgrade(m module.Version) (module.Version, error)
57
58
59
60 Previous(m module.Version) (module.Version, error)
61 }
62
63
64
65
66 type BuildListError struct {
67 Err error
68 stack []buildListErrorElem
69 }
70
71 type buildListErrorElem struct {
72 m module.Version
73
74
75
76 nextReason string
77 }
78
79
80
81 func (e *BuildListError) Module() module.Version {
82 if len(e.stack) == 0 {
83 return module.Version{}
84 }
85 return e.stack[0].m
86 }
87
88 func (e *BuildListError) Error() string {
89 b := &strings.Builder{}
90 stack := e.stack
91
92
93
94
95 for len(stack) > 0 && stack[len(stack)-1].m.Version == "" {
96 stack = stack[:len(stack)-1]
97 }
98
99 for i := len(stack) - 1; i >= 1; i-- {
100 fmt.Fprintf(b, "%s@%s %s\n\t", stack[i].m.Path, stack[i].m.Version, stack[i].nextReason)
101 }
102 if len(stack) == 0 {
103 b.WriteString(e.Err.Error())
104 } else {
105
106
107 if _, ok := e.Err.(*module.ModuleError); ok {
108 fmt.Fprintf(b, "%v", e.Err)
109 } else {
110 fmt.Fprintf(b, "%v", module.VersionError(stack[0].m, e.Err))
111 }
112 }
113 return b.String()
114 }
115
116
117
118 func BuildList(target module.Version, reqs Reqs) ([]module.Version, error) {
119 return buildList(target, reqs, nil)
120 }
121
122 func buildList(target module.Version, reqs Reqs, upgrade func(module.Version) (module.Version, error)) ([]module.Version, error) {
123
124
125 type modGraphNode struct {
126 m module.Version
127 required []module.Version
128 upgrade module.Version
129 err error
130 }
131 var (
132 mu sync.Mutex
133 modGraph = map[module.Version]*modGraphNode{}
134 min = map[string]string{}
135 haveErr int32
136 )
137 setErr := func(n *modGraphNode, err error) {
138 n.err = err
139 atomic.StoreInt32(&haveErr, 1)
140 }
141
142 var work par.Work
143 work.Add(target)
144 work.Do(10, func(item interface{}) {
145 m := item.(module.Version)
146
147 node := &modGraphNode{m: m}
148 mu.Lock()
149 modGraph[m] = node
150 if v, ok := min[m.Path]; !ok || reqs.Max(v, m.Version) != v {
151 min[m.Path] = m.Version
152 }
153 mu.Unlock()
154
155 required, err := reqs.Required(m)
156 if err != nil {
157 setErr(node, err)
158 return
159 }
160 node.required = required
161 for _, r := range node.required {
162 work.Add(r)
163 }
164
165 if upgrade != nil {
166 u, err := upgrade(m)
167 if err != nil {
168 setErr(node, err)
169 return
170 }
171 if u != m {
172 node.upgrade = u
173 work.Add(u)
174 }
175 }
176 })
177
178
179
180 if haveErr != 0 {
181
182 neededBy := make(map[*modGraphNode]*modGraphNode)
183 q := make([]*modGraphNode, 0, len(modGraph))
184 q = append(q, modGraph[target])
185 for len(q) > 0 {
186 node := q[0]
187 q = q[1:]
188
189 if node.err != nil {
190 err := &BuildListError{
191 Err: node.err,
192 stack: []buildListErrorElem{{m: node.m}},
193 }
194 for n, prev := neededBy[node], node; n != nil; n, prev = neededBy[n], n {
195 reason := "requires"
196 if n.upgrade == prev.m {
197 reason = "updating to"
198 }
199 err.stack = append(err.stack, buildListErrorElem{m: n.m, nextReason: reason})
200 }
201 return nil, err
202 }
203
204 neighbors := node.required
205 if node.upgrade.Path != "" {
206 neighbors = append(neighbors, node.upgrade)
207 }
208 for _, neighbor := range neighbors {
209 nn := modGraph[neighbor]
210 if neededBy[nn] != nil {
211 continue
212 }
213 neededBy[nn] = node
214 q = append(q, nn)
215 }
216 }
217 }
218
219
220
221 if v := min[target.Path]; v != target.Version {
222
223
224
225
226
227 panic(fmt.Sprintf("mistake: chose version %q instead of target %+v", v, target))
228 }
229
230 list := []module.Version{target}
231 for path, vers := range min {
232 if path != target.Path {
233 list = append(list, module.Version{Path: path, Version: vers})
234 }
235
236 n := modGraph[module.Version{Path: path, Version: vers}]
237 required := n.required
238 for _, r := range required {
239 v := min[r.Path]
240 if r.Path != target.Path && reqs.Max(v, r.Version) != v {
241 panic(fmt.Sprintf("mistake: version %q does not satisfy requirement %+v", v, r))
242 }
243 }
244 }
245
246 tail := list[1:]
247 sort.Slice(tail, func(i, j int) bool {
248 return tail[i].Path < tail[j].Path
249 })
250 return list, nil
251 }
252
253
254
255
256 func Req(target module.Version, list []module.Version, base []string, reqs Reqs) ([]module.Version, error) {
257
258
259
260
261
262 var postorder []module.Version
263 reqCache := map[module.Version][]module.Version{}
264 reqCache[target] = nil
265 var walk func(module.Version) error
266 walk = func(m module.Version) error {
267 _, ok := reqCache[m]
268 if ok {
269 return nil
270 }
271 required, err := reqs.Required(m)
272 if err != nil {
273 return err
274 }
275 reqCache[m] = required
276 for _, m1 := range required {
277 if err := walk(m1); err != nil {
278 return err
279 }
280 }
281 postorder = append(postorder, m)
282 return nil
283 }
284 for _, m := range list {
285 if err := walk(m); err != nil {
286 return nil, err
287 }
288 }
289
290
291 have := map[module.Version]bool{}
292 walk = func(m module.Version) error {
293 if have[m] {
294 return nil
295 }
296 have[m] = true
297 for _, m1 := range reqCache[m] {
298 walk(m1)
299 }
300 return nil
301 }
302 max := map[string]string{}
303 for _, m := range list {
304 if v, ok := max[m.Path]; ok {
305 max[m.Path] = reqs.Max(m.Version, v)
306 } else {
307 max[m.Path] = m.Version
308 }
309 }
310
311 var min []module.Version
312 for _, path := range base {
313 m := module.Version{Path: path, Version: max[path]}
314 min = append(min, m)
315 walk(m)
316 }
317
318 for i := len(postorder) - 1; i >= 0; i-- {
319 m := postorder[i]
320 if max[m.Path] != m.Version {
321
322 continue
323 }
324 if !have[m] {
325 min = append(min, m)
326 walk(m)
327 }
328 }
329 sort.Slice(min, func(i, j int) bool {
330 return min[i].Path < min[j].Path
331 })
332 return min, nil
333 }
334
335
336
337 func UpgradeAll(target module.Version, reqs Reqs) ([]module.Version, error) {
338 return buildList(target, reqs, func(m module.Version) (module.Version, error) {
339 if m.Path == target.Path {
340 return target, nil
341 }
342
343 return reqs.Upgrade(m)
344 })
345 }
346
347
348
349 func Upgrade(target module.Version, reqs Reqs, upgrade ...module.Version) ([]module.Version, error) {
350 list, err := reqs.Required(target)
351 if err != nil {
352 return nil, err
353 }
354
355
356
357 list = append([]module.Version(nil), list...)
358 list = append(list, upgrade...)
359 return BuildList(target, &override{target, list, reqs})
360 }
361
362
363
364
365
366
367
368 func Downgrade(target module.Version, reqs Reqs, downgrade ...module.Version) ([]module.Version, error) {
369 list, err := reqs.Required(target)
370 if err != nil {
371 return nil, err
372 }
373 max := make(map[string]string)
374 for _, r := range list {
375 max[r.Path] = r.Version
376 }
377 for _, d := range downgrade {
378 if v, ok := max[d.Path]; !ok || reqs.Max(v, d.Version) != d.Version {
379 max[d.Path] = d.Version
380 }
381 }
382
383 var (
384 added = make(map[module.Version]bool)
385 rdeps = make(map[module.Version][]module.Version)
386 excluded = make(map[module.Version]bool)
387 )
388 var exclude func(module.Version)
389 exclude = func(m module.Version) {
390 if excluded[m] {
391 return
392 }
393 excluded[m] = true
394 for _, p := range rdeps[m] {
395 exclude(p)
396 }
397 }
398 var add func(module.Version)
399 add = func(m module.Version) {
400 if added[m] {
401 return
402 }
403 added[m] = true
404 if v, ok := max[m.Path]; ok && reqs.Max(m.Version, v) != v {
405 exclude(m)
406 return
407 }
408 list, err := reqs.Required(m)
409 if err != nil {
410
411
412
413
414
415
416
417
418
419
420 exclude(m)
421 }
422 for _, r := range list {
423 add(r)
424 if excluded[r] {
425 exclude(m)
426 return
427 }
428 rdeps[r] = append(rdeps[r], m)
429 }
430 }
431
432 var out []module.Version
433 out = append(out, target)
434 List:
435 for _, r := range list {
436 add(r)
437 for excluded[r] {
438 p, err := reqs.Previous(r)
439 if err != nil {
440
441
442
443
444
445 return nil, err
446 }
447
448
449
450
451 if v := max[r.Path]; reqs.Max(v, r.Version) != v && reqs.Max(p.Version, v) != p.Version {
452 p.Version = v
453 }
454 if p.Version == "none" {
455 continue List
456 }
457 add(p)
458 r = p
459 }
460 out = append(out, r)
461 }
462
463 return out, nil
464 }
465
466 type override struct {
467 target module.Version
468 list []module.Version
469 Reqs
470 }
471
472 func (r *override) Required(m module.Version) ([]module.Version, error) {
473 if m == r.target {
474 return r.list, nil
475 }
476 return r.Reqs.Required(m)
477 }
478
View as plain text