mirror of
https://github.com/spf13/cobra
synced 2024-11-24 14:47:12 +00:00
Merge master, and adapt flag completion getters
This commit is contained in:
parent
53fb4ebbd1
commit
4d3a6e1d56
5 changed files with 94 additions and 5 deletions
5
.github/workflows/test.yml
vendored
5
.github/workflows/test.yml
vendored
|
@ -43,13 +43,13 @@ jobs:
|
||||||
|
|
||||||
- uses: actions/setup-go@v3
|
- uses: actions/setup-go@v3
|
||||||
with:
|
with:
|
||||||
go-version: '^1.20'
|
go-version: '^1.21'
|
||||||
check-latest: true
|
check-latest: true
|
||||||
cache: true
|
cache: true
|
||||||
|
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- uses: golangci/golangci-lint-action@v3.6.0
|
- uses: golangci/golangci-lint-action@v3.7.0
|
||||||
with:
|
with:
|
||||||
version: latest
|
version: latest
|
||||||
args: --verbose
|
args: --verbose
|
||||||
|
@ -67,6 +67,7 @@ jobs:
|
||||||
- 18
|
- 18
|
||||||
- 19
|
- 19
|
||||||
- 20
|
- 20
|
||||||
|
- 21
|
||||||
name: '${{ matrix.platform }} | 1.${{ matrix.go }}.x'
|
name: '${{ matrix.platform }} | 1.${{ matrix.go }}.x'
|
||||||
runs-on: ${{ matrix.platform }}-latest
|
runs-on: ${{ matrix.platform }}-latest
|
||||||
steps:
|
steps:
|
||||||
|
|
28
command.go
28
command.go
|
@ -189,6 +189,9 @@ type Command struct {
|
||||||
// versionTemplate is the version template defined by user.
|
// versionTemplate is the version template defined by user.
|
||||||
versionTemplate string
|
versionTemplate string
|
||||||
|
|
||||||
|
// errPrefix is the error message prefix defined by user.
|
||||||
|
errPrefix string
|
||||||
|
|
||||||
// inReader is a reader defined by the user that replaces stdin
|
// inReader is a reader defined by the user that replaces stdin
|
||||||
inReader io.Reader
|
inReader io.Reader
|
||||||
// outWriter is a writer defined by the user that replaces stdout
|
// outWriter is a writer defined by the user that replaces stdout
|
||||||
|
@ -354,6 +357,11 @@ func (c *Command) SetVersionTemplate(s string) {
|
||||||
c.versionTemplate = s
|
c.versionTemplate = s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetErrPrefix sets error message prefix to be used. Application can use it to set custom prefix.
|
||||||
|
func (c *Command) SetErrPrefix(s string) {
|
||||||
|
c.errPrefix = 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) {
|
||||||
|
@ -603,6 +611,18 @@ func (c *Command) VersionTemplate() string {
|
||||||
`
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ErrPrefix return error message prefix for the command
|
||||||
|
func (c *Command) ErrPrefix() string {
|
||||||
|
if c.errPrefix != "" {
|
||||||
|
return c.errPrefix
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.HasParent() {
|
||||||
|
return c.parent.ErrPrefix()
|
||||||
|
}
|
||||||
|
return "Error:"
|
||||||
|
}
|
||||||
|
|
||||||
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 {
|
||||||
|
@ -760,7 +780,9 @@ func (c *Command) findNext(next string) *Command {
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(matches) == 1 {
|
if len(matches) == 1 {
|
||||||
return matches[0]
|
// Temporarily disable gosec G602, which produces a false positive.
|
||||||
|
// See https://github.com/securego/gosec/issues/1005.
|
||||||
|
return matches[0] // #nosec G602
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -1056,7 +1078,7 @@ func (c *Command) ExecuteC() (cmd *Command, err error) {
|
||||||
c = cmd
|
c = cmd
|
||||||
}
|
}
|
||||||
if !c.SilenceErrors {
|
if !c.SilenceErrors {
|
||||||
c.PrintErrln("Error:", err.Error())
|
c.PrintErrln(c.ErrPrefix(), err.Error())
|
||||||
c.PrintErrf("Run '%v --help' for usage.\n", c.CommandPath())
|
c.PrintErrf("Run '%v --help' for usage.\n", c.CommandPath())
|
||||||
}
|
}
|
||||||
return c, err
|
return c, err
|
||||||
|
@ -1085,7 +1107,7 @@ func (c *Command) ExecuteC() (cmd *Command, err error) {
|
||||||
// If root command has SilenceErrors flagged,
|
// If root command has SilenceErrors flagged,
|
||||||
// all subcommands should respect it
|
// all subcommands should respect it
|
||||||
if !cmd.SilenceErrors && !c.SilenceErrors {
|
if !cmd.SilenceErrors && !c.SilenceErrors {
|
||||||
c.PrintErrln("Error:", err.Error())
|
c.PrintErrln(cmd.ErrPrefix(), err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
// If root command has SilenceUsage flagged,
|
// If root command has SilenceUsage flagged,
|
||||||
|
|
|
@ -1099,6 +1099,39 @@ func TestShorthandVersionTemplate(t *testing.T) {
|
||||||
checkStringContains(t, output, "customized version: 1.0.0")
|
checkStringContains(t, output, "customized version: 1.0.0")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRootErrPrefixExecutedOnSubcommand(t *testing.T) {
|
||||||
|
rootCmd := &Command{Use: "root", Run: emptyRun}
|
||||||
|
rootCmd.SetErrPrefix("root error prefix:")
|
||||||
|
rootCmd.AddCommand(&Command{Use: "sub", Run: emptyRun})
|
||||||
|
|
||||||
|
output, err := executeCommand(rootCmd, "sub", "--unknown-flag")
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("Expected error")
|
||||||
|
}
|
||||||
|
|
||||||
|
checkStringContains(t, output, "root error prefix: unknown flag: --unknown-flag")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRootAndSubErrPrefix(t *testing.T) {
|
||||||
|
rootCmd := &Command{Use: "root", Run: emptyRun}
|
||||||
|
subCmd := &Command{Use: "sub", Run: emptyRun}
|
||||||
|
rootCmd.AddCommand(subCmd)
|
||||||
|
rootCmd.SetErrPrefix("root error prefix:")
|
||||||
|
subCmd.SetErrPrefix("sub error prefix:")
|
||||||
|
|
||||||
|
if output, err := executeCommand(rootCmd, "--unknown-root-flag"); err == nil {
|
||||||
|
t.Errorf("Expected error")
|
||||||
|
} else {
|
||||||
|
checkStringContains(t, output, "root error prefix: unknown flag: --unknown-root-flag")
|
||||||
|
}
|
||||||
|
|
||||||
|
if output, err := executeCommand(rootCmd, "sub", "--unknown-sub-flag"); err == nil {
|
||||||
|
t.Errorf("Expected error")
|
||||||
|
} else {
|
||||||
|
checkStringContains(t, output, "sub error prefix: unknown flag: --unknown-sub-flag")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestVersionFlagExecutedOnSubcommand(t *testing.T) {
|
func TestVersionFlagExecutedOnSubcommand(t *testing.T) {
|
||||||
rootCmd := &Command{Use: "root", Version: "1.0.0"}
|
rootCmd := &Command{Use: "root", Version: "1.0.0"}
|
||||||
rootCmd.AddCommand(&Command{Use: "sub", Run: emptyRun})
|
rootCmd.AddCommand(&Command{Use: "sub", Run: emptyRun})
|
||||||
|
|
|
@ -150,6 +150,33 @@ func (c *Command) RegisterFlagCompletionFunc(flagName string, f func(cmd *Comman
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetFlagCompletion returns the completion function for the given flag, if available.
|
||||||
|
func (c *Command) GetFlagCompletion(flag *pflag.Flag) (func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective), bool) {
|
||||||
|
c.initializeCompletionStorage()
|
||||||
|
|
||||||
|
c.flagCompletionMutex.RLock()
|
||||||
|
defer c.flagCompletionMutex.RUnlock()
|
||||||
|
|
||||||
|
completionFunc, exists := c.flagCompletionFunctions[flag]
|
||||||
|
|
||||||
|
if completionFunc != nil && exists {
|
||||||
|
return completionFunc, exists
|
||||||
|
}
|
||||||
|
|
||||||
|
// If not found on the current, walk up the command tree.
|
||||||
|
return c.Parent().GetFlagCompletion(flag)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetFlagCompletionByName returns the completion function for the given flag in the command by name, if available.
|
||||||
|
func (c *Command) GetFlagCompletionByName(flagName string) (func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective), bool) {
|
||||||
|
flag := c.Flags().Lookup(flagName)
|
||||||
|
if flag == nil {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.GetFlagCompletion(flag)
|
||||||
|
}
|
||||||
|
|
||||||
// initializeCompletionStorage is (and should be) called in all
|
// initializeCompletionStorage is (and should be) called in all
|
||||||
// functions that make use of the command's flag completion functions.
|
// functions that make use of the command's flag completion functions.
|
||||||
func (c *Command) initializeCompletionStorage() {
|
func (c *Command) initializeCompletionStorage() {
|
||||||
|
|
|
@ -596,6 +596,12 @@ Running an application with the '--version' flag will print the version to stdou
|
||||||
the version template. The template can be customized using the
|
the version template. The template can be customized using the
|
||||||
`cmd.SetVersionTemplate(s string)` function.
|
`cmd.SetVersionTemplate(s string)` function.
|
||||||
|
|
||||||
|
## Error Message Prefix
|
||||||
|
|
||||||
|
Cobra prints an error message when receiving a non-nil error value.
|
||||||
|
The default error message is `Error: <error contents>`.
|
||||||
|
The Prefix, `Error:` can be customized using the `cmd.SetErrPrefix(s string)` function.
|
||||||
|
|
||||||
## PreRun and PostRun Hooks
|
## PreRun and PostRun Hooks
|
||||||
|
|
||||||
It is possible to run functions before or after the main `Run` function of your command. The `PersistentPreRun` and `PreRun` functions will be executed before `Run`. `PersistentPostRun` and `PostRun` will be executed after `Run`. The `Persistent*Run` functions will be inherited by children if they do not declare their own. These functions are run in the following order:
|
It is possible to run functions before or after the main `Run` function of your command. The `PersistentPreRun` and `PreRun` functions will be executed before `Run`. `PersistentPostRun` and `PostRun` will be executed after `Run`. The `Persistent*Run` functions will be inherited by children if they do not declare their own. These functions are run in the following order:
|
||||||
|
|
Loading…
Reference in a new issue