зеркало из https://github.com/golang/tools.git
internal/imports: use a module resolver if GOWORK is set
Previously, gopls would fall back on a gopath resolver when running goimports from a directory containing go.work (but not go.mod). Fix this by update the code to recognize that GOWORK also puts goimports into module mode. All the work to _support_ go.work had already been done, but the tests were only passing because they were setting GO111MODULE=on explicitly (and therefore GOMOD=/dev/null was satisfying the pre-existing check). Also add a test for the regression in gopls. Fixes golang/go#52784 Change-Id: I31df6f71a949a5668e8dc001b3ee25ad26f2f927 Reviewed-on: https://go-review.googlesource.com/c/tools/+/413689 TryBot-Result: Gopher Robot <gobot@golang.org> Run-TryBot: Robert Findley <rfindley@google.com> gopls-CI: kokoro <noreply+kokoro@google.com> Reviewed-by: Michael Matloob <matloob@golang.org>
This commit is contained in:
Родитель
60ca6366e6
Коммит
e1ec1f3230
|
@ -214,3 +214,49 @@ func TestA(t *testing.T) {
|
|||
)
|
||||
})
|
||||
}
|
||||
|
||||
// Test for golang/go#52784
|
||||
func TestGoWorkImports(t *testing.T) {
|
||||
testenv.NeedsGo1Point(t, 18)
|
||||
const pkg = `
|
||||
-- go.work --
|
||||
go 1.19
|
||||
|
||||
use (
|
||||
./caller
|
||||
./mod
|
||||
)
|
||||
-- caller/go.mod --
|
||||
module caller.com
|
||||
|
||||
go 1.18
|
||||
|
||||
require mod.com v0.0.0
|
||||
|
||||
replace mod.com => ../mod
|
||||
-- caller/caller.go --
|
||||
package main
|
||||
|
||||
func main() {
|
||||
a.Test()
|
||||
}
|
||||
-- mod/go.mod --
|
||||
module mod.com
|
||||
|
||||
go 1.18
|
||||
-- mod/a/a.go --
|
||||
package a
|
||||
|
||||
func Test() {
|
||||
}
|
||||
`
|
||||
Run(t, pkg, func(t *testing.T, env *Env) {
|
||||
env.OpenFile("caller/caller.go")
|
||||
env.Await(env.DiagnosticAtRegexp("caller/caller.go", "a.Test"))
|
||||
|
||||
// Saving caller.go should trigger goimports, which should find a.Test in
|
||||
// the mod.com module, thanks to the go.work file.
|
||||
env.SaveBuffer("caller/caller.go")
|
||||
env.Await(EmptyDiagnostics("caller/caller.go"))
|
||||
})
|
||||
}
|
||||
|
|
|
@ -796,7 +796,7 @@ func GetPackageExports(ctx context.Context, wrapped func(PackageExport), searchP
|
|||
return getCandidatePkgs(ctx, callback, filename, filePkg, env)
|
||||
}
|
||||
|
||||
var RequiredGoEnvVars = []string{"GO111MODULE", "GOFLAGS", "GOINSECURE", "GOMOD", "GOMODCACHE", "GONOPROXY", "GONOSUMDB", "GOPATH", "GOPROXY", "GOROOT", "GOSUMDB"}
|
||||
var RequiredGoEnvVars = []string{"GO111MODULE", "GOFLAGS", "GOINSECURE", "GOMOD", "GOMODCACHE", "GONOPROXY", "GONOSUMDB", "GOPATH", "GOPROXY", "GOROOT", "GOSUMDB", "GOWORK"}
|
||||
|
||||
// ProcessEnv contains environment variables and settings that affect the use of
|
||||
// the go command, the go/build package, etc.
|
||||
|
@ -906,7 +906,7 @@ func (e *ProcessEnv) GetResolver() (Resolver, error) {
|
|||
if err := e.init(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(e.Env["GOMOD"]) == 0 {
|
||||
if len(e.Env["GOMOD"]) == 0 && len(e.Env["GOWORK"]) == 0 {
|
||||
e.resolver = newGopathResolver(e)
|
||||
return e.resolver, nil
|
||||
}
|
||||
|
|
|
@ -70,9 +70,17 @@ func (r *ModuleResolver) init() error {
|
|||
Logf: r.env.Logf,
|
||||
WorkingDir: r.env.WorkingDir,
|
||||
}
|
||||
vendorEnabled, mainModVendor, err := gocommand.VendorEnabled(context.TODO(), inv, r.env.GocmdRunner)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
vendorEnabled := false
|
||||
var mainModVendor *gocommand.ModuleJSON
|
||||
|
||||
// Module vendor directories are ignored in workspace mode:
|
||||
// https://go.googlesource.com/proposal/+/master/design/45713-workspace.md
|
||||
if len(r.env.Env["GOWORK"]) == 0 {
|
||||
vendorEnabled, mainModVendor, err = gocommand.VendorEnabled(context.TODO(), inv, r.env.GocmdRunner)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if mainModVendor != nil && vendorEnabled {
|
||||
|
|
|
@ -29,7 +29,7 @@ import (
|
|||
|
||||
// Tests that we can find packages in the stdlib.
|
||||
func TestScanStdlib(t *testing.T) {
|
||||
mt := setup(t, `
|
||||
mt := setup(t, nil, `
|
||||
-- go.mod --
|
||||
module x
|
||||
`, "")
|
||||
|
@ -42,7 +42,7 @@ module x
|
|||
// where the module is in scope -- here we have to figure out the import path
|
||||
// without any help from go list.
|
||||
func TestScanOutOfScopeNestedModule(t *testing.T) {
|
||||
mt := setup(t, `
|
||||
mt := setup(t, nil, `
|
||||
-- go.mod --
|
||||
module x
|
||||
|
||||
|
@ -68,7 +68,7 @@ package x`, "")
|
|||
// Tests that we don't find a nested module contained in a local replace target.
|
||||
// The code for this case is too annoying to write, so it's just ignored.
|
||||
func TestScanNestedModuleInLocalReplace(t *testing.T) {
|
||||
mt := setup(t, `
|
||||
mt := setup(t, nil, `
|
||||
-- go.mod --
|
||||
module x
|
||||
|
||||
|
@ -107,7 +107,7 @@ package z
|
|||
|
||||
// Tests that path encoding is handled correctly. Adapted from mod_case.txt.
|
||||
func TestModCase(t *testing.T) {
|
||||
mt := setup(t, `
|
||||
mt := setup(t, nil, `
|
||||
-- go.mod --
|
||||
module x
|
||||
|
||||
|
@ -124,7 +124,7 @@ import _ "rsc.io/QUOTE/QUOTE"
|
|||
|
||||
// Not obviously relevant to goimports. Adapted from mod_domain_root.txt anyway.
|
||||
func TestModDomainRoot(t *testing.T) {
|
||||
mt := setup(t, `
|
||||
mt := setup(t, nil, `
|
||||
-- go.mod --
|
||||
module x
|
||||
|
||||
|
@ -140,7 +140,7 @@ import _ "example.com"
|
|||
|
||||
// Tests that scanning the module cache > 1 time is able to find the same module.
|
||||
func TestModMultipleScans(t *testing.T) {
|
||||
mt := setup(t, `
|
||||
mt := setup(t, nil, `
|
||||
-- go.mod --
|
||||
module x
|
||||
|
||||
|
@ -159,7 +159,7 @@ import _ "example.com"
|
|||
// Tests that scanning the module cache > 1 time is able to find the same module
|
||||
// in the module cache.
|
||||
func TestModMultipleScansWithSubdirs(t *testing.T) {
|
||||
mt := setup(t, `
|
||||
mt := setup(t, nil, `
|
||||
-- go.mod --
|
||||
module x
|
||||
|
||||
|
@ -178,7 +178,7 @@ import _ "rsc.io/quote"
|
|||
// Tests that scanning the module cache > 1 after changing a package in module cache to make it unimportable
|
||||
// is able to find the same module.
|
||||
func TestModCacheEditModFile(t *testing.T) {
|
||||
mt := setup(t, `
|
||||
mt := setup(t, nil, `
|
||||
-- go.mod --
|
||||
module x
|
||||
|
||||
|
@ -219,7 +219,7 @@ import _ "rsc.io/quote"
|
|||
|
||||
// Tests that -mod=vendor works. Adapted from mod_vendor_build.txt.
|
||||
func TestModVendorBuild(t *testing.T) {
|
||||
mt := setup(t, `
|
||||
mt := setup(t, nil, `
|
||||
-- go.mod --
|
||||
module m
|
||||
go 1.12
|
||||
|
@ -250,7 +250,7 @@ import _ "rsc.io/sampler"
|
|||
// Tests that -mod=vendor is auto-enabled only for go1.14 and higher.
|
||||
// Vaguely inspired by mod_vendor_auto.txt.
|
||||
func TestModVendorAuto(t *testing.T) {
|
||||
mt := setup(t, `
|
||||
mt := setup(t, nil, `
|
||||
-- go.mod --
|
||||
module m
|
||||
go 1.14
|
||||
|
@ -276,7 +276,7 @@ import _ "rsc.io/sampler"
|
|||
// Tests that a module replace works. Adapted from mod_list.txt. We start with
|
||||
// go.mod2; the first part of the test is irrelevant.
|
||||
func TestModList(t *testing.T) {
|
||||
mt := setup(t, `
|
||||
mt := setup(t, nil, `
|
||||
-- go.mod --
|
||||
module x
|
||||
require rsc.io/quote v1.5.1
|
||||
|
@ -293,7 +293,7 @@ import _ "rsc.io/quote"
|
|||
|
||||
// Tests that a local replace works. Adapted from mod_local_replace.txt.
|
||||
func TestModLocalReplace(t *testing.T) {
|
||||
mt := setup(t, `
|
||||
mt := setup(t, nil, `
|
||||
-- x/y/go.mod --
|
||||
module x/y
|
||||
require zz v1.0.0
|
||||
|
@ -317,7 +317,7 @@ package z
|
|||
// Tests that the package at the root of the main module can be found.
|
||||
// Adapted from the first part of mod_multirepo.txt.
|
||||
func TestModMultirepo1(t *testing.T) {
|
||||
mt := setup(t, `
|
||||
mt := setup(t, nil, `
|
||||
-- go.mod --
|
||||
module rsc.io/quote
|
||||
|
||||
|
@ -333,7 +333,7 @@ package quote
|
|||
// of mod_multirepo.txt (We skip the case where it doesn't have a go.mod
|
||||
// entry -- we just don't work in that case.)
|
||||
func TestModMultirepo3(t *testing.T) {
|
||||
mt := setup(t, `
|
||||
mt := setup(t, nil, `
|
||||
-- go.mod --
|
||||
module rsc.io/quote
|
||||
|
||||
|
@ -352,7 +352,7 @@ import _ "rsc.io/quote/v2"
|
|||
// Tests that a nested module is found in the module cache, even though
|
||||
// it's checked out. Adapted from the fourth part of mod_multirepo.txt.
|
||||
func TestModMultirepo4(t *testing.T) {
|
||||
mt := setup(t, `
|
||||
mt := setup(t, nil, `
|
||||
-- go.mod --
|
||||
module rsc.io/quote
|
||||
require rsc.io/quote/v2 v2.0.1
|
||||
|
@ -376,7 +376,7 @@ import _ "rsc.io/quote/v2"
|
|||
|
||||
// Tests a simple module dependency. Adapted from the first part of mod_replace.txt.
|
||||
func TestModReplace1(t *testing.T) {
|
||||
mt := setup(t, `
|
||||
mt := setup(t, nil, `
|
||||
-- go.mod --
|
||||
module quoter
|
||||
|
||||
|
@ -392,7 +392,7 @@ package main
|
|||
|
||||
// Tests a local replace. Adapted from the second part of mod_replace.txt.
|
||||
func TestModReplace2(t *testing.T) {
|
||||
mt := setup(t, `
|
||||
mt := setup(t, nil, `
|
||||
-- go.mod --
|
||||
module quoter
|
||||
|
||||
|
@ -418,7 +418,7 @@ import "rsc.io/sampler"
|
|||
// Tests that a module can be replaced by a different module path. Adapted
|
||||
// from the third part of mod_replace.txt.
|
||||
func TestModReplace3(t *testing.T) {
|
||||
mt := setup(t, `
|
||||
mt := setup(t, nil, `
|
||||
-- go.mod --
|
||||
module quoter
|
||||
|
||||
|
@ -451,7 +451,7 @@ package quote
|
|||
// mod_replace_import.txt, with example.com/v changed to /vv because Go 1.11
|
||||
// thinks /v is an invalid major version.
|
||||
func TestModReplaceImport(t *testing.T) {
|
||||
mt := setup(t, `
|
||||
mt := setup(t, nil, `
|
||||
-- go.mod --
|
||||
module example.com/m
|
||||
|
||||
|
@ -556,7 +556,7 @@ package v
|
|||
func TestModWorkspace(t *testing.T) {
|
||||
testenv.NeedsGo1Point(t, 18)
|
||||
|
||||
mt := setup(t, `
|
||||
mt := setup(t, nil, `
|
||||
-- go.work --
|
||||
go 1.18
|
||||
|
||||
|
@ -592,7 +592,7 @@ package b
|
|||
func TestModWorkspaceReplace(t *testing.T) {
|
||||
testenv.NeedsGo1Point(t, 18)
|
||||
|
||||
mt := setup(t, `
|
||||
mt := setup(t, nil, `
|
||||
-- go.work --
|
||||
use m
|
||||
|
||||
|
@ -651,7 +651,7 @@ func G() {
|
|||
func TestModWorkspaceReplaceOverride(t *testing.T) {
|
||||
testenv.NeedsGo1Point(t, 18)
|
||||
|
||||
mt := setup(t, `-- go.work --
|
||||
mt := setup(t, nil, `-- go.work --
|
||||
use m
|
||||
use n
|
||||
replace example.com/dep => ./dep3
|
||||
|
@ -716,7 +716,7 @@ func G() {
|
|||
func TestModWorkspacePrune(t *testing.T) {
|
||||
testenv.NeedsGo1Point(t, 18)
|
||||
|
||||
mt := setup(t, `
|
||||
mt := setup(t, nil, `
|
||||
-- go.work --
|
||||
go 1.18
|
||||
|
||||
|
@ -885,7 +885,7 @@ package z
|
|||
// Tests that we handle GO111MODULE=on with no go.mod file. See #30855.
|
||||
func TestNoMainModule(t *testing.T) {
|
||||
testenv.NeedsGo1Point(t, 12)
|
||||
mt := setup(t, `
|
||||
mt := setup(t, map[string]string{"GO111MODULE": "on"}, `
|
||||
-- x.go --
|
||||
package x
|
||||
`, "")
|
||||
|
@ -993,7 +993,9 @@ type modTest struct {
|
|||
|
||||
// setup builds a test environment from a txtar and supporting modules
|
||||
// in testdata/mod, along the lines of TestScript in cmd/go.
|
||||
func setup(t *testing.T, main, wd string) *modTest {
|
||||
//
|
||||
// extraEnv is applied on top of the default test env.
|
||||
func setup(t *testing.T, extraEnv map[string]string, main, wd string) *modTest {
|
||||
t.Helper()
|
||||
testenv.NeedsGo1Point(t, 11)
|
||||
testenv.NeedsTool(t, "go")
|
||||
|
@ -1023,13 +1025,16 @@ func setup(t *testing.T, main, wd string) *modTest {
|
|||
Env: map[string]string{
|
||||
"GOPATH": filepath.Join(dir, "gopath"),
|
||||
"GOMODCACHE": "",
|
||||
"GO111MODULE": "on",
|
||||
"GO111MODULE": "auto",
|
||||
"GOSUMDB": "off",
|
||||
"GOPROXY": proxydir.ToURL(proxyDir),
|
||||
},
|
||||
WorkingDir: filepath.Join(mainDir, wd),
|
||||
GocmdRunner: &gocommand.Runner{},
|
||||
}
|
||||
for k, v := range extraEnv {
|
||||
env.Env[k] = v
|
||||
}
|
||||
if *testDebug {
|
||||
env.Logf = log.Printf
|
||||
}
|
||||
|
@ -1168,7 +1173,7 @@ func removeDir(dir string) {
|
|||
|
||||
// Tests that findModFile can find the mod files from a path in the module cache.
|
||||
func TestFindModFileModCache(t *testing.T) {
|
||||
mt := setup(t, `
|
||||
mt := setup(t, nil, `
|
||||
-- go.mod --
|
||||
module x
|
||||
|
||||
|
@ -1220,7 +1225,7 @@ func TestInvalidModCache(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestGetCandidatesRanking(t *testing.T) {
|
||||
mt := setup(t, `
|
||||
mt := setup(t, nil, `
|
||||
-- go.mod --
|
||||
module example.com
|
||||
|
||||
|
|
|
@ -253,7 +253,7 @@ func (m *moduleErrorMap) Error() string {
|
|||
var buf bytes.Buffer
|
||||
fmt.Fprintf(&buf, "%d modules have errors:\n", len(paths))
|
||||
for _, path := range paths {
|
||||
fmt.Fprintf(&buf, "\t%s", m.errs[path][0].Msg)
|
||||
fmt.Fprintf(&buf, "\t%s:%s\n", path, m.errs[path][0].Msg)
|
||||
}
|
||||
|
||||
return buf.String()
|
||||
|
|
Загрузка…
Ссылка в новой задаче