]> Cypherpunks repositories - gostls13.git/commitdiff
go/build: implement default GOPATH
authorFrancesc Campoy <campoy@golang.org>
Tue, 1 Nov 2016 04:36:38 +0000 (21:36 -0700)
committerFrancesc Campoy Flores <campoy@golang.org>
Fri, 11 Nov 2016 00:44:28 +0000 (00:44 +0000)
Whenever GOPATH is not defined in the environment, use $HOME/go
as its default value. For Windows systems use %USERPROFILE%/go
and $home/go for plan9.

The choice of these environment variables is based on what Docker
currently does. The os/user package is not used to avoid having
a cgo dependency.

Updates #17262. Documentation changes forthcoming.

Change-Id: I6368fbfbc5afda99d6e64c35c1980076fcf45344
Reviewed-on: https://go-review.googlesource.com/32019
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Russ Cox <rsc@golang.org>
src/cmd/go/env.go
src/cmd/go/get.go
src/cmd/go/go_test.go
src/cmd/go/main.go
src/go/build/build.go

index 366b6c0fbe24ae01302b9fb9a8da0d87a8472ed0..cf614bb3569951e67e402b0ff954e8323a863782 100644 (file)
@@ -40,7 +40,7 @@ func mkEnv() []envVar {
                {"GOHOSTARCH", runtime.GOARCH},
                {"GOHOSTOS", runtime.GOOS},
                {"GOOS", goos},
-               {"GOPATH", os.Getenv("GOPATH")},
+               {"GOPATH", buildContext.GOPATH},
                {"GORACE", os.Getenv("GORACE")},
                {"GOROOT", goroot},
                {"GOTOOLDIR", toolDir},
index 256800affa722e6cf8242a25c6d6c9987fe2b7d5..82408d6a392222ebbf1c7d28b828fea6add9fbd0 100644 (file)
@@ -417,6 +417,10 @@ func downloadPackage(p *Package) error {
                if list[0] == goroot {
                        return fmt.Errorf("cannot download, $GOPATH must not be set to $GOROOT. For more details see: 'go help gopath'")
                }
+               if _, err := os.Stat(filepath.Join(list[0], "src/cmd/go/alldocs.go")); err == nil {
+                       return fmt.Errorf("cannot download, %s is a GOROOT, not a GOPATH. For more details see: 'go help gopath'", list[0])
+               }
+               p.build.Root = list[0]
                p.build.SrcRoot = filepath.Join(list[0], "src")
                p.build.PkgRoot = filepath.Join(list[0], "pkg")
        }
@@ -445,11 +449,19 @@ func downloadPackage(p *Package) error {
                if _, err := os.Stat(root); err == nil {
                        return fmt.Errorf("%s exists but %s does not - stale checkout?", root, meta)
                }
+
+               _, err := os.Stat(p.build.Root)
+               gopathExisted := err == nil
+
                // Some version control tools require the parent of the target to exist.
                parent, _ := filepath.Split(root)
                if err = os.MkdirAll(parent, 0777); err != nil {
                        return err
                }
+               if buildV && !gopathExisted && p.build.Root == buildContext.GOPATH {
+                       fmt.Fprintf(os.Stderr, "created GOPATH=%s; see 'go help gopath'\n", p.build.Root)
+               }
+
                if err = vcs.create(root, repo); err != nil {
                        return err
                }
index a5dc9a8ce865edc10d7302926f7f71a91987663d..456e1b669ae96900346456d8f304b61718398638 100644 (file)
@@ -1664,15 +1664,150 @@ func TestMentionGOPATHNotOnSecondEntry(t *testing.T) {
        }
 }
 
-// Test missing GOPATH is reported.
-func TestMissingGOPATHIsReported(t *testing.T) {
+func homeEnvName() string {
+       switch runtime.GOOS {
+       case "windows":
+               return "USERPROFILE"
+       case "plan9":
+               return "home"
+       default:
+               return "HOME"
+       }
+}
+
+// Test go env missing GOPATH shows default.
+func TestMissingGOPATHEnvShowsDefault(t *testing.T) {
        tg := testgo(t)
        defer tg.cleanup()
        tg.parallel()
        tg.setenv("GOPATH", "")
-       tg.runFail("install", "foo/quxx")
-       if tg.grepCountBoth(`\(\$GOPATH not set\. For more details see: 'go help gopath'\)$`) != 1 {
-               t.Error(`go install foo/quxx expected error: ($GOPATH not set. For more details see: 'go help gopath')`)
+       tg.run("env", "GOPATH")
+
+       want := filepath.Join(os.Getenv(homeEnvName()), "go")
+       got := strings.TrimSpace(tg.getStdout())
+       if got != want {
+               t.Errorf("got %q; want %q", got, want)
+       }
+}
+
+// Test go get missing GOPATH causes go get to warn if directory doesn't exist.
+func TestMissingGOPATHGetWarnsIfNotExists(t *testing.T) {
+       if _, err := exec.LookPath("git"); err != nil {
+               t.Skip("skipping because git binary not found")
+       }
+
+       tg := testgo(t)
+       defer tg.cleanup()
+
+       // setenv variables for test and defer deleting temporary home directory.
+       tg.setenv("GOPATH", "")
+       tmp, err := ioutil.TempDir("", "")
+       if err != nil {
+               t.Fatalf("could not create tmp home: %v", err)
+       }
+       defer os.RemoveAll(tmp)
+       tg.setenv(homeEnvName(), tmp)
+
+       tg.run("get", "-v", "github.com/golang/example/hello")
+
+       want := fmt.Sprintf("created GOPATH=%s; see 'go help gopath'", filepath.Join(tmp, "go"))
+       got := strings.TrimSpace(tg.getStderr())
+       if !strings.Contains(got, want) {
+               t.Errorf("got %q; want %q", got, want)
+       }
+}
+
+// Test go get missing GOPATH causes no warning if directory exists.
+func TestMissingGOPATHGetDoesntWarnIfExists(t *testing.T) {
+       if _, err := exec.LookPath("git"); err != nil {
+               t.Skip("skipping because git binary not found")
+       }
+
+       tg := testgo(t)
+       defer tg.cleanup()
+
+       // setenv variables for test and defer resetting them.
+       tg.setenv("GOPATH", "")
+       tmp, err := ioutil.TempDir("", "")
+       if err != nil {
+               t.Fatalf("could not create tmp home: %v", err)
+       }
+       defer os.RemoveAll(tmp)
+       if err := os.Mkdir(filepath.Join(tmp, "go"), 0777); err != nil {
+               t.Fatalf("could not create $HOME/go: %v", err)
+       }
+
+       tg.setenv(homeEnvName(), tmp)
+
+       tg.run("get", "github.com/golang/example/hello")
+
+       got := strings.TrimSpace(tg.getStderr())
+       if got != "" {
+               t.Errorf("got %q; wants empty", got)
+       }
+}
+
+// Test go get missing GOPATH fails if pointed file is not a directory.
+func TestMissingGOPATHGetFailsIfItsNotDirectory(t *testing.T) {
+       tg := testgo(t)
+       defer tg.cleanup()
+
+       // setenv variables for test and defer resetting them.
+       tg.setenv("GOPATH", "")
+       tmp, err := ioutil.TempDir("", "")
+       if err != nil {
+               t.Fatalf("could not create tmp home: %v", err)
+       }
+       defer os.RemoveAll(tmp)
+
+       path := filepath.Join(tmp, "go")
+       if err := ioutil.WriteFile(path, nil, 0777); err != nil {
+               t.Fatalf("could not create GOPATH at %s: %v", path, err)
+       }
+       tg.setenv(homeEnvName(), tmp)
+
+       const pkg = "github.com/golang/example/hello"
+       tg.runFail("get", pkg)
+
+       msg := "not a directory"
+       if runtime.GOOS == "windows" {
+               msg = "The system cannot find the path specified."
+       }
+       want := fmt.Sprintf("package %s: mkdir %s: %s", pkg, filepath.Join(tmp, "go"), msg)
+       got := strings.TrimSpace(tg.getStderr())
+       if got != want {
+               t.Errorf("got %q; wants %q", got, want)
+       }
+}
+
+// Test go install of missing package when missing GOPATH fails and shows default GOPATH.
+func TestMissingGOPATHInstallMissingPackageFailsAndShowsDefault(t *testing.T) {
+       tg := testgo(t)
+       defer tg.cleanup()
+
+       // setenv variables for test and defer resetting them.
+       tg.setenv("GOPATH", "")
+       tmp, err := ioutil.TempDir("", "")
+       if err != nil {
+               t.Fatalf("could not create tmp home: %v", err)
+       }
+       defer os.RemoveAll(tmp)
+       if err := os.Mkdir(filepath.Join(tmp, "go"), 0777); err != nil {
+               t.Fatalf("could not create $HOME/go: %v", err)
+       }
+       tg.setenv(homeEnvName(), tmp)
+
+       const pkg = "github.com/golang/example/hello"
+       tg.runFail("install", pkg)
+
+       pkgPath := filepath.Join(strings.Split(pkg, "/")...)
+       want := fmt.Sprintf("can't load package: package %s: cannot find package \"%s\" in any of:", pkg, pkg) +
+               fmt.Sprintf("\n\t%s (from $GOROOT)", filepath.Join(runtime.GOROOT(), "src", pkgPath)) +
+               fmt.Sprintf("\n\t%s (from $GOPATH)", filepath.Join(tmp, "go", "src", pkgPath))
+
+       got := strings.TrimSpace(tg.getStderr())
+       if got != want {
+               t.Errorf("got %q; wants %q", got, want)
        }
 }
 
index 90e1a9d02dff019c5656b7f0ae4b80e31e635818..27d02924c0ee7d0fada1015eacea3ffbbe7135ce 100644 (file)
@@ -135,7 +135,7 @@ func main() {
        // Diagnose common mistake: GOPATH==GOROOT.
        // This setting is equivalent to not setting GOPATH at all,
        // which is not what most people want when they do it.
-       if gopath := os.Getenv("GOPATH"); gopath == runtime.GOROOT() {
+       if gopath := buildContext.GOPATH; gopath == runtime.GOROOT() {
                fmt.Fprintf(os.Stderr, "warning: GOPATH set to GOROOT (%s) has no effect\n", gopath)
        } else {
                for _, p := range filepath.SplitList(gopath) {
index 28de5596c50fcd3ba949a4095fc50ea854b2ac5f..0801565f02bfdfe9b8bf1e17a9b80a5886163c0a 100644 (file)
@@ -256,13 +256,26 @@ func (ctxt *Context) SrcDirs() []string {
 // if set, or else the compiled code's GOARCH, GOOS, and GOROOT.
 var Default Context = defaultContext()
 
+func defaultGOPATH() string {
+       env := "HOME"
+       if runtime.GOOS == "windows" {
+               env = "USERPROFILE"
+       } else if runtime.GOOS == "plan9" {
+               env = "home"
+       }
+       if home := os.Getenv(env); home != "" {
+               return filepath.Join(home, "go")
+       }
+       return ""
+}
+
 func defaultContext() Context {
        var c Context
 
        c.GOARCH = envOr("GOARCH", runtime.GOARCH)
        c.GOOS = envOr("GOOS", runtime.GOOS)
        c.GOROOT = pathpkg.Clean(runtime.GOROOT())
-       c.GOPATH = envOr("GOPATH", "")
+       c.GOPATH = envOr("GOPATH", defaultGOPATH())
        c.Compiler = runtime.Compiler
 
        // Each major Go release in the Go 1.x series should add a tag here.