Complete migration to GAE flex environment
+ Remove reliance on GAE-specific API calls
+ Adds instructions to do local dev using the datastore emulator
+ Small golint fixes
Update golang/go#21645
Change-Id: Icc7679fab4c166a3d8fef3043414d6069865661d
Reviewed-on: https://go-review.googlesource.com/84815
Reviewed-by: Chris Broadfoot <cbro@golang.org>
diff --git a/README.md b/README.md
index 4cb0d12..2e43bde 100644
--- a/README.md
+++ b/README.md
@@ -14,11 +14,21 @@
docker build -t frontend frontend/
```
+### Dev Setup
+
+```
+gcloud components install cloud-datastore-emulator
+```
+
### Running
```
+# run the datastore emulator
+gcloud --project golang-org beta emulators datastore start
+# set env vars
+$(gcloud beta emulators datastore env-init)
# run the frontend
-docker run -d --rm -p 8080:8080 frontend
+cd frontend && go install && frontend
```
Now visit localhost:8080 to ensure it worked.
diff --git a/frontend/Dockerfile b/frontend/Dockerfile
index 0b81a86..1594a89 100644
--- a/frontend/Dockerfile
+++ b/frontend/Dockerfile
@@ -6,42 +6,126 @@
# BEGIN deps (run `make update-deps` to update)
+# Repo cloud.google.com/go at 3051b91 (2017-12-06)
+ENV REV=3051b919da3b8d62bc3a57ab4b353ca1c72402d5
+RUN go get -d cloud.google.com/go/compute/metadata `#and 6 other pkgs` &&\
+ (cd /go/src/cloud.google.com/go && (git cat-file -t $REV 2>/dev/null || git fetch -q origin $REV) && git reset --hard $REV)
+
# Repo github.com/golang/protobuf at 1e59b77 (2017-11-13)
ENV REV=1e59b77b52bf8e4b449a57e6f79f21226d571845
-RUN go get -d github.com/golang/protobuf/proto &&\
+RUN go get -d github.com/golang/protobuf/proto `#and 8 other pkgs` &&\
(cd /go/src/github.com/golang/protobuf && (git cat-file -t $REV 2>/dev/null || git fetch -q origin $REV) && git reset --hard $REV)
+# Repo github.com/googleapis/gax-go at 317e000 (2017-09-15)
+ENV REV=317e0006254c44a0ac427cc52a0e083ff0b9622f
+RUN go get -d github.com/googleapis/gax-go &&\
+ (cd /go/src/github.com/googleapis/gax-go && (git cat-file -t $REV 2>/dev/null || git fetch -q origin $REV) && git reset --hard $REV)
+
# Repo golang.org/x/net at faacc1b (2017-12-07)
ENV REV=faacc1b5e36e3ff02cbec9661c69ac63dd5a83ad
-RUN go get -d golang.org/x/net/context &&\
+RUN go get -d golang.org/x/net/context `#and 8 other pkgs` &&\
(cd /go/src/golang.org/x/net && (git cat-file -t $REV 2>/dev/null || git fetch -q origin $REV) && git reset --hard $REV)
+# Repo golang.org/x/oauth2 at 6a2004c (2017-12-06)
+ENV REV=6a2004c8907a86949d71c664c81574897a4e55a6
+RUN go get -d golang.org/x/oauth2 `#and 5 other pkgs` &&\
+ (cd /go/src/golang.org/x/oauth2 && (git cat-file -t $REV 2>/dev/null || git fetch -q origin $REV) && git reset --hard $REV)
+
+# Repo golang.org/x/text at be25de4 (2017-12-07)
+ENV REV=be25de41fadfae372d6470bda81ca6beb55ef551
+RUN go get -d golang.org/x/text/secure/bidirule `#and 4 other pkgs` &&\
+ (cd /go/src/golang.org/x/text && (git cat-file -t $REV 2>/dev/null || git fetch -q origin $REV) && git reset --hard $REV)
+
# Repo golang.org/x/tools at 5d8e38b (2017-12-10)
ENV REV=5d8e38b9550d35d893ff8276756b4118ec1bf360
RUN go get -d golang.org/x/tools/go/ast/astutil `#and 3 other pkgs` &&\
(cd /go/src/golang.org/x/tools && (git cat-file -t $REV 2>/dev/null || git fetch -q origin $REV) && git reset --hard $REV)
-# Repo google.golang.org/appengine at 24e4144 (2017-09-21)
-ENV REV=24e4144ec923c2374f6b06610c0df16a9222c3d9
-RUN go get -d google.golang.org/appengine `#and 10 other pkgs` &&\
- (cd /go/src/google.golang.org/appengine && (git cat-file -t $REV 2>/dev/null || git fetch -q origin $REV) && git reset --hard $REV)
+# Repo google.golang.org/api at 9a048ca (2017-12-07)
+ENV REV=9a048cac3675aa589c62a35d7d42b25451dd15f1
+RUN go get -d google.golang.org/api/googleapi `#and 6 other pkgs` &&\
+ (cd /go/src/google.golang.org/api && (git cat-file -t $REV 2>/dev/null || git fetch -q origin $REV) && git reset --hard $REV)
+
+# Repo google.golang.org/genproto at 7f0da29 (2017-11-23)
+ENV REV=7f0da29060c682909f650ad8ed4e515bd74fa12a
+RUN go get -d google.golang.org/genproto/googleapis/api/annotations `#and 4 other pkgs` &&\
+ (cd /go/src/google.golang.org/genproto && (git cat-file -t $REV 2>/dev/null || git fetch -q origin $REV) && git reset --hard $REV)
+
+# Repo google.golang.org/grpc at b8191e5 (2017-12-06)
+ENV REV=b8191e57b23de650278db4d23bf596219e5f3665
+RUN go get -d google.golang.org/grpc `#and 24 other pkgs` &&\
+ (cd /go/src/google.golang.org/grpc && (git cat-file -t $REV 2>/dev/null || git fetch -q origin $REV) && git reset --hard $REV)
# Optimization to speed up iterative development, not necessary for correctness:
-RUN go install github.com/golang/protobuf/proto \
+RUN go install cloud.google.com/go/compute/metadata \
+ cloud.google.com/go/datastore \
+ cloud.google.com/go/internal \
+ cloud.google.com/go/internal/atomiccache \
+ cloud.google.com/go/internal/fields \
+ cloud.google.com/go/internal/version \
+ github.com/golang/protobuf/proto \
+ github.com/golang/protobuf/protoc-gen-go/descriptor \
+ github.com/golang/protobuf/ptypes \
+ github.com/golang/protobuf/ptypes/any \
+ github.com/golang/protobuf/ptypes/duration \
+ github.com/golang/protobuf/ptypes/struct \
+ github.com/golang/protobuf/ptypes/timestamp \
+ github.com/golang/protobuf/ptypes/wrappers \
+ github.com/googleapis/gax-go \
golang.org/x/net/context \
+ golang.org/x/net/context/ctxhttp \
+ golang.org/x/net/http2 \
+ golang.org/x/net/http2/hpack \
+ golang.org/x/net/idna \
+ golang.org/x/net/internal/timeseries \
+ golang.org/x/net/lex/httplex \
+ golang.org/x/net/trace \
+ golang.org/x/oauth2 \
+ golang.org/x/oauth2/google \
+ golang.org/x/oauth2/internal \
+ golang.org/x/oauth2/jws \
+ golang.org/x/oauth2/jwt \
+ golang.org/x/text/secure/bidirule \
+ golang.org/x/text/transform \
+ golang.org/x/text/unicode/bidi \
+ golang.org/x/text/unicode/norm \
golang.org/x/tools/go/ast/astutil \
golang.org/x/tools/godoc/static \
golang.org/x/tools/imports \
- google.golang.org/appengine \
- google.golang.org/appengine/datastore \
- google.golang.org/appengine/internal \
- google.golang.org/appengine/internal/app_identity \
- google.golang.org/appengine/internal/base \
- google.golang.org/appengine/internal/datastore \
- google.golang.org/appengine/internal/log \
- google.golang.org/appengine/internal/modules \
- google.golang.org/appengine/internal/remote_api \
- google.golang.org/appengine/log
+ google.golang.org/api/googleapi \
+ google.golang.org/api/googleapi/internal/uritemplates \
+ google.golang.org/api/internal \
+ google.golang.org/api/iterator \
+ google.golang.org/api/option \
+ google.golang.org/api/transport/grpc \
+ google.golang.org/genproto/googleapis/api/annotations \
+ google.golang.org/genproto/googleapis/datastore/v1 \
+ google.golang.org/genproto/googleapis/rpc/status \
+ google.golang.org/genproto/googleapis/type/latlng \
+ google.golang.org/grpc \
+ google.golang.org/grpc/balancer \
+ google.golang.org/grpc/balancer/base \
+ google.golang.org/grpc/balancer/roundrobin \
+ google.golang.org/grpc/codes \
+ google.golang.org/grpc/connectivity \
+ google.golang.org/grpc/credentials \
+ google.golang.org/grpc/credentials/oauth \
+ google.golang.org/grpc/encoding \
+ google.golang.org/grpc/grpclb/grpc_lb_v1/messages \
+ google.golang.org/grpc/grpclog \
+ google.golang.org/grpc/internal \
+ google.golang.org/grpc/keepalive \
+ google.golang.org/grpc/metadata \
+ google.golang.org/grpc/naming \
+ google.golang.org/grpc/peer \
+ google.golang.org/grpc/resolver \
+ google.golang.org/grpc/resolver/dns \
+ google.golang.org/grpc/resolver/manual \
+ google.golang.org/grpc/resolver/passthrough \
+ google.golang.org/grpc/stats \
+ google.golang.org/grpc/status \
+ google.golang.org/grpc/tap \
+ google.golang.org/grpc/transport
# END deps
# Add and compile frontend daemon
diff --git a/frontend/edit.go b/frontend/edit.go
index 8312f4f..f24fcb7 100644
--- a/frontend/edit.go
+++ b/frontend/edit.go
@@ -8,11 +8,10 @@
"fmt"
"html/template"
"net/http"
+ "os"
"strings"
- "google.golang.org/appengine"
- "google.golang.org/appengine/datastore"
- "google.golang.org/appengine/log"
+ "cloud.google.com/go/datastore"
)
const hostname = "play.golang.org"
@@ -20,7 +19,7 @@
var editTemplate = template.Must(template.ParseFiles("edit.html"))
type editData struct {
- Snippet *Snippet
+ Snippet *snippet
Share bool
}
@@ -31,25 +30,25 @@
return
}
- snip := &Snippet{Body: []byte(hello)}
+ snip := &snippet{Body: []byte(hello)}
if strings.HasPrefix(r.URL.Path, "/p/") {
if !allowShare(r) {
w.WriteHeader(http.StatusUnavailableForLegalReasons)
w.Write([]byte(`<h1>Unavailable For Legal Reasons</h1><p>Viewing and/or sharing code snippets is not available in your country for legal reasons. This message might also appear if your country is misdetected. If you believe this is an error, please <a href="https://golang.org/issue">file an issue</a>.</p>`))
return
}
- c := appengine.NewContext(r)
+ ctx := r.Context()
id := r.URL.Path[3:]
serveText := false
if strings.HasSuffix(id, ".go") {
id = id[:len(id)-3]
serveText = true
}
- key := datastore.NewKey(c, "Snippet", id, 0, nil)
- err := datastore.Get(c, key, snip)
+ key := datastore.NameKey("Snippet", id, nil)
+ err := datastoreClient.Get(ctx, key, snip)
if err != nil {
if err != datastore.ErrNoSuchEntity {
- log.Errorf(c, "loading Snippet: %v", err)
+ fmt.Fprintf(os.Stderr, "loading Snippet: %v", err)
}
http.Error(w, "Snippet not found", http.StatusNotFound)
return
diff --git a/frontend/frontend.go b/frontend/frontend.go
index fc97f08..2d831e3 100644
--- a/frontend/frontend.go
+++ b/frontend/frontend.go
@@ -5,14 +5,30 @@
package main
import (
+ "context"
+ "flag"
+ "fmt"
"io"
+ "log"
"net/http"
+ "os"
+ "cloud.google.com/go/compute/metadata"
+ "cloud.google.com/go/datastore"
"golang.org/x/tools/godoc/static"
- "google.golang.org/appengine"
)
+var datastoreClient *datastore.Client
+
func main() {
+ flag.Parse()
+
+ var err error
+ datastoreClient, err = datastore.NewClient(context.Background(), projectID())
+ if err != nil {
+ log.Fatal(err)
+ }
+
http.Handle("/", hstsHandler(edit))
http.Handle("/compile", hstsHandler(compile))
http.Handle("/fmt", hstsHandler(fmtHandler))
@@ -23,7 +39,27 @@
http.HandleFunc("/favicon.ico", func(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, "./static/favicon.ico")
})
- appengine.Main()
+ http.HandleFunc("/_ah/health", func(w http.ResponseWriter, r *http.Request) {
+ fmt.Fprintf(w, "ok")
+ })
+ port := os.Getenv("PORT")
+ if port == "" {
+ port = "8080"
+ }
+ log.Printf("Listening on :%v ...", port)
+ http.ListenAndServe(":"+port, nil)
+}
+
+func projectID() string {
+ id := os.Getenv("DATASTORE_PROJECT_ID")
+ if id != "" {
+ return id
+ }
+ id, err := metadata.ProjectID()
+ if err != nil {
+ log.Fatalf("Could not determine the project ID (%v); If running locally, ensure DATASTORE_PROJECT_ID is set.", err)
+ }
+ return id
}
func play(w http.ResponseWriter, r *http.Request) {
diff --git a/frontend/share.go b/frontend/share.go
index fb0c9c0..60c9a78 100644
--- a/frontend/share.go
+++ b/frontend/share.go
@@ -13,20 +13,18 @@
"net/http"
"os"
- "google.golang.org/appengine"
- "google.golang.org/appengine/datastore"
- "google.golang.org/appengine/log"
+ "cloud.google.com/go/datastore"
)
const salt = "[replace this with something unique]"
const maxSnippetSize = 64 * 1024
-type Snippet struct {
+type snippet struct {
Body []byte
}
-func (s *Snippet) Id() string {
+func (s *snippet) ID() string {
h := sha1.New()
io.WriteString(h, salt)
h.Write(s.Body)
@@ -52,13 +50,13 @@
http.Error(w, http.StatusText(status), status)
return
}
- c := appengine.NewContext(r)
+ ctx := r.Context()
var body bytes.Buffer
_, err := io.Copy(&body, io.LimitReader(r.Body, maxSnippetSize+1))
r.Body.Close()
if err != nil {
- log.Errorf(c, "reading Body: %v", err)
+ fmt.Fprintf(os.Stderr, "reading Body: %v", err)
http.Error(w, "Server Error", http.StatusInternalServerError)
return
}
@@ -67,13 +65,13 @@
return
}
- snip := &Snippet{Body: body.Bytes()}
- id := snip.Id()
- key := datastore.NewKey(c, "Snippet", id, 0, nil)
- _, err = datastore.Put(c, key, snip)
+ snip := &snippet{Body: body.Bytes()}
+ id := snip.ID()
+ key := datastore.NameKey("Snippet", id, nil)
+ _, err = datastoreClient.Put(ctx, key, snip)
if err != nil {
- log.Errorf(c, "putting Snippet: %v", err)
- http.Error(w, "Server Error", http.StatusInternalServerError)
+ fmt.Fprintf(os.Stderr, "putting Snippet: %v", err)
+ http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}