Chromium Code Reviews| Index: go/src/infra/tools/cipd/apps/cipd/main.go |
| diff --git a/go/src/infra/tools/cipd/apps/cipd/main.go b/go/src/infra/tools/cipd/apps/cipd/main.go |
| index 0858745a00746fd89d409bf1a5d126c759b08429..a70c2fdc8c08035ddbda3fef49b601ac81e040cf 100644 |
| --- a/go/src/infra/tools/cipd/apps/cipd/main.go |
| +++ b/go/src/infra/tools/cipd/apps/cipd/main.go |
| @@ -66,14 +66,20 @@ func (c *Subcommand) init(args []string, minPosCount, maxPosCount int) bool { |
| c.printError(makeCLIError("unexpected arguments %v", args)) |
| return false |
| } |
| - if len(args) < minPosCount || len(args) > maxPosCount { |
| + if len(args) < minPosCount || (maxPosCount >= 0 && len(args) > maxPosCount) { |
| var err error |
| if minPosCount == maxPosCount { |
| err = makeCLIError("expecting %d positional argument, got %d instead", minPosCount, len(args)) |
| } else { |
| - err = makeCLIError( |
| - "expecting from %d to %d positional arguments, got %d instead", |
| - minPosCount, maxPosCount, len(args)) |
| + if maxPosCount >= 0 { |
| + err = makeCLIError( |
| + "expecting from %d to %d positional arguments, got %d instead", |
| + minPosCount, maxPosCount, len(args)) |
| + } else { |
| + err = makeCLIError( |
| + "expecting at least %d positional arguments, got %d instead", |
| + minPosCount, len(args)) |
| + } |
| } |
| c.printError(err) |
| return false |
| @@ -114,7 +120,7 @@ func (c *Subcommand) printError(err error) { |
| fmt.Fprintf(os.Stderr, "Bad command line: %s.\n\n", err) |
| c.Flags.Usage() |
| } else { |
| - fmt.Fprintln(os.Stderr, err) |
| + fmt.Fprintf(os.Stderr, "Error: %s.\n", err) |
| } |
| } |
| @@ -170,6 +176,21 @@ func (c *Subcommand) done(result interface{}, err error) int { |
| return 0 |
| } |
| +// doneWithPins is a handy shortcut that prints array of pinOrError and deduces |
|
nodir
2015/09/21 22:26:59
it is a slice, but whatever
Vadim Sh.
2015/09/29 01:43:34
renamed to "list"
|
| +// process exit code based on presence of errors there. |
| +func (c *Subcommand) doneWithPins(pins []pinOrError, err error) int { |
| + if len(pins) == 0 { |
| + fmt.Println("No packages.") |
| + } else { |
| + printPinsAndError(pins) |
| + } |
| + ret := c.done(pins, err) |
| + if hasErrors(pins) && ret == 0 { |
| + return 1 |
| + } |
| + return ret |
| +} |
| + |
| // commandLineError is used to tag errors related to CLI. |
| type commandLineError struct { |
| error |
| @@ -423,9 +444,10 @@ type batchOperation struct { |
| // pinOrError is passed through channels and also dumped to JSON results file. |
| type pinOrError struct { |
| - Pkg string `json:"package"` |
| - Pin *common.Pin `json:"pin,omitempty"` |
| - Err string `json:"error,omitempty"` |
| + Pkg string `json:"package"` |
| + Pin *common.Pin `json:"pin,omitempty"` |
| + Err string `json:"error,omitempty"` |
| + Tracking string `json:"tracking,omitempty"` |
| } |
| // expandPkgDir takes a package name or '<prefix>/' and returns a list |
| @@ -466,9 +488,9 @@ func performBatchOperation(op batchOperation) ([]pinOrError, error) { |
| return callConcurrently(pkgs, func(pkg string) pinOrError { |
| pin, err := op.callback(pkg) |
| if err != nil { |
| - return pinOrError{pkg, nil, err.Error()} |
| + return pinOrError{pkg, nil, err.Error(), ""} |
| } |
| - return pinOrError{pkg, &pin, ""} |
| + return pinOrError{pkg, &pin, "", ""} |
| }), nil |
| } |
| @@ -498,17 +520,22 @@ func printPinsAndError(pins []pinOrError) { |
| hasPins := false |
| hasErrors := false |
| for _, p := range pins { |
| - if p.Err == "" { |
| - hasPins = true |
| - } else { |
| + if p.Err != "" { |
| hasErrors = true |
| + } else if p.Pin != nil { |
| + hasPins = true |
| } |
| } |
| if hasPins { |
| - fmt.Println("Instances:") |
| + fmt.Println("Packages:") |
| for _, p := range pins { |
| - if p.Err == "" { |
| + if p.Err != "" || p.Pin == nil { |
| + continue |
| + } |
| + if p.Tracking == "" { |
| fmt.Printf(" %s\n", p.Pin) |
| + } else { |
| + fmt.Printf(" %s (tracking %q)\n", p.Pin, p.Tracking) |
| } |
| } |
| } |
| @@ -516,7 +543,7 @@ func printPinsAndError(pins []pinOrError) { |
| fmt.Fprintln(os.Stderr, "Errors:") |
| for _, p := range pins { |
| if p.Err != "" { |
| - fmt.Fprintf(os.Stderr, " %s\n", p.Err) |
| + fmt.Fprintf(os.Stderr, " %s: %s.\n", p.Pkg, p.Err) |
| } |
| } |
| } |
| @@ -586,12 +613,15 @@ func buildAndUploadInstance(inputOpts InputOptions, refsOpts RefsOptions, tagsOp |
| var cmdEnsure = &subcommands.Command{ |
| UsageLine: "ensure [options]", |
| ShortDesc: "installs, removes and updates packages in one go", |
| - LongDesc: "Installs, removes and updates packages in one go.", |
| + LongDesc: "Installs, removes and updates packages in one go.\n\n" + |
| + "Supposed to be used from scripts and automation. Alternative to 'init', " + |
| + "'install' and 'remove'. As such, it doesn't try to discover site root " + |
| + "directory on its own.", |
| CommandRun: func() subcommands.CommandRun { |
| c := &ensureRun{} |
| c.registerBaseFlags() |
| c.ServiceOptions.registerFlags(&c.Flags) |
| - c.Flags.StringVar(&c.rootDir, "root", "<path>", "Path to a installation site root directory.") |
| + c.Flags.StringVar(&c.rootDir, "root", "<path>", "Path to an installation site root directory.") |
| c.Flags.StringVar(&c.listFile, "list", "<path>", "A file with a list of '<package name> <version>' pairs.") |
| return c |
| }, |
| @@ -659,13 +689,7 @@ func (c *resolveRun) Run(a subcommands.Application, args []string) int { |
| if !c.init(args, 1, 1) { |
| return 1 |
| } |
| - pins, err := resolveVersion(args[0], c.version, c.ServiceOptions) |
| - printPinsAndError(pins) |
| - ret := c.done(pins, err) |
| - if hasErrors(pins) && ret == 0 { |
| - return 1 |
| - } |
| - return ret |
| + return c.doneWithPins(resolveVersion(args[0], c.version, c.ServiceOptions)) |
| } |
| func resolveVersion(packagePrefix, version string, serviceOpts ServiceOptions) ([]pinOrError, error) { |
| @@ -714,13 +738,7 @@ func (c *setRefRun) Run(a subcommands.Application, args []string) int { |
| if len(c.refs) == 0 { |
| return c.done(nil, makeCLIError("at least one -ref must be provided")) |
| } |
| - pins, err := setRef(args[0], c.version, c.RefsOptions, c.ServiceOptions) |
| - printPinsAndError(pins) |
| - ret := c.done(pins, err) |
| - if hasErrors(pins) && ret == 0 { |
| - return 1 |
| - } |
| - return ret |
| + return c.doneWithPins(setRef(args[0], c.version, c.RefsOptions, c.ServiceOptions)) |
| } |
| func setRef(packagePrefix, version string, refsOpts RefsOptions, serviceOpts ServiceOptions) ([]pinOrError, error) { |
| @@ -743,7 +761,7 @@ func setRef(packagePrefix, version string, refsOpts RefsOptions, serviceOpts Ser |
| } |
| if hasErrors(pins) { |
| printPinsAndError(pins) |
| - return nil, fmt.Errorf("can't find %q version in all packages, aborting.", version) |
| + return nil, fmt.Errorf("can't find %q version in all packages, aborting", version) |
| } |
| // Prepare for the next batch call. |
| @@ -775,7 +793,7 @@ func setRef(packagePrefix, version string, refsOpts RefsOptions, serviceOpts Ser |
| var cmdListPackages = &subcommands.Command{ |
| UsageLine: "ls [-r] [<prefix string>]", |
| - ShortDesc: "lists matching packages", |
| + ShortDesc: "queries backend for a list of matching packages", |
|
nodir
2015/09/21 22:26:59
looks like mentioning impl details. I'd move them
Vadim Sh.
2015/09/29 01:43:34
Done. I wanted to clarify that it lists packages o
tandrii(chromium)
2015/09/29 14:21:25
weak suggestion: maybe then say in short version "
|
| LongDesc: "List packages in the given path to which the user has access, optionally recursively.", |
| CommandRun: func() subcommands.CommandRun { |
| c := &listPackagesRun{} |
| @@ -1047,7 +1065,7 @@ var cmdDeploy = &subcommands.Command{ |
| CommandRun: func() subcommands.CommandRun { |
| c := &deployRun{} |
| c.registerBaseFlags() |
| - c.Flags.StringVar(&c.rootDir, "root", "<path>", "Path to a installation site root directory.") |
| + c.Flags.StringVar(&c.rootDir, "root", "<path>", "Path to an installation site root directory.") |
| return c |
| }, |
| } |
| @@ -1270,6 +1288,12 @@ var application = &subcommands.DefaultApplication{ |
| subcommands.CmdHelp, |
| cipd_lib.SubcommandVersion, |
| + // User friendly subcommands that operates within a site root. Implemented |
| + // in friendly.go. |
| + cmdInit, |
| + cmdInstall, |
| + cmdInstalled, |
| + |
| // Authentication related commands. |
| authcli.SubcommandInfo(auth.Options{Logger: log}, "auth-info"), |
| authcli.SubcommandLogin(auth.Options{Logger: log}, "auth-login"), |