Refactor TakesArgs to use an interface for arg validation.
Fix some typos in README and comments. Move arg validation to after flag validation so that the help flag is run first. Pass the same args to ValidateArgs as the Run methods receive. Update README. Signed-off-by: Daniel Nephin <dnephin@gmail.com>
This commit is contained in:
committed by
Albert Nigmatzianov
parent
d89c499964
commit
f20b4e9c32
67
command.go
67
command.go
@ -27,15 +27,6 @@ import (
|
||||
flag "github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
type Args int
|
||||
|
||||
const (
|
||||
Legacy Args = iota
|
||||
Arbitrary
|
||||
ValidOnly
|
||||
None
|
||||
)
|
||||
|
||||
// Command is just that, a command for your application.
|
||||
// E.g. 'go run ...' - 'run' is the command. Cobra requires
|
||||
// you to define the usage and description as part of your command
|
||||
@ -68,8 +59,8 @@ type Command struct {
|
||||
// but accepted if entered manually.
|
||||
ArgAliases []string
|
||||
|
||||
// Does this command take arbitrary arguments
|
||||
TakesArgs Args
|
||||
// Expected arguments
|
||||
Args PositionalArgs
|
||||
// BashCompletionFunction is custom functions used by the bash autocompletion generator.
|
||||
BashCompletionFunction string
|
||||
|
||||
@ -483,15 +474,6 @@ func argsMinusFirstX(args []string, x string) []string {
|
||||
return args
|
||||
}
|
||||
|
||||
func stringInSlice(a string, list []string) bool {
|
||||
for _, b := range list {
|
||||
if b == a {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Find the target command given the args and command tree
|
||||
// Meant to be run on the highest node. Only searches down.
|
||||
func (c *Command) Find(args []string) (*Command, []string, error) {
|
||||
@ -533,39 +515,13 @@ func (c *Command) Find(args []string) (*Command, []string, error) {
|
||||
}
|
||||
|
||||
commandFound, a := innerfind(c, args)
|
||||
argsWOflags := stripFlags(a, commandFound)
|
||||
|
||||
// "Legacy" has some 'odd' characteristics.
|
||||
// - root commands with no subcommands can take arbitrary arguments
|
||||
// - root commands with subcommands will do subcommand validity checking
|
||||
// - subcommands will always accept arbitrary arguments
|
||||
if commandFound.TakesArgs == Legacy {
|
||||
// no subcommand, always take args
|
||||
if !commandFound.HasSubCommands() {
|
||||
return commandFound, a, nil
|
||||
}
|
||||
// root command with subcommands, do subcommand checking
|
||||
if commandFound == c && len(argsWOflags) > 0 {
|
||||
return commandFound, a, fmt.Errorf("unknown command %q for %q%s", argsWOflags[0], commandFound.CommandPath(), c.findSuggestions(argsWOflags))
|
||||
}
|
||||
return commandFound, a, nil
|
||||
}
|
||||
|
||||
if commandFound.TakesArgs == None && len(argsWOflags) > 0 {
|
||||
return commandFound, a, fmt.Errorf("unknown command %q for %q", argsWOflags[0], commandFound.CommandPath())
|
||||
}
|
||||
|
||||
if commandFound.TakesArgs == ValidOnly && len(commandFound.ValidArgs) > 0 {
|
||||
for _, v := range argsWOflags {
|
||||
if !stringInSlice(v, commandFound.ValidArgs) {
|
||||
return commandFound, a, fmt.Errorf("invalid argument %q for %q%s", v, commandFound.CommandPath(), c.findSuggestions(argsWOflags))
|
||||
}
|
||||
}
|
||||
if commandFound.Args == nil {
|
||||
return commandFound, a, legacyArgs(commandFound, stripFlags(a, commandFound))
|
||||
}
|
||||
return commandFound, a, nil
|
||||
}
|
||||
|
||||
func (c *Command) findSuggestions(argsWOflags []string) string {
|
||||
func (c *Command) findSuggestions(arg string) string {
|
||||
if c.DisableSuggestions {
|
||||
return ""
|
||||
}
|
||||
@ -573,7 +529,7 @@ func (c *Command) findSuggestions(argsWOflags []string) string {
|
||||
c.SuggestionsMinimumDistance = 2
|
||||
}
|
||||
suggestionsString := ""
|
||||
if suggestions := c.SuggestionsFor(argsWOflags[0]); len(suggestions) > 0 {
|
||||
if suggestions := c.SuggestionsFor(arg); len(suggestions) > 0 {
|
||||
suggestionsString += "\n\nDid you mean this?\n"
|
||||
for _, s := range suggestions {
|
||||
suggestionsString += fmt.Sprintf("\t%v\n", s)
|
||||
@ -666,6 +622,10 @@ func (c *Command) execute(a []string) (err error) {
|
||||
argWoFlags = a
|
||||
}
|
||||
|
||||
if err := c.ValidateArgs(argWoFlags); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for p := c; p != nil; p = p.Parent() {
|
||||
if p.PersistentPreRunE != nil {
|
||||
if err := p.PersistentPreRunE(c, argWoFlags); err != nil {
|
||||
@ -789,6 +749,13 @@ func (c *Command) ExecuteC() (cmd *Command, err error) {
|
||||
return cmd, err
|
||||
}
|
||||
|
||||
func (c *Command) ValidateArgs(args []string) error {
|
||||
if c.Args == nil {
|
||||
return nil
|
||||
}
|
||||
return c.Args(c, args)
|
||||
}
|
||||
|
||||
// InitDefaultHelpFlag adds default help flag to c.
|
||||
// It is called automatically by executing the c or by calling help and usage.
|
||||
// If c already has help flag, it will do nothing.
|
||||
|
Reference in New Issue
Block a user