9
9
"cmd/go/internal/cfg"
10
10
"fmt"
11
11
"go/build"
12
- "log"
13
12
"os"
14
13
"path"
15
14
"path/filepath"
@@ -22,6 +21,35 @@ type Match struct {
22
21
Pattern string // the pattern itself
23
22
Literal bool // whether it is a literal (no wildcards)
24
23
Pkgs []string // matching packages (dirs or import paths)
24
+ Errs []error // errors matching the patterns to packages, NOT errors loading those packages
25
+
26
+ // Errs may be non-empty even if len(Pkgs) > 0, indicating that some matching
27
+ // packages could be located but results may be incomplete.
28
+ // If len(Pkgs) == 0 && len(Errs) == 0, the pattern is well-formed but did not
29
+ // match any packages.
30
+ }
31
+
32
+ // AddError appends a MatchError wrapping err to m.Errs.
33
+ func (m * Match ) AddError (err error ) {
34
+ m .Errs = append (m .Errs , & MatchError {Match : m , Err : err })
35
+ }
36
+
37
+ // A MatchError indicates an error that occurred while attempting to match a
38
+ // pattern.
39
+ type MatchError struct {
40
+ * Match
41
+ Err error
42
+ }
43
+
44
+ func (e * MatchError ) Error () string {
45
+ if e .Literal {
46
+ return fmt .Sprintf ("matching %s: %v" , e .Pattern , e .Err )
47
+ }
48
+ return fmt .Sprintf ("pattern %s: %v" , e .Pattern , e .Err )
49
+ }
50
+
51
+ func (e * MatchError ) Unwrap () error {
52
+ return e .Err
25
53
}
26
54
27
55
// MatchPackages returns all the packages that can be found
@@ -56,7 +84,7 @@ func MatchPackages(pattern string) *Match {
56
84
if pattern == "cmd" {
57
85
root += "cmd" + string (filepath .Separator )
58
86
}
59
- filepath .Walk (root , func (path string , fi os.FileInfo , err error ) error {
87
+ err := filepath .Walk (root , func (path string , fi os.FileInfo , err error ) error {
60
88
if err != nil || path == src {
61
89
return nil
62
90
}
@@ -100,21 +128,29 @@ func MatchPackages(pattern string) *Match {
100
128
pkg , err := cfg .BuildContext .ImportDir (path , 0 )
101
129
if err != nil {
102
130
if _ , noGo := err .(* build.NoGoError ); noGo {
131
+ // The package does not actually exist, so record neither the package
132
+ // nor the error.
103
133
return nil
104
134
}
135
+ // There was an error importing path, but not matching it,
136
+ // which is all that Match promises to do.
137
+ // Ignore the import error.
105
138
}
106
139
107
140
// If we are expanding "cmd", skip main
108
141
// packages under cmd/vendor. At least as of
109
142
// March, 2017, there is one there for the
110
143
// vendored pprof tool.
111
- if pattern == "cmd" && strings .HasPrefix (pkg .ImportPath , "cmd/vendor" ) && pkg .Name == "main" {
144
+ if pattern == "cmd" && pkg != nil && strings .HasPrefix (pkg .ImportPath , "cmd/vendor" ) && pkg .Name == "main" {
112
145
return nil
113
146
}
114
147
115
148
m .Pkgs = append (m .Pkgs , name )
116
149
return nil
117
150
})
151
+ if err != nil {
152
+ m .AddError (err )
153
+ }
118
154
}
119
155
return m
120
156
}
@@ -166,15 +202,16 @@ func MatchPackagesInFS(pattern string) *Match {
166
202
if modRoot != "" {
167
203
abs , err := filepath .Abs (dir )
168
204
if err != nil {
169
- base .Fatalf ("go: %v" , err )
205
+ m .AddError (err )
206
+ return m
170
207
}
171
208
if ! hasFilepathPrefix (abs , modRoot ) {
172
- base . Fatalf ( "go: pattern %s refers to dir %s, outside module root %s " , pattern , abs , modRoot )
173
- return nil
209
+ m . AddError ( fmt . Errorf ( "directory %s is outside module root (%s) " , abs , modRoot ) )
210
+ return m
174
211
}
175
212
}
176
213
177
- filepath .Walk (dir , func (path string , fi os.FileInfo , err error ) error {
214
+ err := filepath .Walk (dir , func (path string , fi os.FileInfo , err error ) error {
178
215
if err != nil || ! fi .IsDir () {
179
216
return nil
180
217
}
@@ -218,14 +255,21 @@ func MatchPackagesInFS(pattern string) *Match {
218
255
// behavior means people miss serious mistakes.
219
256
// See golang.org/issue/11407.
220
257
if p , err := cfg .BuildContext .ImportDir (path , 0 ); err != nil && (p == nil || len (p .InvalidGoFiles ) == 0 ) {
221
- if _ , noGo := err .(* build.NoGoError ); ! noGo {
222
- log .Print (err )
258
+ if _ , noGo := err .(* build.NoGoError ); noGo {
259
+ // The package does not actually exist, so record neither the package
260
+ // nor the error.
261
+ return nil
223
262
}
224
- return nil
263
+ // There was an error importing path, but not matching it,
264
+ // which is all that Match promises to do.
265
+ // Ignore the import error.
225
266
}
226
267
m .Pkgs = append (m .Pkgs , name )
227
268
return nil
228
269
})
270
+ if err != nil {
271
+ m .AddError (err )
272
+ }
229
273
return m
230
274
}
231
275
@@ -316,7 +360,7 @@ func replaceVendor(x, repl string) string {
316
360
// WarnUnmatched warns about patterns that didn't match any packages.
317
361
func WarnUnmatched (matches []* Match ) {
318
362
for _ , m := range matches {
319
- if len (m .Pkgs ) == 0 {
363
+ if len (m .Pkgs ) == 0 && len ( m . Errs ) == 0 {
320
364
fmt .Fprintf (os .Stderr , "go: warning: %q matched no packages\n " , m .Pattern )
321
365
}
322
366
}
0 commit comments