Skip to content

Commit 4dca902

Browse files
committed
go/internal/packagesdriver: be defensive wrt error results
While investigating a bug that turned out to lie elsewhere (#63700), we were troubled by the inconsistencies between the pair of errors returned by functions in this package. This change makes things more consistent. Updates golang/go#63700 Change-Id: I926c47572b7f666327bd1dba71ace68a5591bf2f Reviewed-on: https://go-review.googlesource.com/c/tools/+/537875 Reviewed-by: Robert Findley <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
1 parent 672de52 commit 4dca902

File tree

2 files changed

+24
-15
lines changed

2 files changed

+24
-15
lines changed

go/internal/packagesdriver/sizes.go

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,17 @@ import (
1313
"golang.org/x/tools/internal/gocommand"
1414
)
1515

16-
var debug = false
17-
1816
func GetSizesForArgsGolist(ctx context.Context, inv gocommand.Invocation, gocmdRunner *gocommand.Runner) (string, string, error) {
1917
inv.Verb = "list"
2018
inv.Args = []string{"-f", "{{context.GOARCH}} {{context.Compiler}}", "--", "unsafe"}
2119
stdout, stderr, friendlyErr, rawErr := gocmdRunner.RunRaw(ctx, inv)
2220
var goarch, compiler string
2321
if rawErr != nil {
24-
if rawErrMsg := rawErr.Error(); strings.Contains(rawErrMsg, "cannot find main module") || strings.Contains(rawErrMsg, "go.mod file not found") {
25-
// User's running outside of a module. All bets are off. Get GOARCH and guess compiler is gc.
22+
rawErrMsg := rawErr.Error()
23+
if strings.Contains(rawErrMsg, "cannot find main module") ||
24+
strings.Contains(rawErrMsg, "go.mod file not found") {
25+
// User's running outside of a module.
26+
// All bets are off. Get GOARCH and guess compiler is gc.
2627
// TODO(matloob): Is this a problem in practice?
2728
inv.Verb = "env"
2829
inv.Args = []string{"GOARCH"}
@@ -32,8 +33,12 @@ func GetSizesForArgsGolist(ctx context.Context, inv gocommand.Invocation, gocmdR
3233
}
3334
goarch = strings.TrimSpace(envout.String())
3435
compiler = "gc"
35-
} else {
36+
} else if friendlyErr != nil {
3637
return "", "", friendlyErr
38+
} else {
39+
// This should be unreachable, but be defensive
40+
// in case RunRaw's error results are inconsistent.
41+
return "", "", rawErr
3742
}
3843
} else {
3944
fields := strings.Fields(stdout.String())

internal/gocommand/invoke.go

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ func (runner *Runner) RunPiped(ctx context.Context, inv Invocation, stdout, stde
8585

8686
// RunRaw runs the invocation, serializing requests only if they fight over
8787
// go.mod changes.
88+
// Postcondition: both error results have same nilness.
8889
func (runner *Runner) RunRaw(ctx context.Context, inv Invocation) (*bytes.Buffer, *bytes.Buffer, error, error) {
8990
ctx, done := event.Start(ctx, "gocommand.Runner.RunRaw", invLabels(inv)...)
9091
defer done()
@@ -95,23 +96,24 @@ func (runner *Runner) RunRaw(ctx context.Context, inv Invocation) (*bytes.Buffer
9596
stdout, stderr, friendlyErr, err := runner.runConcurrent(ctx, inv)
9697

9798
// If we encounter a load concurrency error, we need to retry serially.
98-
if friendlyErr == nil || !modConcurrencyError.MatchString(friendlyErr.Error()) {
99-
return stdout, stderr, friendlyErr, err
99+
if friendlyErr != nil && modConcurrencyError.MatchString(friendlyErr.Error()) {
100+
event.Error(ctx, "Load concurrency error, will retry serially", err)
101+
102+
// Run serially by calling runPiped.
103+
stdout.Reset()
104+
stderr.Reset()
105+
friendlyErr, err = runner.runPiped(ctx, inv, stdout, stderr)
100106
}
101-
event.Error(ctx, "Load concurrency error, will retry serially", err)
102107

103-
// Run serially by calling runPiped.
104-
stdout.Reset()
105-
stderr.Reset()
106-
friendlyErr, err = runner.runPiped(ctx, inv, stdout, stderr)
107108
return stdout, stderr, friendlyErr, err
108109
}
109110

111+
// Postcondition: both error results have same nilness.
110112
func (runner *Runner) runConcurrent(ctx context.Context, inv Invocation) (*bytes.Buffer, *bytes.Buffer, error, error) {
111113
// Wait for 1 worker to become available.
112114
select {
113115
case <-ctx.Done():
114-
return nil, nil, nil, ctx.Err()
116+
return nil, nil, ctx.Err(), ctx.Err()
115117
case runner.inFlight <- struct{}{}:
116118
defer func() { <-runner.inFlight }()
117119
}
@@ -121,6 +123,7 @@ func (runner *Runner) runConcurrent(ctx context.Context, inv Invocation) (*bytes
121123
return stdout, stderr, friendlyErr, err
122124
}
123125

126+
// Postcondition: both error results have same nilness.
124127
func (runner *Runner) runPiped(ctx context.Context, inv Invocation, stdout, stderr io.Writer) (error, error) {
125128
// Make sure the runner is always initialized.
126129
runner.initialize()
@@ -129,7 +132,7 @@ func (runner *Runner) runPiped(ctx context.Context, inv Invocation, stdout, stde
129132
// runPiped commands.
130133
select {
131134
case <-ctx.Done():
132-
return nil, ctx.Err()
135+
return ctx.Err(), ctx.Err()
133136
case runner.serialized <- struct{}{}:
134137
defer func() { <-runner.serialized }()
135138
}
@@ -139,7 +142,7 @@ func (runner *Runner) runPiped(ctx context.Context, inv Invocation, stdout, stde
139142
for i := 0; i < maxInFlight; i++ {
140143
select {
141144
case <-ctx.Done():
142-
return nil, ctx.Err()
145+
return ctx.Err(), ctx.Err()
143146
case runner.inFlight <- struct{}{}:
144147
// Make sure we always "return" any workers we took.
145148
defer func() { <-runner.inFlight }()
@@ -172,6 +175,7 @@ type Invocation struct {
172175
Logf func(format string, args ...interface{})
173176
}
174177

178+
// Postcondition: both error results have same nilness.
175179
func (i *Invocation) runWithFriendlyError(ctx context.Context, stdout, stderr io.Writer) (friendlyError error, rawError error) {
176180
rawError = i.run(ctx, stdout, stderr)
177181
if rawError != nil {

0 commit comments

Comments
 (0)