summaryrefslogtreecommitdiff
path: root/parse.go
diff options
context:
space:
mode:
Diffstat (limited to 'parse.go')
-rw-r--r--parse.go52
1 files changed, 29 insertions, 23 deletions
diff --git a/parse.go b/parse.go
index 0bdddc7..2bed8bf 100644
--- a/parse.go
+++ b/parse.go
@@ -56,12 +56,13 @@ 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
type command struct {
name string
+ aliases []string
help string
dest path
specs []*spec
@@ -75,27 +76,21 @@ 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
// MustParse processes command line arguments and exits upon failure
func MustParse(dest ...interface{}) *Parser {
- return mustParse(Config{Exit: mustParseExit}, dest...)
+ return mustParse(Config{Exit: mustParseExit, Out: mustParseOut}, dest...)
}
// 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
}
@@ -153,7 +148,7 @@ type Parser struct {
epilogue string
// the following field changes during processing of command line arguments
- lastCmd *command
+ subcommand []string
}
// Versioned is the interface that the destination struct should implement to
@@ -341,9 +336,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
@@ -384,18 +378,24 @@ func cmdFromStruct(name string, dest path, t reflect.Type) (*command, error) {
}
case key == "subcommand":
// decide on a name for the subcommand
- cmdname := value
- if cmdname == "" {
- cmdname = strings.ToLower(field.Name)
+ var cmdnames []string
+ if value == "" {
+ cmdnames = []string{strings.ToLower(field.Name)}
+ } else {
+ cmdnames = strings.Split(value, "|")
+ }
+ for i := range cmdnames {
+ cmdnames[i] = strings.TrimSpace(cmdnames[i])
}
// parse the subcommand recursively
- subcmd, err := cmdFromStruct(cmdname, subdest, field.Type)
+ subcmd, err := cmdFromStruct(cmdnames[0], subdest, field.Type)
if err != nil {
errs = append(errs, err.Error())
return false
}
+ subcmd.aliases = cmdnames[1:]
subcmd.parent = &cmd
subcmd.help = field.Tag.Get("help")
@@ -407,6 +407,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
@@ -514,13 +515,13 @@ func (p *Parser) MustParse(args []string) {
err := p.Parse(args)
switch {
case err == ErrHelp:
- p.writeHelpForSubcommand(p.config.Out, p.lastCmd)
+ p.WriteHelpForSubcommand(p.config.Out, p.subcommand...)
p.config.Exit(0)
case err == ErrVersion:
fmt.Fprintln(p.config.Out, p.version)
p.config.Exit(0)
case err != nil:
- p.failWithSubcommand(err.Error(), p.lastCmd)
+ p.FailSubcommand(err.Error(), p.subcommand...)
}
}
@@ -577,7 +578,7 @@ func (p *Parser) process(args []string) error {
// union of specs for the chain of subcommands encountered so far
curCmd := p.cmd
- p.lastCmd = curCmd
+ p.subcommand = nil
// make a copy of the specs because we will add to this list each time we expand a subcommand
specs := make([]*spec, len(curCmd.specs))
@@ -648,7 +649,7 @@ func (p *Parser) process(args []string) error {
}
curCmd = subcmd
- p.lastCmd = curCmd
+ p.subcommand = append(p.subcommand, arg)
continue
}
@@ -842,6 +843,11 @@ func findSubcommand(cmds []*command, name string) *command {
if cmd.name == name {
return cmd
}
+ for _, alias := range cmd.aliases {
+ if alias == name {
+ return cmd
+ }
+ }
}
return nil
}