add Parser.Subcommand and Parser.SubcommandNames

This commit is contained in:
Alex Flint 2019-05-03 16:08:29 -07:00
parent 3c5e61a292
commit bd97edec87
3 changed files with 69 additions and 11 deletions

View File

@ -19,15 +19,20 @@ func setenv(t *testing.T, name, val string) {
} }
func parse(cmdline string, dest interface{}) error { func parse(cmdline string, dest interface{}) error {
_, err := pparse(cmdline, dest)
return err
}
func pparse(cmdline string, dest interface{}) (*Parser, error) {
p, err := NewParser(Config{}, dest) p, err := NewParser(Config{}, dest)
if err != nil { if err != nil {
return err return nil, err
} }
var parts []string var parts []string
if len(cmdline) > 0 { if len(cmdline) > 0 {
parts = strings.Split(cmdline, " ") parts = strings.Split(cmdline, " ")
} }
return p.Parse(parts) return p, p.Parse(parts)
} }
func TestString(t *testing.T) { func TestString(t *testing.T) {

37
subcommand.go Normal file
View File

@ -0,0 +1,37 @@
package arg
// Subcommand returns the user struct for the subcommand selected by
// the command line arguments most recently processed by the parser.
// The return value is always a pointer to a struct. If no subcommand
// was specified then it returns the top-level arguments struct. If
// no command line arguments have been processed by this parser then it
// returns nil.
func (p *Parser) Subcommand() interface{} {
if p.lastCmd == nil || p.lastCmd.parent == nil {
return nil
}
return p.readable(p.lastCmd.dest).Interface()
}
// SubcommandNames returns the sequence of subcommands specified by the
// user. If no subcommands were given then it returns an empty slice.
func (p *Parser) SubcommandNames() []string {
if p.lastCmd == nil {
return nil
}
// make a list of ancestor commands
var ancestors []string
cur := p.lastCmd
for cur.parent != nil { // we want to exclude the root
ancestors = append(ancestors, cur.name)
cur = cur.parent
}
// reverse the list
out := make([]string, len(ancestors))
for i := 0; i < len(ancestors); i++ {
out[i] = ancestors[len(ancestors)-i-1]
}
return out
}

View File

@ -41,9 +41,11 @@ func TestMinimalSubcommand(t *testing.T) {
var args struct { var args struct {
List *listCmd `arg:"subcommand"` List *listCmd `arg:"subcommand"`
} }
err := parse("list", &args) p, err := pparse("list", &args)
require.NoError(t, err) require.NoError(t, err)
assert.NotNil(t, args.List) assert.NotNil(t, args.List)
assert.Equal(t, args.List, p.Subcommand())
assert.Equal(t, []string{"list"}, p.SubcommandNames())
} }
func TestNoSuchSubcommand(t *testing.T) { func TestNoSuchSubcommand(t *testing.T) {
@ -52,7 +54,7 @@ func TestNoSuchSubcommand(t *testing.T) {
var args struct { var args struct {
List *listCmd `arg:"subcommand"` List *listCmd `arg:"subcommand"`
} }
err := parse("invalid", &args) _, err := pparse("invalid", &args)
assert.Error(t, err) assert.Error(t, err)
} }
@ -62,9 +64,11 @@ func TestNamedSubcommand(t *testing.T) {
var args struct { var args struct {
List *listCmd `arg:"subcommand:ls"` List *listCmd `arg:"subcommand:ls"`
} }
err := parse("ls", &args) p, err := pparse("ls", &args)
require.NoError(t, err) require.NoError(t, err)
assert.NotNil(t, args.List) assert.NotNil(t, args.List)
assert.Equal(t, args.List, p.Subcommand())
assert.Equal(t, []string{"ls"}, p.SubcommandNames())
} }
func TestEmptySubcommand(t *testing.T) { func TestEmptySubcommand(t *testing.T) {
@ -73,9 +77,11 @@ func TestEmptySubcommand(t *testing.T) {
var args struct { var args struct {
List *listCmd `arg:"subcommand"` List *listCmd `arg:"subcommand"`
} }
err := parse("", &args) p, err := pparse("", &args)
require.NoError(t, err) require.NoError(t, err)
assert.Nil(t, args.List) assert.Nil(t, args.List)
assert.Nil(t, p.Subcommand())
assert.Empty(t, p.SubcommandNames())
} }
func TestTwoSubcommands(t *testing.T) { func TestTwoSubcommands(t *testing.T) {
@ -87,10 +93,12 @@ func TestTwoSubcommands(t *testing.T) {
Get *getCmd `arg:"subcommand"` Get *getCmd `arg:"subcommand"`
List *listCmd `arg:"subcommand"` List *listCmd `arg:"subcommand"`
} }
err := parse("list", &args) p, err := pparse("list", &args)
require.NoError(t, err) require.NoError(t, err)
assert.Nil(t, args.Get) assert.Nil(t, args.Get)
assert.NotNil(t, args.List) assert.NotNil(t, args.List)
assert.Equal(t, args.List, p.Subcommand())
assert.Equal(t, []string{"list"}, p.SubcommandNames())
} }
func TestSubcommandsWithOptions(t *testing.T) { func TestSubcommandsWithOptions(t *testing.T) {
@ -185,35 +193,43 @@ func TestNestedSubcommands(t *testing.T) {
{ {
var args root var args root
err := parse("grandparent parent child", &args) p, err := pparse("grandparent parent child", &args)
require.NoError(t, err) require.NoError(t, err)
require.NotNil(t, args.Grandparent) require.NotNil(t, args.Grandparent)
require.NotNil(t, args.Grandparent.Parent) require.NotNil(t, args.Grandparent.Parent)
require.NotNil(t, args.Grandparent.Parent.Child) require.NotNil(t, args.Grandparent.Parent.Child)
assert.Equal(t, args.Grandparent.Parent.Child, p.Subcommand())
assert.Equal(t, []string{"grandparent", "parent", "child"}, p.SubcommandNames())
} }
{ {
var args root var args root
err := parse("grandparent parent", &args) p, err := pparse("grandparent parent", &args)
require.NoError(t, err) require.NoError(t, err)
require.NotNil(t, args.Grandparent) require.NotNil(t, args.Grandparent)
require.NotNil(t, args.Grandparent.Parent) require.NotNil(t, args.Grandparent.Parent)
require.Nil(t, args.Grandparent.Parent.Child) require.Nil(t, args.Grandparent.Parent.Child)
assert.Equal(t, args.Grandparent.Parent, p.Subcommand())
assert.Equal(t, []string{"grandparent", "parent"}, p.SubcommandNames())
} }
{ {
var args root var args root
err := parse("grandparent", &args) p, err := pparse("grandparent", &args)
require.NoError(t, err) require.NoError(t, err)
require.NotNil(t, args.Grandparent) require.NotNil(t, args.Grandparent)
require.Nil(t, args.Grandparent.Parent) require.Nil(t, args.Grandparent.Parent)
assert.Equal(t, args.Grandparent, p.Subcommand())
assert.Equal(t, []string{"grandparent"}, p.SubcommandNames())
} }
{ {
var args root var args root
err := parse("", &args) p, err := pparse("", &args)
require.NoError(t, err) require.NoError(t, err)
require.Nil(t, args.Grandparent) require.Nil(t, args.Grandparent)
assert.Nil(t, p.Subcommand())
assert.Empty(t, p.SubcommandNames())
} }
} }