forked from mirror/cobra
Add support for --version flag (#584)
This commit is contained in:
parent
1be1d2841c
commit
b1ec2ce1ad
65
command.go
65
command.go
|
@ -75,6 +75,11 @@ type Command struct {
|
||||||
// group commands.
|
// group commands.
|
||||||
Annotations map[string]string
|
Annotations map[string]string
|
||||||
|
|
||||||
|
// Version defines the version for this command. If this value is non-empty and the command does not
|
||||||
|
// define a "version" flag, a "version" boolean flag will be added to the command and, if specified,
|
||||||
|
// will print content of the "Version" variable.
|
||||||
|
Version string
|
||||||
|
|
||||||
// The *Run functions are executed in the following order:
|
// The *Run functions are executed in the following order:
|
||||||
// * PersistentPreRun()
|
// * PersistentPreRun()
|
||||||
// * PreRun()
|
// * PreRun()
|
||||||
|
@ -177,6 +182,8 @@ type Command struct {
|
||||||
// helpCommand is command with usage 'help'. If it's not defined by user,
|
// helpCommand is command with usage 'help'. If it's not defined by user,
|
||||||
// cobra uses default help command.
|
// cobra uses default help command.
|
||||||
helpCommand *Command
|
helpCommand *Command
|
||||||
|
// versionTemplate is the version template defined by user.
|
||||||
|
versionTemplate string
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetArgs sets arguments for the command. It is set to os.Args[1:] by default, if desired, can be overridden
|
// SetArgs sets arguments for the command. It is set to os.Args[1:] by default, if desired, can be overridden
|
||||||
|
@ -222,6 +229,11 @@ func (c *Command) SetHelpTemplate(s string) {
|
||||||
c.helpTemplate = s
|
c.helpTemplate = s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetVersionTemplate sets version template to be used. Application can use it to set custom template.
|
||||||
|
func (c *Command) SetVersionTemplate(s string) {
|
||||||
|
c.versionTemplate = s
|
||||||
|
}
|
||||||
|
|
||||||
// SetGlobalNormalizationFunc sets a normalization function to all flag sets and also to child commands.
|
// SetGlobalNormalizationFunc sets a normalization function to all flag sets and also to child commands.
|
||||||
// The user should not have a cyclic dependency on commands.
|
// The user should not have a cyclic dependency on commands.
|
||||||
func (c *Command) SetGlobalNormalizationFunc(n func(f *flag.FlagSet, name string) flag.NormalizedName) {
|
func (c *Command) SetGlobalNormalizationFunc(n func(f *flag.FlagSet, name string) flag.NormalizedName) {
|
||||||
|
@ -411,6 +423,19 @@ func (c *Command) HelpTemplate() string {
|
||||||
{{end}}{{if or .Runnable .HasSubCommands}}{{.UsageString}}{{end}}`
|
{{end}}{{if or .Runnable .HasSubCommands}}{{.UsageString}}{{end}}`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// VersionTemplate return version template for the command.
|
||||||
|
func (c *Command) VersionTemplate() string {
|
||||||
|
if c.versionTemplate != "" {
|
||||||
|
return c.versionTemplate
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.HasParent() {
|
||||||
|
return c.parent.VersionTemplate()
|
||||||
|
}
|
||||||
|
return `{{with .Name}}{{printf "%s " .}}{{end}}{{printf "version %s" .Version}}
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
func hasNoOptDefVal(name string, fs *flag.FlagSet) bool {
|
func hasNoOptDefVal(name string, fs *flag.FlagSet) bool {
|
||||||
flag := fs.Lookup(name)
|
flag := fs.Lookup(name)
|
||||||
if flag == nil {
|
if flag == nil {
|
||||||
|
@ -640,9 +665,10 @@ func (c *Command) execute(a []string) (err error) {
|
||||||
c.Printf("Command %q is deprecated, %s\n", c.Name(), c.Deprecated)
|
c.Printf("Command %q is deprecated, %s\n", c.Name(), c.Deprecated)
|
||||||
}
|
}
|
||||||
|
|
||||||
// initialize help flag as the last point possible to allow for user
|
// initialize help and version flag at the last point possible to allow for user
|
||||||
// overriding
|
// overriding
|
||||||
c.InitDefaultHelpFlag()
|
c.InitDefaultHelpFlag()
|
||||||
|
c.InitDefaultVersionFlag()
|
||||||
|
|
||||||
err = c.ParseFlags(a)
|
err = c.ParseFlags(a)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -663,6 +689,22 @@ func (c *Command) execute(a []string) (err error) {
|
||||||
return flag.ErrHelp
|
return flag.ErrHelp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// for back-compat, only add version flag behavior if version is defined
|
||||||
|
if c.Version != "" {
|
||||||
|
versionVal, err := c.Flags().GetBool("version")
|
||||||
|
if err != nil {
|
||||||
|
c.Println("\"version\" flag declared as non-bool. Please correct your code")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if versionVal {
|
||||||
|
err := tmpl(c.OutOrStdout(), c.VersionTemplate(), c)
|
||||||
|
if err != nil {
|
||||||
|
c.Println(err)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
c.preRun()
|
c.preRun()
|
||||||
|
|
||||||
argWoFlags := c.Flags().Args()
|
argWoFlags := c.Flags().Args()
|
||||||
|
@ -848,6 +890,27 @@ func (c *Command) InitDefaultHelpFlag() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InitDefaultVersionFlag adds default version flag to c.
|
||||||
|
// It is called automatically by executing the c.
|
||||||
|
// If c already has a version flag, it will do nothing.
|
||||||
|
// If c.Version is empty, it will do nothing.
|
||||||
|
func (c *Command) InitDefaultVersionFlag() {
|
||||||
|
if c.Version == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.mergePersistentFlags()
|
||||||
|
if c.Flags().Lookup("version") == nil {
|
||||||
|
usage := "version for "
|
||||||
|
if c.Name() == "" {
|
||||||
|
usage += "this command"
|
||||||
|
} else {
|
||||||
|
usage += c.Name()
|
||||||
|
}
|
||||||
|
c.Flags().Bool("version", false, usage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// InitDefaultHelpCmd adds default help command to c.
|
// InitDefaultHelpCmd adds default help command to c.
|
||||||
// It is called automatically by executing the c or by calling help and usage.
|
// It is called automatically by executing the c or by calling help and usage.
|
||||||
// If c already has help command or c has no subcommands, it will do nothing.
|
// If c already has help command or c has no subcommands, it will do nothing.
|
||||||
|
|
|
@ -843,6 +843,63 @@ func TestHelpExecutedOnNonRunnableChild(t *testing.T) {
|
||||||
checkStringContains(t, output, childCmd.Long)
|
checkStringContains(t, output, childCmd.Long)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestVersionFlagExecuted(t *testing.T) {
|
||||||
|
rootCmd := &Command{Use: "root", Version: "1.0.0", Run: emptyRun}
|
||||||
|
|
||||||
|
output, err := executeCommand(rootCmd, "--version", "arg1")
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
checkStringContains(t, output, "root version 1.0.0")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVersionTemplate(t *testing.T) {
|
||||||
|
rootCmd := &Command{Use: "root", Version: "1.0.0", Run: emptyRun}
|
||||||
|
rootCmd.SetVersionTemplate(`customized version: {{.Version}}`)
|
||||||
|
|
||||||
|
output, err := executeCommand(rootCmd, "--version", "arg1")
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
checkStringContains(t, output, "customized version: 1.0.0")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVersionFlagExecutedOnSubcommand(t *testing.T) {
|
||||||
|
rootCmd := &Command{Use: "root", Version: "1.0.0", Run: emptyRun}
|
||||||
|
rootCmd.AddCommand(&Command{Use: "sub", Run: emptyRun})
|
||||||
|
|
||||||
|
output, err := executeCommand(rootCmd, "--version", "sub")
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
checkStringContains(t, output, "root version 1.0.0")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVersionFlagOnlyAddedToRoot(t *testing.T) {
|
||||||
|
rootCmd := &Command{Use: "root", Version: "1.0.0", Run: emptyRun}
|
||||||
|
rootCmd.AddCommand(&Command{Use: "sub", Run: emptyRun})
|
||||||
|
|
||||||
|
_, err := executeCommand(rootCmd, "sub", "--version")
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("Expected error")
|
||||||
|
}
|
||||||
|
|
||||||
|
checkStringContains(t, err.Error(), "unknown flag: --version")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVersionFlagOnlyExistsIfVersionNonEmpty(t *testing.T) {
|
||||||
|
rootCmd := &Command{Use: "root", Run: emptyRun}
|
||||||
|
|
||||||
|
_, err := executeCommand(rootCmd, "--version")
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("Expected error")
|
||||||
|
}
|
||||||
|
checkStringContains(t, err.Error(), "unknown flag: --version")
|
||||||
|
}
|
||||||
|
|
||||||
func TestUsageIsNotPrintedTwice(t *testing.T) {
|
func TestUsageIsNotPrintedTwice(t *testing.T) {
|
||||||
var cmd = &Command{Use: "root"}
|
var cmd = &Command{Use: "root"}
|
||||||
var sub = &Command{Use: "sub"}
|
var sub = &Command{Use: "sub"}
|
||||||
|
|
Loading…
Reference in New Issue