1
2
3
4
5 package mvs
6
7 import (
8 "fmt"
9 "strings"
10
11 "golang.org/x/mod/module"
12 )
13
14
15
16
17 type BuildListError struct {
18 Err error
19 stack []buildListErrorElem
20 }
21
22 type buildListErrorElem struct {
23 m module.Version
24
25
26
27 nextReason string
28 }
29
30
31
32
33
34
35
36
37
38 func NewBuildListError(err error, path []module.Version, isVersionChange func(from, to module.Version) bool) *BuildListError {
39 stack := make([]buildListErrorElem, 0, len(path))
40 for len(path) > 1 {
41 reason := "requires"
42 if isVersionChange != nil && isVersionChange(path[0], path[1]) {
43 reason = "updating to"
44 }
45 stack = append(stack, buildListErrorElem{
46 m: path[0],
47 nextReason: reason,
48 })
49 path = path[1:]
50 }
51 stack = append(stack, buildListErrorElem{m: path[0]})
52
53 return &BuildListError{
54 Err: err,
55 stack: stack,
56 }
57 }
58
59
60
61 func (e *BuildListError) Module() module.Version {
62 if len(e.stack) == 0 {
63 return module.Version{}
64 }
65 return e.stack[len(e.stack)-1].m
66 }
67
68 func (e *BuildListError) Error() string {
69 b := &strings.Builder{}
70 stack := e.stack
71
72
73
74
75 for len(stack) > 0 && stack[0].m.Version == "" {
76 stack = stack[1:]
77 }
78
79 if len(stack) == 0 {
80 b.WriteString(e.Err.Error())
81 } else {
82 for _, elem := range stack[:len(stack)-1] {
83 fmt.Fprintf(b, "%s %s\n\t", elem.m, elem.nextReason)
84 }
85
86
87 m := stack[len(stack)-1].m
88 if mErr, ok := e.Err.(*module.ModuleError); ok {
89 actual := module.Version{Path: mErr.Path, Version: mErr.Version}
90 if v, ok := mErr.Err.(*module.InvalidVersionError); ok {
91 actual.Version = v.Version
92 }
93 if actual == m {
94 fmt.Fprintf(b, "%v", e.Err)
95 } else {
96 fmt.Fprintf(b, "%s (replaced by %s): %v", m, actual, mErr.Err)
97 }
98 } else {
99 fmt.Fprintf(b, "%v", module.VersionError(m, e.Err))
100 }
101 }
102 return b.String()
103 }
104
View as plain text