app: update App Engine runtime to go111

Starting October 1, App Engine will not allow apps using the 1.9
runtime to be deployed.

In module mode on go111 AppEngine, paths have changed to be relative to
the go.mod file.

More information can be found at
https://cloud.google.com/appengine/docs/standard/go111/go-differences

Change-Id: I3e291f20559ec8d3c5e8f51b756bd3b23b0c70bd
Reviewed-on: https://go-review.googlesource.com/c/build/+/192103
Run-TryBot: Alexander Rakoczy <alex@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Andrew Bonventre <andybons@golang.org>
diff --git a/app/appengine/.gcloudignore b/app/appengine/.gcloudignore
new file mode 100644
index 0000000..199e6d9
--- /dev/null
+++ b/app/appengine/.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/app/appengine/app.yaml b/app/appengine/app.yaml
index 785cd3f..0e4c010 100644
--- a/app/appengine/app.yaml
+++ b/app/appengine/app.yaml
@@ -1,15 +1,14 @@
-runtime: go
-api_version: go1.9
+runtime: go111
 service: build
 
 handlers:
   - url: /static
-    static_dir: static
+    static_dir: app/appengine/static
     secure: always
   - url: /(init|buildtest|key|perflearn|_ah/queue/go/delay)
-    script: _go_app
+    script: auto
     login: admin
     secure: always
   - url: /.*
-    script: _go_app
+    script: auto
     secure: always
diff --git a/app/appengine/build.go b/app/appengine/build.go
index c9a8559..0a9e603 100644
--- a/app/appengine/build.go
+++ b/app/appengine/build.go
@@ -2,9 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build appengine
-
-package build
+package main
 
 import (
 	"bytes"
diff --git a/app/appengine/config.go b/app/appengine/config.go
index 4556a6d..4d1dd80 100644
--- a/app/appengine/config.go
+++ b/app/appengine/config.go
@@ -2,14 +2,12 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build appengine
-
-package build
+package main
 
 import (
+	"context"
 	"sync"
 
-	"context"
 	"google.golang.org/appengine/datastore"
 	"google.golang.org/appengine/log"
 )
diff --git a/app/appengine/dash.go b/app/appengine/dash.go
index 04ad138..9323393 100644
--- a/app/appengine/dash.go
+++ b/app/appengine/dash.go
@@ -2,17 +2,46 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build appengine
-
-package build
+package main
 
 import (
 	"context"
+	"encoding/gob"
 	"net/http"
 
 	"google.golang.org/appengine"
 )
 
+func main() {
+	gob.Register(&Commit{}) // needed for google.golang.org/appengine/delay
+
+	// admin handlers
+	handleFunc("/init", initHandler)
+	handleFunc("/key", keyHandler)
+
+	// authenticated handlers
+	handleFunc("/building", AuthHandler(buildingHandler))
+	handleFunc("/clear-results", AuthHandler(clearResultsHandler))
+	handleFunc("/commit", AuthHandler(commitHandler))
+	handleFunc("/packages", AuthHandler(packagesHandler))
+	handleFunc("/perf-result", AuthHandler(perfResultHandler))
+	handleFunc("/result", AuthHandler(resultHandler))
+	handleFunc("/tag", AuthHandler(tagHandler))
+	handleFunc("/todo", AuthHandler(todoHandler))
+
+	// public handlers
+	handleFunc("/", uiHandler)
+	handleFunc("/log/", logHandler)
+	handleFunc("/perf", perfChangesHandler)
+	handleFunc("/perfdetail", perfDetailUIHandler)
+	handleFunc("/perfgraph", perfGraphHandler)
+	handleFunc("/updatebenchmark", updateBenchmark)
+	handleFunc("/buildtest", testHandler)
+	handleFunc("/perflearn", perfLearnHandler)
+
+	appengine.Main()
+}
+
 func handleFunc(path string, h http.HandlerFunc) {
 	http.Handle(path, hstsHandler(h))
 }
diff --git a/app/appengine/handler.go b/app/appengine/handler.go
index 6073ad1..587aa61 100644
--- a/app/appengine/handler.go
+++ b/app/appengine/handler.go
@@ -2,9 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build appengine
-
-package build
+package main
 
 import (
 	"bytes"
@@ -971,25 +969,6 @@
 	fmt.Fprint(w, builderKey(c, builder))
 }
 
-func init() {
-	// admin handlers
-	handleFunc("/init", initHandler)
-	handleFunc("/key", keyHandler)
-
-	// authenticated handlers
-	handleFunc("/building", AuthHandler(buildingHandler))
-	handleFunc("/clear-results", AuthHandler(clearResultsHandler))
-	handleFunc("/commit", AuthHandler(commitHandler))
-	handleFunc("/packages", AuthHandler(packagesHandler))
-	handleFunc("/perf-result", AuthHandler(perfResultHandler))
-	handleFunc("/result", AuthHandler(resultHandler))
-	handleFunc("/tag", AuthHandler(tagHandler))
-	handleFunc("/todo", AuthHandler(todoHandler))
-
-	// public handlers
-	handleFunc("/log/", logHandler)
-}
-
 func validHash(hash string) bool {
 	// TODO(adg): correctly validate a hash
 	return hash != ""
diff --git a/app/appengine/init.go b/app/appengine/init.go
index 616de44..e02cde9 100644
--- a/app/appengine/init.go
+++ b/app/appengine/init.go
@@ -2,9 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build appengine
-
-package build
+package main
 
 import (
 	"fmt"
diff --git a/app/appengine/notify.go b/app/appengine/notify.go
index a999780..6c0b9fb 100644
--- a/app/appengine/notify.go
+++ b/app/appengine/notify.go
@@ -2,14 +2,11 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build appengine
-
-package build
+package main
 
 import (
 	"bytes"
 	"context"
-	"encoding/gob"
 	"encoding/json"
 	"fmt"
 	"io/ioutil"
@@ -126,7 +123,7 @@
 var (
 	notifyLater = delay.Func("notify", notify)
 	notifyTmpl  = template.Must(template.New("notify.txt").
-			Funcs(template.FuncMap(tmplFuncs)).ParseFiles("notify.txt"))
+			Funcs(template.FuncMap(tmplFuncs)).ParseFiles("app/appengine/notify.txt"))
 )
 
 // notify tries to update the CL for the given Commit with a failure message.
@@ -200,10 +197,6 @@
 	return nil
 }
 
-func init() {
-	gob.Register(&Commit{}) // for delay
-}
-
 // MUST be called from inside a transaction.
 func sendPerfFailMail(c context.Context, builder string, res *PerfResult) error {
 	com := &Commit{Hash: res.CommitHash}
@@ -279,7 +272,7 @@
 	sendPerfMailTmpl  = template.Must(
 		template.New("perf_notify.txt").
 			Funcs(template.FuncMap(tmplFuncs)).
-			ParseFiles("perf_notify.txt"),
+			ParseFiles("app/appengine/perf_notify.txt"),
 	)
 )
 
diff --git a/app/appengine/perf.go b/app/appengine/perf.go
index 6a6a5cd..bb2aec1 100644
--- a/app/appengine/perf.go
+++ b/app/appengine/perf.go
@@ -2,9 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build appengine
-
-package build
+package main
 
 import (
 	"context"
diff --git a/app/appengine/perf_changes.go b/app/appengine/perf_changes.go
index 4ded513..ec276ee 100644
--- a/app/appengine/perf_changes.go
+++ b/app/appengine/perf_changes.go
@@ -2,9 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build appengine
-
-package build
+package main
 
 import (
 	"bytes"
@@ -18,10 +16,6 @@
 	"google.golang.org/appengine/datastore"
 )
 
-func init() {
-	handleFunc("/perf", perfChangesHandler)
-}
-
 // perfSummaryHandler draws the main benchmarking page.
 func perfChangesHandler(w http.ResponseWriter, r *http.Request) {
 	d := goDash
@@ -221,7 +215,7 @@
 }
 
 var perfChangesTemplate = template.Must(
-	template.New("perf_changes.html").Funcs(tmplFuncs).ParseFiles("perf_changes.html"),
+	template.New("perf_changes.html").Funcs(tmplFuncs).ParseFiles("app/appengine/perf_changes.html"),
 )
 
 type perfChangesData struct {
diff --git a/app/appengine/perf_detail.go b/app/appengine/perf_detail.go
index cefdd08..2ff7a96 100644
--- a/app/appengine/perf_detail.go
+++ b/app/appengine/perf_detail.go
@@ -2,9 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build appengine
-
-package build
+package main
 
 import (
 	"bytes"
@@ -19,10 +17,6 @@
 	"google.golang.org/appengine/datastore"
 )
 
-func init() {
-	handleFunc("/perfdetail", perfDetailUIHandler)
-}
-
 func perfDetailUIHandler(w http.ResponseWriter, r *http.Request) {
 	d := goDash
 	c := d.Context(appengine.NewContext(r))
@@ -215,5 +209,5 @@
 func (l uiPerfDetailMetrics) Less(i, j int) bool { return l[i].Name < l[j].Name }
 
 var uiPerfDetailTemplate = template.Must(
-	template.New("perf_detail.html").Funcs(tmplFuncs).ParseFiles("perf_detail.html"),
+	template.New("perf_detail.html").Funcs(tmplFuncs).ParseFiles("app/appengine/perf_detail.html"),
 )
diff --git a/app/appengine/perf_graph.go b/app/appengine/perf_graph.go
index 8959ffb..319a22a 100644
--- a/app/appengine/perf_graph.go
+++ b/app/appengine/perf_graph.go
@@ -2,9 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build appengine
-
-package build
+package main
 
 import (
 	"bytes"
@@ -17,10 +15,6 @@
 	"google.golang.org/appengine/datastore"
 )
 
-func init() {
-	handleFunc("/perfgraph", perfGraphHandler)
-}
-
 func perfGraphHandler(w http.ResponseWriter, r *http.Request) {
 	d := goDash
 	c := d.Context(appengine.NewContext(r))
@@ -244,7 +238,7 @@
 }
 
 var perfGraphTemplate = template.Must(
-	template.New("perf_graph.html").ParseFiles("perf_graph.html"),
+	template.New("perf_graph.html").ParseFiles("app/appengine/perf_graph.html"),
 )
 
 type perfGraphData struct {
diff --git a/app/appengine/perf_learn.go b/app/appengine/perf_learn.go
index 737628b..156f014 100644
--- a/app/appengine/perf_learn.go
+++ b/app/appengine/perf_learn.go
@@ -2,9 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build appengine
-
-package build
+package main
 
 import (
 	"bytes"
@@ -18,10 +16,6 @@
 	"google.golang.org/appengine/datastore"
 )
 
-func init() {
-	handleFunc("/perflearn", perfLearnHandler)
-}
-
 const (
 	learnPercentile       = 0.95
 	learnSignalMultiplier = 1.1
@@ -163,7 +157,7 @@
 }
 
 var perfLearnTemplate = template.Must(
-	template.New("perf_learn.html").Funcs(tmplFuncs).ParseFiles("perf_learn.html"),
+	template.New("perf_learn.html").Funcs(tmplFuncs).ParseFiles("app/appengine/perf_learn.html"),
 )
 
 type perfLearnData struct {
diff --git a/app/appengine/test.go b/app/appengine/test.go
index fbc8d4d..345f52b 100644
--- a/app/appengine/test.go
+++ b/app/appengine/test.go
@@ -2,9 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build appengine
-
-package build
+package main
 
 // TODO(adg): test authentication
 // TODO(adg): refactor to use appengine/aetest instead
@@ -27,10 +25,6 @@
 	"google.golang.org/appengine/log"
 )
 
-func init() {
-	handleFunc("/buildtest", testHandler)
-}
-
 var testEntityKinds = []string{
 	"Package",
 	"Commit",
diff --git a/app/appengine/ui.go b/app/appengine/ui.go
index 9aa8a50..d273393 100644
--- a/app/appengine/ui.go
+++ b/app/appengine/ui.go
@@ -5,9 +5,7 @@
 // TODO(adg): packages at weekly/release
 // TODO(adg): some means to register new packages
 
-// +build appengine
-
-package build
+package main
 
 import (
 	"bytes"
@@ -16,7 +14,6 @@
 	"fmt"
 	"html/template"
 	"net/http"
-	"os"
 	"sort"
 	"strconv"
 	"strings"
@@ -32,15 +29,6 @@
 	"google.golang.org/appengine/memcache"
 )
 
-// isDevAppServer is whether we're running locally with dev_appserver.py.
-// This is the documented way to check which environment we're running in, per:
-//   https://cloud.google.com/appengine/docs/standard/python/tools/using-local-server#detecting_application_runtime_environment
-var isDevAppServer = !strings.HasPrefix(os.Getenv("SERVER_SOFTWARE"), "Google App Engine/")
-
-func init() {
-	handleFunc("/", uiHandler)
-}
-
 // uiHandler draws the build status page.
 func uiHandler(w http.ResponseWriter, r *http.Request) {
 	d := goDash
@@ -113,7 +101,7 @@
 			s, err := GetTagState(c, "tip", "")
 			if err != nil {
 				if err == datastore.ErrNoSuchEntity {
-					if isDevAppServer {
+					if appengine.IsDevAppServer() {
 						goto BuildData
 					}
 					err = fmt.Errorf("tip tag not found")
@@ -337,7 +325,7 @@
 
 	// If we're running locally and don't have data, return some test data.
 	// This lets people hack on the UI without setting up gitmirror & friends.
-	if len(commits) == 0 && isDevAppServer && err == nil {
+	if len(commits) == 0 && appengine.IsDevAppServer() && err == nil {
 		commits = []*Commit{
 			{
 				Hash:       "7d7c6a97f815e9279d08cfaea7d5efb5e90695a8",
@@ -594,7 +582,7 @@
 }
 
 var uiTemplate = template.Must(
-	template.New("ui.html").Funcs(tmplFuncs).ParseFiles("ui.html"),
+	template.New("ui.html").Funcs(tmplFuncs).ParseFiles("app/appengine/ui.html"),
 )
 
 var tmplFuncs = template.FuncMap{
diff --git a/app/appengine/update.go b/app/appengine/update.go
index 8147839..357a2dd 100644
--- a/app/appengine/update.go
+++ b/app/appengine/update.go
@@ -2,9 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build appengine
-
-package build
+package main
 
 import (
 	"encoding/json"
@@ -12,14 +10,11 @@
 	"net/http"
 
 	"context"
+
 	"google.golang.org/appengine"
 	"google.golang.org/appengine/datastore"
 )
 
-func init() {
-	handleFunc("/updatebenchmark", updateBenchmark)
-}
-
 func updateBenchmark(w http.ResponseWriter, r *http.Request) {
 	if !appengine.IsDevAppServer() {
 		fmt.Fprint(w, "Update must not run on real server.")
diff --git a/app/cache/cache.go b/app/cache/cache.go
index 2c1effe..2aa2603 100644
--- a/app/cache/cache.go
+++ b/app/cache/cache.go
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build appengine
-
 package cache
 
 import (
diff --git a/app/key/key.go b/app/key/key.go
index b3cbd7a..70f25de 100644
--- a/app/key/key.go
+++ b/app/key/key.go
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build appengine
-
 package key
 
 import (