golang.org/x/build@v0.0.0-20240506185731-218518f32b70/cmd/gomote/get.go (about) 1 // Copyright 2015 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package main 6 7 import ( 8 "context" 9 "flag" 10 "fmt" 11 "io" 12 "net/http" 13 "os" 14 "time" 15 16 "golang.org/x/build/internal/gomote/protos" 17 "golang.org/x/sync/errgroup" 18 ) 19 20 // getTar a .tar.gz 21 func getTar(args []string) error { 22 fs := flag.NewFlagSet("get", flag.ContinueOnError) 23 fs.Usage = func() { 24 fmt.Fprintln(os.Stderr, "gettar usage: gomote gettar [get-opts] [buildlet-name]") 25 fmt.Fprintln(os.Stderr, "") 26 fmt.Fprintln(os.Stderr, "Writes tarball into the current working directory.") 27 fmt.Fprintln(os.Stderr, "") 28 fmt.Fprintln(os.Stderr, "Buildlet name is optional if a group is selected, in which case") 29 fmt.Fprintln(os.Stderr, "tarballs from all buildlets in the group are downloaded into the") 30 fmt.Fprintln(os.Stderr, "current working directory.") 31 fs.PrintDefaults() 32 os.Exit(1) 33 } 34 var dir string 35 fs.StringVar(&dir, "dir", "", "relative directory from buildlet's work dir to tar up") 36 37 fs.Parse(args) 38 39 var getSet []string 40 if fs.NArg() == 1 { 41 getSet = []string{fs.Arg(0)} 42 } else if fs.NArg() == 0 && activeGroup != nil { 43 for _, inst := range activeGroup.Instances { 44 getSet = append(getSet, inst) 45 } 46 } else { 47 fs.Usage() 48 } 49 50 eg, ctx := errgroup.WithContext(context.Background()) 51 for _, inst := range getSet { 52 inst := inst 53 eg.Go(func() error { 54 f, err := os.Create(fmt.Sprintf("%s.tar.gz", inst)) 55 if err != nil { 56 fmt.Fprintf(os.Stderr, "failed to create file to write instance tarball: %v", err) 57 return nil 58 } 59 defer f.Close() 60 fmt.Fprintf(os.Stderr, "# Downloading tarball for %q to %q...\n", inst, f.Name()) 61 return doGetTar(ctx, inst, dir, f) 62 }) 63 } 64 return eg.Wait() 65 } 66 67 func doGetTar(ctx context.Context, name, dir string, out io.Writer) error { 68 client := gomoteServerClient(ctx) 69 resp, err := client.ReadTGZToURL(ctx, &protos.ReadTGZToURLRequest{ 70 GomoteId: name, 71 Directory: dir, 72 }) 73 if err != nil { 74 return fmt.Errorf("unable to retrieve tgz URL: %w", err) 75 } 76 httpClient := &http.Client{ 77 Timeout: 10 * time.Second, 78 Transport: &http.Transport{ 79 TLSHandshakeTimeout: 5 * time.Second, 80 }, 81 } 82 req, err := http.NewRequestWithContext(ctx, http.MethodGet, resp.GetUrl(), nil) 83 if err != nil { 84 return fmt.Errorf("unable to create HTTP Request: %w", err) 85 } 86 r, err := httpClient.Do(req) 87 if err != nil { 88 return fmt.Errorf("unable to download tgz: %w", err) 89 } 90 defer r.Body.Close() 91 _, err = io.Copy(out, r.Body) 92 if err != nil { 93 return fmt.Errorf("unable to copy tgz to stdout: %w", err) 94 } 95 return nil 96 }