playground: support third-party imports (off by default for now)

Also, modernize the Dockerfile while I'm at it, using multi-stage
builds more aggressively, and stop using gitlock (golang/go#26872) and
switch to using Go modules to build the playground. (This also turns
the playground into a module.)

Updates golang/go#31944

Change-Id: Ic6f6152469f1930fd04180a3d1e63ed92ea2cfbd
Reviewed-on: https://go-review.googlesource.com/c/playground/+/176317
Reviewed-by: Yury Smolsky <yury@smolsky.by>
diff --git a/Dockerfile b/Dockerfile
index 8193954..ea9bfea 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,15 +1,21 @@
 # Copyright 2017 The Go Authors. All rights reserved.
 # Use of this source code is governed by a BSD-style
 # license that can be found in the LICENSE file.
-FROM debian:stretch as builder
+
+FROM debian:stretch AS nacl
+
+RUN apt-get update && apt-get install -y --no-install-recommends curl bzip2 ca-certificates
+
+RUN curl -s https://storage.googleapis.com/nativeclient-mirror/nacl/nacl_sdk/trunk.544461/naclsdk_linux.tar.bz2 | tar -xj -C /tmp --strip-components=2 pepper_67/tools/sel_ldr_x86_64
+
+FROM debian:stretch AS build
 LABEL maintainer "golang-dev@googlegroups.com"
 
 ENV GOPATH /go
 ENV PATH /usr/local/go/bin:$GOPATH/bin:$PATH
 ENV GOROOT_BOOTSTRAP /usr/local/gobootstrap
-ENV CGO_ENABLED=0
-ENV GO_VERSION 1.12
-ENV BUILD_DEPS 'curl bzip2 git gcc patch libc6-dev ca-certificates'
+ENV GO_VERSION 1.12.5
+ENV BUILD_DEPS 'curl git gcc patch libc6-dev ca-certificates'
 
 # Fake time
 COPY enable-fake-time.patch /usr/local/playground/
@@ -18,8 +24,6 @@
 
 RUN apt-get update && apt-get install -y ${BUILD_DEPS} --no-install-recommends
 
-RUN curl -s https://storage.googleapis.com/nativeclient-mirror/nacl/nacl_sdk/trunk.544461/naclsdk_linux.tar.bz2 | tar -xj -C /tmp --strip-components=2 pepper_67/tools/sel_ldr_x86_64
-
 # Get the Go binary.
 RUN curl -sSL https://dl.google.com/go/go$GO_VERSION.linux-amd64.tar.gz -o /tmp/go.tar.gz
 RUN curl -sSL https://dl.google.com/go/go$GO_VERSION.linux-amd64.tar.gz.sha256 -o /tmp/go.tar.gz.sha256
@@ -33,194 +37,28 @@
 # Re-build the Go toolchain.
 RUN cd /usr/local/go/src && GOOS=nacl GOARCH=amd64p32 ./make.bash --no-clean
 
-# BEGIN deps (run `make update-deps` to update)
+RUN mkdir /gocache
+ENV GOCACHE /gocache
+ENV GO111MODULE on
 
-# Repo cloud.google.com/go at e2c125c (2019-02-22)
-ENV REV=e2c125ceac8b663cfcf4610477d4d67827377cb7
-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/bradfitz/gomemcache at bc664df (2018-07-10)
-ENV REV=bc664df9673713a0ccf26e3b55a673ec7301088b
-RUN go get -d github.com/bradfitz/gomemcache/memcache &&\
-    (cd /go/src/github.com/bradfitz/gomemcache && (git cat-file -t $REV 2>/dev/null || git fetch -q origin $REV) && git reset --hard $REV)
-
-# Repo github.com/golang/protobuf at c823c79 (2019-02-05)
-ENV REV=c823c79ea1570fb5ff454033735a8e68575d1d0f
-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 ddfab93 (2019-01-11)
-ENV REV=ddfab93c3faef4935403ac75a7c11f0e731dc181
-RUN go get -d github.com/googleapis/gax-go/v2 &&\
-    (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 github.com/hashicorp/golang-lru at 20f1fb7 (2018-08-29)
-ENV REV=20f1fb78b0740ba8c3cb143a61e86ba5c8669768
-RUN go get -d github.com/hashicorp/golang-lru/simplelru &&\
-    (cd /go/src/github.com/hashicorp/golang-lru && (git cat-file -t $REV 2>/dev/null || git fetch -q origin $REV) && git reset --hard $REV)
-
-# Repo go.opencensus.io at beafb2a (2019-02-22)
-ENV REV=beafb2a85a579a4918ba259877a1625e9213a263
-RUN go get -d go.opencensus.io `#and 13 other pkgs` &&\
-    (cd /go/src/go.opencensus.io && (git cat-file -t $REV 2>/dev/null || git fetch -q origin $REV) && git reset --hard $REV)
-
-# Repo golang.org/x/net at fe579d4 (2019-02-25)
-ENV REV=fe579d43d83210096a79b46dcca0e3721058393a
-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 9b3c759 (2019-02-20)
-ENV REV=9b3c75971fc92dd27c6436a37c05c831498658f1
-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/sys at cc5685c (2019-02-25)
-ENV REV=cc5685c2db1239775905f3911f0067c0fa74762f
-RUN go get -d golang.org/x/sys/unix &&\
-    (cd /go/src/golang.org/x/sys && (git cat-file -t $REV 2>/dev/null || git fetch -q origin $REV) && git reset --hard $REV)
-
-# Repo golang.org/x/text at d14c52b (2019-02-25)
-ENV REV=d14c52b222ee852cdba8b07206ca0c614b389876
-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 2dc4ef2 (2019-02-25)
-ENV REV=2dc4ef2775b8122dd5afe2c18fd6f775e87f89e5
-RUN go get -d golang.org/x/tools/go/ast/astutil `#and 12 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/api at 8a550ba (2019-02-24)
-ENV REV=8a550ba84cafabe9b2262c41303f31e5a4626318
-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 082222b (2019-02-19)
-ENV REV=082222b4a5c572e33e82ee9162d1352c7cf38682
-RUN go get -d google.golang.org/genproto/googleapis/api/annotations `#and 5 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 40cb561 (2019-02-25)
-ENV REV=40cb5618f475e7b9d61aa7920ae4b04ef9bbaf89
-RUN go get -d google.golang.org/grpc `#and 32 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 cloud.google.com/go/compute/metadata \
-	cloud.google.com/go/datastore \
-	cloud.google.com/go/internal \
-	cloud.google.com/go/internal/fields \
-	cloud.google.com/go/internal/trace \
-	cloud.google.com/go/internal/version \
-	github.com/bradfitz/gomemcache/memcache \
-	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/v2 \
-	github.com/hashicorp/golang-lru/simplelru \
-	go.opencensus.io \
-	go.opencensus.io/exemplar \
-	go.opencensus.io/internal \
-	go.opencensus.io/internal/tagencoding \
-	go.opencensus.io/plugin/ocgrpc \
-	go.opencensus.io/stats \
-	go.opencensus.io/stats/internal \
-	go.opencensus.io/stats/view \
-	go.opencensus.io/tag \
-	go.opencensus.io/trace \
-	go.opencensus.io/trace/internal \
-	go.opencensus.io/trace/propagation \
-	go.opencensus.io/trace/tracestate \
-	golang.org/x/net/context \
-	golang.org/x/net/context/ctxhttp \
-	golang.org/x/net/http/httpguts \
-	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/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/sys/unix \
-	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/go/gcexportdata \
-	golang.org/x/tools/go/internal/cgo \
-	golang.org/x/tools/go/internal/gcimporter \
-	golang.org/x/tools/go/internal/packagesdriver \
-	golang.org/x/tools/go/packages \
-	golang.org/x/tools/godoc/static \
-	golang.org/x/tools/imports \
-	golang.org/x/tools/internal/fastwalk \
-	golang.org/x/tools/internal/gopathwalk \
-	golang.org/x/tools/internal/module \
-	golang.org/x/tools/internal/semver \
-	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/code \
-	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/binarylog/grpc_binarylog_v1 \
-	google.golang.org/grpc/codes \
-	google.golang.org/grpc/connectivity \
-	google.golang.org/grpc/credentials \
-	google.golang.org/grpc/credentials/internal \
-	google.golang.org/grpc/credentials/oauth \
-	google.golang.org/grpc/encoding \
-	google.golang.org/grpc/encoding/proto \
-	google.golang.org/grpc/grpclog \
-	google.golang.org/grpc/internal \
-	google.golang.org/grpc/internal/backoff \
-	google.golang.org/grpc/internal/binarylog \
-	google.golang.org/grpc/internal/channelz \
-	google.golang.org/grpc/internal/envconfig \
-	google.golang.org/grpc/internal/grpcrand \
-	google.golang.org/grpc/internal/grpcsync \
-	google.golang.org/grpc/internal/syscall \
-	google.golang.org/grpc/internal/transport \
-	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/passthrough \
-	google.golang.org/grpc/stats \
-	google.golang.org/grpc/status \
-	google.golang.org/grpc/tap
-# END deps
+# Pre-build some packages to speed final install later.
+RUN go install cloud.google.com/go/compute/metadata
+RUN go install cloud.google.com/go/datastore
+RUN go install github.com/bradfitz/gomemcache/memcache
+RUN go install golang.org/x/tools/godoc/static
+RUN go install golang.org/x/tools/imports
 
 # Add and compile playground daemon
 COPY . /go/src/playground/
-RUN go install playground
+WORKDIR /go/src/playground
+RUN go install
 
 FROM debian:stretch
 
 RUN apt-get update && apt-get install -y git ca-certificates --no-install-recommends
 
-COPY --from=builder /usr/local/go /usr/local/go
-COPY --from=builder /tmp/sel_ldr_x86_64 /usr/local/bin
+COPY --from=build /usr/local/go /usr/local/go
+COPY --from=nacl /tmp/sel_ldr_x86_64 /usr/local/bin
 
 ENV GOPATH /go
 ENV PATH /usr/local/go/bin:$GOPATH/bin:$PATH
@@ -247,7 +85,7 @@
 
 RUN mkdir /app
 
-COPY --from=builder /go/bin/playground /app
+COPY --from=build /go/bin/playground /app
 COPY edit.html /app
 COPY static /app/static
 WORKDIR /app
@@ -255,5 +93,8 @@
 # Run tests
 RUN /app/playground test
 
+# Whether we allow third-party imports via proxy.golang.org:
+ENV ALLOW_PLAY_MODULE_DOWNLOADS false
+
 EXPOSE 8080
 ENTRYPOINT ["/app/playground"]
diff --git a/Makefile b/Makefile
index e4c4d87..3fbb2ed 100644
--- a/Makefile
+++ b/Makefile
@@ -1,9 +1,5 @@
 .PHONY: update-deps docker test
 
-update-deps:
-	go install golang.org/x/build/cmd/gitlock
-	gitlock --update=Dockerfile golang.org/x/playground
-
 docker: Dockerfile
 	docker build -t playground .
 
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..522d24a
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,9 @@
+module golang.org/x/playground
+
+go 1.12
+
+require (
+	cloud.google.com/go v0.38.0
+	github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668
+	golang.org/x/tools v0.0.0-20190509153222-73554e0f7805
+)
diff --git a/go.sum b/go.sum
new file mode 100644
index 0000000..9bf9295
--- /dev/null
+++ b/go.sum
@@ -0,0 +1,67 @@
+cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.38.0 h1:ROfEUZz+Gh5pa62DJWXSaonyu3StP6EA6lPEXPI6mCo=
+cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668 h1:U/lr3Dgy4WK+hNk4tyD+nuGjpVLPEHuJSFXMw11/HPA=
+github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
+github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/googleapis/gax-go/v2 v2.0.4 h1:hU4mGcQI4DaAYW+IbTun+2qEZVFxK0ySjQLTbS0VQKc=
+github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
+github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo=
+github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
+go.opencensus.io v0.21.0 h1:mU6zScU4U1YAFPHEHYk+3JC4SY7JxgkqS10ZOSyksNg=
+go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
+golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421 h1:Wo7BWFiOk0QRFMLYMqJGFMd9CgUAcGx7V+qEg/h5IBI=
+golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2 h1:z99zHgr7hKfrUcX/KsoJk5FJfjTceCKIp96+biqP4To=
+golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
+golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190509153222-73554e0f7805 h1:1ufBXAsTpUhSmmPXEEs5PrGQSfnBhsjAd2SmVhp9xrY=
+golang.org/x/tools v0.0.0-20190509153222-73554e0f7805/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+google.golang.org/api v0.4.0 h1:KKgc1aqhV8wDPbDzlDtpvyjZFY3vjz85FP7p4wcQUyI=
+google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7 h1:ZUjXAXmrAyrmmCPHgCA/vChHcpsX27MZ3yBonD/z1KE=
+google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/grpc v1.19.0 h1:cfg4PD8YEdSFnm7qLV4++93WcmhH2nIUhMjhdCvl3j8=
+google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
diff --git a/sandbox.go b/sandbox.go
index 7493213..56ab9e3 100644
--- a/sandbox.go
+++ b/sandbox.go
@@ -26,6 +26,7 @@
 	"path/filepath"
 	"reflect"
 	"runtime"
+	"strconv"
 	"strings"
 	"syscall"
 	"text/template"
@@ -325,7 +326,23 @@
 	exe := filepath.Join(tmpDir, "a.out")
 	goCache := filepath.Join(tmpDir, "gocache")
 	cmd := exec.Command("go", "build", "-o", exe, in)
-	cmd.Env = []string{"GOOS=nacl", "GOARCH=amd64p32", "GOPATH=" + os.Getenv("GOPATH"), "GOCACHE=" + goCache}
+	cmd.Env = []string{"GOOS=nacl", "GOARCH=amd64p32", "GOCACHE=" + goCache}
+	if allowModuleDownloads(src) {
+		// Create a GOPATH just for modules to be downloaded
+		// into GOPATH/pkg/mod.
+		gopath, err := ioutil.TempDir("", "gopath")
+		if err != nil {
+			return nil, fmt.Errorf("error creating temp directory: %v", err)
+		}
+		defer os.RemoveAll(gopath)
+		cmd.Env = append(cmd.Env, "GO111MODULE=on", "GOPROXY=https://proxy.golang.org", "GOPATH="+gopath)
+	} else {
+
+		cmd.Env = append(cmd.Env,
+			"GO111MODULE=off",             // in case it becomes on by default later
+			"GOPATH="+os.Getenv("GOPATH"), // contains old code.google.com/p/go-tour, etc
+		)
+	}
 	if out, err := cmd.CombinedOutput(); err != nil {
 		if _, ok := err.(*exec.ExitError); ok {
 			// Return compile errors to the user.
@@ -380,6 +397,21 @@
 	return &response{Events: events, Status: status, IsTest: testParam != "", TestsFailed: fails}, nil
 }
 
+// allowModuleDownloads reports whether the code snippet in src should be allowed
+// to download modules.
+func allowModuleDownloads(src []byte) bool {
+	if bytes.Contains(src, []byte(`"code.google.com/p/go-tour/`)) {
+		// This domain doesn't exist anymore but we want old snippets using
+		// these packages to still run, so the Dockerfile adds these packages
+		// at this name in $GOPATH. Any snippets using this old name wouldn't
+		// have expected (or been able to use) third-party packages anyway,
+		// so disabling modules and proxy.golang.org fetches is acceptable.
+		return false
+	}
+	v, _ := strconv.ParseBool(os.Getenv("ALLOW_PLAY_MODULE_DOWNLOADS"))
+	return v
+}
+
 func (s *server) healthCheck() error {
 	resp, err := compileAndRun(&request{Body: healthProg})
 	if err != nil {
@@ -406,6 +438,11 @@
 	if err := s.healthCheck(); err != nil {
 		stdlog.Fatal(err)
 	}
+
+	// Enable module downloads for testing:
+	defer func(old string) { os.Setenv("ALLOW_PLAY_MODULE_DOWNLOADS", old) }(os.Getenv("ALLOW_PLAY_MODULE_DOWNLOADS"))
+	os.Setenv("ALLOW_PLAY_MODULE_DOWNLOADS", "true")
+
 	for _, t := range tests {
 		resp, err := compileAndRun(&request{Body: t.prog})
 		if err != nil {
@@ -733,4 +770,11 @@
 		{"B\n", "stderr", time.Second - 2*time.Nanosecond},
 		{"A\n", "stdout", time.Second},
 	}},
+
+	// Test third-party imports:
+	{prog: `
+package main
+import ("fmt"; "github.com/bradfitz/iter")
+func main() { for i := range iter.N(5) { fmt.Println(i) } }
+`, want: "0\n1\n2\n3\n4\n"},
 }