github.com/saucelabs/saucectl@v0.175.1/internal/cmd/apit/downloadfile.go (about)

     1  package apit
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  	"io"
     8  	"os"
     9  
    10  	"github.com/spf13/cobra"
    11  	"golang.org/x/text/cases"
    12  	"golang.org/x/text/language"
    13  
    14  	"github.com/saucelabs/saucectl/internal/apitest"
    15  	cmds "github.com/saucelabs/saucectl/internal/cmd"
    16  	"github.com/saucelabs/saucectl/internal/http"
    17  	"github.com/saucelabs/saucectl/internal/segment"
    18  	"github.com/saucelabs/saucectl/internal/usage"
    19  )
    20  
    21  func DownloadFileCommand() *cobra.Command {
    22  	cmd := &cobra.Command{
    23  		Use:   "download-file FILENAME [--project PROJECT_NAME]",
    24  		Short: "Download a vault file",
    25  		Long: `Download a file from a project's vault.
    26  
    27  Use [--project] to specify the project by its name or run without [--project] to choose from a list of projects.
    28  `,
    29  		SilenceUsage: true,
    30  		Args: func(cmd *cobra.Command, args []string) error {
    31  			if len(args) == 0 || args[0] == "" {
    32  				return errors.New("no file name specified")
    33  			}
    34  			return nil
    35  		},
    36  		PreRunE: func(cmd *cobra.Command, args []string) error {
    37  			err := http.CheckProxy()
    38  			if err != nil {
    39  				return fmt.Errorf("invalid HTTP_PROXY value")
    40  			}
    41  
    42  			tracker := segment.DefaultTracker
    43  
    44  			go func() {
    45  				tracker.Collect(
    46  					cases.Title(language.English).String(cmds.FullName(cmd)),
    47  					usage.Properties{}.SetFlags(cmd.Flags()),
    48  				)
    49  				_ = tracker.Close()
    50  			}()
    51  			return nil
    52  		},
    53  		RunE: func(cmd *cobra.Command, args []string) error {
    54  			name := args[0]
    55  			files, err := apitesterClient.ListVaultFiles(context.Background(), selectedProject.ID)
    56  			if err != nil {
    57  				return err
    58  			}
    59  
    60  			file, err := findMatchingFile(name, files)
    61  			if err != nil {
    62  				return fmt.Errorf("project %q has no vault drive file with name %q", selectedProject.ProjectMeta.Name, name)
    63  			}
    64  
    65  			bodyReader, err := apitesterClient.GetVaultFileContent(context.Background(), selectedProject.ID, file.ID)
    66  			if err != nil {
    67  				return err
    68  			}
    69  
    70  			err = saveFileToDisk(bodyReader, name)
    71  			if err != nil {
    72  				return err
    73  			}
    74  			fmt.Printf("File %q has been successfully retrieved.\n", name)
    75  			return nil
    76  		},
    77  	}
    78  	return cmd
    79  }
    80  
    81  func saveFileToDisk(rc io.ReadCloser, fileName string) error {
    82  	defer rc.Close()
    83  
    84  	fd, err := os.Create(fileName)
    85  	if err != nil {
    86  		return err
    87  	}
    88  	defer fd.Close()
    89  
    90  	_, err = io.Copy(fd, rc)
    91  	return err
    92  }
    93  
    94  func findMatchingFile(fileName string, files []apitest.VaultFile) (apitest.VaultFile, error) {
    95  	for _, file := range files {
    96  		if file.Name == fileName {
    97  			return file, nil
    98  		}
    99  	}
   100  	return apitest.VaultFile{}, fmt.Errorf("no file named %s found", fileName)
   101  }