diff --git a/command.go b/command.go index 6535690..82e1e2e 100644 --- a/command.go +++ b/command.go @@ -16,6 +16,7 @@ var ( ErrNoRunner = errors.New("gommand: command has no run function") ErrNoSubcommand = errors.New("gommand: must specify a subcommand") errShowHelp = errors.New("show help") + errShowVersion = errors.New("show version") ) // Command represents a command line command @@ -66,6 +67,15 @@ type Command struct { // Description is the longer description of the command printed out by the help text Description string + // Version is the value that will be printed when `--version` is passed to the command. + // When retrieving the command version, the call tree is traversed backwards until a Command + // is reached that has a non-zero value for the version. This means that it is possible + // to version individual branches of the call tree, though this is not recommended. It is + // intended to be set at the root of the tree, ideally through a package level var that can + // be set using ldflags at build time + // ie: go build -ldflags="cmd.Version=1.1.0" + Version string + // ArgValidator is an ArgValidator to be called on the args of the function being executed. This is called before any of // the functions for this command are called. // If this is not defined ArgsNone is used. @@ -158,6 +168,15 @@ func (c *Command) ExecuteContext(ctx context.Context) error { cmdCtx.cmd.help() return nil } + if errors.Is(err, errShowVersion) { + v := c._version() + if v == "" { + v = "N/A" + } + fmt.Println(v) + return nil + } + if mErr := errors.Join(err, c.err); mErr != nil { if !cmdCtx.silenceHelp { cmdCtx.cmd.help() @@ -185,6 +204,17 @@ func (c *Command) name() (name string) { return } +func (c *Command) _version() string { + _c := c + for _c.Version == "" { + if _c.parent == nil { + break + } + _c = _c.parent + } + return _c.Version +} + func (c *Command) help() { if c.Description != "" { fmt.Println(c.Description) @@ -194,6 +224,11 @@ func (c *Command) help() { fmt.Println() } + if v := c._version(); v != "" { + fmt.Println("Version:", v) + fmt.Println() + } + fmt.Println("Usage:") usage := []string{c.Name} for parent := c.parent; parent != nil; parent = parent.parent { @@ -352,6 +387,9 @@ func (c *Command) execute(ctx *Context) error { if token.Name == "help" { return errShowHelp } + if token.Name == "version" { + return errShowVersion + } f = fs.FromName(token.Name) } diff --git a/examples/simple/main.go b/examples/simple/main.go index 510e275..91bcbda 100644 --- a/examples/simple/main.go +++ b/examples/simple/main.go @@ -12,6 +12,7 @@ var rootCmd = &gommand.Command{ Name: "sum", Usage: "sum [...n]", Description: "sum all provided numbers", + Version: "1.0.0", ArgValidator: gommand.ArgsEvery(gommand.ArgsMin(1), ints), Run: func(ctx *gommand.Context) error { var total int diff --git a/examples/subcommands/main.go b/examples/subcommands/main.go index edd5b58..8b12590 100644 --- a/examples/subcommands/main.go +++ b/examples/subcommands/main.go @@ -13,6 +13,7 @@ var ( rootCmd = &gommand.Command{ Name: "math", Usage: "a collection of math commands", + Version: "1.0.0", SilenceError: true, PersistentFlagSet: flags.NewFlagSet().AddFlags( flags.StringFlag("host", "", "host address"),