playground: copy a build cache containing std archives on each build

Following CL 432535, archive files for std are not included in GOROOT.
As a result, the playground had to recompile the relevant parts of std
on each build, causing it to time out during health checks.

Try to fix this by copying a minimal amount of GOCACHE content for each
build, rather than recompiling. Use hard linking to avoid copying bytes.

For golang/go#57495

Change-Id: I06bf9f2630d1f9e4675847586911b45054d05222
Reviewed-on: https://go-review.googlesource.com/c/playground/+/460635
Reviewed-by: Heschi Kreinick <heschi@google.com>
Run-TryBot: Robert Findley <rfindley@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Bryan Mills <bcmills@google.com>
diff --git a/Dockerfile b/Dockerfile
index caa55e3..668b68b 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -10,7 +10,7 @@
 
 # GO_VERSION is provided by Cloud Build, and is set to the latest
 # version of Go. See the configuration in the deploy directory.
-ARG GO_VERSION=go1.18
+ARG GO_VERSION=go1.19
 
 ############################################################################
 # Build Go at GO_VERSION, and build faketime standard library.
@@ -84,7 +84,10 @@
 ENV PATH="/go/bin:/usr/local/go-faketime/bin:${PATH}"
 
 WORKDIR /usr/local/go-faketime
-RUN ./bin/go install --tags=faketime std
+# golang/go#57495: install std to warm the build cache. We only set
+# GOCACHE=/gocache here to keep it as small as possible, since it must be
+# copied on every build.
+RUN GOCACHE=/gocache ./bin/go install --tags=faketime std
 # Ignore the exit code. go vet std does not pass vet with the faketime
 # patches, but it successfully caches results for when we vet user
 # snippets.
diff --git a/sandbox.go b/sandbox.go
index 47f3b06..4854cc5 100644
--- a/sandbox.go
+++ b/sandbox.go
@@ -464,6 +464,16 @@
 	br.exePath = filepath.Join(tmpDir, "a.out")
 	goCache := filepath.Join(tmpDir, "gocache")
 
+	// Copy the gocache directory containing .a files for std, so that we can
+	// avoid recompiling std during this build. Using -al (hard linking) is
+	// faster than actually copying the bytes.
+	//
+	// This is necessary as .a files are no longer included in GOROOT following
+	// https://go.dev/cl/432535.
+	if err := exec.Command("cp", "-al", "/gocache", goCache).Run(); err != nil {
+		return nil, fmt.Errorf("error copying GOCACHE: %v", err)
+	}
+
 	cmd := exec.Command("/usr/local/go-faketime/bin/go", "build", "-o", br.exePath, "-tags=faketime")
 	cmd.Dir = tmpDir
 	cmd.Env = []string{"GOOS=linux", "GOARCH=amd64", "GOROOT=/usr/local/go-faketime"}