go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/buildbucket/cli/builders.go (about) 1 // Copyright 2019 The LUCI Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package cli 16 17 import ( 18 "context" 19 "fmt" 20 "io" 21 "os" 22 "strings" 23 "time" 24 25 "github.com/maruel/subcommands" 26 27 "go.chromium.org/luci/common/cli" 28 "go.chromium.org/luci/common/system/pager" 29 30 pb "go.chromium.org/luci/buildbucket/proto" 31 ) 32 33 func cmdBuilders(p Params) *subcommands.Command { 34 return &subcommands.Command{ 35 UsageLine: `builders [flags] [PATH]`, 36 ShortDesc: "lists builders", 37 LongDesc: doc(` 38 Lists builders. 39 40 A PATH argument has the form "<project>/<bucket>". 41 `), 42 CommandRun: func() subcommands.CommandRun { 43 r := &buildersRun{} 44 r.RegisterDefaultFlags(p) 45 r.Flags.IntVar(&r.limit, "n", 0, doc(` 46 Limit the number of builders to print. If 0, then unlimited. 47 `)) 48 r.Flags.BoolVar(&r.noPager, "nopage", false, doc(` 49 Disable paging. 50 `)) 51 return r 52 }, 53 } 54 } 55 56 type buildersRun struct { 57 printRun 58 59 limit int 60 noPager bool 61 } 62 63 func (r *buildersRun) Run(a subcommands.Application, args []string, env subcommands.Env) int { 64 ctx := cli.GetContext(a, r, env) 65 66 if err := r.initClients(ctx, nil); err != nil { 67 return r.done(ctx, err) 68 } 69 70 if r.limit < 0 { 71 return r.done(ctx, fmt.Errorf("-n value must be non-negative")) 72 } 73 if len(args) != 1 { 74 return r.done(ctx, fmt.Errorf("exactly one PATH of the form \"<project>/<bucket>\" must be specified")) 75 } 76 77 parts := strings.Split(args[0], "/") 78 if len(parts) != 2 { 79 return r.done(ctx, fmt.Errorf("PATH must have the form \"<project>/<bucket>\"")) 80 } 81 82 req := &pb.ListBuildersRequest{ 83 Project: parts[0], 84 Bucket: parts[1], 85 } 86 87 disableColors := r.noColor || shouldDisableColors() 88 89 listBuilders := func(ctx context.Context, out io.WriteCloser) int { 90 p := newPrinter(out, disableColors, time.Now) 91 92 for count := 0; count < r.limit || r.limit == 0; { 93 if r.limit > 0 { 94 req.PageSize = int32(r.limit - count) 95 } 96 if r.limit == 0 || req.PageSize > defaultPageSize { 97 req.PageSize = defaultPageSize 98 } 99 rsp, err := r.buildersClient.ListBuilders(ctx, req, expectedCodeRPCOption) 100 if err != nil { 101 return r.done(ctx, err) 102 } 103 for _, b := range rsp.Builders { 104 // TODO(crbug/1240349): Improve formatting when printing builders. 105 p.f("%s/%s/%s\n", b.Id.Project, b.Id.Bucket, b.Id.Builder) 106 count++ 107 if count > r.limit && r.limit > 0 { 108 break 109 } 110 } 111 if rsp.NextPageToken == "" { 112 break 113 } 114 req.PageToken = rsp.NextPageToken 115 } 116 117 return 0 118 } 119 120 if r.noPager { 121 return listBuilders(ctx, os.Stdout) 122 } 123 return pager.Main(ctx, listBuilders) 124 }