github.com/saucelabs/saucectl@v0.175.1/internal/cmd/storage/list.go (about) 1 package storage 2 3 import ( 4 "encoding/json" 5 "errors" 6 "fmt" 7 "os" 8 "time" 9 10 "github.com/dustin/go-humanize" 11 "github.com/jedib0t/go-pretty/v6/table" 12 "github.com/jedib0t/go-pretty/v6/text" 13 cmds "github.com/saucelabs/saucectl/internal/cmd" 14 "github.com/saucelabs/saucectl/internal/segment" 15 "github.com/saucelabs/saucectl/internal/storage" 16 "github.com/saucelabs/saucectl/internal/usage" 17 "github.com/spf13/cobra" 18 "golang.org/x/text/cases" 19 "golang.org/x/text/language" 20 ) 21 22 var defaultTableStyle = table.Style{ 23 Name: "saucy", 24 Box: table.BoxStyle{ 25 BottomLeft: "└", 26 BottomRight: "┘", 27 BottomSeparator: "", 28 EmptySeparator: text.RepeatAndTrim(" ", text.RuneCount("+")), 29 Left: "│", 30 LeftSeparator: "", 31 MiddleHorizontal: "─", 32 MiddleSeparator: "", 33 MiddleVertical: "", 34 PaddingLeft: " ", 35 PaddingRight: " ", 36 PageSeparator: "\n", 37 Right: "│", 38 RightSeparator: "", 39 TopLeft: "┌", 40 TopRight: "┐", 41 TopSeparator: "", 42 UnfinishedRow: " ...", 43 }, 44 Color: table.ColorOptionsDefault, 45 Format: table.FormatOptions{ 46 Footer: text.FormatDefault, 47 Header: text.FormatDefault, 48 Row: text.FormatDefault, 49 }, 50 HTML: table.DefaultHTMLOptions, 51 Options: table.Options{ 52 DrawBorder: false, 53 SeparateColumns: false, 54 SeparateFooter: true, 55 SeparateHeader: true, 56 SeparateRows: false, 57 }, 58 Title: table.TitleOptionsDefault, 59 } 60 61 func ListCommand() *cobra.Command { 62 var query string 63 var name string 64 var out string 65 var sha256 string 66 67 cmd := &cobra.Command{ 68 Use: "list", 69 Aliases: []string{ 70 "ls", 71 }, 72 Short: "Returns the list of files that have been uploaded to Sauce Storage.", 73 SilenceUsage: true, 74 PreRun: func(cmd *cobra.Command, args []string) { 75 tracker := segment.DefaultTracker 76 77 go func() { 78 tracker.Collect( 79 cases.Title(language.English).String(cmds.FullName(cmd)), 80 usage.Properties{}.SetFlags(cmd.Flags()), 81 ) 82 _ = tracker.Close() 83 }() 84 }, 85 RunE: func(cmd *cobra.Command, args []string) error { 86 list, err := appsClient.List(storage.ListOptions{ 87 Q: query, 88 Name: name, 89 SHA256: sha256, 90 }) 91 if err != nil { 92 return fmt.Errorf("failed to retrieve list: %w", err) 93 } 94 switch out { 95 case "text": 96 renderTable(list) 97 case "json": 98 if err := renderJSON(list); err != nil { 99 return fmt.Errorf("failed to render output: %w", err) 100 } 101 default: 102 return errors.New("unknown output format") 103 } 104 105 return nil 106 }, 107 } 108 109 flags := cmd.Flags() 110 flags.StringVarP(&query, "query", "q", "", 111 "Any search term (such as app name, file name, description, build number or version) by which you want to filter.", 112 ) 113 flags.StringVarP(&name, "name", "n", "", 114 "The filename (case-insensitive) by which you want to filter.", 115 ) 116 flags.StringVar(&sha256, "sha256", "", 117 "The checksum of the file by which you want to filter.", 118 ) 119 flags.StringVarP(&out, "out", "o", "text", 120 "Output format to the console. Options: text, json.", 121 ) 122 123 return cmd 124 } 125 126 func renderTable(list storage.List) { 127 if len(list.Items) == 0 { 128 println("No files match the search criteria.") 129 } 130 131 t := table.NewWriter() 132 t.SetStyle(defaultTableStyle) 133 t.SuppressEmptyColumns() 134 135 t.AppendHeader(table.Row{"Size", "Uploaded", "ID", "Name"}) 136 t.SetColumnConfigs([]table.ColumnConfig{ 137 { 138 Name: "Size", 139 AlignHeader: text.AlignLeft, 140 Align: text.AlignRight, 141 AlignFooter: text.AlignRight, 142 Transformer: func(val interface{}) string { 143 t, _ := val.(int) 144 return humanize.Bytes(uint64(t)) 145 }, 146 }, 147 { 148 Name: "Uploaded", 149 Align: text.AlignRight, 150 AlignFooter: text.AlignRight, 151 Transformer: func(val interface{}) string { 152 t, _ := val.(time.Time) 153 return t.Format(time.Stamp) 154 }, 155 }, 156 { 157 Name: "ID", 158 }, 159 { 160 Name: "Name", 161 }, 162 }) 163 164 for _, item := range list.Items { 165 // the order of values must match the order of the header 166 t.AppendRow(table.Row{item.Size, item.Uploaded, item.ID, item.Name}) 167 } 168 169 fmt.Println(t.Render()) 170 171 if list.Truncated { 172 println("\nYour query returned more files than we can display. Please refine your query.") 173 } 174 } 175 176 func renderJSON(val any) error { 177 return json.NewEncoder(os.Stdout).Encode(val) 178 }