cmd/heapview: look for tools repository in all GOPATH entries

The GOPATH environment variable is defined at
https://golang.org/cmd/go/#hdr-GOPATH_environment_variable as:

> The GOPATH environment variable lists places to look for Go code. On
> Unix, the value is a colon-separated string. On Windows, the value is
> a semicolon-separated string. On Plan 9, the value is a list.

It is legal for Go packages to be in any of those places, not only
the first entry. Look in all places for golang.org/x/tools repository.

Cache the directory that is found. It's slightly more expensive
to look for it, since potentially multiple directories must be
checked for existence.

Updates golang/go#19400.

Change-Id: I16661b7149d52ea6168fffc605c842d7a4da009b
Reviewed-on: https://go-review.googlesource.com/38778
Reviewed-by: Michael Matloob <matloob@golang.org>
diff --git a/cmd/heapview/main.go b/cmd/heapview/main.go
index b65f52a..6dac12e 100644
--- a/cmd/heapview/main.go
+++ b/cmd/heapview/main.go
@@ -8,6 +8,7 @@
 import (
 	"flag"
 	"fmt"
+	"go/build"
 	"io"
 	"log"
 	"net/http"
@@ -34,12 +35,12 @@
 `
 
 func toolsDir() string {
-	gopath := os.Getenv("GOPATH")
-	if gopath == "" {
-		log.Println("error: GOPATH not set. Can't find client files")
+	p, err := build.Import("golang.org/x/tools", "", build.FindOnly)
+	if err != nil {
+		log.Println("error: can't find client files:", err)
 		os.Exit(1)
 	}
-	return filepath.Join(filepath.SplitList(gopath)[0], "src/golang.org/x/tools")
+	return p.Dir
 }
 
 var parseFlags = func() {
@@ -47,19 +48,21 @@
 }
 
 var addHandlers = func() {
+	toolsDir := toolsDir()
+
 	// Directly serve typescript code in client directory for development.
 	http.Handle("/client/", http.StripPrefix("/client",
-		http.FileServer(http.Dir(filepath.Join(toolsDir(), "cmd/heapview/client")))))
+		http.FileServer(http.Dir(filepath.Join(toolsDir, "cmd/heapview/client")))))
 
 	// Serve typescript.js and moduleloader.js for development.
 	http.HandleFunc("/js/typescript.js", func(w http.ResponseWriter, r *http.Request) {
-		http.ServeFile(w, r, filepath.Join(toolsDir(), "third_party/typescript/typescript.js"))
+		http.ServeFile(w, r, filepath.Join(toolsDir, "third_party/typescript/typescript.js"))
 	})
 	http.HandleFunc("/js/moduleloader.js", func(w http.ResponseWriter, r *http.Request) {
-		http.ServeFile(w, r, filepath.Join(toolsDir(), "third_party/moduleloader/moduleloader.js"))
+		http.ServeFile(w, r, filepath.Join(toolsDir, "third_party/moduleloader/moduleloader.js"))
 	})
 	http.HandleFunc("/js/customelements.js", func(w http.ResponseWriter, r *http.Request) {
-		http.ServeFile(w, r, filepath.Join(toolsDir(), "third_party/webcomponents/customelements.js"))
+		http.ServeFile(w, r, filepath.Join(toolsDir, "third_party/webcomponents/customelements.js"))
 	})
 
 	// Serve index.html using html string above.