summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/spf13/cobra/command.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/spf13/cobra/command.go')
-rw-r--r--vendor/github.com/spf13/cobra/command.go187
1 files changed, 144 insertions, 43 deletions
diff --git a/vendor/github.com/spf13/cobra/command.go b/vendor/github.com/spf13/cobra/command.go
index 185e45263..6cb642647 100644
--- a/vendor/github.com/spf13/cobra/command.go
+++ b/vendor/github.com/spf13/cobra/command.go
@@ -125,8 +125,9 @@ type Command struct {
// Must be > 0.
SuggestionsMinimumDistance int
- // name is the command name, usually the executable's name.
- name string
+ // TraverseChildren parses flags on all parents before executing child command.
+ TraverseChildren bool
+
// commands is the list of commands supported by this program.
commands []*Command
// parent is a parent command for this command.
@@ -475,13 +476,14 @@ func argsMinusFirstX(args []string, x string) []string {
return args
}
+func isFlagArg(arg string) bool {
+ return ((len(arg) >= 3 && arg[1] == '-') ||
+ (len(arg) >= 2 && arg[0] == '-' && arg[1] != '-'))
+}
+
// 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) {
- if c == nil {
- return nil, nil, fmt.Errorf("Called find() on a nil Command")
- }
-
var innerfind func(*Command, []string) (*Command, []string)
innerfind = func(c *Command, innerArgs []string) (*Command, []string) {
@@ -490,28 +492,11 @@ func (c *Command) Find(args []string) (*Command, []string, error) {
return c, innerArgs
}
nextSubCmd := argsWOflags[0]
- matches := make([]*Command, 0)
- for _, cmd := range c.commands {
- if cmd.Name() == nextSubCmd || cmd.HasAlias(nextSubCmd) { // exact name or alias match
- return innerfind(cmd, argsMinusFirstX(innerArgs, nextSubCmd))
- }
- if EnablePrefixMatching {
- if strings.HasPrefix(cmd.Name(), nextSubCmd) { // prefix match
- matches = append(matches, cmd)
- }
- for _, x := range cmd.Aliases {
- if strings.HasPrefix(x, nextSubCmd) {
- matches = append(matches, cmd)
- }
- }
- }
- }
- // only accept a single prefix match - multiple matches would be ambiguous
- if len(matches) == 1 {
- return innerfind(matches[0], argsMinusFirstX(innerArgs, argsWOflags[0]))
+ cmd := c.findNext(nextSubCmd)
+ if cmd != nil {
+ return innerfind(cmd, argsMinusFirstX(innerArgs, nextSubCmd))
}
-
return c, innerArgs
}
@@ -539,6 +524,66 @@ func (c *Command) findSuggestions(arg string) string {
return suggestionsString
}
+func (c *Command) findNext(next string) *Command {
+ matches := make([]*Command, 0)
+ for _, cmd := range c.commands {
+ if cmd.Name() == next || cmd.HasAlias(next) {
+ return cmd
+ }
+ if EnablePrefixMatching && cmd.hasNameOrAliasPrefix(next) {
+ matches = append(matches, cmd)
+ }
+ }
+
+ if len(matches) == 1 {
+ return matches[0]
+ }
+ return nil
+}
+
+// Traverse the command tree to find the command, and parse args for
+// each parent.
+func (c *Command) Traverse(args []string) (*Command, []string, error) {
+ flags := []string{}
+ inFlag := false
+
+ for i, arg := range args {
+ switch {
+ // A long flag with a space separated value
+ case strings.HasPrefix(arg, "--") && !strings.Contains(arg, "="):
+ // TODO: this isn't quite right, we should really check ahead for 'true' or 'false'
+ inFlag = !hasNoOptDefVal(arg[2:], c.Flags())
+ flags = append(flags, arg)
+ continue
+ // A short flag with a space separated value
+ case strings.HasPrefix(arg, "-") && !strings.Contains(arg, "=") && len(arg) == 2 && !shortHasNoOptDefVal(arg[1:], c.Flags()):
+ inFlag = true
+ flags = append(flags, arg)
+ continue
+ // The value for a flag
+ case inFlag:
+ inFlag = false
+ flags = append(flags, arg)
+ continue
+ // A flag without a value, or with an `=` separated value
+ case isFlagArg(arg):
+ flags = append(flags, arg)
+ continue
+ }
+
+ cmd := c.findNext(arg)
+ if cmd == nil {
+ return c, args, nil
+ }
+
+ if err := c.ParseFlags(flags); err != nil {
+ return nil, args, err
+ }
+ return cmd.Traverse(args[i+1:])
+ }
+ return c, args, nil
+}
+
// SuggestionsFor provides suggestions for the typedName.
func (c *Command) SuggestionsFor(typedName string) []string {
suggestions := []string{}
@@ -576,10 +621,8 @@ func (c *Command) Root() *Command {
return c
}
-// ArgsLenAtDash will return the length of f.Args at the moment when a -- was
-// found during arg parsing. This allows your program to know which args were
-// before the -- and which came after. (Description from
-// https://godoc.org/github.com/spf13/pflag#FlagSet.ArgsLenAtDash).
+// ArgsLenAtDash will return the length of c.Flags().Args at the moment
+// when a -- was found during args parsing.
func (c *Command) ArgsLenAtDash() int {
return c.Flags().ArgsLenAtDash()
}
@@ -646,6 +689,9 @@ func (c *Command) execute(a []string) (err error) {
c.PreRun(c, argWoFlags)
}
+ if err := c.validateRequiredFlags(); err != nil {
+ return err
+ }
if c.RunE != nil {
if err := c.RunE(c, argWoFlags); err != nil {
return err
@@ -714,7 +760,12 @@ func (c *Command) ExecuteC() (cmd *Command, err error) {
args = c.args
}
- cmd, flags, err := c.Find(args)
+ var flags []string
+ if c.TraverseChildren {
+ cmd, flags, err = c.Traverse(args)
+ } else {
+ cmd, flags, err = c.Find(args)
+ }
if err != nil {
// If found parse to a subcommand and then failed, talk about the subcommand
if cmd != nil {
@@ -726,6 +777,7 @@ func (c *Command) ExecuteC() (cmd *Command, err error) {
}
return c, err
}
+
err = cmd.execute(flags)
if err != nil {
// Always show help if requested, even if SilenceErrors is in
@@ -757,6 +809,25 @@ func (c *Command) ValidateArgs(args []string) error {
return c.Args(c, args)
}
+func (c *Command) validateRequiredFlags() error {
+ flags := c.Flags()
+ missingFlagNames := []string{}
+ flags.VisitAll(func(pflag *flag.Flag) {
+ requiredAnnotation, found := pflag.Annotations[BashCompOneRequiredFlag]
+ if !found {
+ return
+ }
+ if (requiredAnnotation[0] == "true") && !pflag.Changed {
+ missingFlagNames = append(missingFlagNames, pflag.Name)
+ }
+ })
+
+ if len(missingFlagNames) > 0 {
+ return fmt.Errorf(`Required flag(s) "%s" have/has not been set`, strings.Join(missingFlagNames, `", "`))
+ }
+ return nil
+}
+
// 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.
@@ -804,8 +875,9 @@ Simply type ` + c.Name() + ` help [path to command] for full details.`,
c.AddCommand(c.helpCommand)
}
-// ResetCommands used for testing.
+// ResetCommands delete parent, subcommand and help command from c.
func (c *Command) ResetCommands() {
+ c.parent = nil
c.commands = nil
c.helpCommand = nil
c.parentsPflags = nil
@@ -971,15 +1043,12 @@ func (c *Command) DebugFlags() {
// Name returns the command's name: the first word in the use line.
func (c *Command) Name() string {
- if c.name == "" {
- name := c.Use
- i := strings.Index(name, " ")
- if i >= 0 {
- name = name[:i]
- }
- c.name = name
+ name := c.Use
+ i := strings.Index(name, " ")
+ if i >= 0 {
+ name = name[:i]
}
- return c.name
+ return name
}
// HasAlias determines if a given string is an alias of the command.
@@ -992,7 +1061,21 @@ func (c *Command) HasAlias(s string) bool {
return false
}
-// NameAndAliases returns string containing name and all aliases
+// hasNameOrAliasPrefix returns true if the Name or any of aliases start
+// with prefix
+func (c *Command) hasNameOrAliasPrefix(prefix string) bool {
+ if strings.HasPrefix(c.Name(), prefix) {
+ return true
+ }
+ for _, alias := range c.Aliases {
+ if strings.HasPrefix(alias, prefix) {
+ return true
+ }
+ }
+ return false
+}
+
+// NameAndAliases returns a list of the command name and all aliases
func (c *Command) NameAndAliases() string {
return strings.Join(append([]string{c.Name()}, c.Aliases...), ", ")
}
@@ -1078,7 +1161,7 @@ func (c *Command) HasAvailableSubCommands() bool {
}
}
- // the command either has no sub comamnds, or no available (non deprecated/help/hidden)
+ // the command either has no sub commands, or no available (non deprecated/help/hidden)
// sub commands
return false
}
@@ -1132,6 +1215,9 @@ func (c *Command) LocalFlags() *flag.FlagSet {
c.lflags.SetOutput(c.flagErrorBuf)
}
c.lflags.SortFlags = c.Flags().SortFlags
+ if c.globNormFunc != nil {
+ c.lflags.SetNormalizeFunc(c.globNormFunc)
+ }
addToLocal := func(f *flag.Flag) {
if c.lflags.Lookup(f.Name) == nil && c.parentsPflags.Lookup(f.Name) == nil {
@@ -1156,6 +1242,10 @@ func (c *Command) InheritedFlags() *flag.FlagSet {
}
local := c.LocalFlags()
+ if c.globNormFunc != nil {
+ c.iflags.SetNormalizeFunc(c.globNormFunc)
+ }
+
c.parentsPflags.VisitAll(func(f *flag.Flag) {
if c.iflags.Lookup(f.Name) == nil && local.Lookup(f.Name) == nil {
c.iflags.AddFlag(f)
@@ -1181,7 +1271,7 @@ func (c *Command) PersistentFlags() *flag.FlagSet {
return c.pflags
}
-// ResetFlags is used in testing.
+// ResetFlags deletes all flags from command.
func (c *Command) ResetFlags() {
c.flagErrorBuf = new(bytes.Buffer)
c.flagErrorBuf.Reset()
@@ -1189,6 +1279,10 @@ func (c *Command) ResetFlags() {
c.flags.SetOutput(c.flagErrorBuf)
c.pflags = flag.NewFlagSet(c.Name(), flag.ContinueOnError)
c.pflags.SetOutput(c.flagErrorBuf)
+
+ c.lflags = nil
+ c.iflags = nil
+ c.parentsPflags = nil
}
// HasFlags checks if the command contains any flags (local plus persistent from the entire structure).
@@ -1264,6 +1358,9 @@ func (c *Command) ParseFlags(args []string) error {
return nil
}
+ if c.flagErrorBuf == nil {
+ c.flagErrorBuf = new(bytes.Buffer)
+ }
beforeErrorBufLen := c.flagErrorBuf.Len()
c.mergePersistentFlags()
err := c.Flags().Parse(args)
@@ -1298,6 +1395,10 @@ func (c *Command) updateParentsPflags() {
c.parentsPflags.SortFlags = false
}
+ if c.globNormFunc != nil {
+ c.parentsPflags.SetNormalizeFunc(c.globNormFunc)
+ }
+
c.Root().PersistentFlags().AddFlagSet(flag.CommandLine)
c.VisitParents(func(parent *Command) {