app: update App Engine runtime to go111

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

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

Change-Id: I522830c1bd47a32944d7caa9a5c913996fe328c1
Reviewed-on: https://go-review.googlesource.com/c/build/+/190902
Reviewed-by: Dmitri Shuralyov <dmitshur@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 7a6ab93..6a9792b 100644
--- a/app/appengine/app.yaml
+++ b/app/appengine/app.yaml
@@ -1,14 +1,13 @@
-runtime: go
-api_version: go1.9
+runtime: go111
 
 handlers:
-- url: /static
-  static_dir: static
-  secure: always
-- url: /(init|buildtest|key|perflearn|_ah/queue/go/delay)
-  script: _go_app
-  login: admin
-  secure: always
-- url: /.*
-  script: _go_app
-  secure: always
+  - url: /static
+    static_dir: static
+    secure: always
+  - url: /(init|buildtest|key|perflearn|_ah/queue/go/delay)
+    script: auto
+    login: admin
+    secure: always
+  - url: /.*
+    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..20d8ffb 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"
@@ -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}
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..7f66377 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
diff --git a/app/appengine/perf_detail.go b/app/appengine/perf_detail.go
index cefdd08..2a376cd 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))
diff --git a/app/appengine/perf_graph.go b/app/appengine/perf_graph.go
index 8959ffb..65158e7 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))
diff --git a/app/appengine/perf_learn.go b/app/appengine/perf_learn.go
index 737628b..d7e182b 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
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..d01bf12 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",
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 (