Filippo Valsorda has uploaded this change for review.
cmd/allcode: add a tool to download all Go code locally
All of it.
Change-Id: I1f8ae99a9f314defe9b48e0293d69e6f83806080
---
A cmd/allcode/README
A cmd/allcode/allcode.go
M go.mod
M go.sum
4 files changed, 481 insertions(+), 2 deletions(-)
diff --git a/cmd/allcode/README b/cmd/allcode/README
new file mode 100644
index 0000000..0ac8a4b
--- /dev/null
+++ b/cmd/allcode/README
@@ -0,0 +1,34 @@
+gcloud config set project $PROJECT
+gcloud config set compute/zone $ZONE
+gcloud compute instances create allcode --machine-type=e2-standard-32
+GOOS=linux go build && gcloud compute scp allcode allcode:
+gcloud compute ssh allcode
+
+ $ sudo -s
+ # mkdir /mnt/allcode
+ # mount -t tmpfs -o size=100G allcode /mnt/allcode
+ # ./allcode /mnt/allcode
+ Fetching index... 4342113 / 4341985 [---------------------------------------------] 100.00% 1m5s
+ Fetching modules... 415759 / 415759 [--------------------------------------------] 100.00% 6m57s
+
+ Unique modules: 415759 -
+ Vendor paths: 5106 -
+ Invalid names: 1 -
+ Gone: 84912 -
+ Invalid go.mod files: 224 -
+ Mismatching go.mod: 74582 -
+ GCS redirects: 6123 -
+ No .go files: 17125 -
+ No go.mod files: 117471 =
+ -------
+ 116338
+
+ Downloaded 294922354713 bytes.
+ Wrote 4029224 Go files (42384890367 bytes).
+ # ls /mnt/allcode/filippo.io/
+ a...@v1.0.0-rc.1.0.20210502224421-85763d390a45
+ cp...@v0.0.0-20210101143347-24d601e2e469
+ edward...@v1.0.0-beta.3.0.20210419044535-8e7780424d7c
+ mkc...@v1.4.3
+ mostly-harmless
+ yubike...@v0.1.5-0.20210430161625-217b58a73aac
diff --git a/cmd/allcode/allcode.go b/cmd/allcode/allcode.go
new file mode 100644
index 0000000..a7306c9
--- /dev/null
+++ b/cmd/allcode/allcode.go
@@ -0,0 +1,418 @@
+// Copyright 2021 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.
+
+package main
+
+import (
+ "archive/zip"
+ "bytes"
+ "context"
+ "encoding/json"
+ "errors"
+ "flag"
+ "fmt"
+ "io"
+ "log"
+ "net/http"
+ "os"
+ "os/signal"
+ "path/filepath"
+ "runtime"
+ "runtime/pprof"
+ "strings"
+ "sync"
+ "sync/atomic"
+ "time"
+
+ "github.com/cheggaaa/pb/v3"
+ "golang.org/x/mod/modfile"
+ "golang.org/x/mod/module"
+ "golang.org/x/mod/semver"
+ "golang.org/x/mod/sumdb/tlog"
+ "golang.org/x/sync/errgroup"
+ "golang.org/x/sync/semaphore"
+)
+
+var httpClient = &http.Client{
+ Timeout: 60 * time.Minute,
+ Transport: &http.Transport{
+ MaxIdleConnsPerHost: 1024,
+ },
+}
+
+func newRequestWithContext(ctx context.Context, method, url string) *http.Request {
+ req, err := http.NewRequestWithContext(ctx, method, url, nil)
+ if err != nil {
+ panic(err)
+ }
+ req.Header.Set("Disable-Module-Fetch", "true")
+ return req
+}
+
+type Index struct {
+ last time.Time
+ d *json.Decoder
+}
+
+func NewIndex(ctx context.Context) (*Index, error) {
+ i := &Index{}
+ if err := i.nextPage(ctx); err != nil {
+ return nil, err
+ }
+ return i, nil
+}
+
+func (i *Index) nextPage(ctx context.Context) error {
+ url := "https://index.golang.org/index?since=" + i.last.Add(1).Format(time.RFC3339Nano)
+ req, err := httpClient.Do(newRequestWithContext(ctx, "GET", url))
+ if err != nil {
+ return err
+ }
+ i.d = json.NewDecoder(req.Body)
+ return nil
+}
+
+type Version struct {
+ Path, Version string
+ Timestamp time.Time
+}
+
+func (i *Index) next(ctx context.Context) (*Version, error) {
+ v := &Version{}
+ err := i.d.Decode(v)
+ if err == io.EOF {
+ if err := i.nextPage(ctx); err != nil {
+ return nil, err
+ }
+ err = i.d.Decode(v)
+ }
+ if err != nil {
+ return nil, err
+ }
+ i.last = v.Timestamp
+ return v, nil
+}
+
+func fetchLatest(ctx context.Context) ([]byte, error) {
+ url := "https://sum.golang.org/latest"
+ res, err := httpClient.Do(newRequestWithContext(ctx, "GET", url))
+ if err != nil {
+ return nil, err
+ }
+ defer res.Body.Close()
+ if res.StatusCode != http.StatusOK {
+ return nil, fmt.Errorf("GET %q: %v", url, res.Status)
+ }
+ return io.ReadAll(res.Body)
+}
+
+var errorInvalidName = errors.New("invalid name")
+
+func proxyURL(path, version, suffix string) (string, error) {
+ p, err := module.EscapePath(path)
+ if err != nil {
+ return "", errorInvalidName
+ }
+ v, err := module.EscapeVersion(version)
+ if err != nil {
+ return "", errorInvalidName
+ }
+ return "https://proxy.golang.org/" + p + "/@v/" + v + suffix, nil
+}
+
+var errorGone = errors.New("410 Gone")
+
+func fetchMod(ctx context.Context, path, version string) ([]byte, error) {
+ url, err := proxyURL(path, version, ".mod")
+ if err != nil {
+ return nil, err
+ }
+ res, err := httpClient.Do(newRequestWithContext(ctx, "GET", url))
+ if err != nil {
+ return nil, err
+ }
+ defer res.Body.Close()
+ if res.StatusCode == http.StatusGone {
+ return nil, errorGone
+ }
+ if res.StatusCode != http.StatusOK {
+ return nil, fmt.Errorf("GET %q: %v", url, res.Status)
+ }
+ return io.ReadAll(res.Body)
+}
+
+func fetchZipHead(ctx context.Context, path, version string) (string, int64, error) {
+ url, err := proxyURL(path, version, ".zip")
+ if err != nil {
+ return "", 0, err
+ }
+ res, err := httpClient.Do(newRequestWithContext(ctx, "HEAD", url))
+ if err != nil {
+ return "", 0, err
+ }
+ defer res.Body.Close()
+ if res.StatusCode != http.StatusOK {
+ return "", 0, fmt.Errorf("GET %q: %v", url, res.Status)
+ }
+ return res.Request.URL.String(), res.ContentLength, nil
+}
+
+func fetchZip(ctx context.Context, path, version string, w io.Writer) error {
+ url, err := proxyURL(path, version, ".zip")
+ if err != nil {
+ return err
+ }
+ res, err := httpClient.Do(newRequestWithContext(ctx, "GET", url))
+ if err != nil {
+ return err
+ }
+ defer res.Body.Close()
+ if res.StatusCode == http.StatusGone {
+ return errorGone
+ }
+ if res.StatusCode != http.StatusOK {
+ return fmt.Errorf("GET %q: %v", url, res.Status)
+ }
+ // I experimented with using Range requests to back the zip
+ // ReaderAt, but it was extremely slow.
+ _, err = io.Copy(w, res.Body)
+ return err
+}
+
+var pbTemplate pb.ProgressBarTemplate = `{{string . "prefix"}} {{counters . }} {{bar . }} {{percent . }} {{etime . }}`
+
+func main() {
+ cpuprofile := flag.String("cpuprofile", "", "write cpu profile to FILE")
+ memprofile := flag.String("memprofile", "", "write memory profile to FILE")
+ flag.Parse()
+
+ if flag.NArg() != 1 {
+ log.Fatal("usage: allcode /mnt/allcode")
+ }
+
+ if *cpuprofile != "" {
+ f, err := os.Create(*cpuprofile)
+ if err != nil {
+ log.Fatal("could not create CPU profile: ", err)
+ }
+ defer f.Close()
+ if err := pprof.StartCPUProfile(f); err != nil {
+ log.Fatal("could not start CPU profile: ", err)
+ }
+ defer pprof.StopCPUProfile()
+ }
+
+ log.SetFlags(log.Lshortfile | log.Flags())
+ ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
+ defer cancel()
+
+ latest, err := fetchLatest(ctx)
+ if err != nil {
+ log.Fatal(err)
+ }
+ tree, err := tlog.ParseTree(latest)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ bar := pbTemplate.Start64(tree.N).Set("prefix", "Fetching index...")
+ latestVersions := make(map[string]string)
+
+ i, err := NewIndex(ctx)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ var linesSeen uint64
+ for {
+ v, err := i.next(ctx)
+ if err == io.EOF {
+ break
+ }
+ if err != nil {
+ log.Fatal(err)
+ }
+ linesSeen++
+ bar.Increment()
+
+ if semver.Compare(v.Version, latestVersions[v.Path]) >= 0 {
+ latestVersions[v.Path] = v.Version
+ }
+ }
+ bar.Finish()
+
+ pool := &sync.Pool{
+ New: func() interface{} {
+ return &bytes.Buffer{}
+ },
+ }
+
+ bar = pbTemplate.Start(len(latestVersions)).Set("prefix", "Fetching modules...")
+ sem := semaphore.NewWeighted(200)
+ gcp := semaphore.NewWeighted(500) // GCS can take it, and it's way way slower
+ g, ctx := errgroup.WithContext(ctx)
+
+ var gone, invalidName, vendor, mismatchedGoMod, invalidGoMod int64
+ var noGoCode, noGoMod, gcsRedirect, good, goBytes, allBytes, goFilesCount int64
+ for path, version := range latestVersions {
+ if err := ctx.Err(); ctx.Err() != nil {
+ bar.Finish()
+ log.Println(err)
+ break
+ }
+
+ if err := sem.Acquire(ctx, 1); err != nil {
+ bar.Finish()
+ log.Println(err)
+ break
+ }
+
+ path, version := path, version
+ g.Go(func() error {
+ releaseOnce := &sync.Once{}
+ defer releaseOnce.Do(func() { sem.Release(1) })
+ defer bar.Increment()
+
+ if strings.Contains(path, "/vendor/") || strings.Contains(path, "/kubernetes/staging/") {
+ atomic.AddInt64(&vendor, 1)
+ return nil
+ }
+ modBytes, err := fetchMod(ctx, path, version)
+ if err == errorInvalidName {
+ atomic.AddInt64(&invalidName, 1)
+ return nil
+ }
+ if err == errorGone {
+ atomic.AddInt64(&gone, 1)
+ return nil
+ }
+ if err != nil {
+ return err
+ }
+ mod, err := modfile.ParseLax(path+"@"+version, modBytes, nil)
+ if err != nil {
+ atomic.AddInt64(&invalidGoMod, 1)
+ return nil
+ }
+ if mod.Module.Mod.Path != path {
+ atomic.AddInt64(&mismatchedGoMod, 1)
+ return nil
+ }
+
+ url, size, err := fetchZipHead(ctx, path, version)
+ if err != nil {
+ return err
+ }
+ if strings.HasPrefix(url, "https://storage.googleapis.com/") {
+ atomic.AddInt64(&gcsRedirect, 1)
+ releaseOnce.Do(func() { sem.Release(1) })
+ gcp.Acquire(ctx, 1)
+ defer gcp.Release(1)
+ }
+
+ zipBytes := pool.Get().(*bytes.Buffer)
+ defer func() {
+ if zipBytes.Len() > 10*1024*1024 {
+ zipBytes.Reset()
+ pool.Put(zipBytes)
+ }
+ }()
+ zipBytes.Grow(int(size))
+
+ if err := fetchZip(ctx, path, version, zipBytes); err != nil {
+ return err
+ }
+ atomic.AddInt64(&allBytes, size)
+
+ zipBytesReader := bytes.NewReader(zipBytes.Bytes())
+ z, err := zip.NewReader(zipBytesReader, size)
+ if err != nil {
+ return err
+ }
+
+ var hasGoMod bool
+ goFiles := make([]*zip.File, 0, len(z.File))
+ for _, f := range z.File {
+ if strings.HasSuffix(f.Name, ".go") {
+ goFiles = append(goFiles, f)
+ }
+ if strings.HasSuffix(f.Name, "/go.mod") {
+ hasGoMod = true
+ }
+ }
+ if len(goFiles) == 0 {
+ atomic.AddInt64(&noGoCode, 1)
+ return nil
+ }
+ if !hasGoMod {
+ atomic.AddInt64(&noGoMod, 1)
+ return nil
+ }
+ atomic.AddInt64(&good, 1)
+
+ for _, zf := range goFiles {
+ src, err := z.Open(zf.Name)
+ if err != nil {
+ return err
+ }
+
+ name := filepath.Join(flag.Arg(0), zf.Name)
+ if err := os.MkdirAll(filepath.Dir(name), 0o777); err != nil {
+ return err
+ }
+ dest, err := os.Create(name)
+ if err != nil {
+ return err
+ }
+
+ n, err := io.Copy(dest, src)
+ if err != nil {
+ return err
+ }
+ if err := dest.Close(); err != nil {
+ return err
+ }
+
+ atomic.AddInt64(&goFilesCount, 1)
+ atomic.AddInt64(&goBytes, n)
+ }
+
+ return nil
+ })
+ }
+
+ if err := g.Wait(); err != nil {
+ bar.Finish()
+ log.Println(err)
+ }
+ bar.Finish()
+
+ fmt.Fprintf(os.Stderr, "\n")
+ fmt.Fprintf(os.Stderr, "Unique modules: % 7d -\n", len(latestVersions))
+ fmt.Fprintf(os.Stderr, "Vendor paths: % 7d -\n", vendor)
+ fmt.Fprintf(os.Stderr, "Invalid names: % 7d -\n", invalidName)
+ fmt.Fprintf(os.Stderr, "Gone: % 7d -\n", gone)
+ fmt.Fprintf(os.Stderr, "Invalid go.mod files: % 7d -\n", invalidGoMod)
+ fmt.Fprintf(os.Stderr, "Mismatching go.mod: % 7d -\n", mismatchedGoMod)
+ fmt.Fprintf(os.Stderr, "GCS redirects: % 7d -\n", gcsRedirect)
+ fmt.Fprintf(os.Stderr, "No .go files: % 7d -\n", noGoCode)
+ fmt.Fprintf(os.Stderr, "No go.mod files: % 7d =\n", noGoMod)
+ fmt.Fprintf(os.Stderr, " -------\n")
+ fmt.Fprintf(os.Stderr, " % 7d\n", good)
+ fmt.Fprintf(os.Stderr, "\n")
+ fmt.Fprintf(os.Stderr, "Downloaded %d bytes.\n", allBytes)
+ fmt.Fprintf(os.Stderr, "Wrote %d Go files (%d bytes).\n", goFilesCount, goBytes)
+
+ if *memprofile != "" {
+ f, err := os.Create(*memprofile)
+ if err != nil {
+ log.Fatal("could not create memory profile: ", err)
+ }
+ defer f.Close()
+ runtime.GC() // get up-to-date statistics
+ if err := pprof.WriteHeapProfile(f); err != nil {
+ log.Fatal("could not write memory profile: ", err)
+ }
+ }
+}
diff --git a/go.mod b/go.mod
index 6f4c758..fcb9ea1 100644
--- a/go.mod
+++ b/go.mod
@@ -5,8 +5,15 @@
require (
dmitri.shuralyov.com/gpu/mtl v0.0.0-20201218220906-28db891af037
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802
+ github.com/VividCortex/ewma v1.1.1 // indirect
+ github.com/cheggaaa/pb/v3 v3.0.8
+ github.com/fatih/color v1.10.0 // indirect
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4
github.com/google/go-cmp v0.5.5
+ github.com/mattn/go-colorable v0.1.8 // indirect
+ github.com/mattn/go-isatty v0.0.12 // indirect
+ github.com/mattn/go-runewidth v0.0.12 // indirect
+ github.com/rivo/uniseg v0.2.0 // indirect
github.com/rs/zerolog v1.21.0
github.com/sirupsen/logrus v1.8.1
go.uber.org/atomic v1.7.0 // indirect
@@ -15,7 +22,8 @@
golang.org/x/image v0.0.0-20190802002840-cff245a6509b
golang.org/x/mobile v0.0.0-20201217150744-e6ae53a27f4f
golang.org/x/mod v0.4.2
- golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4
+ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9
+ golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57
golang.org/x/tools v0.1.0
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1
honnef.co/go/tools v0.1.3 // indirect
diff --git a/go.sum b/go.sum
index f073f79..c2358f8 100644
--- a/go.sum
+++ b/go.sum
@@ -4,10 +4,16 @@
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802 h1:1BDTz0u9nC3//pOCMdNH+CiXJVYJh5UQNCOBG7jbELc=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
+github.com/VividCortex/ewma v1.1.1 h1:MnEK4VOv6n0RSY4vtRe3h11qjxL3+t0B8yOL8iMXdcM=
+github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA=
+github.com/cheggaaa/pb/v3 v3.0.8 h1:bC8oemdChbke2FHIIGy9mn4DPJ2caZYQnfbRqwmdCoA=
+github.com/cheggaaa/pb/v3 v3.0.8/go.mod h1:UICbiLec/XO6Hw6k+BHEtHeQFzzBH4i2/qk/ow1EJTA=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg=
+github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4 h1:WtGNWLvXpe6ZudgnXrq0barxBImvnnJoMEhXAzcbM0I=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
@@ -17,11 +23,20 @@
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
+github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
+github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
+github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
+github.com/mattn/go-runewidth v0.0.12 h1:Y41i/hVW3Pgwr8gV+J23B9YEY0zxjptBuCWEaxmAOow=
+github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
+github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
+github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
github.com/rs/zerolog v1.21.0 h1:Q3vdXlfLNT+OftyBHsU0Y445MD+8m8axjKgf2si0QcM=
@@ -68,13 +83,17 @@
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4 h1:myAQVi0cGEoqQVR5POX+8RR2mrocKqNN1hmeMqhX27k=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57 h1:F5Gozwx4I1xtr/sr/8CFbb57iKi3297KFs0QDbGN60A=
+golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
To view, visit change 321030. To unsubscribe, or for help writing mail filters, visit settings.
Filippo Valsorda uploaded patch set #2 to this change.
cmd/allcode: add a tool to download all Go code locally
All of it.
Change-Id: I1f8ae99a9f314defe9b48e0293d69e6f83806080
---
A cmd/allcode/README
A cmd/allcode/allcode.go
M go.mod
M go.sum
4 files changed, 466 insertions(+), 2 deletions(-)
To view, visit change 321030. To unsubscribe, or for help writing mail filters, visit settings.
Filippo Valsorda uploaded patch set #3 to this change.
cmd/allcode: add a tool to download all Go code locally
All of it.
Change-Id: I1f8ae99a9f314defe9b48e0293d69e6f83806080
---
A cmd/allcode/README
A cmd/allcode/allcode.go
M go.mod
M go.sum
4 files changed, 475 insertions(+), 2 deletions(-)
To view, visit change 321030. To unsubscribe, or for help writing mail filters, visit settings.
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |