diff options
Diffstat (limited to 'vendor/github.com/integrii/flaggy/parser.go')
-rw-r--r-- | vendor/github.com/integrii/flaggy/parser.go | 96 |
1 files changed, 90 insertions, 6 deletions
diff --git a/vendor/github.com/integrii/flaggy/parser.go b/vendor/github.com/integrii/flaggy/parser.go index 066393266..41ab76e60 100644 --- a/vendor/github.com/integrii/flaggy/parser.go +++ b/vendor/github.com/integrii/flaggy/parser.go @@ -4,18 +4,20 @@ import ( "errors" "fmt" "os" + "strconv" "text/template" ) -// Parser represents the set of vars and subcommands we are expecting -// from our input args, and the parser than handles them all. +// Parser represents the set of flags and subcommands we are expecting +// from our input arguments. Parser is the top level struct responsible for +// parsing an entire set of subcommands and flags. type Parser struct { Subcommand Version string // the optional version of the parser. ShowHelpWithHFlag bool // display help when -h or --help passed ShowVersionWithVersionFlag bool // display the version when --version passed - ShowHelpOnUnexpected bool // display help when an unexpected flag is passed + ShowHelpOnUnexpected bool // display help when an unexpected flag or subcommand is passed TrailingArguments []string // everything after a -- is placed here HelpTemplate *template.Template // template for Help output trailingArgumentsExtracted bool // indicates that trailing args have been parsed and should not be appended again @@ -46,8 +48,89 @@ func (p *Parser) ParseArgs(args []string) error { return errors.New("Parser.Parse() called twice on parser with name: " + " " + p.Name + " " + p.ShortName) } p.parsed = true - // debugPrint("Kicking off parsing with args:", args) - return p.parse(p, args, 0) + + debugPrint("Kicking off parsing with args:", args) + err := p.parse(p, args, 0) + if err != nil { + return err + } + + // if we are set to crash on unexpected args, look for those here TODO + if p.ShowHelpOnUnexpected { + parsedValues := p.findAllParsedValues() + debugPrint("parsedValues:", parsedValues) + argsNotParsed := findArgsNotInParsedValues(args, parsedValues) + if len(argsNotParsed) > 0 { + // flatten out unused args for our error message + var argsNotParsedFlat string + for _, a := range argsNotParsed { + argsNotParsedFlat = argsNotParsedFlat + " " + a + } + p.ShowHelpAndExit("Unknown arguments supplied: " + argsNotParsedFlat) + } + } + + return nil +} + +// findArgsNotInParsedValues finds arguments not used in parsed values. The +// incoming args should be in the order supplied by the user and should not +// include the invoked binary, which is normally the first thing in os.Args. +func findArgsNotInParsedValues(args []string, parsedValues []parsedValue) []string { + var argsNotUsed []string + var skipNext bool + for _, a := range args { + + // if the final argument (--) is seen, then we stop checking because all + // further values are trailing arguments. + if determineArgType(a) == argIsFinal { + return argsNotUsed + } + + // allow for skipping the next arg when needed + if skipNext { + skipNext = false + continue + } + + // strip flag slashes from incoming arguments so they match up with the + // keys from parsedValues. + arg := parseFlagToName(a) + + // indicates that we found this arg used in one of the parsed values. Used + // to indicate which values should be added to argsNotUsed. + var foundArgUsed bool + + // search all args for a corresponding parsed value + for _, pv := range parsedValues { + // this argumenet was a key + // debugPrint(pv.Key, "==", arg) + debugPrint(pv.Key + "==" + arg + " || (" + strconv.FormatBool(pv.IsPositional) + " && " + pv.Value + " == " + arg + ")") + if pv.Key == arg || (pv.IsPositional && pv.Value == arg) { + debugPrint("Found matching parsed arg for " + pv.Key) + foundArgUsed = true // the arg was used in this parsedValues set + // if the value is not a positional value and the parsed value had a + // value that was not blank, we skip the next value in the argument list + if !pv.IsPositional && len(pv.Value) > 0 { + skipNext = true + break + } + } + // this prevents excessive parsed values from being checked after we find + // the arg used for the first time + if foundArgUsed { + break + } + } + + // if the arg was not used in any parsed values, then we add it to the slice + // of arguments not used + if !foundArgUsed { + argsNotUsed = append(argsNotUsed, arg) + } + } + + return argsNotUsed } // ShowVersionAndExit shows the version of this parser @@ -105,7 +188,8 @@ func (p *Parser) ShowHelpWithMessage(message string) { } } -// Disable show version with --version. It is enabled by default. +// DisableShowVersionWithVersion disables the showing of version information +// with --version. It is enabled by default. func (p *Parser) DisableShowVersionWithVersion() { p.ShowVersionWithVersionFlag = false } |