Skip to content

Commit 1e9d12d

Browse files
committed
go/packages: pass -overlay to all 'go list' invocations
Even in the trivial go list invocations (to enumerate modules or type sizes), the complex behavior of Go modules requires that the appropriate overlays are visible, since they may define go.mod files. Also, a test case suggested by Dominik Honnef. Fixes golang/go#67644 Change-Id: I19348ae7270769de438a7f4ce69c3f7a55fb2f55 Reviewed-on: https://go-review.googlesource.com/c/tools/+/588936 Reviewed-by: Michael Matloob <matloob@golang.org> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
1 parent 3c293ad commit 1e9d12d

File tree

3 files changed

+58
-12
lines changed

3 files changed

+58
-12
lines changed

go/packages/golist.go

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -841,6 +841,7 @@ func (state *golistState) cfgInvocation() gocommand.Invocation {
841841
Env: cfg.Env,
842842
Logf: cfg.Logf,
843843
WorkingDir: cfg.Dir,
844+
Overlay: cfg.goListOverlayFile,
844845
}
845846
}
846847

@@ -849,18 +850,6 @@ func (state *golistState) invokeGo(verb string, args ...string) (*bytes.Buffer,
849850
cfg := state.cfg
850851

851852
inv := state.cfgInvocation()
852-
853-
// Since go1.16, `go list` accepts overlays directly via the
854-
// -overlay flag. (The check for "list" avoids unnecessarily
855-
// writing the overlay file for a 'go env' command.)
856-
if verb == "list" {
857-
overlay, cleanup, err := gocommand.WriteOverlays(cfg.Overlay)
858-
if err != nil {
859-
return nil, err
860-
}
861-
defer cleanup()
862-
inv.Overlay = overlay
863-
}
864853
inv.Verb = verb
865854
inv.Args = args
866855
gocmdRunner := cfg.gocmdRunner

go/packages/packages.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,14 @@ const (
133133

134134
// A Config specifies details about how packages should be loaded.
135135
// The zero value is a valid configuration.
136+
//
136137
// Calls to Load do not modify this struct.
138+
//
139+
// TODO(adonovan): #67702: this is currently false: in fact,
140+
// calls to [Load] do not modify the public fields of this struct, but
141+
// may modify hidden fields, so concurrent calls to [Load] must not
142+
// use the same Config. But perhaps we should reestablish the
143+
// documented invariant.
137144
type Config struct {
138145
// Mode controls the level of information returned for each package.
139146
Mode LoadMode
@@ -222,6 +229,10 @@ type Config struct {
222229
// consistent package metadata about unsaved files. However,
223230
// drivers may vary in their level of support for overlays.
224231
Overlay map[string][]byte
232+
233+
// goListOverlayFile is the JSON file that encodes the Overlay
234+
// mapping, used by 'go list -overlay=...'
235+
goListOverlayFile string
225236
}
226237

227238
// Load loads and returns the Go packages named by the given patterns.
@@ -316,6 +327,17 @@ func defaultDriver(cfg *Config, patterns ...string) (*DriverResponse, bool, erro
316327
// (fall through)
317328
}
318329

330+
// go list fallback
331+
//
332+
// Write overlays once, as there are many calls
333+
// to 'go list' (one per chunk plus others too).
334+
overlay, cleanupOverlay, err := gocommand.WriteOverlays(cfg.Overlay)
335+
if err != nil {
336+
return nil, false, err
337+
}
338+
defer cleanupOverlay()
339+
cfg.goListOverlayFile = overlay
340+
319341
response, err := callDriverOnChunks(goListDriver, cfg, chunks)
320342
if err != nil {
321343
return nil, false, err

go/packages/packages_test.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3024,3 +3024,38 @@ func TestLoadEitherSucceedsOrFails(t *testing.T) {
30243024
t.Errorf("Load returned %d packages (want 1) and no error", len(initial))
30253025
}
30263026
}
3027+
3028+
// TestLoadOverlayGoMod ensures that overlays containing go.mod files
3029+
// are effective for all 'go list' calls made by go/packages (#67644).
3030+
func TestLoadOverlayGoMod(t *testing.T) {
3031+
testenv.NeedsGoBuild(t)
3032+
3033+
cwd, _ := os.Getwd()
3034+
3035+
// This test ensures that the overlaid go.mod file is seen by
3036+
// all runs of 'go list', in particular the early run that
3037+
// enumerates the modules: if the go.mod file were absent,
3038+
// it would ascend to the parent directory (x/tools) and
3039+
// then (falsely) report inconsistent vendoring.
3040+
//
3041+
// (Ideally the testdata would be constructed from nothing
3042+
// rather than rely on the go/packages source tree, but it is
3043+
// turned out to a bigger project than bargained for.)
3044+
cfg := &packages.Config{
3045+
Mode: packages.LoadSyntax,
3046+
Overlay: map[string][]byte{
3047+
filepath.Join(cwd, "go.mod"): []byte("module example.com\ngo 1.0"),
3048+
},
3049+
Env: append(os.Environ(), "GOFLAGS=-mod=vendor", "GOWORK=off"),
3050+
}
3051+
3052+
pkgs, err := packages.Load(cfg, "./testdata")
3053+
if err != nil {
3054+
t.Fatal(err) // (would previously fail here with "inconsistent vendoring")
3055+
}
3056+
got := fmt.Sprint(pkgs)
3057+
want := `[./testdata]`
3058+
if got != want {
3059+
t.Errorf("Load: got %s, want %v", got, want)
3060+
}
3061+
}

0 commit comments

Comments
 (0)