cmd/golangorg: simplify local vs prod programs
There was too much duplicated code between main.go
and appinit.go and too many build-tagged-out files.
Make main.go the func main for both prod and local.
Introduce local.go, merging dl.go and play.go.
Introduce prod.go, holding the prod-specific bits of appinit.go
(the rest are in main.go).
Rename the build tag to prod instead of golangorg
(the whole program is golangorg; it's very confusing).
Fixes golang/go#41102.
Change-Id: I261ce8e9171110f01798025f8218ce9f8253af81
Reviewed-on: https://go-review.googlesource.com/c/website/+/293413
Trust: Russ Cox <rsc@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
diff --git a/README.md b/README.md
index 17d6276..ec3d08e 100644
--- a/README.md
+++ b/README.md
@@ -8,7 +8,7 @@
To run the server to preview local content changes, use:
- go run ./cmd/golangorg -a
+ go run ./cmd/golangorg
The supporting programs cmd/admingolangorg and cmd/googlegolangorg
are the servers for admin.golang.org and google.golang.org.
diff --git a/cmd/golangorg/Dockerfile.prod b/cmd/golangorg/Dockerfile.prod
index 6c22980..e60c99e 100644
--- a/cmd/golangorg/Dockerfile.prod
+++ b/cmd/golangorg/Dockerfile.prod
@@ -21,7 +21,7 @@
WORKDIR /website/cmd/golangorg
-RUN go build -o /golangorg -tags=golangorg golang.org/x/website/cmd/golangorg
+RUN go build -o /golangorg -tags=prod golang.org/x/website/cmd/golangorg
# Clean up goroot for the final image.
RUN cd /goroot && git clean -xdf
diff --git a/cmd/golangorg/README.md b/cmd/golangorg/README.md
index 228b62f..233e605 100644
--- a/cmd/golangorg/README.md
+++ b/cmd/golangorg/README.md
@@ -16,10 +16,9 @@
* Godoc sources inside $GOPATH
(`go get -d golang.org/x/website/cmd/golangorg`)
-Build with the `golangorg` tag and run:
+Run with the `prod` tag:
- go build -tags golangorg
- ./golangorg
+ go run -tags prod .
In production mode it serves on localhost:8080 (not 6060).
The port is controlled by $PORT, as in:
diff --git a/cmd/golangorg/appinit.go b/cmd/golangorg/appinit.go
deleted file mode 100644
index 9dc4076..0000000
--- a/cmd/golangorg/appinit.go
+++ /dev/null
@@ -1,137 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build go1.16
-// +build golangorg
-
-package main
-
-// This file replaces main.go when running golangorg under App Engine.
-// See README.md for details.
-
-import (
- "context"
- "go/build"
- "io"
- "log"
- "net/http"
- "os"
- "regexp"
- "runtime"
- "strings"
-
- "golang.org/x/tools/godoc"
- "golang.org/x/tools/godoc/vfs"
- "golang.org/x/tools/godoc/vfs/gatefs"
- "golang.org/x/website"
- "golang.org/x/website/internal/dl"
- "golang.org/x/website/internal/proxy"
- "golang.org/x/website/internal/redirect"
- "golang.org/x/website/internal/short"
-
- "cloud.google.com/go/datastore"
- "golang.org/x/website/internal/memcache"
-)
-
-func main() {
- log.SetFlags(log.Lshortfile | log.LstdFlags)
-
- playEnabled = true
-
- log.Println("initializing golang.org server ...")
-
- fsGate := make(chan bool, 20)
-
- rootfs := gatefs.New(vfs.OS(runtime.GOROOT()), fsGate)
- fs.Bind("/", rootfs, "/", vfs.BindReplace)
-
- // Try serving files in /doc from a local copy before trying the main
- // go repository. This lets us update some documentation outside the
- // Go release cycle. This includes root.html, which redirects to "/".
- // See golang.org/issue/29206.
- fs.Bind("/doc", vfs.FromFS(website.Content), "/doc", vfs.BindBefore)
- fs.Bind("/lib/godoc", vfs.FromFS(website.Content), "/", vfs.BindReplace)
-
- webroot := getFullPath("/src/golang.org/x/website")
- fs.Bind("/favicon.ico", gatefs.New(vfs.OS(webroot), fsGate), "/favicon.ico", vfs.BindBefore)
-
- corpus := godoc.NewCorpus(fs)
- corpus.Verbose = false
- corpus.MaxResults = 10000 // matches flag default in main.go
- corpus.IndexEnabled = false
- if err := corpus.Init(); err != nil {
- log.Fatal(err)
- }
- corpus.InitVersionInfo()
-
- pres = godoc.NewPresentation(corpus)
- pres.ShowPlayground = true
- pres.DeclLinks = true
- pres.NotesRx = regexp.MustCompile("BUG")
- pres.GoogleAnalytics = os.Getenv("GOLANGORG_ANALYTICS")
-
- readTemplates(pres)
-
- datastoreClient, memcacheClient := getClients()
-
- // NOTE(cbro): registerHandlers registers itself against DefaultServeMux.
- // The mux returned has host enforcement, so it's important to register
- // against this mux and not DefaultServeMux.
- mux := registerHandlers(pres)
- dl.RegisterHandlers(mux, datastoreClient, memcacheClient)
- short.RegisterHandlers(mux, datastoreClient, memcacheClient)
-
- // Register /compile and /share handlers against the default serve mux
- // so that other app modules can make plain HTTP requests to those
- // hosts. (For reasons, HTTPS communication between modules is broken.)
- proxy.RegisterHandlers(http.DefaultServeMux)
-
- http.HandleFunc("/_ah/health", func(w http.ResponseWriter, r *http.Request) {
- io.WriteString(w, "ok")
- })
-
- http.HandleFunc("/robots.txt", func(w http.ResponseWriter, r *http.Request) {
- io.WriteString(w, "User-agent: *\nDisallow: /search\n")
- })
-
- if err := redirect.LoadChangeMap("hg-git-mapping.bin"); err != nil {
- log.Fatalf("LoadChangeMap: %v", err)
- }
-
- log.Println("godoc initialization complete")
-
- // TODO(cbro): add instrumentation via opencensus.
- port := "8080"
- if p := os.Getenv("PORT"); p != "" { // PORT is set by GAE flex.
- port = p
- }
- log.Fatal(http.ListenAndServe(":"+port, nil))
-}
-
-func getFullPath(relPath string) string {
- gopath := os.Getenv("GOPATH")
- if gopath == "" {
- gopath = build.Default.GOPATH
- }
- return gopath + relPath
-}
-
-func getClients() (*datastore.Client, *memcache.Client) {
- ctx := context.Background()
-
- datastoreClient, err := datastore.NewClient(ctx, "")
- if err != nil {
- if strings.Contains(err.Error(), "missing project") {
- log.Fatalf("Missing datastore project. Set the DATASTORE_PROJECT_ID env variable. Use `gcloud beta emulators datastore` to start a local datastore.")
- }
- log.Fatalf("datastore.NewClient: %v.", err)
- }
-
- redisAddr := os.Getenv("GOLANGORG_REDIS_ADDR")
- if redisAddr == "" {
- log.Fatalf("Missing redis server for golangorg in production mode. set GOLANGORG_REDIS_ADDR environment variable.")
- }
- memcacheClient := memcache.New(redisAddr)
- return datastoreClient, memcacheClient
-}
diff --git a/cmd/golangorg/blog.go b/cmd/golangorg/blog.go
index 219fec8..e9edade 100644
--- a/cmd/golangorg/blog.go
+++ b/cmd/golangorg/blog.go
@@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build go1.16
+// +build go1.16
+
package main
import (
diff --git a/cmd/golangorg/codewalk.go b/cmd/golangorg/codewalk.go
index 91c8cdc..961b008 100644
--- a/cmd/golangorg/codewalk.go
+++ b/cmd/golangorg/codewalk.go
@@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build go1.16
+// +build go1.16
+
// The /doc/codewalk/ tree is synthesized from codewalk descriptions,
// files named $GOROOT/doc/codewalk/*.xml.
// For an example and a description of the format, see
diff --git a/cmd/golangorg/dl.go b/cmd/golangorg/dl.go
deleted file mode 100644
index edeecb8..0000000
--- a/cmd/golangorg/dl.go
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2014 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build !golangorg
-
-package main
-
-import "net/http"
-
-// Register a redirect handler for /dl/ to the golang.org download page.
-// This file will not be included when deploying godoc to golang.org.
-
-func init() {
- http.Handle("/dl/", http.RedirectHandler("https://golang.org/dl/", http.StatusFound))
-}
diff --git a/cmd/golangorg/go115.go b/cmd/golangorg/go115.go
index c53a808..38174dc 100644
--- a/cmd/golangorg/go115.go
+++ b/cmd/golangorg/go115.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build !go1.16
// +build !go1.16
package main
diff --git a/cmd/golangorg/godoc.go b/cmd/golangorg/godoc.go
index 74a8978..54b71a3 100644
--- a/cmd/golangorg/godoc.go
+++ b/cmd/golangorg/godoc.go
@@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build go1.16
+// +build go1.16
+
package main
import (
diff --git a/cmd/golangorg/godoc_test.go b/cmd/golangorg/godoc_test.go
index 6afe551..1e18436 100644
--- a/cmd/golangorg/godoc_test.go
+++ b/cmd/golangorg/godoc_test.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build go1.16
// +build go1.16
package main_test
@@ -77,14 +78,6 @@
false)
}
-func waitForSearchReady(t *testing.T, addr string) {
- waitForServer(t,
- fmt.Sprintf("http://%v/search?q=FALLTHROUGH", addr),
- "The list of tokens.",
- 2*time.Minute,
- false)
-}
-
func waitUntilScanComplete(t *testing.T, addr string) {
waitForServer(t,
fmt.Sprintf("http://%v/pkg", addr),
diff --git a/cmd/golangorg/goroot.go b/cmd/golangorg/goroot.go
deleted file mode 100644
index 998e869..0000000
--- a/cmd/golangorg/goroot.go
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright 2018 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package main
-
-import (
- "os"
- "path/filepath"
- "runtime"
-)
-
-// Copies of functions from src/cmd/go/internal/cfg/cfg.go for
-// finding the GOROOT.
-// Keep them in sync until support is moved to a common place, if ever.
-
-func findGOROOT() string {
- if env := os.Getenv("GOROOT"); env != "" {
- return filepath.Clean(env)
- }
- def := filepath.Clean(runtime.GOROOT())
- if runtime.Compiler == "gccgo" {
- // gccgo has no real GOROOT, and it certainly doesn't
- // depend on the executable's location.
- return def
- }
- exe, err := os.Executable()
- if err == nil {
- exe, err = filepath.Abs(exe)
- if err == nil {
- if dir := filepath.Join(exe, "../.."); isGOROOT(dir) {
- // If def (runtime.GOROOT()) and dir are the same
- // directory, prefer the spelling used in def.
- if isSameDir(def, dir) {
- return def
- }
- return dir
- }
- exe, err = filepath.EvalSymlinks(exe)
- if err == nil {
- if dir := filepath.Join(exe, "../.."); isGOROOT(dir) {
- if isSameDir(def, dir) {
- return def
- }
- return dir
- }
- }
- }
- }
- return def
-}
-
-// isGOROOT reports whether path looks like a GOROOT.
-//
-// It does this by looking for the path/pkg/tool directory,
-// which is necessary for useful operation of the cmd/go tool,
-// and is not typically present in a GOPATH.
-func isGOROOT(path string) bool {
- stat, err := os.Stat(filepath.Join(path, "pkg", "tool"))
- if err != nil {
- return false
- }
- return stat.IsDir()
-}
-
-// isSameDir reports whether dir1 and dir2 are the same directory.
-func isSameDir(dir1, dir2 string) bool {
- if dir1 == dir2 {
- return true
- }
- info1, err1 := os.Stat(dir1)
- info2, err2 := os.Stat(dir2)
- return err1 == nil && err2 == nil && os.SameFile(info1, info2)
-}
diff --git a/cmd/golangorg/handlers.go b/cmd/golangorg/handlers.go
index 1cafdcb..57c6cc5 100644
--- a/cmd/golangorg/handlers.go
+++ b/cmd/golangorg/handlers.go
@@ -2,13 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// The /doc/codewalk/ tree is synthesized from codewalk descriptions,
-// files named $GOROOT/doc/codewalk/*.xml.
-// For an example and a description of the format, see
-// http://golang.org/doc/codewalk/codewalk or run godoc -http=:6060
-// and see http://localhost:6060/doc/codewalk/codewalk .
-// That page is itself a codewalk; the source code for it is
-// $GOROOT/doc/codewalk/codewalk.xml.
+//go:build go1.16
+// +build go1.16
package main
diff --git a/cmd/golangorg/local.go b/cmd/golangorg/local.go
new file mode 100644
index 0000000..ea32c54
--- /dev/null
+++ b/cmd/golangorg/local.go
@@ -0,0 +1,40 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build go1.16 && !prod
+// +build go1.16,!prod
+
+package main
+
+import (
+ "fmt"
+ "log"
+ "net/http"
+ "os"
+ "path/filepath"
+ "runtime"
+
+ // This package registers "/compile" and "/share" handlers
+ // that redirect to the golang.org playground.
+ _ "golang.org/x/tools/playground"
+)
+
+func earlySetup() {
+ _, file, _, ok := runtime.Caller(0)
+ if !ok {
+ fmt.Fprintln(os.Stderr, "runtime.Caller failed: cannot find templates for -a mode.")
+ os.Exit(2)
+ }
+ dir := filepath.Join(file, "../../../_content")
+ if _, err := os.Stat(filepath.Join(dir, "godoc.html")); err != nil {
+ log.Printf("warning: cannot find template dir; using embedded copy")
+ return
+ }
+ *templateDir = dir
+}
+
+func lateSetup(mux *http.ServeMux) {
+ // Register a redirect handler for /dl/ to the golang.org download page.
+ http.Handle("/dl/", http.RedirectHandler("https://golang.org/dl/", http.StatusFound))
+}
diff --git a/cmd/golangorg/main.go b/cmd/golangorg/main.go
index d6534fe..3faf663 100644
--- a/cmd/golangorg/main.go
+++ b/cmd/golangorg/main.go
@@ -15,22 +15,16 @@
// https://golang.org/pkg/compress/zlib)
//
-// Some pages are being transitioned from $GOROOT to content/doc.
-// See golang.org/issue/29206 and golang.org/issue/33637.
-
+//go:build go1.16
// +build go1.16
-// +build !golangorg
package main
import (
- _ "expvar" // to serve /debug/vars
"flag"
"fmt"
- "go/build"
"log"
"net/http"
- _ "net/http/pprof" // to serve /debug/pprof/*
"os"
"path/filepath"
"regexp"
@@ -42,39 +36,19 @@
"golang.org/x/website"
)
-const defaultAddr = "localhost:6060" // default webserver address
-
var (
- // network
- httpAddr = flag.String("http", defaultAddr, "HTTP service address")
-
- verbose = flag.Bool("v", false, "verbose mode")
-
- // file system roots
- // TODO(gri) consider the invariant that goroot always end in '/'
- goroot = flag.String("goroot", findGOROOT(), "Go root directory")
-
- // layout control
- autoFlag = flag.Bool("a", false, "update templates automatically")
+ httpAddr = flag.String("http", "localhost:6060", "HTTP service address")
+ verbose = flag.Bool("v", false, "verbose mode")
+ goroot = flag.String("goroot", runtime.GOROOT(), "Go root directory")
showTimestamps = flag.Bool("timestamps", false, "show timestamps with directory listings")
templateDir = flag.String("templates", "", "load templates/JS/CSS from disk in this directory (usually /path-to-website/content)")
- showPlayground = flag.Bool("play", false, "enable playground")
+ showPlayground = flag.Bool("play", true, "enable playground")
declLinks = flag.Bool("links", true, "link identifiers to their declarations")
-
- // source code notes
- notesRx = flag.String("notes", "BUG", "regular expression matching note markers to show")
+ notesRx = flag.String("notes", "BUG", "regular expression matching note markers to show")
)
-func getFullPath(relPath string) string {
- gopath := os.Getenv("GOPATH")
- if gopath == "" {
- gopath = build.Default.GOPATH
- }
- return gopath + relPath
-}
-
func usage() {
- fmt.Fprintf(os.Stderr, "usage: golangorg -http="+defaultAddr+"\n")
+ fmt.Fprintf(os.Stderr, "usage: golangorg\n")
flag.PrintDefaults()
os.Exit(2)
}
@@ -86,37 +60,12 @@
})
}
-func initCorpus(corpus *godoc.Corpus) {
- err := corpus.Init()
- if err != nil {
- log.Fatal(err)
- }
-}
-
func main() {
+ earlySetup()
+
flag.Usage = usage
flag.Parse()
- // Find templates in -a mode.
- if *autoFlag {
- if *templateDir != "" {
- fmt.Fprintln(os.Stderr, "Cannot use -a and -templates together.")
- usage()
- }
- _, file, _, ok := runtime.Caller(0)
- if !ok {
- fmt.Fprintln(os.Stderr, "runtime.Caller failed: cannot find templates for -a mode.")
- os.Exit(2)
- }
- dir := filepath.Join(file, "../../../_content")
- if _, err := os.Stat(filepath.Join(dir, "godoc.html")); err != nil {
- fmt.Fprintln(os.Stderr, err)
- fmt.Fprintln(os.Stderr, "Cannot find templates for -a mode.")
- os.Exit(2)
- }
- *templateDir = dir
- }
-
playEnabled = *showPlayground
// Check usage.
@@ -129,14 +78,12 @@
usage()
}
- // Set the resolved goroot.
- vfs.GOROOT = *goroot
-
fsGate := make(chan bool, 20)
// Determine file system to use.
rootfs := gatefs.New(vfs.OS(*goroot), fsGate)
fs.Bind("/", rootfs, "/", vfs.BindReplace)
+
// Try serving files in /doc from a local copy before trying the main
// go repository. This lets us update some documentation outside the
// Go release cycle. This includes root.html, which redirects to "/".
@@ -144,25 +91,22 @@
if *templateDir != "" {
fs.Bind("/doc", vfs.OS(*templateDir), "/doc", vfs.BindBefore)
fs.Bind("/lib/godoc", vfs.OS(*templateDir), "/", vfs.BindBefore)
+ root := filepath.Join(*templateDir, "..")
+ fs.Bind("/robots.txt", vfs.OS(root), "/robots.txt", vfs.BindBefore)
+ fs.Bind("/favicon.ico", vfs.OS(root), "/favicon.ico", vfs.BindBefore)
} else {
fs.Bind("/doc", vfs.FromFS(website.Content), "/doc", vfs.BindBefore)
fs.Bind("/lib/godoc", vfs.FromFS(website.Content), "/", vfs.BindReplace)
+ fs.Bind("/robots.txt", vfs.FromFS(website.Root), "/robots.txt", vfs.BindBefore)
+ fs.Bind("/favicon.ico", vfs.FromFS(website.Root), "/favicon.ico", vfs.BindBefore)
}
- // Bind $GOPATH trees into Go root.
- for _, p := range filepath.SplitList(build.Default.GOPATH) {
- fs.Bind("/src", gatefs.New(vfs.OS(p), fsGate), "/src", vfs.BindAfter)
- }
-
- webroot := getFullPath("/src/golang.org/x/website")
- fs.Bind("/robots.txt", gatefs.New(vfs.OS(webroot), fsGate), "/robots.txt", vfs.BindBefore)
- fs.Bind("/favicon.ico", gatefs.New(vfs.OS(webroot), fsGate), "/favicon.ico", vfs.BindBefore)
-
corpus := godoc.NewCorpus(fs)
corpus.Verbose = *verbose
-
- go initCorpus(corpus)
-
+ corpus.IndexEnabled = false
+ if err := corpus.Init(); err != nil {
+ log.Fatal(err)
+ }
// Initialize the version info before readTemplates, which saves
// the map value in a method value.
corpus.InitVersionInfo()
@@ -176,7 +120,8 @@
}
readTemplates(pres)
- registerHandlers(pres)
+ mux := registerHandlers(pres)
+ lateSetup(mux)
var handler http.Handler = http.DefaultServeMux
if *verbose {
diff --git a/cmd/golangorg/play.go b/cmd/golangorg/play.go
deleted file mode 100644
index f44a3cc..0000000
--- a/cmd/golangorg/play.go
+++ /dev/null
@@ -1,11 +0,0 @@
-// Copyright 2012 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build !golangorg
-
-package main
-
-// This package registers "/compile" and "/share" handlers
-// that redirect to the golang.org playground.
-import _ "golang.org/x/tools/playground"
diff --git a/cmd/golangorg/prod.go b/cmd/golangorg/prod.go
new file mode 100644
index 0000000..e2b8328
--- /dev/null
+++ b/cmd/golangorg/prod.go
@@ -0,0 +1,83 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build go1.16 && prod
+// +build go1.16,prod
+
+package main
+
+import (
+ "context"
+ "io"
+ "log"
+ "net/http"
+ "os"
+ "strings"
+
+ "golang.org/x/website/internal/dl"
+ "golang.org/x/website/internal/proxy"
+ "golang.org/x/website/internal/redirect"
+ "golang.org/x/website/internal/short"
+
+ "cloud.google.com/go/datastore"
+ "golang.org/x/website/internal/memcache"
+)
+
+func earlySetup() {
+ log.SetFlags(log.Lshortfile | log.LstdFlags)
+ log.Println("initializing golang.org server ...")
+
+ port := "8080"
+ if p := os.Getenv("PORT"); p != "" {
+ port = p
+ }
+ *httpAddr = ":" + port
+}
+
+func lateSetup(mux *http.ServeMux) {
+ pres.GoogleAnalytics = os.Getenv("GOLANGORG_ANALYTICS")
+
+ datastoreClient, memcacheClient := getClients()
+
+ dl.RegisterHandlers(mux, datastoreClient, memcacheClient)
+ short.RegisterHandlers(mux, datastoreClient, memcacheClient)
+
+ // Register /compile and /share handlers against the default serve mux
+ // so that other app modules can make plain HTTP requests to those
+ // hosts. (For reasons, HTTPS communication between modules is broken.)
+ proxy.RegisterHandlers(http.DefaultServeMux)
+
+ http.HandleFunc("/_ah/health", func(w http.ResponseWriter, r *http.Request) {
+ io.WriteString(w, "ok")
+ })
+
+ http.HandleFunc("/robots.txt", func(w http.ResponseWriter, r *http.Request) {
+ io.WriteString(w, "User-agent: *\nDisallow: /search\n")
+ })
+
+ if err := redirect.LoadChangeMap("hg-git-mapping.bin"); err != nil {
+ log.Fatalf("LoadChangeMap: %v", err)
+ }
+
+ log.Println("godoc initialization complete")
+}
+
+func getClients() (*datastore.Client, *memcache.Client) {
+ ctx := context.Background()
+
+ datastoreClient, err := datastore.NewClient(ctx, "")
+ if err != nil {
+ if strings.Contains(err.Error(), "missing project") {
+ log.Fatalf("Missing datastore project. Set the DATASTORE_PROJECT_ID env variable. Use `gcloud beta emulators datastore` to start a local datastore.")
+ }
+ log.Fatalf("datastore.NewClient: %v.", err)
+ }
+
+ redisAddr := os.Getenv("GOLANGORG_REDIS_ADDR")
+ if redisAddr == "" {
+ log.Fatalf("Missing redis server for golangorg in production mode. set GOLANGORG_REDIS_ADDR environment variable.")
+ }
+ memcacheClient := memcache.New(redisAddr)
+ return datastoreClient, memcacheClient
+}
diff --git a/cmd/golangorg/project.go b/cmd/golangorg/project.go
index dd5e8d3..ca57382 100644
--- a/cmd/golangorg/project.go
+++ b/cmd/golangorg/project.go
@@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build go1.16
+// +build go1.16
+
package main
import (
diff --git a/cmd/golangorg/regtest_test.go b/cmd/golangorg/regtest_test.go
index 84e83a5..28c40f1 100644
--- a/cmd/golangorg/regtest_test.go
+++ b/cmd/golangorg/regtest_test.go
@@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build go1.16
+// +build go1.16
+
// Regression tests to run against a production instance of godoc.
package main_test
diff --git a/cmd/golangorg/release.go b/cmd/golangorg/release.go
index ea62317..0c5d9d1 100644
--- a/cmd/golangorg/release.go
+++ b/cmd/golangorg/release.go
@@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build go1.16
+// +build go1.16
+
package main
import (
diff --git a/cmd/golangorg/x.go b/cmd/golangorg/x.go
index 1b3de3f..af2a068 100644
--- a/cmd/golangorg/x.go
+++ b/cmd/golangorg/x.go
@@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build go1.16
+// +build go1.16
+
// This file contains the handlers that serve go-import redirects for Go
// sub-repositories. It specifies the mapping from import paths like
// "golang.org/x/tools" to the actual repository locations.
diff --git a/cmd/golangorg/x_test.go b/cmd/golangorg/x_test.go
index a97dda9..1cd5afb 100644
--- a/cmd/golangorg/x_test.go
+++ b/cmd/golangorg/x_test.go
@@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build go1.16
+// +build go1.16
+
package main
import (
diff --git a/content.go b/content.go
index b3b7245..58646fb 100644
--- a/content.go
+++ b/content.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build go1.16
// +build go1.16
// Package website exports the static content as an embed.FS.
@@ -25,3 +26,7 @@
}
return s
}
+
+// Root is the website root files: favicon.ico and robots.txt.
+//go:embed favicon.ico robots.txt
+var Root embed.FS