Skip to content

Commit 156c607

Browse files
author
Bryan C. Mills
committed
cmd/go/internal/search: record errors in the Match struct
Previously, we would either invoke base.Fatalf (which is too aggressive), or log.Print (which is too passive). Updates #32917 Change-Id: I5475e873e76948de7df65dca08bc0ce67a7fc827 Reviewed-on: https://go-review.googlesource.com/c/go/+/185344 Run-TryBot: Bryan C. Mills <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Jay Conrod <[email protected]>
1 parent d464c7c commit 156c607

File tree

5 files changed

+75
-15
lines changed

5 files changed

+75
-15
lines changed

src/cmd/go/internal/get/get.go

+7-2
Original file line numberDiff line numberDiff line change
@@ -285,10 +285,15 @@ func download(arg string, parent *load.Package, stk *load.ImportStack, mode int)
285285
// We delay this until after reloadPackage so that the old entry
286286
// for p has been replaced in the package cache.
287287
if wildcardOkay && strings.Contains(arg, "...") {
288+
var match *search.Match
288289
if build.IsLocalImport(arg) {
289-
args = search.MatchPackagesInFS(arg).Pkgs
290+
match = search.MatchPackagesInFS(arg)
290291
} else {
291-
args = search.MatchPackages(arg).Pkgs
292+
match = search.MatchPackages(arg)
293+
}
294+
args = match.Pkgs
295+
for _, err := range match.Errs {
296+
base.Errorf("%s", err)
292297
}
293298
isWildcard = true
294299
}

src/cmd/go/internal/load/pkg.go

+3
Original file line numberDiff line numberDiff line change
@@ -2091,6 +2091,9 @@ func PackagesAndErrors(patterns []string) []*Package {
20912091
seenPkg[p] = true
20922092
pkgs = append(pkgs, p)
20932093
}
2094+
2095+
// TODO: if len(m.Pkgs) == 0 && len(m.Errs) > 0, should we add a *Package
2096+
// with a non-nil Error field?
20942097
}
20952098

20962099
// Now that CmdlinePkg is set correctly,

src/cmd/go/internal/modget/get.go

+4
Original file line numberDiff line numberDiff line change
@@ -522,6 +522,10 @@ func runGet(cmd *base.Command, args []string) {
522522
// we'll print a warning after the outer loop.
523523
if !search.IsRelativePath(arg.path) && !match.Literal && arg.path != "all" {
524524
addQuery(&query{querySpec: querySpec{path: arg.path, vers: arg.vers}, arg: arg.raw})
525+
} else {
526+
for _, err := range match.Errs {
527+
base.Errorf("go get: %v", err)
528+
}
525529
}
526530
continue
527531
}

src/cmd/go/internal/modload/load.go

+6-2
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,9 @@ func ImportPathsQuiet(patterns []string, tags map[string]bool) []*search.Match {
7979
if m.Literal {
8080
dirs = []string{m.Pattern}
8181
} else {
82-
dirs = search.MatchPackagesInFS(m.Pattern).Pkgs
82+
match := search.MatchPackagesInFS(m.Pattern)
83+
dirs = match.Pkgs
84+
m.Errs = match.Errs
8385
}
8486
fsDirs[i] = dirs
8587
}
@@ -187,7 +189,9 @@ func ImportPathsQuiet(patterns []string, tags map[string]bool) []*search.Match {
187189

188190
case search.IsMetaPackage(m.Pattern): // std, cmd
189191
if len(m.Pkgs) == 0 {
190-
m.Pkgs = search.MatchPackages(m.Pattern).Pkgs
192+
match := search.MatchPackages(m.Pattern)
193+
m.Pkgs = match.Pkgs
194+
m.Errs = match.Errs
191195
}
192196

193197
default:

src/cmd/go/internal/search/search.go

+55-11
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import (
99
"cmd/go/internal/cfg"
1010
"fmt"
1111
"go/build"
12-
"log"
1312
"os"
1413
"path"
1514
"path/filepath"
@@ -22,6 +21,35 @@ type Match struct {
2221
Pattern string // the pattern itself
2322
Literal bool // whether it is a literal (no wildcards)
2423
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
2553
}
2654

2755
// MatchPackages returns all the packages that can be found
@@ -56,7 +84,7 @@ func MatchPackages(pattern string) *Match {
5684
if pattern == "cmd" {
5785
root += "cmd" + string(filepath.Separator)
5886
}
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 {
6088
if err != nil || path == src {
6189
return nil
6290
}
@@ -100,21 +128,29 @@ func MatchPackages(pattern string) *Match {
100128
pkg, err := cfg.BuildContext.ImportDir(path, 0)
101129
if err != nil {
102130
if _, noGo := err.(*build.NoGoError); noGo {
131+
// The package does not actually exist, so record neither the package
132+
// nor the error.
103133
return nil
104134
}
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.
105138
}
106139

107140
// If we are expanding "cmd", skip main
108141
// packages under cmd/vendor. At least as of
109142
// March, 2017, there is one there for the
110143
// 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" {
112145
return nil
113146
}
114147

115148
m.Pkgs = append(m.Pkgs, name)
116149
return nil
117150
})
151+
if err != nil {
152+
m.AddError(err)
153+
}
118154
}
119155
return m
120156
}
@@ -166,15 +202,16 @@ func MatchPackagesInFS(pattern string) *Match {
166202
if modRoot != "" {
167203
abs, err := filepath.Abs(dir)
168204
if err != nil {
169-
base.Fatalf("go: %v", err)
205+
m.AddError(err)
206+
return m
170207
}
171208
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
174211
}
175212
}
176213

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 {
178215
if err != nil || !fi.IsDir() {
179216
return nil
180217
}
@@ -218,14 +255,21 @@ func MatchPackagesInFS(pattern string) *Match {
218255
// behavior means people miss serious mistakes.
219256
// See golang.org/issue/11407.
220257
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
223262
}
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.
225266
}
226267
m.Pkgs = append(m.Pkgs, name)
227268
return nil
228269
})
270+
if err != nil {
271+
m.AddError(err)
272+
}
229273
return m
230274
}
231275

@@ -316,7 +360,7 @@ func replaceVendor(x, repl string) string {
316360
// WarnUnmatched warns about patterns that didn't match any packages.
317361
func WarnUnmatched(matches []*Match) {
318362
for _, m := range matches {
319-
if len(m.Pkgs) == 0 {
363+
if len(m.Pkgs) == 0 && len(m.Errs) == 0 {
320364
fmt.Fprintf(os.Stderr, "go: warning: %q matched no packages\n", m.Pattern)
321365
}
322366
}

0 commit comments

Comments
 (0)