aboutsummaryrefslogtreecommitdiff
path: root/local.go
diff options
context:
space:
mode:
authorDmitri Shuralyov <dmitshur@golang.org>2021-03-03 19:35:43 -0500
committerDmitri Shuralyov <dmitshur@golang.org>2021-03-05 16:09:21 +0000
commitb3263fcf7749f3600c8928d5f7d4e8a66a34b74f (patch)
tree287aca5c78ac73f85c0037abbd176ac6d752ba4d /local.go
parentb72029adf3393d3635828fedcddd5ae7053d3250 (diff)
downloadgolang-id-tour-b3263fcf7749f3600c8928d5f7d4e8a66a34b74f.tar.xz
tour: look for content in module cache, not GOROOT/misc/tour
Tour content hasn't been available in GOROOT since Go 1.12¹, so stop looking for it there. A more useful fallback place to find tour content is the module cache. When the golang.org/x/tour is in the build list, it will be found via build.Import. It will not be found, however, when the tour binary is run outside of a module. This situation is more common as of Go 1.16, since the default GO111MODULE value changed to on². If the version of the tour binary is known, access the content for that version from the module cache. In the future, this complex and imperfect machinery will be replaced with simply embedding the needed files in the binary. We can't do that quite yet (not without duplicating a lot of code) because Go 1.15 is supported, and because Go 1.14 is used for deployment. It's not neccessary to provide a custom socket.Environ (which served to provide a custom GOPATH value pointing inside GOROOT; that path is being removed here). Delete it along with some other unused code. ¹ https://golang.org/doc/go1.12#tour ² https://golang.org/doc/go1.16#modules Fixes golang/go#44243. Change-Id: Ia239700170b8614d21cafe9617b51dddf3e337d5 Reviewed-on: https://go-review.googlesource.com/c/tour/+/298529 Run-TryBot: Dmitri Shuralyov <dmitshur@golang.org> TryBot-Result: Go Bot <gobot@golang.org> Trust: Dmitri Shuralyov <dmitshur@golang.org> Reviewed-by: Russ Cox <rsc@golang.org>
Diffstat (limited to 'local.go')
-rw-r--r--local.go77
1 files changed, 37 insertions, 40 deletions
diff --git a/local.go b/local.go
index 7702c8f..076cf94 100644
--- a/local.go
+++ b/local.go
@@ -5,8 +5,8 @@
package main
import (
+ "encoding/json"
"flag"
- "fmt"
"go/build"
"html/template"
"io"
@@ -18,6 +18,7 @@ import (
"os/exec"
"path/filepath"
"runtime"
+ "runtime/debug"
"strings"
"time"
@@ -30,7 +31,6 @@ import (
)
const (
- basePkg = "golang.org/x/tour"
socketPath = "/socket"
)
@@ -40,9 +40,6 @@ var (
)
var (
- // GOPATH containing the tour packages
- gopath = os.Getenv("GOPATH")
-
httpAddr string
)
@@ -56,20 +53,41 @@ func isRoot(path string) bool {
return err == nil
}
-func findRoot() (string, error) {
- ctx := build.Default
- p, err := ctx.Import(basePkg, "", build.FindOnly)
+// findRoot is a best-effort attempt to find a tour directory
+// that contains the files it needs. It may not always work.
+//
+// TODO: Delete after Go 1.17 is out and we can just use embed; see CL 291849.
+func findRoot() (string, bool) {
+ // Try finding the golang.org/x/tour package in the
+ // legacy GOPATH mode workspace or in build list.
+ p, err := build.Import("golang.org/x/tour", "", build.FindOnly)
if err == nil && isRoot(p.Dir) {
- return p.Dir, nil
+ return p.Dir, true
}
- tourRoot := filepath.Join(runtime.GOROOT(), "misc", "tour")
- ctx.GOPATH = tourRoot
- p, err = ctx.Import(basePkg, "", build.FindOnly)
- if err == nil && isRoot(tourRoot) {
- gopath = tourRoot
- return tourRoot, nil
+ // If that didn't work, perhaps we're not inside any module
+ // and the binary was built in module mode (e.g., 'go install
+ // golang.org/x/tour@latest' or 'go get golang.org/x/tour'
+ // outside a module).
+ // In that's the case, find out what version it is,
+ // and access its content from the module cache.
+ if info, ok := debug.ReadBuildInfo(); ok &&
+ info.Main.Path == "golang.org/x/tour" &&
+ info.Main.Replace == nil &&
+ info.Main.Version != "(devel)" {
+ // Make some assumptions for brevity:
+ // • the 'go' binary is in $PATH
+ // • the main module isn't replaced
+ // • the version isn't "(devel)"
+ // They should hold for the use cases we care about, until this
+ // entire mechanism is obsoleted by file embedding.
+ out, execError := exec.Command("go", "mod", "download", "-json", "--", "golang.org/x/tour@"+info.Main.Version).Output()
+ var tourRoot struct{ Dir string }
+ jsonError := json.Unmarshal(out, &tourRoot)
+ if execError == nil && jsonError == nil && isRoot(tourRoot.Dir) {
+ return tourRoot.Dir, true
+ }
}
- return "", fmt.Errorf("could not find go-tour content; check $GOROOT and $GOPATH")
+ return "", false
}
func main() {
@@ -82,9 +100,9 @@ func main() {
}
// find and serve the go tour files
- root, err := findRoot()
- if err != nil {
- log.Fatalf("Couldn't find tour files: %v", err)
+ root, ok := findRoot()
+ if !ok {
+ log.Fatalln("Couldn't find files for the Go tour. Try reinstalling it.")
}
log.Println("Serving content from", root)
@@ -166,27 +184,6 @@ If you don't understand this message, hit Control-C to terminate this process.
WARNING! WARNING! WARNING!
`
-type response struct {
- Output string `json:"output"`
- Errors string `json:"compile_errors"`
-}
-
-func init() {
- socket.Environ = environ
-}
-
-// environ returns the original execution environment with GOPATH
-// replaced (or added) with the value of the global var gopath.
-func environ() (env []string) {
- for _, v := range os.Environ() {
- if !strings.HasPrefix(v, "GOPATH=") {
- env = append(env, v)
- }
- }
- env = append(env, "GOPATH="+gopath)
- return
-}
-
// waitServer waits some time for the http Server to start
// serving url. The return value reports whether it starts.
func waitServer(url string) bool {