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>
This commit is contained in:
Родитель
fd7d167356
Коммит
66996d0d91
|
@ -8,7 +8,7 @@ Content is in _content/. Server code is in cmd/ and internal/.
|
|||
|
||||
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.
|
||||
|
|
|
@ -21,7 +21,7 @@ COPY . /website
|
|||
|
||||
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
|
||||
|
|
|
@ -16,10 +16,9 @@ To run in production mode locally, you need:
|
|||
* 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:
|
||||
|
|
|
@ -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 (
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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))
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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 (
|
||||
|
|
|
@ -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 @@ func waitForServerReady(t *testing.T, addr string) {
|
|||
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),
|
||||
|
|
|
@ -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)
|
||||
}
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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))
|
||||
}
|
|
@ -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 @@ import (
|
|||
"golang.org/x/website"
|
||||
)
|
||||
|
||||
const defaultAddr = "localhost:6060" // default webserver address
|
||||
|
||||
var (
|
||||
// network
|
||||
httpAddr = flag.String("http", defaultAddr, "HTTP service address")
|
||||
|
||||
httpAddr = flag.String("http", "localhost:6060", "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")
|
||||
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")
|
||||
)
|
||||
|
||||
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 loggingHandler(h http.Handler) http.Handler {
|
|||
})
|
||||
}
|
||||
|
||||
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 @@ func main() {
|
|||
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 @@ func main() {
|
|||
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 @@ func main() {
|
|||
}
|
||||
|
||||
readTemplates(pres)
|
||||
registerHandlers(pres)
|
||||
mux := registerHandlers(pres)
|
||||
lateSetup(mux)
|
||||
|
||||
var handler http.Handler = http.DefaultServeMux
|
||||
if *verbose {
|
||||
|
|
|
@ -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"
|
|
@ -2,29 +2,19 @@
|
|||
// 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
|
||||
//go:build go1.16 && prod
|
||||
// +build go1.16,prod
|
||||
|
||||
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"
|
||||
|
@ -34,51 +24,22 @@ import (
|
|||
"golang.org/x/website/internal/memcache"
|
||||
)
|
||||
|
||||
func main() {
|
||||
func earlySetup() {
|
||||
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)
|
||||
port := "8080"
|
||||
if p := os.Getenv("PORT"); p != "" {
|
||||
port = p
|
||||
}
|
||||
*httpAddr = ":" + port
|
||||
}
|
||||
corpus.InitVersionInfo()
|
||||
|
||||
pres = godoc.NewPresentation(corpus)
|
||||
pres.ShowPlayground = true
|
||||
pres.DeclLinks = true
|
||||
pres.NotesRx = regexp.MustCompile("BUG")
|
||||
func lateSetup(mux *http.ServeMux) {
|
||||
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)
|
||||
|
||||
|
@ -100,21 +61,6 @@ func main() {
|
|||
}
|
||||
|
||||
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) {
|
|
@ -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 (
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 (
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 (
|
||||
|
|
|
@ -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 @@ func subdir(fsys fs.FS, path string) fs.FS {
|
|||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Root is the website root files: favicon.ico and robots.txt.
|
||||
//go:embed favicon.ico robots.txt
|
||||
var Root embed.FS
|
||||
|
|
Загрузка…
Ссылка в новой задаче