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  }