Skip to content

Commit 1363eeb

Browse files
committed
[release-branch.go1.8] cmd/go, go/build: better defenses against GOPATH=GOROOT
Fixes #18863. Change-Id: I0723563cd23728b0d43ebcc25979bf8d21e2a72c Reviewed-on: https://go-review.googlesource.com/36427 Run-TryBot: Russ Cox <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]> Reviewed-on: https://go-review.googlesource.com/36536 Reviewed-by: Brad Fitzpatrick <[email protected]> TryBot-Result: Gobot Gobot <[email protected]>
1 parent 1edfd64 commit 1363eeb

File tree

4 files changed

+71
-133
lines changed

4 files changed

+71
-133
lines changed

src/cmd/go/get.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -428,7 +428,7 @@ func downloadPackage(p *Package) error {
428428
return fmt.Errorf("cannot download, $GOPATH not set. For more details see: 'go help gopath'")
429429
}
430430
// Guard against people setting GOPATH=$GOROOT.
431-
if list[0] == goroot {
431+
if filepath.Clean(list[0]) == filepath.Clean(goroot) {
432432
return fmt.Errorf("cannot download, $GOPATH must not be set to $GOROOT. For more details see: 'go help gopath'")
433433
}
434434
if _, err := os.Stat(filepath.Join(list[0], "src/cmd/go/alldocs.go")); err == nil {

src/cmd/go/go_test.go

+68-130
Original file line numberDiff line numberDiff line change
@@ -1683,173 +1683,111 @@ func homeEnvName() string {
16831683
}
16841684
}
16851685

1686-
// Test go env missing GOPATH shows default.
1687-
func TestMissingGOPATHEnvShowsDefault(t *testing.T) {
1686+
func TestDefaultGOPATH(t *testing.T) {
16881687
tg := testgo(t)
16891688
defer tg.cleanup()
16901689
tg.parallel()
1691-
tg.setenv("GOPATH", "")
1692-
tg.run("env", "GOPATH")
1693-
1694-
want := filepath.Join(os.Getenv(homeEnvName()), "go")
1695-
got := strings.TrimSpace(tg.getStdout())
1696-
if got != want {
1697-
t.Errorf("got %q; want %q", got, want)
1698-
}
1699-
}
1700-
1701-
// Test go get missing GOPATH causes go get to warn if directory doesn't exist.
1702-
func TestMissingGOPATHGetWarnsIfNotExists(t *testing.T) {
1703-
testenv.MustHaveExternalNetwork(t)
1690+
tg.tempDir("home/go")
1691+
tg.setenv(homeEnvName(), tg.path("home"))
17041692

1705-
if _, err := exec.LookPath("git"); err != nil {
1706-
t.Skip("skipping because git binary not found")
1707-
}
1708-
1709-
tg := testgo(t)
1710-
defer tg.cleanup()
1711-
1712-
// setenv variables for test and defer deleting temporary home directory.
1713-
tg.setenv("GOPATH", "")
1714-
tmp, err := ioutil.TempDir("", "")
1715-
if err != nil {
1716-
t.Fatalf("could not create tmp home: %v", err)
1717-
}
1718-
defer os.RemoveAll(tmp)
1719-
tg.setenv(homeEnvName(), tmp)
1693+
tg.run("env", "GOPATH")
1694+
tg.grepStdout(regexp.QuoteMeta(tg.path("home/go")), "want GOPATH=$HOME/go")
17201695

1721-
tg.run("get", "-v", "github.com/golang/example/hello")
1696+
tg.setenv("GOROOT", tg.path("home/go"))
1697+
tg.run("env", "GOPATH")
1698+
tg.grepStdoutNot(".", "want unset GOPATH because GOROOT=$HOME/go")
17221699

1723-
want := fmt.Sprintf("created GOPATH=%s; see 'go help gopath'", filepath.Join(tmp, "go"))
1724-
got := strings.TrimSpace(tg.getStderr())
1725-
if !strings.Contains(got, want) {
1726-
t.Errorf("got %q; want %q", got, want)
1727-
}
1700+
tg.setenv("GOROOT", tg.path("home/go")+"/")
1701+
tg.run("env", "GOPATH")
1702+
tg.grepStdoutNot(".", "want unset GOPATH because GOROOT=$HOME/go/")
17281703
}
17291704

1730-
// Test go get missing GOPATH causes no warning if directory exists.
1731-
func TestMissingGOPATHGetDoesntWarnIfExists(t *testing.T) {
1705+
func TestDefaultGOPATHGet(t *testing.T) {
17321706
testenv.MustHaveExternalNetwork(t)
17331707

1734-
if _, err := exec.LookPath("git"); err != nil {
1735-
t.Skip("skipping because git binary not found")
1736-
}
1737-
17381708
tg := testgo(t)
17391709
defer tg.cleanup()
1740-
1741-
// setenv variables for test and defer resetting them.
17421710
tg.setenv("GOPATH", "")
1743-
tmp, err := ioutil.TempDir("", "")
1744-
if err != nil {
1745-
t.Fatalf("could not create tmp home: %v", err)
1746-
}
1747-
defer os.RemoveAll(tmp)
1748-
if err := os.Mkdir(filepath.Join(tmp, "go"), 0777); err != nil {
1749-
t.Fatalf("could not create $HOME/go: %v", err)
1750-
}
1711+
tg.tempDir("home")
1712+
tg.setenv(homeEnvName(), tg.path("home"))
17511713

1752-
tg.setenv(homeEnvName(), tmp)
1714+
// warn for creating directory
1715+
tg.run("get", "-v", "github.com/golang/example/hello")
1716+
tg.grepStderr("created GOPATH="+regexp.QuoteMeta(tg.path("home/go"))+"; see 'go help gopath'", "did not create GOPATH")
17531717

1718+
// no warning if directory already exists
1719+
tg.must(os.RemoveAll(tg.path("home/go")))
1720+
tg.tempDir("home/go")
17541721
tg.run("get", "github.com/golang/example/hello")
1722+
tg.grepStderrNot(".", "expected no output on standard error")
17551723

1756-
got := strings.TrimSpace(tg.getStderr())
1757-
if got != "" {
1758-
t.Errorf("got %q; wants empty", got)
1759-
}
1760-
}
1761-
1762-
// Test go get missing GOPATH fails if pointed file is not a directory.
1763-
func TestMissingGOPATHGetFailsIfItsNotDirectory(t *testing.T) {
1764-
testenv.MustHaveExternalNetwork(t)
1765-
1766-
tg := testgo(t)
1767-
defer tg.cleanup()
1768-
1769-
// setenv variables for test and defer resetting them.
1770-
tg.setenv("GOPATH", "")
1771-
tmp, err := ioutil.TempDir("", "")
1772-
if err != nil {
1773-
t.Fatalf("could not create tmp home: %v", err)
1774-
}
1775-
defer os.RemoveAll(tmp)
1776-
1777-
path := filepath.Join(tmp, "go")
1778-
if err := ioutil.WriteFile(path, nil, 0777); err != nil {
1779-
t.Fatalf("could not create GOPATH at %s: %v", path, err)
1780-
}
1781-
tg.setenv(homeEnvName(), tmp)
1782-
1783-
const pkg = "github.com/golang/example/hello"
1784-
tg.runFail("get", pkg)
1785-
1786-
msg := "not a directory"
1787-
if runtime.GOOS == "windows" {
1788-
msg = "The system cannot find the path specified."
1789-
}
1790-
want := fmt.Sprintf("package %s: mkdir %s: %s", pkg, filepath.Join(tmp, "go"), msg)
1791-
got := strings.TrimSpace(tg.getStderr())
1792-
if got != want {
1793-
t.Errorf("got %q; wants %q", got, want)
1794-
}
1724+
// error if $HOME/go is a file
1725+
tg.must(os.RemoveAll(tg.path("home/go")))
1726+
tg.tempFile("home/go", "")
1727+
tg.runFail("get", "github.com/golang/example/hello")
1728+
tg.grepStderr(`mkdir .*[/\\]go: .*(not a directory|cannot find the path)`, "expected error because $HOME/go is a file")
17951729
}
17961730

1797-
// Test go install of missing package when missing GOPATH fails and shows default GOPATH.
1798-
func TestMissingGOPATHInstallMissingPackageFailsAndShowsDefault(t *testing.T) {
1731+
func TestDefaultGOPATHPrintedSearchList(t *testing.T) {
17991732
tg := testgo(t)
18001733
defer tg.cleanup()
1801-
1802-
// setenv variables for test and defer resetting them.
18031734
tg.setenv("GOPATH", "")
1804-
tmp, err := ioutil.TempDir("", "")
1805-
if err != nil {
1806-
t.Fatalf("could not create tmp home: %v", err)
1807-
}
1808-
defer os.RemoveAll(tmp)
1809-
if err := os.Mkdir(filepath.Join(tmp, "go"), 0777); err != nil {
1810-
t.Fatalf("could not create $HOME/go: %v", err)
1811-
}
1812-
tg.setenv(homeEnvName(), tmp)
1813-
1814-
const pkg = "github.com/golang/example/hello"
1815-
tg.runFail("install", pkg)
1735+
tg.tempDir("home")
1736+
tg.setenv(homeEnvName(), tg.path("home"))
18161737

1817-
pkgPath := filepath.Join(strings.Split(pkg, "/")...)
1818-
want := fmt.Sprintf("can't load package: package %s: cannot find package \"%s\" in any of:", pkg, pkg) +
1819-
fmt.Sprintf("\n\t%s (from $GOROOT)", filepath.Join(runtime.GOROOT(), "src", pkgPath)) +
1820-
fmt.Sprintf("\n\t%s (from $GOPATH)", filepath.Join(tmp, "go", "src", pkgPath))
1821-
1822-
got := strings.TrimSpace(tg.getStderr())
1823-
if got != want {
1824-
t.Errorf("got %q; wants %q", got, want)
1825-
}
1738+
tg.runFail("install", "github.com/golang/example/hello")
1739+
tg.grepStderr(regexp.QuoteMeta(tg.path("home/go/src/github.com/golang/example/hello"))+`.*from \$GOPATH`, "expected default GOPATH")
18261740
}
18271741

18281742
// Issue 4186. go get cannot be used to download packages to $GOROOT.
18291743
// Test that without GOPATH set, go get should fail.
1830-
func TestWithoutGOPATHGoGetFails(t *testing.T) {
1744+
func TestGoGetIntoGOROOT(t *testing.T) {
18311745
testenv.MustHaveExternalNetwork(t)
18321746

18331747
tg := testgo(t)
18341748
defer tg.cleanup()
18351749
tg.parallel()
18361750
tg.tempDir("src")
1837-
tg.setenv("GOPATH", "")
1751+
1752+
// Fails because GOROOT=GOPATH
1753+
tg.setenv("GOPATH", tg.path("."))
18381754
tg.setenv("GOROOT", tg.path("."))
1839-
tg.runFail("get", "-d", "golang.org/x/codereview/cmd/hgpatch")
1840-
}
1755+
tg.runFail("get", "-d", "github.com/golang/example/hello")
1756+
tg.grepStderr("warning: GOPATH set to GOROOT", "go should detect GOPATH=GOROOT")
1757+
tg.grepStderr(`\$GOPATH must not be set to \$GOROOT`, "go should detect GOPATH=GOROOT")
18411758

1842-
// Test that with GOPATH=$GOROOT, go get should fail.
1843-
func TestWithGOPATHEqualsGOROOTGoGetFails(t *testing.T) {
1844-
testenv.MustHaveExternalNetwork(t)
1759+
// Fails because GOROOT=GOPATH after cleaning.
1760+
tg.setenv("GOPATH", tg.path(".")+"/")
1761+
tg.setenv("GOROOT", tg.path("."))
1762+
tg.runFail("get", "-d", "github.com/golang/example/hello")
1763+
tg.grepStderr("warning: GOPATH set to GOROOT", "go should detect GOPATH=GOROOT")
1764+
tg.grepStderr(`\$GOPATH must not be set to \$GOROOT`, "go should detect GOPATH=GOROOT")
18451765

1846-
tg := testgo(t)
1847-
defer tg.cleanup()
1848-
tg.parallel()
1849-
tg.tempDir("src")
18501766
tg.setenv("GOPATH", tg.path("."))
1851-
tg.setenv("GOROOT", tg.path("."))
1852-
tg.runFail("get", "-d", "golang.org/x/codereview/cmd/hgpatch")
1767+
tg.setenv("GOROOT", tg.path(".")+"/")
1768+
tg.runFail("get", "-d", "github.com/golang/example/hello")
1769+
tg.grepStderr("warning: GOPATH set to GOROOT", "go should detect GOPATH=GOROOT")
1770+
tg.grepStderr(`\$GOPATH must not be set to \$GOROOT`, "go should detect GOPATH=GOROOT")
1771+
1772+
// Fails because GOROOT=$HOME/go so default GOPATH unset.
1773+
tg.tempDir("home/go")
1774+
tg.setenv(homeEnvName(), tg.path("home"))
1775+
tg.setenv("GOPATH", "")
1776+
tg.setenv("GOROOT", tg.path("home/go"))
1777+
tg.runFail("get", "-d", "github.com/golang/example/hello")
1778+
tg.grepStderr(`\$GOPATH not set`, "expected GOPATH not set")
1779+
1780+
tg.setenv(homeEnvName(), tg.path("home")+"/")
1781+
tg.setenv("GOPATH", "")
1782+
tg.setenv("GOROOT", tg.path("home/go"))
1783+
tg.runFail("get", "-d", "github.com/golang/example/hello")
1784+
tg.grepStderr(`\$GOPATH not set`, "expected GOPATH not set")
1785+
1786+
tg.setenv(homeEnvName(), tg.path("home"))
1787+
tg.setenv("GOPATH", "")
1788+
tg.setenv("GOROOT", tg.path("home/go")+"/")
1789+
tg.runFail("get", "-d", "github.com/golang/example/hello")
1790+
tg.grepStderr(`\$GOPATH not set`, "expected GOPATH not set")
18531791
}
18541792

18551793
func TestLdflagsArgumentsWithSpacesIssue3941(t *testing.T) {

src/cmd/go/main.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ func main() {
136136
// Diagnose common mistake: GOPATH==GOROOT.
137137
// This setting is equivalent to not setting GOPATH at all,
138138
// which is not what most people want when they do it.
139-
if gopath := buildContext.GOPATH; gopath == runtime.GOROOT() {
139+
if gopath := buildContext.GOPATH; filepath.Clean(gopath) == filepath.Clean(runtime.GOROOT()) {
140140
fmt.Fprintf(os.Stderr, "warning: GOPATH set to GOROOT (%s) has no effect\n", gopath)
141141
} else {
142142
for _, p := range filepath.SplitList(gopath) {

src/go/build/build.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ func defaultGOPATH() string {
266266
}
267267
if home := os.Getenv(env); home != "" {
268268
def := filepath.Join(home, "go")
269-
if def == runtime.GOROOT() {
269+
if filepath.Clean(def) == filepath.Clean(runtime.GOROOT()) {
270270
// Don't set the default GOPATH to GOROOT,
271271
// as that will trigger warnings from the go tool.
272272
return ""

0 commit comments

Comments
 (0)