diff options
Diffstat (limited to 'parse.go')
| -rw-r--r-- | parse.go | 48 |
1 files changed, 26 insertions, 22 deletions
@@ -56,7 +56,7 @@ type spec struct { env string // the name of the environment variable for this option, or empty for none defaultValue reflect.Value // default value for this option defaultString string // default value for this option, in string form to be displayed in help text - placeholder string // name of the data in help + placeholder string // placeholder string in help } // command represents a named subcommand, or the top-level command @@ -76,8 +76,9 @@ var ErrHelp = errors.New("help requested by user") // ErrVersion indicates that the builtin --version was provided var ErrVersion = errors.New("version requested by user") -// for monkey patching in example code +// for monkey patching in example and test code var mustParseExit = os.Exit +var mustParseOut io.Writer = os.Stdout // This stores the args sent from modules var register []interface{} @@ -98,23 +99,16 @@ func Register(dest ...interface{}) { // MustParse processes command line arguments and exits upon failure func MustParse(dest ...interface{}) *Parser { register = append(register, dest...) - return mustParse(Config{Exit: mustParseExit}, register...) + return mustParse(Config{Exit: mustParseExit, Out: mustParseOut}, register...) } // mustParse is a helper that facilitates testing func mustParse(config Config, dest ...interface{}) *Parser { - if config.Exit == nil { - config.Exit = os.Exit - } - if config.Out == nil { - config.Out = os.Stdout - } - p, err := NewParser(config, dest...) if err != nil { fmt.Fprintln(config.Out, err) - config.Exit(-1) + config.Exit(2) return nil } @@ -155,6 +149,9 @@ type Config struct { // subcommand StrictSubcommands bool + // EnvPrefix instructs the library to use a name prefix when reading environment variables. + EnvPrefix string + // Exit is called to terminate the process with an error code (defaults to os.Exit) Exit func(int) @@ -259,7 +256,7 @@ func NewParser(config Config, dests ...interface{}) (*Parser, error) { panic(fmt.Sprintf("%s is not a pointer (did you forget an ampersand?)", t)) } - cmd, err := cmdFromStruct(name, path{root: i}, t) + cmd, err := cmdFromStruct(name, path{root: i}, t, config.EnvPrefix) if err != nil { return nil, err } @@ -309,7 +306,7 @@ func NewParser(config Config, dests ...interface{}) (*Parser, error) { return &p, nil } -func cmdFromStruct(name string, dest path, t reflect.Type) (*command, error) { +func cmdFromStruct(name string, dest path, t reflect.Type, envPrefix string) (*command, error) { // commands can only be created from pointers to structs if t.Kind() != reflect.Ptr { return nil, fmt.Errorf("subcommands must be pointers to structs but %s is a %s", @@ -360,9 +357,8 @@ func cmdFromStruct(name string, dest path, t reflect.Type) (*command, error) { spec.help = help } - // Look at the tag - var isSubcommand bool // tracks whether this field is a subcommand - + // process each comma-separated part of the tag + var isSubcommand bool for _, key := range strings.Split(tag, ",") { if key == "" { continue @@ -397,9 +393,9 @@ func cmdFromStruct(name string, dest path, t reflect.Type) (*command, error) { case key == "env": // Use override name if provided if value != "" { - spec.env = value + spec.env = envPrefix + value } else { - spec.env = strings.ToUpper(field.Name) + spec.env = envPrefix + strings.ToUpper(field.Name) } case key == "subcommand": // decide on a name for the subcommand @@ -414,7 +410,7 @@ func cmdFromStruct(name string, dest path, t reflect.Type) (*command, error) { } // parse the subcommand recursively - subcmd, err := cmdFromStruct(cmdnames[0], subdest, field.Type) + subcmd, err := cmdFromStruct(cmdnames[0], subdest, field.Type, envPrefix) if err != nil { errs = append(errs, err.Error()) return false @@ -432,6 +428,7 @@ func cmdFromStruct(name string, dest path, t reflect.Type) (*command, error) { } } + // placeholder is the string used in the help text like this: "--somearg PLACEHOLDER" placeholder, hasPlaceholder := field.Tag.Lookup("placeholder") if hasPlaceholder { spec.placeholder = placeholder @@ -517,8 +514,15 @@ func cmdFromStruct(name string, dest path, t reflect.Type) (*command, error) { return &cmd, nil } -// Parse processes the given command line option, storing the results in the field -// of the structs from which NewParser was constructed +// Parse processes the given command line option, storing the results in the fields +// of the structs from which NewParser was constructed. +// +// It returns ErrHelp if "--help" is one of the command line args and ErrVersion if +// "--version" is one of the command line args (the latter only applies if the +// destination struct passed to NewParser implements Versioned.) +// +// To respond to --help and --version in the way that MustParse does, see examples +// in the README under "Custom handling of --help and --version". func (p *Parser) Parse(args []string) error { err := p.process(args) if err != nil { @@ -632,7 +636,7 @@ func (p *Parser) process(args []string) error { // must use explicit for loop, not range, because we manipulate i inside the loop for i := 0; i < len(args); i++ { arg := args[i] - if arg == "--" { + if arg == "--" && !allpositional { allpositional = true continue } |
