diff options
Diffstat (limited to 'vendor/github.com/integrii/flaggy/subCommand.go')
-rw-r--r-- | vendor/github.com/integrii/flaggy/subCommand.go | 691 |
1 files changed, 691 insertions, 0 deletions
diff --git a/vendor/github.com/integrii/flaggy/subCommand.go b/vendor/github.com/integrii/flaggy/subCommand.go new file mode 100644 index 000000000..95d872952 --- /dev/null +++ b/vendor/github.com/integrii/flaggy/subCommand.go @@ -0,0 +1,691 @@ +package flaggy + +import ( + "fmt" + "log" + "net" + "os" + "strconv" + "strings" + "time" +) + +// Subcommand represents a subcommand which contains a set of child +// subcommands along with a set of flags relevant to it. Parsing +// runs until a subcommand is detected by matching its name and +// position. Once a matching subcommand is found, the next set +// of parsing occurs within that matched subcommand. +type Subcommand struct { + Name string + ShortName string + Description string + Position int // the position of this subcommand, not including flags + Subcommands []*Subcommand + Flags []*Flag + PositionalFlags []*PositionalValue + AdditionalHelpPrepend string // additional prepended message when Help is displayed + AdditionalHelpAppend string // additional appended message when Help is displayed + Used bool // indicates this subcommand was found and parsed + Hidden bool // indicates this subcommand should be hidden from help +} + +// NewSubcommand creates a new subcommand that can have flags or PositionalFlags +// added to it. The position starts with 1, not 0 +func NewSubcommand(name string) *Subcommand { + newSC := &Subcommand{ + Name: name, + } + return newSC +} + +// parseAllFlagsFromArgs parses the non-positional flags such as -f or -v=value +// out of the supplied args and returns the positional items in order. +func (sc *Subcommand) parseAllFlagsFromArgs(p *Parser, args []string) ([]string, bool, error) { + + var err error + var positionalOnlyArguments []string + var helpRequested bool // indicates the user has supplied -h and we + // should render help if we are the last subcommand + + // indicates we should skip the next argument, like when parsing a flag + // that separates key and value by space + var skipNext bool + + // endArgfound indicates that a -- was found and everything + // remaining should be added to the trailing arguments slices + var endArgFound bool + + // find all the normal flags (not positional) and parse them out + for i, a := range args { + + debugPrint("parsing arg", 1, a) + + // evaluate if there is a following arg to avoid panics + var nextArgExists bool + var nextArg string + if len(args)-1 >= i+1 { + nextArgExists = true + nextArg = args[i+1] + } + + // if end arg -- has been found, just add everything to TrailingArguments + if endArgFound { + if !p.trailingArgumentsExtracted { + p.TrailingArguments = append(p.TrailingArguments, a) + } + continue + } + + // skip this run if specified + if skipNext { + skipNext = false + debugPrint("skipping flag because it is an arg:", a) + continue + } + + // parse the flag into its name for consideration without dashes + flagName := parseFlagToName(a) + + // if the flag being passed is version or v and the option to display + // version with version flags, then display version + if p.ShowVersionWithVersionFlag { + if flagName == versionFlagLongName { + p.ShowVersionAndExit() + } + } + + // if the show Help on h flag option is set, then show Help when h or Help + // is passed as an option + if p.ShowHelpWithHFlag { + if flagName == helpFlagShortName || flagName == helpFlagLongName { + // Ensure this is the last subcommand passed so we give the correct + // help output + helpRequested = true + continue + } + } + + // determine what kind of flag this is + argType := determineArgType(a) + + // strip flags from arg + // debugPrint("Parsing flag named", a, "of type", argType) + + // depending on the flag type, parse the key and value out, then apply it + switch argType { + case argIsFinal: + // debugPrint("Arg", i, "is final:", a) + endArgFound = true + case argIsPositional: + // debugPrint("Arg is positional or subcommand:", a) + // this positional argument into a slice of their own, so that + // we can determine if its a subcommand or positional value later + positionalOnlyArguments = append(positionalOnlyArguments, a) + case argIsFlagWithSpace: + a = parseFlagToName(a) + // debugPrint("Arg", i, "is flag with space:", a) + // parse next arg as value to this flag and apply to subcommand flags + // if the flag is a bool flag, then we check for a following positional + // and skip it if necessary + if flagIsBool(sc, p, a) { + debugPrint(sc.Name, "bool flag", a, "next var is:", nextArg) + _, err = setValueForParsers(a, "true", p, sc) + + // if an error occurs, just return it and quit parsing + if err != nil { + return []string{}, false, err + } + // by default, we just assign the next argument to the value and continue + continue + } + + skipNext = true + debugPrint(sc.Name, "NOT bool flag", a) + + // if the next arg was not found, then show a Help message + if !nextArgExists { + p.ShowHelpWithMessage("Expected a following arg for flag " + a + ", but it did not exist.") + exitOrPanic(2) + } + _, err = setValueForParsers(a, nextArg, p, sc) + if err != nil { + return []string{}, false, err + } + case argIsFlagWithValue: + // debugPrint("Arg", i, "is flag with value:", a) + a = parseFlagToName(a) + // parse flag into key and value and apply to subcommand flags + key, val := parseArgWithValue(a) + _, err = setValueForParsers(key, val, p, sc) + if err != nil { + return []string{}, false, err + } + // if this flag type was found and not set, and the parser is set to show + // Help when an unknown flag is found, then show Help and exit. + } + + } + + return positionalOnlyArguments, helpRequested, nil +} + +// Parse causes the argument parser to parse based on the supplied []string. +// depth specifies the non-flag subcommand positional depth +func (sc *Subcommand) parse(p *Parser, args []string, depth int) error { + + debugPrint("- Parsing subcommand", sc.Name, "with depth of", depth, "and args", args) + + // if a command is parsed, its used + sc.Used = true + + // as subcommands are used, they become the context of the parser. This helps + // us understand how to display help based on which subcommand is being used + p.subcommandContext = sc + + // ensure that help and version flags are not used if the parser has the + // built-in help and version flags enabled + if p.ShowHelpWithHFlag { + sc.ensureNoConflictWithBuiltinHelp() + } + if p.ShowVersionWithVersionFlag { + sc.ensureNoConflictWithBuiltinVersion() + } + + // Parse the normal flags out of the argument list and retain the positionals. + // Apply the flags to the parent parser and the current subcommand context. + // ./command -f -z subcommand someVar -b becomes ./command subcommand somevar + positionalOnlyArguments, helpRequested, err := sc.parseAllFlagsFromArgs(p, args) + if err != nil { + return err + } + + // indicate that trailing arguments have been extracted, so that they aren't + // appended a second time + p.trailingArgumentsExtracted = true + + // loop over positional values and look for their matching positional + // parameter, or their positional command. If neither are found, then + // we throw an error + var parsedArgCount int + for pos, v := range positionalOnlyArguments { + + // the first relative positional argument will be human natural at position 1 + // but offset for the depth of relative commands being parsed for currently. + relativeDepth := pos - depth + 1 + // debugPrint("Parsing positional only position", relativeDepth, "with value", v) + + if relativeDepth < 1 { + // debugPrint(sc.Name, "skipped value:", v) + continue + } + parsedArgCount++ + + // determine subcommands and parse them by positional value and name + for _, cmd := range sc.Subcommands { + // debugPrint("Subcommand being compared", relativeDepth, "==", cmd.Position, "and", v, "==", cmd.Name, "==", cmd.ShortName) + if relativeDepth == cmd.Position && (v == cmd.Name || v == cmd.ShortName) { + debugPrint("Decending into positional subcommand", cmd.Name, "at relativeDepth", relativeDepth, "and absolute depth", depth+1) + return cmd.parse(p, args, depth+parsedArgCount) // continue recursive positional parsing + } + } + + // determine positional args and parse them by positional value and name + var foundPositional bool + for _, val := range sc.PositionalFlags { + if relativeDepth == val.Position { + debugPrint("Found a positional value at relativePos:", relativeDepth, "value:", v) + + // set original value for help output + val.defaultValue = *val.AssignmentVar + + // defrerence the struct pointer, then set the pointer property within it + *val.AssignmentVar = v + // debugPrint("set positional to value", *val.AssignmentVar) + foundPositional = true + val.Found = true + break + } + } + + // if there aren't any positional flags but there are subcommands that + // were not used, display a useful message with subcommand options. + if !foundPositional && p.ShowHelpOnUnexpected { + debugPrint("No positional at position", relativeDepth) + var foundSubcommandAtDepth bool + for _, cmd := range sc.Subcommands { + if cmd.Position == relativeDepth { + foundSubcommandAtDepth = true + } + } + + // if there is a subcommand here but it was not specified, display them all + // as a suggestion to the user before exiting. + if foundSubcommandAtDepth { + // determine which name to use in upcoming help output + fmt.Fprintln(os.Stderr, sc.Name+":", "No subcommand or positional value found at position", strconv.Itoa(relativeDepth)+".") + var output string + for _, cmd := range sc.Subcommands { + if cmd.Hidden { + continue + } + output = output + " " + cmd.Name + } + // if there are available subcommands, let the user know + if len(output) > 0 { + output = strings.TrimLeft(output, " ") + fmt.Println("Available subcommands:", output) + } + exitOrPanic(2) + } + + // if there were not any flags or subcommands at this position at all, then + // throw an error (display Help if necessary) + p.ShowHelpWithMessage("Unexpected argument: " + v) + exitOrPanic(2) + } + } + + // if help was requested and we should show help when h is passed, + if helpRequested && p.ShowHelpWithHFlag { + p.ShowHelp() + exitOrPanic(0) + } + + // find any positionals that were not used on subcommands that were + // found and throw help (unknown argument) + for _, pv := range p.PositionalFlags { + if pv.Required && !pv.Found { + p.ShowHelpWithMessage("Required global positional variable " + pv.Name + " not found at position " + strconv.Itoa(pv.Position)) + exitOrPanic(2) + } + } + for _, pv := range sc.PositionalFlags { + if pv.Required && !pv.Found { + p.ShowHelpWithMessage("Required positional of subcommand " + sc.Name + " named " + pv.Name + " not found at position " + strconv.Itoa(pv.Position)) + exitOrPanic(2) + } + } + + return nil +} + +// FlagExists lets you know if the flag name exists as either a short or long +// name in the (sub)command +func (sc *Subcommand) FlagExists(name string) bool { + + for _, f := range sc.Flags { + if f.HasName(name) { + return true + } + } + + return false +} + +// AttachSubcommand adds a possible subcommand to the Parser. +func (sc *Subcommand) AttachSubcommand(newSC *Subcommand, relativePosition int) { + + // assign the depth of the subcommand when its attached + newSC.Position = relativePosition + + // ensure no subcommands at this depth with this name + for _, other := range sc.Subcommands { + if newSC.Position == other.Position { + if newSC.Name != "" { + if newSC.Name == other.Name { + log.Panicln("Unable to add subcommand because one already exists at position" + strconv.Itoa(newSC.Position) + " with name " + other.Name) + } + } + if newSC.ShortName != "" { + if newSC.ShortName == other.ShortName { + log.Panicln("Unable to add subcommand because one already exists at position" + strconv.Itoa(newSC.Position) + " with name " + other.ShortName) + } + } + } + } + + // ensure no positionals at this depth + for _, other := range sc.PositionalFlags { + if newSC.Position == other.Position { + log.Panicln("Unable to add subcommand because a positional value already exists at position " + strconv.Itoa(newSC.Position) + ": " + other.Name) + } + } + + sc.Subcommands = append(sc.Subcommands, newSC) +} + +// add is a "generic" to add flags of any type. Checks the supplied parent +// parser to ensure that the user isn't setting version or help flags that +// conflict with the built-in help and version flag behavior. +func (sc *Subcommand) add(assignmentVar interface{}, shortName string, longName string, description string) { + + // if the flag is already used, throw an error + for _, existingFlag := range sc.Flags { + if longName != "" && existingFlag.LongName == longName { + log.Panicln("Flag " + longName + " added to subcommand " + sc.Name + " but the name is already assigned.") + } + if shortName != "" && existingFlag.ShortName == shortName { + log.Panicln("Flag " + shortName + " added to subcommand " + sc.Name + " but the short name is already assigned.") + } + } + + newFlag := Flag{ + AssignmentVar: assignmentVar, + ShortName: shortName, + LongName: longName, + Description: description, + } + sc.Flags = append(sc.Flags, &newFlag) +} + +// String adds a new string flag +func (sc *Subcommand) String(assignmentVar *string, shortName string, longName string, description string) { + sc.add(assignmentVar, shortName, longName, description) +} + +// StringSlice adds a new slice of strings flag +// Specify the flag multiple times to fill the slice +func (sc *Subcommand) StringSlice(assignmentVar *[]string, shortName string, longName string, description string) { + sc.add(assignmentVar, shortName, longName, description) +} + +// Bool adds a new bool flag +func (sc *Subcommand) Bool(assignmentVar *bool, shortName string, longName string, description string) { + sc.add(assignmentVar, shortName, longName, description) +} + +// BoolSlice adds a new slice of bools flag +// Specify the flag multiple times to fill the slice +func (sc *Subcommand) BoolSlice(assignmentVar *[]bool, shortName string, longName string, description string) { + sc.add(assignmentVar, shortName, longName, description) +} + +// ByteSlice adds a new slice of bytes flag +// Specify the flag multiple times to fill the slice. Takes hex as input. +func (sc *Subcommand) ByteSlice(assignmentVar *[]byte, shortName string, longName string, description string) { + sc.add(assignmentVar, shortName, longName, description) +} + +// Duration adds a new time.Duration flag. +// Input format is described in time.ParseDuration(). +// Example values: 1h, 1h50m, 32s +func (sc *Subcommand) Duration(assignmentVar *time.Duration, shortName string, longName string, description string) { + sc.add(assignmentVar, shortName, longName, description) +} + +// DurationSlice adds a new time.Duration flag. +// Input format is described in time.ParseDuration(). +// Example values: 1h, 1h50m, 32s +// Specify the flag multiple times to fill the slice. +func (sc *Subcommand) DurationSlice(assignmentVar *[]time.Duration, shortName string, longName string, description string) { + sc.add(assignmentVar, shortName, longName, description) +} + +// Float32 adds a new float32 flag. +func (sc *Subcommand) Float32(assignmentVar *float32, shortName string, longName string, description string) { + sc.add(assignmentVar, shortName, longName, description) +} + +// Float32Slice adds a new float32 flag. +// Specify the flag multiple times to fill the slice. +func (sc *Subcommand) Float32Slice(assignmentVar *[]float32, shortName string, longName string, description string) { + sc.add(assignmentVar, shortName, longName, description) +} + +// Float64 adds a new float64 flag. +func (sc *Subcommand) Float64(assignmentVar *float64, shortName string, longName string, description string) { + sc.add(assignmentVar, shortName, longName, description) +} + +// Float64Slice adds a new float64 flag. +// Specify the flag multiple times to fill the slice. +func (sc *Subcommand) Float64Slice(assignmentVar *[]float64, shortName string, longName string, description string) { + sc.add(assignmentVar, shortName, longName, description) +} + +// Int adds a new int flag +func (sc *Subcommand) Int(assignmentVar *int, shortName string, longName string, description string) { + sc.add(assignmentVar, shortName, longName, description) +} + +// IntSlice adds a new int slice flag. +// Specify the flag multiple times to fill the slice. +func (sc *Subcommand) IntSlice(assignmentVar *[]int, shortName string, longName string, description string) { + sc.add(assignmentVar, shortName, longName, description) +} + +// UInt adds a new uint flag +func (sc *Subcommand) UInt(assignmentVar *uint, shortName string, longName string, description string) { + sc.add(assignmentVar, shortName, longName, description) +} + +// UIntSlice adds a new uint slice flag. +// Specify the flag multiple times to fill the slice. +func (sc *Subcommand) UIntSlice(assignmentVar *[]uint, shortName string, longName string, description string) { + sc.add(assignmentVar, shortName, longName, description) +} + +// UInt64 adds a new uint64 flag +func (sc *Subcommand) UInt64(assignmentVar *uint64, shortName string, longName string, description string) { + sc.add(assignmentVar, shortName, longName, description) +} + +// UInt64Slice adds a new uint64 slice flag. +// Specify the flag multiple times to fill the slice. +func (sc *Subcommand) UInt64Slice(assignmentVar *[]uint64, shortName string, longName string, description string) { + sc.add(assignmentVar, shortName, longName, description) +} + +// UInt32 adds a new uint32 flag +func (sc *Subcommand) UInt32(assignmentVar *uint32, shortName string, longName string, description string) { + sc.add(assignmentVar, shortName, longName, description) +} + +// UInt32Slice adds a new uint32 slice flag. +// Specify the flag multiple times to fill the slice. +func (sc *Subcommand) UInt32Slice(assignmentVar *[]uint32, shortName string, longName string, description string) { + sc.add(assignmentVar, shortName, longName, description) +} + +// UInt16 adds a new uint16 flag +func (sc *Subcommand) UInt16(assignmentVar *uint16, shortName string, longName string, description string) { + sc.add(assignmentVar, shortName, longName, description) +} + +// UInt16Slice adds a new uint16 slice flag. +// Specify the flag multiple times to fill the slice. +func (sc *Subcommand) UInt16Slice(assignmentVar *[]uint16, shortName string, longName string, description string) { + sc.add(assignmentVar, shortName, longName, description) +} + +// UInt8 adds a new uint8 flag +func (sc *Subcommand) UInt8(assignmentVar *uint8, shortName string, longName string, description string) { + sc.add(assignmentVar, shortName, longName, description) +} + +// UInt8Slice adds a new uint8 slice flag. +// Specify the flag multiple times to fill the slice. +func (sc *Subcommand) UInt8Slice(assignmentVar *[]uint8, shortName string, longName string, description string) { + sc.add(assignmentVar, shortName, longName, description) +} + +// Int64 adds a new int64 flag. +func (sc *Subcommand) Int64(assignmentVar *int64, shortName string, longName string, description string) { + sc.add(assignmentVar, shortName, longName, description) +} + +// Int64Slice adds a new int64 slice flag. +// Specify the flag multiple times to fill the slice. +func (sc *Subcommand) Int64Slice(assignmentVar *[]int64, shortName string, longName string, description string) { + sc.add(assignmentVar, shortName, longName, description) +} + +// Int32 adds a new int32 flag +func (sc *Subcommand) Int32(assignmentVar *int32, shortName string, longName string, description string) { + sc.add(assignmentVar, shortName, longName, description) +} + +// Int32Slice adds a new int32 slice flag. +// Specify the flag multiple times to fill the slice. +func (sc *Subcommand) Int32Slice(assignmentVar *[]int32, shortName string, longName string, description string) { + sc.add(assignmentVar, shortName, longName, description) +} + +// Int16 adds a new int16 flag +func (sc *Subcommand) Int16(assignmentVar *int16, shortName string, longName string, description string) { + sc.add(assignmentVar, shortName, longName, description) +} + +// Int16Slice adds a new int16 slice flag. +// Specify the flag multiple times to fill the slice. +func (sc *Subcommand) Int16Slice(assignmentVar *[]int16, shortName string, longName string, description string) { + sc.add(assignmentVar, shortName, longName, description) +} + +// Int8 adds a new int8 flag +func (sc *Subcommand) Int8(assignmentVar *int8, shortName string, longName string, description string) { + sc.add(assignmentVar, shortName, longName, description) +} + +// Int8Slice adds a new int8 slice flag. +// Specify the flag multiple times to fill the slice. +func (sc *Subcommand) Int8Slice(assignmentVar *[]int8, shortName string, longName string, description string) { + sc.add(assignmentVar, shortName, longName, description) +} + +// IP adds a new net.IP flag. +func (sc *Subcommand) IP(assignmentVar *net.IP, shortName string, longName string, description string) { + sc.add(assignmentVar, shortName, longName, description) +} + +// IPSlice adds a new int8 slice flag. +// Specify the flag multiple times to fill the slice. +func (sc *Subcommand) IPSlice(assignmentVar *[]net.IP, shortName string, longName string, description string) { + sc.add(assignmentVar, shortName, longName, description) +} + +// HardwareAddr adds a new net.HardwareAddr flag. +func (sc *Subcommand) HardwareAddr(assignmentVar *net.HardwareAddr, shortName string, longName string, description string) { + sc.add(assignmentVar, shortName, longName, description) +} + +// HardwareAddrSlice adds a new net.HardwareAddr slice flag. +// Specify the flag multiple times to fill the slice. +func (sc *Subcommand) HardwareAddrSlice(assignmentVar *[]net.HardwareAddr, shortName string, longName string, description string) { + sc.add(assignmentVar, shortName, longName, description) +} + +// IPMask adds a new net.IPMask flag. IPv4 Only. +func (sc *Subcommand) IPMask(assignmentVar *net.IPMask, shortName string, longName string, description string) { + sc.add(assignmentVar, shortName, longName, description) +} + +// IPMaskSlice adds a new net.HardwareAddr slice flag. IPv4 only. +// Specify the flag multiple times to fill the slice. +func (sc *Subcommand) IPMaskSlice(assignmentVar *[]net.IPMask, shortName string, longName string, description string) { + sc.add(assignmentVar, shortName, longName, description) +} + +// AddPositionalValue adds a positional value to the subcommand. the +// relativePosition starts at 1 and is relative to the subcommand it belongs to +func (sc *Subcommand) AddPositionalValue(assignmentVar *string, name string, relativePosition int, required bool, description string) { + + // ensure no other positionals are at this depth + for _, other := range sc.PositionalFlags { + if relativePosition == other.Position { + log.Panicln("Unable to add positional value because one already exists at position: " + strconv.Itoa(relativePosition)) + } + } + + // ensure no subcommands at this depth + for _, other := range sc.Subcommands { + if relativePosition == other.Position { + log.Panicln("Unable to add positional value a subcommand already exists at position: " + strconv.Itoa(relativePosition)) + } + } + + newPositionalValue := PositionalValue{ + Name: name, + Position: relativePosition, + AssignmentVar: assignmentVar, + Required: required, + Description: description, + } + sc.PositionalFlags = append(sc.PositionalFlags, &newPositionalValue) +} + +// SetValueForKey sets the value for the specified key. If setting a bool +// value, then send "true" or "false" as strings. The returned bool indicates +// that a value was set. +func (sc *Subcommand) SetValueForKey(key string, value string) (bool, error) { + + // debugPrint("Looking to set key", key, "to value", value) + // check for and assign flags that match the key + for _, f := range sc.Flags { + // debugPrint("Evaluating string flag", f.ShortName, "==", key, "||", f.LongName, "==", key) + if f.ShortName == key || f.LongName == key { + // debugPrint("Setting string value for", key, "to", value) + f.identifyAndAssignValue(value) + return true, nil + } + } + + // debugPrint(sc.Name, "was unable to find a key named", key, "to set to value", value) + return false, nil +} + +// ensureNoConflictWithBuiltinHelp ensures that the flags on this subcommand do +// not conflict with the builtin help flags (-h or --help). Exits the program +// if a conflict is found. +func (sc *Subcommand) ensureNoConflictWithBuiltinHelp() { + for _, f := range sc.Flags { + if f.LongName == helpFlagLongName { + sc.exitBecauseOfHelpFlagConflict(f.LongName) + } + if f.LongName == helpFlagShortName { + sc.exitBecauseOfHelpFlagConflict(f.LongName) + } + if f.ShortName == helpFlagLongName { + sc.exitBecauseOfHelpFlagConflict(f.ShortName) + } + if f.ShortName == helpFlagShortName { + sc.exitBecauseOfHelpFlagConflict(f.ShortName) + } + } +} + +// ensureNoConflictWithBuiltinVersion ensures that the flags on this subcommand do +// not conflict with the builtin version flag (--version). Exits the program +// if a conflict is found. +func (sc *Subcommand) ensureNoConflictWithBuiltinVersion() { + for _, f := range sc.Flags { + if f.LongName == versionFlagLongName { + sc.exitBecauseOfVersionFlagConflict(f.LongName) + } + if f.ShortName == versionFlagLongName { + sc.exitBecauseOfVersionFlagConflict(f.ShortName) + } + } +} + +// exitBecauseOfVersionFlagConflict exits the program with a message about how to prevent +// flags being defined from conflicting with the builtin flags. +func (sc *Subcommand) exitBecauseOfVersionFlagConflict(flagName string) { + fmt.Println(`Flag with name '` + flagName + `' conflicts with the internal --version flag in flaggy. + +You must either change the flag's name, or disable flaggy's internal version +flag with 'flaggy.DefaultParser.ShowVersionWithVersionFlag = false'. If you are using +a custom parser, you must instead set '.ShowVersionWithVersionFlag = false' on it.`) + exitOrPanic(1) +} + +// exitBecauseOfHelpFlagConflict exits the program with a message about how to prevent +// flags being defined from conflicting with the builtin flags. +func (sc *Subcommand) exitBecauseOfHelpFlagConflict(flagName string) { + fmt.Println(`Flag with name '` + flagName + `' conflicts with the internal --help or -h flag in flaggy. + +You must either change the flag's name, or disable flaggy's internal help +flag with 'flaggy.DefaultParser.ShowHelpWithHFlag = false'. If you are using +a custom parser, you must instead set '.ShowHelpWithHFlag = false' on it.`) + exitOrPanic(1) +} |