Skip to content

Commit 99b9ee3

Browse files
author
Jay Conrod
committed
go/build: import packages in module mode when GO111MODULE is "on"
go/build.Import locates package dirctories using 'go list' when in module mode (finding, downloading, and extracting modules is complicated, so go/build does not handle it). Previously, Import used 'go list' if GO111MODULE was not explicitly off and a go.mod file was present (plus some other conditions). With this change, if GO111MODULE is "on", a go.mod file does not need to be present. Fixes #34669 Change-Id: I9e56871054d4b07c3fc04b6f14a5c8c8e9f3c333 Reviewed-on: https://go-review.googlesource.com/c/go/+/199818 Run-TryBot: Jay Conrod <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Bryan C. Mills <[email protected]>
1 parent 07b4abd commit 99b9ee3

File tree

2 files changed

+59
-13
lines changed

2 files changed

+59
-13
lines changed

src/go/build/build.go

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1008,8 +1008,12 @@ func (ctxt *Context) importGo(p *Package, path, srcDir string, mode ImportMode,
10081008
return errNoModules
10091009
}
10101010

1011-
// If modules are not enabled, then the in-process code works fine and we should keep using it.
1012-
switch os.Getenv("GO111MODULE") {
1011+
// Predict whether module aware mode is enabled by checking the value of
1012+
// GO111MODULE and looking for a go.mod file in the source directory or
1013+
// one of its parents. Running 'go env GOMOD' in the source directory would
1014+
// give a canonical answer, but we'd prefer not to execute another command.
1015+
go111Module := os.Getenv("GO111MODULE")
1016+
switch go111Module {
10131017
case "off":
10141018
return errNoModules
10151019
default: // "", "on", "auto", anything else
@@ -1031,19 +1035,21 @@ func (ctxt *Context) importGo(p *Package, path, srcDir string, mode ImportMode,
10311035
}
10321036
}
10331037

1034-
// Look to see if there is a go.mod.
1038+
// Unless GO111MODULE=on, look to see if there is a go.mod.
10351039
// Since go1.13, it doesn't matter if we're inside GOPATH.
1036-
parent := absSrcDir
1037-
for {
1038-
info, err := os.Stat(filepath.Join(parent, "go.mod"))
1039-
if err == nil && !info.IsDir() {
1040-
break
1041-
}
1042-
d := filepath.Dir(parent)
1043-
if len(d) >= len(parent) {
1044-
return errNoModules // reached top of file system, no go.mod
1040+
if go111Module != "on" {
1041+
parent := absSrcDir
1042+
for {
1043+
info, err := os.Stat(filepath.Join(parent, "go.mod"))
1044+
if err == nil && !info.IsDir() {
1045+
break
1046+
}
1047+
d := filepath.Dir(parent)
1048+
if len(d) >= len(parent) {
1049+
return errNoModules // reached top of file system, no go.mod
1050+
}
1051+
parent = d
10451052
}
1046-
parent = d
10471053
}
10481054

10491055
cmd := exec.Command("go", "list", "-e", "-compiler="+ctxt.Compiler, "-tags="+strings.Join(ctxt.BuildTags, ","), "-installsuffix="+ctxt.InstallSuffix, "-f={{.Dir}}\n{{.ImportPath}}\n{{.Root}}\n{{.Goroot}}\n{{if .Error}}{{.Error}}{{end}}\n", "--", path)

src/go/build/build_test.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,46 @@ func TestImportVendorParentFailure(t *testing.T) {
420420
}
421421
}
422422

423+
// Check that a package is loaded in module mode if GO111MODULE=on, even when
424+
// no go.mod file is present. It should fail to resolve packages outside std.
425+
// Verifies golang.org/issue/34669.
426+
func TestImportPackageOutsideModule(t *testing.T) {
427+
testenv.MustHaveGoBuild(t)
428+
429+
// Disable module fetching for this test so that 'go list' fails quickly
430+
// without trying to find the latest version of a module.
431+
defer os.Setenv("GOPROXY", os.Getenv("GOPROXY"))
432+
os.Setenv("GOPROXY", "off")
433+
434+
// Create a GOPATH in a temporary directory. We don't use testdata
435+
// because it's in GOROOT, which interferes with the module heuristic.
436+
gopath, err := ioutil.TempDir("", "gobuild-notmodule")
437+
if err != nil {
438+
t.Fatal(err)
439+
}
440+
defer os.RemoveAll(gopath)
441+
if err := os.MkdirAll(filepath.Join(gopath, "src/example.com/p"), 0777); err != nil {
442+
t.Fatal(err)
443+
}
444+
if err := ioutil.WriteFile(filepath.Join(gopath, "src/example.com/p/p.go"), []byte("package p"), 0666); err != nil {
445+
t.Fatal(err)
446+
}
447+
448+
defer os.Setenv("GO111MODULE", os.Getenv("GO111MODULE"))
449+
os.Setenv("GO111MODULE", "on")
450+
defer os.Setenv("GOPATH", os.Getenv("GOPATH"))
451+
os.Setenv("GOPATH", gopath)
452+
ctxt := Default
453+
ctxt.GOPATH = gopath
454+
455+
want := "cannot find module providing package"
456+
if _, err := ctxt.Import("example.com/p", gopath, FindOnly); err == nil {
457+
t.Fatal("importing package when no go.mod is present succeeded unexpectedly")
458+
} else if errStr := err.Error(); !strings.Contains(errStr, want) {
459+
t.Fatalf("error when importing package when no go.mod is present: got %q; want %q", errStr, want)
460+
}
461+
}
462+
423463
func TestImportDirTarget(t *testing.T) {
424464
testenv.MustHaveGoBuild(t) // really must just have source
425465
ctxt := Default

0 commit comments

Comments
 (0)