Skip to content

Commit b894a32

Browse files
committed
all: use explicit -mod, -modfile fields for gocommand.Invocation
Build flags, -mod, and -modfile are all accepted by disjoint go command verbs. Mixing them together had the effect of forcing gocommand users to figure out which went where themselves, which was annoying and error-prone. Add ModFlag and ModFile fields to Invocation and update all uses to use them. go/packages has a BuildFlags field that's bad for the same reason. Add private modFlag and modFile fields that forward to the corresponding Invocation fields. imports.ProcessEnv gets the same treatment. Fixes golang/go#41826. Change-Id: If74d19146e9e62930d7c34f40859c27c25566c4e Reviewed-on: https://go-review.googlesource.com/c/tools/+/263213 Trust: Heschi Kreinick <[email protected]> Run-TryBot: Heschi Kreinick <[email protected]> gopls-CI: kokoro <[email protected]> TryBot-Result: Go Bot <[email protected]> Reviewed-by: Rebecca Stambler <[email protected]>
1 parent 0a3dccc commit b894a32

File tree

11 files changed

+108
-76
lines changed

11 files changed

+108
-76
lines changed

go/internal/packagesdriver/sizes.go

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,12 @@ func GetSizes(ctx context.Context, buildFlags, env []string, gocmdRunner *gocomm
3939
}
4040

4141
if tool == "off" {
42-
return GetSizesGolist(ctx, buildFlags, env, gocmdRunner, dir)
42+
inv := gocommand.Invocation{
43+
BuildFlags: buildFlags,
44+
Env: env,
45+
WorkingDir: dir,
46+
}
47+
return GetSizesGolist(ctx, inv, gocmdRunner)
4348
}
4449

4550
req, err := json.Marshal(struct {
@@ -75,26 +80,17 @@ func GetSizes(ctx context.Context, buildFlags, env []string, gocmdRunner *gocomm
7580
return response.Sizes, nil
7681
}
7782

78-
func GetSizesGolist(ctx context.Context, buildFlags, env []string, gocmdRunner *gocommand.Runner, dir string) (types.Sizes, error) {
79-
inv := gocommand.Invocation{
80-
Verb: "list",
81-
Args: []string{"-f", "{{context.GOARCH}} {{context.Compiler}}", "--", "unsafe"},
82-
Env: env,
83-
BuildFlags: buildFlags,
84-
WorkingDir: dir,
85-
}
83+
func GetSizesGolist(ctx context.Context, inv gocommand.Invocation, gocmdRunner *gocommand.Runner) (types.Sizes, error) {
84+
inv.Verb = "list"
85+
inv.Args = []string{"-f", "{{context.GOARCH}} {{context.Compiler}}", "--", "unsafe"}
8686
stdout, stderr, friendlyErr, rawErr := gocmdRunner.RunRaw(ctx, inv)
8787
var goarch, compiler string
8888
if rawErr != nil {
8989
if strings.Contains(rawErr.Error(), "cannot find main module") {
9090
// User's running outside of a module. All bets are off. Get GOARCH and guess compiler is gc.
9191
// TODO(matloob): Is this a problem in practice?
92-
inv := gocommand.Invocation{
93-
Verb: "env",
94-
Args: []string{"GOARCH"},
95-
Env: env,
96-
WorkingDir: dir,
97-
}
92+
inv.Verb = "env"
93+
inv.Args = []string{"GOARCH"}
9894
envout, enverr := gocmdRunner.Run(ctx, inv)
9995
if enverr != nil {
10096
return nil, enverr

go/packages/golist.go

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -139,26 +139,26 @@ func goListDriver(cfg *Config, patterns ...string) (*driverResponse, error) {
139139

140140
response := newDeduper()
141141

142+
state := &golistState{
143+
cfg: cfg,
144+
ctx: ctx,
145+
vendorDirs: map[string]bool{},
146+
}
147+
142148
// Fill in response.Sizes asynchronously if necessary.
143149
var sizeserr error
144150
var sizeswg sync.WaitGroup
145151
if cfg.Mode&NeedTypesSizes != 0 || cfg.Mode&NeedTypes != 0 {
146152
sizeswg.Add(1)
147153
go func() {
148154
var sizes types.Sizes
149-
sizes, sizeserr = packagesdriver.GetSizesGolist(ctx, cfg.BuildFlags, cfg.Env, cfg.gocmdRunner, cfg.Dir)
155+
sizes, sizeserr = packagesdriver.GetSizesGolist(ctx, state.cfgInvocation(), cfg.gocmdRunner)
150156
// types.SizesFor always returns nil or a *types.StdSizes.
151157
response.dr.Sizes, _ = sizes.(*types.StdSizes)
152158
sizeswg.Done()
153159
}()
154160
}
155161

156-
state := &golistState{
157-
cfg: cfg,
158-
ctx: ctx,
159-
vendorDirs: map[string]bool{},
160-
}
161-
162162
// Determine files requested in contains patterns
163163
var containFiles []string
164164
restPatterns := make([]string, 0, len(patterns))
@@ -839,18 +839,26 @@ func golistargs(cfg *Config, words []string) []string {
839839
return fullargs
840840
}
841841

842-
// invokeGo returns the stdout of a go command invocation.
843-
func (state *golistState) invokeGo(verb string, args ...string) (*bytes.Buffer, error) {
842+
// cfgInvocation returns an Invocation that reflects cfg's settings.
843+
func (state *golistState) cfgInvocation() gocommand.Invocation {
844844
cfg := state.cfg
845-
846-
inv := gocommand.Invocation{
847-
Verb: verb,
848-
Args: args,
845+
return gocommand.Invocation{
849846
BuildFlags: cfg.BuildFlags,
847+
ModFile: cfg.modFile,
848+
ModFlag: cfg.modFlag,
850849
Env: cfg.Env,
851850
Logf: cfg.Logf,
852851
WorkingDir: cfg.Dir,
853852
}
853+
}
854+
855+
// invokeGo returns the stdout of a go command invocation.
856+
func (state *golistState) invokeGo(verb string, args ...string) (*bytes.Buffer, error) {
857+
cfg := state.cfg
858+
859+
inv := state.cfgInvocation()
860+
inv.Verb = verb
861+
inv.Args = args
854862
gocmdRunner := cfg.gocmdRunner
855863
if gocmdRunner == nil {
856864
gocmdRunner = &gocommand.Runner{}

go/packages/packages.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,12 @@ type Config struct {
144144
// the build system's query tool.
145145
BuildFlags []string
146146

147+
// modFile will be used for -modfile in go command invocations.
148+
modFile string
149+
150+
// modFlag will be used for -modfile in go command invocations.
151+
modFlag string
152+
147153
// Fset provides source position information for syntax trees and types.
148154
// If Fset is nil, Load will use a new fileset, but preserve Fset's value.
149155
Fset *token.FileSet
@@ -366,6 +372,12 @@ func init() {
366372
packagesinternal.SetGoCmdRunner = func(config interface{}, runner *gocommand.Runner) {
367373
config.(*Config).gocmdRunner = runner
368374
}
375+
packagesinternal.SetModFile = func(config interface{}, value string) {
376+
config.(*Config).modFile = value
377+
}
378+
packagesinternal.SetModFlag = func(config interface{}, value string) {
379+
config.(*Config).modFlag = value
380+
}
369381
packagesinternal.TypecheckCgo = int(typecheckCgo)
370382
}
371383

internal/gocommand/invoke.go

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,8 @@ type Invocation struct {
130130
Verb string
131131
Args []string
132132
BuildFlags []string
133+
ModFlag string
134+
ModFile string
133135
Env []string
134136
WorkingDir string
135137
Logf func(format string, args ...interface{})
@@ -158,17 +160,35 @@ func (i *Invocation) run(ctx context.Context, stdout, stderr io.Writer) error {
158160
}
159161

160162
goArgs := []string{i.Verb}
163+
164+
appendModFile := func() {
165+
if i.ModFile != "" {
166+
goArgs = append(goArgs, "-modfile="+i.ModFile)
167+
}
168+
}
169+
appendModFlag := func() {
170+
if i.ModFlag != "" {
171+
goArgs = append(goArgs, "-mod="+i.ModFlag)
172+
}
173+
}
174+
161175
switch i.Verb {
176+
case "env", "version":
177+
goArgs = append(goArgs, i.Args...)
162178
case "mod":
163-
// mod needs the sub-verb before build flags.
179+
// mod needs the sub-verb before flags.
164180
goArgs = append(goArgs, i.Args[0])
165-
goArgs = append(goArgs, i.BuildFlags...)
181+
appendModFile()
166182
goArgs = append(goArgs, i.Args[1:]...)
167-
case "env":
168-
// env doesn't take build flags.
183+
case "get":
184+
goArgs = append(goArgs, i.BuildFlags...)
185+
appendModFile()
169186
goArgs = append(goArgs, i.Args...)
170-
default:
187+
188+
default: // notably list and build.
171189
goArgs = append(goArgs, i.BuildFlags...)
190+
appendModFile()
191+
appendModFlag()
172192
goArgs = append(goArgs, i.Args...)
173193
}
174194
cmd := exec.Command("go", goArgs...)

internal/imports/fix.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -804,6 +804,8 @@ type ProcessEnv struct {
804804
GocmdRunner *gocommand.Runner
805805

806806
BuildFlags []string
807+
ModFlag string
808+
ModFile string
807809

808810
// Env overrides the OS environment, and can be used to specify
809811
// GOPROXY, GO111MODULE, etc. PATH cannot be set here, because

internal/imports/mod.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ func (r *ModuleResolver) init() error {
5959
}
6060
inv := gocommand.Invocation{
6161
BuildFlags: r.env.BuildFlags,
62+
ModFlag: r.env.ModFlag,
63+
ModFile: r.env.ModFile,
6264
Env: r.env.env(),
6365
Logf: r.env.Logf,
6466
WorkingDir: r.env.WorkingDir,

internal/lsp/cache/imports.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -160,9 +160,7 @@ func (s *importsState) populateProcessEnv(ctx context.Context, snapshot *snapsho
160160
return cleanup, err
161161
}
162162
if modmod {
163-
// -mod isn't really a build flag, but we can get away with it given
164-
// the set of commands that goimports wants to run.
165-
pe.BuildFlags = append([]string{"-mod=mod"}, pe.BuildFlags...)
163+
pe.ModFlag = "mod"
166164
}
167165

168166
// Add -modfile to the build flags, if we are using it.
@@ -172,7 +170,7 @@ func (s *importsState) populateProcessEnv(ctx context.Context, snapshot *snapsho
172170
if err != nil {
173171
return nil, err
174172
}
175-
pe.BuildFlags = append(pe.BuildFlags, fmt.Sprintf("-modfile=%s", tmpURI.Filename()))
173+
pe.ModFile = tmpURI.Filename()
176174
}
177175

178176
return cleanup, nil

internal/lsp/cache/load.go

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ func (s *snapshot) load(ctx context.Context, scopes ...interface{}) error {
9292
cleanup := func() {}
9393
wdir := s.view.rootURI.Filename()
9494

95-
var buildFlags []string
95+
var modFile string
9696
var modURI span.URI
9797
var modContent []byte
9898
switch {
@@ -141,18 +141,17 @@ func (s *snapshot) load(ctx context.Context, scopes ...interface{}) error {
141141
if err != nil {
142142
return err
143143
}
144-
buildFlags = append(buildFlags, fmt.Sprintf("-modfile=%s", tmpURI.Filename()))
144+
modFile = tmpURI.Filename()
145145
}
146146

147147
cfg := s.config(ctx, wdir)
148-
cfg.BuildFlags = append(cfg.BuildFlags, buildFlags...)
149-
148+
packagesinternal.SetModFile(cfg, modFile)
150149
modMod, err := s.needsModEqualsMod(ctx, modURI, modContent)
151150
if err != nil {
152151
return err
153152
}
154153
if modMod {
155-
cfg.BuildFlags = append([]string{"-mod=mod"}, cfg.BuildFlags...)
154+
packagesinternal.SetModFlag(cfg, "mod")
156155
}
157156

158157
pkgs, err := packages.Load(cfg, query...)

internal/lsp/cache/mod.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"golang.org/x/tools/internal/lsp/protocol"
2424
"golang.org/x/tools/internal/lsp/source"
2525
"golang.org/x/tools/internal/memoize"
26+
"golang.org/x/tools/internal/packagesinternal"
2627
"golang.org/x/tools/internal/span"
2728
errors "golang.org/x/xerrors"
2829
)
@@ -329,7 +330,7 @@ func (s *snapshot) ModUpgrade(ctx context.Context, fh source.FileHandle) (map[st
329330
if s.workspaceMode()&tempModfile == 0 || containsVendor(fh.URI()) {
330331
// Use -mod=readonly if the module contains a vendor directory
331332
// (see golang/go#38711).
332-
args = append([]string{"-mod", "readonly"}, args...)
333+
packagesinternal.SetModFlag(cfg, "readonly")
333334
}
334335
stdout, err := snapshot.runGoCommandWithConfig(ctx, cfg, "list", args)
335336
if err != nil {

internal/lsp/cache/snapshot.go

Lines changed: 24 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -255,13 +255,14 @@ func (s *snapshot) RunGoCommandPiped(ctx context.Context, wd, verb string, args
255255
func (s *snapshot) goCommandInvocation(ctx context.Context, cfg *packages.Config, allowTempModfile bool, verb string, args []string) (tmpURI span.URI, runner *gocommand.Runner, inv *gocommand.Invocation, cleanup func(), err error) {
256256
cleanup = func() {} // fallback
257257
modURI := s.GoModForFile(ctx, span.URIFromPath(cfg.Dir))
258-
var buildFlags []string
259-
// `go mod`, `go env`, and `go version` don't take build flags.
260-
switch verb {
261-
case "mod", "env", "version":
262-
default:
263-
buildFlags = append(cfg.BuildFlags, buildFlags...)
258+
259+
inv = &gocommand.Invocation{
260+
Verb: verb,
261+
Args: args,
262+
Env: cfg.Env,
263+
WorkingDir: cfg.Dir,
264264
}
265+
265266
if allowTempModfile && s.workspaceMode()&tempModfile != 0 {
266267
if modURI == "" {
267268
return "", nil, nil, cleanup, fmt.Errorf("no go.mod file found in %s", cfg.Dir)
@@ -277,40 +278,30 @@ func (s *snapshot) goCommandInvocation(ctx context.Context, cfg *packages.Config
277278
if err != nil {
278279
return "", nil, nil, cleanup, err
279280
}
280-
buildFlags = append(buildFlags, fmt.Sprintf("-modfile=%s", tmpURI.Filename()))
281+
inv.ModFile = tmpURI.Filename()
281282
}
282-
// TODO(rstambler): Remove this when golang/go#41826 is resolved.
283-
// Don't add -mod=mod for `go mod` or `go get`.
284-
switch verb {
285-
case "mod", "get":
286-
default:
287-
var modContent []byte
288-
if modURI != "" {
289-
modFH, err := s.GetFile(ctx, modURI)
290-
if err != nil {
291-
return "", nil, nil, cleanup, err
292-
}
293-
modContent, err = modFH.Read()
294-
if err != nil {
295-
return "", nil, nil, nil, err
296-
}
297-
}
298-
modMod, err := s.needsModEqualsMod(ctx, modURI, modContent)
283+
284+
var modContent []byte
285+
if modURI != "" {
286+
modFH, err := s.GetFile(ctx, modURI)
299287
if err != nil {
300288
return "", nil, nil, cleanup, err
301289
}
302-
if modMod {
303-
buildFlags = append([]string{"-mod=mod"}, buildFlags...)
290+
modContent, err = modFH.Read()
291+
if err != nil {
292+
return "", nil, nil, nil, err
304293
}
305294
}
295+
modMod, err := s.needsModEqualsMod(ctx, modURI, modContent)
296+
if err != nil {
297+
return "", nil, nil, cleanup, err
298+
}
299+
if modMod {
300+
inv.ModFlag = "mod"
301+
}
302+
306303
runner = packagesinternal.GetGoCmdRunner(cfg)
307-
return tmpURI, runner, &gocommand.Invocation{
308-
Verb: verb,
309-
Args: args,
310-
Env: cfg.Env,
311-
BuildFlags: buildFlags,
312-
WorkingDir: cfg.Dir,
313-
}, cleanup, nil
304+
return tmpURI, runner, inv, cleanup, nil
314305
}
315306

316307
func (s *snapshot) buildOverlay() map[string][]byte {

internal/packagesinternal/packages.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,6 @@ var GetGoCmdRunner = func(config interface{}) *gocommand.Runner { return nil }
1212
var SetGoCmdRunner = func(config interface{}, runner *gocommand.Runner) {}
1313

1414
var TypecheckCgo int
15+
16+
var SetModFlag = func(config interface{}, value string) {}
17+
var SetModFile = func(config interface{}, value string) {}

0 commit comments

Comments
 (0)