cmd/googlegolangorg: add GAE app that serves google.golang.org
This code was originally in Google's internal repo, but there's
no good reason for it to stay there.
Change-Id: Id2cd2b2bb3691a14182a02e01c40005652106402
Reviewed-on: https://go-review.googlesource.com/c/website/+/191160
Reviewed-by: Katie Hockman <katie@golang.org>
diff --git a/cmd/googlegolangorg/.gcloudignore b/cmd/googlegolangorg/.gcloudignore
new file mode 100644
index 0000000..199e6d9
--- /dev/null
+++ b/cmd/googlegolangorg/.gcloudignore
@@ -0,0 +1,25 @@
+# This file specifies files that are *not* uploaded to Google Cloud Platform
+# using gcloud. It follows the same syntax as .gitignore, with the addition of
+# "#!include" directives (which insert the entries of the given .gitignore-style
+# file at that point).
+#
+# For more information, run:
+# $ gcloud topic gcloudignore
+#
+.gcloudignore
+# If you would like to upload your .git directory, .gitignore file or files
+# from your .gitignore file, remove the corresponding line
+# below:
+.git
+.gitignore
+
+# Binaries for programs and plugins
+*.exe
+*.exe~
+*.dll
+*.so
+*.dylib
+# Test binary, build with `go test -c`
+*.test
+# Output of the go coverage tool, specifically when used with LiteIDE
+*.out
\ No newline at end of file
diff --git a/cmd/googlegolangorg/README.md b/cmd/googlegolangorg/README.md
new file mode 100644
index 0000000..4e1aeac
--- /dev/null
+++ b/cmd/googlegolangorg/README.md
@@ -0,0 +1,18 @@
+This trivial App Engine app serves the small meta+redirector HTML pages
+for https://google.golang.org/. For example:
+
+- https://google.golang.org/appengine
+- https://google.golang.org/cloud
+- https://google.golang.org/api/
+- https://google.golang.org/api/storage/v1
+- https://google.golang.org/grpc
+
+The page includes a meta tag to instruct the go tool to translate e.g. the
+import path "google.golang.org/appengine" to "github.com/golang/appengine".
+See `go help importpath` for the mechanics.
+
+To update the public site, run:
+
+```
+gcloud app --account=username@domain.com --project=golang-org deploy --no-promote -v google app.yaml
+```
diff --git a/cmd/googlegolangorg/app.yaml b/cmd/googlegolangorg/app.yaml
new file mode 100644
index 0000000..ac11081
--- /dev/null
+++ b/cmd/googlegolangorg/app.yaml
@@ -0,0 +1 @@
+runtime: go112
diff --git a/cmd/googlegolangorg/main.go b/cmd/googlegolangorg/main.go
new file mode 100644
index 0000000..efddcf9
--- /dev/null
+++ b/cmd/googlegolangorg/main.go
@@ -0,0 +1,139 @@
+// A trivial redirector for google.golang.org.
+package main
+
+import (
+ "fmt"
+ "html/template"
+ "net/http"
+ "os"
+ "strings"
+)
+
+var repoMap = map[string]*repoImport{
+ "api": {
+ VCS: "git",
+ URL: "https://code.googlesource.com/google-api-go-client",
+ Src: github("google/google-api-go-client"),
+ },
+ "appengine": {
+ VCS: "git",
+ URL: "https://github.com/golang/appengine",
+ Src: github("golang/appengine"),
+ },
+ "cloud": {
+ // This repo is now at "cloud.google.com/go", but still specifying the repo
+ // here gives nicer errors in godoc.org and the go tool.
+ VCS: "git",
+ URL: "https://code.googlesource.com/gocloud",
+ Src: github("GoogleCloudPlatform/gcloud-golang"),
+ },
+ "genproto": {
+ VCS: "git",
+ URL: "https://github.com/google/go-genproto",
+ Src: github("google/go-genproto"),
+ },
+ "grpc": {
+ VCS: "git",
+ URL: "https://github.com/grpc/grpc-go",
+ Src: github("grpc/grpc-go"),
+ },
+ "protobuf": {
+ VCS: "git",
+ URL: "https://go.googlesource.com/protobuf",
+ Src: github("protocolbuffers/protobuf-go"),
+ },
+}
+
+// repoImport represents an import meta-tag, as per
+// https://golang.org/cmd/go/#hdr-Import_path_syntax
+type repoImport struct {
+ VCS string
+ URL string
+ Src *src
+}
+
+// src represents a godoc.org source redirect.
+// https://github.com/golang/gddo/search?utf8=%E2%9C%93&q=sourceMeta
+type src struct {
+ URL string
+ DirTpl string
+ FileTpl string
+}
+
+// github returns the *src representing a github repo.
+func github(base string) *src {
+ return &src{
+ URL: fmt.Sprintf("https://github.com/%s", base),
+ DirTpl: fmt.Sprintf("https://github.com/%s/tree/master{/dir}", base),
+ FileTpl: fmt.Sprintf("https://github.com/%s/tree/master{/dir}/{file}#L{line}", base),
+ }
+}
+
+func googsource(repo, base string) *src {
+ return &src{
+ URL: fmt.Sprintf("https://%s.googlesource.com/%s", repo, base),
+ DirTpl: fmt.Sprintf("https://%s.googlesource.com/%s/+/master{/dir}", repo, base),
+ FileTpl: fmt.Sprintf("https://%s.googlesource.com/%s/+/master{/dir}/{file}#{line}", repo, base),
+ }
+}
+
+func main() {
+ http.HandleFunc("/", handler)
+
+ port := os.Getenv("PORT")
+ if port == "" {
+ port = "8080"
+ fmt.Printf("Defaulting to port %s\n", port)
+ }
+
+ fmt.Printf("Listening on port %s\n", port)
+ if err := http.ListenAndServe(fmt.Sprintf(":%s", port), nil); err != nil {
+ fmt.Fprintf(os.Stderr, "http.ListenAndServe: %v\n", err)
+ return
+ }
+}
+
+func handler(w http.ResponseWriter, r *http.Request) {
+ head, tail := strings.TrimPrefix(r.URL.Path, "/"), ""
+ if i := strings.Index(head, "/"); i != -1 {
+ head, tail = head[:i], head[i:]
+ }
+ if head == "" {
+ http.Redirect(w, r, "https://cloud.google.com/go/google.golang.org", http.StatusFound)
+ return
+ }
+ repo, ok := repoMap[head]
+ if !ok {
+ http.NotFound(w, r)
+ return
+ }
+ godoc := "https://godoc.org/google.golang.org/" + head + tail
+ // For users visting in a browser, redirect straight to godoc.org.
+ if isBrowser := r.FormValue("go-get") == ""; isBrowser {
+ http.Redirect(w, r, godoc, http.StatusFound)
+ return
+ }
+ data := struct {
+ Head, GoDoc string
+ Repo *repoImport
+ }{head, godoc, repo}
+ w.Header().Set("Content-Type", "text/html; charset=utf-8")
+ if err := tmpl.Execute(w, data); err != nil {
+ fmt.Fprintf(os.Stderr, "tmpl.Execute: %v\n", err)
+ }
+}
+
+var tmpl = template.Must(template.New("redir").Parse(`<!DOCTYPE html>
+<html>
+<head>
+<meta name="go-import" content="google.golang.org/{{.Head}} {{.Repo.VCS}} {{.Repo.URL}}">
+{{if .Repo.Src}}
+<meta name="go-source" content="google.golang.org/{{.Head}} {{.Repo.Src.URL}} {{.Repo.Src.DirTpl}} {{.Repo.Src.FileTpl}}">
+{{end}}
+<meta http-equiv="refresh" content="0; url={{.GoDoc}}">
+</head>
+<body>
+Nothing to see here. Please <a href="{{.GoDoc}}">move along</a>.
+</body>
+</html>
+`))