Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(45)

Unified Diff: go/src/infra/tools/cipd/apps/cipd/main.go

Issue 1358533003: cipd: Implement 'init', 'install' and 'installed' subcommands. (Closed) Base URL: https://chromium.googlesource.com/infra/infra.git@master
Patch Set: Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « go/src/infra/tools/cipd/apps/cipd/friendly.go ('k') | go/src/infra/tools/cipd/local/deployer.go » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 b5232dc0da98f9625bd5c9411a6138c732b3bf07..d33f4a841e9b1993a61593dacc715f61e97a06c0 100644
--- a/go/src/infra/tools/cipd/apps/cipd/main.go
+++ b/go/src/infra/tools/cipd/apps/cipd/main.go
@@ -42,6 +42,20 @@ var log = gologger.Get()
////////////////////////////////////////////////////////////////////////////////
// Common subcommand functions.
+// pinInfo contains information about single package pin inside some site root,
+// or an error related to it. It is passed through channels when running batch
+// operations and dumped to JSON results file in doneWithPins.
+type pinInfo struct {
+ // Pkg is package name. Always set.
+ Pkg string `json:"package"`
+ // Pin is not nil if pin related operation succeeded. It contains instanceID.
+ Pin *common.Pin `json:"pin,omitempty"`
+ // Tracking is what ref is being tracked by that package in the site root.
+ Tracking string `json:"tracking,omitempty"`
+ // Err is not empty if pin related operation failed. Pin is nil in that case.
+ Err string `json:"error,omitempty"`
+}
+
// Subcommand is a base of all CIPD subcommands. It defines some common flags,
// such as logging and JSON output parameters.
type Subcommand struct {
@@ -66,14 +80,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 +134,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 +190,21 @@ func (c *Subcommand) done(result interface{}, err error) int {
return 0
}
+// doneWithPins is a handy shortcut that prints list of pinInfo and deduces
+// process exit code based on presence of errors there.
+func (c *Subcommand) doneWithPins(pins []pinInfo, 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
@@ -421,13 +456,6 @@ type batchOperation struct {
callback func(pkg string) (common.Pin, error)
}
-// 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"`
-}
-
// expandPkgDir takes a package name or '<prefix>/' and returns a list
// of matching packages (asking backend if necessary). Doesn't recurse, returns
// only direct children.
@@ -454,7 +482,7 @@ func expandPkgDir(c cipd.Client, packagePrefix string) ([]string, error) {
// performBatchOperation expands a package prefix into a list of packages and
// calls callback for each of them (concurrently) gathering the results.
-func performBatchOperation(op batchOperation) ([]pinOrError, error) {
+func performBatchOperation(op batchOperation) ([]pinInfo, error) {
pkgs := op.packages
if len(pkgs) == 0 {
var err error
@@ -463,52 +491,57 @@ func performBatchOperation(op batchOperation) ([]pinOrError, error) {
return nil, err
}
}
- return callConcurrently(pkgs, func(pkg string) pinOrError {
+ return callConcurrently(pkgs, func(pkg string) pinInfo {
pin, err := op.callback(pkg)
if err != nil {
- return pinOrError{pkg, nil, err.Error()}
+ return pinInfo{pkg, nil, "", err.Error()}
}
- return pinOrError{pkg, &pin, ""}
+ return pinInfo{pkg, &pin, "", ""}
}), nil
}
-func callConcurrently(pkgs []string, callback func(pkg string) pinOrError) []pinOrError {
+func callConcurrently(pkgs []string, callback func(pkg string) pinInfo) []pinInfo {
// Push index through channel to make results ordered as 'pkgs'.
ch := make(chan struct {
int
- pinOrError
+ pinInfo
})
for idx, pkg := range pkgs {
go func(idx int, pkg string) {
ch <- struct {
int
- pinOrError
+ pinInfo
}{idx, callback(pkg)}
}(idx, pkg)
}
- pins := make([]pinOrError, len(pkgs))
+ pins := make([]pinInfo, len(pkgs))
for i := 0; i < len(pkgs); i++ {
res := <-ch
- pins[res.int] = res.pinOrError
+ pins[res.int] = res.pinInfo
}
return pins
}
-func printPinsAndError(pins []pinOrError) {
+func printPinsAndError(pins []pinInfo) {
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,13 +549,13 @@ 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)
}
}
}
}
-func hasErrors(pins []pinOrError) bool {
+func hasErrors(pins []pinInfo) bool {
for _, p := range pins {
if p.Err != "" {
return true
@@ -586,12 +619,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,16 +695,10 @@ 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) {
+func resolveVersion(packagePrefix, version string, serviceOpts ServiceOptions) ([]pinInfo, error) {
client, err := serviceOpts.makeCipdClient("")
if err != nil {
return nil, err
@@ -714,16 +744,10 @@ 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) {
+func setRef(packagePrefix, version string, refsOpts RefsOptions, serviceOpts ServiceOptions) ([]pinInfo, error) {
client, err := serviceOpts.makeCipdClient("")
if err != nil {
return nil, err
@@ -775,8 +799,9 @@ func setRef(packagePrefix, version string, refsOpts RefsOptions, serviceOpts Ser
var cmdListPackages = &subcommands.Command{
UsageLine: "ls [-r] [<prefix string>]",
- ShortDesc: "lists matching packages",
- LongDesc: "List packages in the given path to which the user has access, optionally recursively.",
+ ShortDesc: "lists matching packages on the server",
+ LongDesc: "Queries the backend for a list of packages in the given path to " +
+ "which the user has access, optionally recursively.",
CommandRun: func() subcommands.CommandRun {
c := &listPackagesRun{}
c.registerBaseFlags()
@@ -1047,7 +1072,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
},
}
@@ -1315,6 +1340,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"),
« no previous file with comments | « go/src/infra/tools/cipd/apps/cipd/friendly.go ('k') | go/src/infra/tools/cipd/local/deployer.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698