add strict subcommand parsing

This commit is contained in:
Alexey Trofimov 2023-01-18 11:50:50 +03:00
parent 727f8533ac
commit cef66fd2f6
3 changed files with 89 additions and 6 deletions

2
go.sum
View File

@ -1,5 +1,3 @@
github.com/alexflint/go-scalar v1.1.0 h1:aaAouLLzI9TChcPXotr6gUhq+Scr8rl0P9P4PnltbhM=
github.com/alexflint/go-scalar v1.1.0/go.mod h1:LoFvNMqS1CPrMVltza4LvnGKhaSpc3oyLEBUZVhhS2o=
github.com/alexflint/go-scalar v1.2.0 h1:WR7JPKkeNpnYIOfHRa7ivM21aWAdHD0gEWHCx+WQBRw=
github.com/alexflint/go-scalar v1.2.0/go.mod h1:LoFvNMqS1CPrMVltza4LvnGKhaSpc3oyLEBUZVhhS2o=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=

View File

@ -115,6 +115,10 @@ type Config struct {
// IgnoreDefault instructs the library not to reset the variables to the
// default values, including pointers to sub commands
IgnoreDefault bool
// IgnoreDefault intructs the library not to allow global commands after
// subcommand
StrictSubcommands bool
}
// Parser represents a set of command line options with destination values
@ -588,7 +592,12 @@ func (p *Parser) process(args []string) error {
}
// add the new options to the set of allowed options
if p.config.StrictSubcommands {
specs = make([]*spec, len(subcmd.specs))
copy(specs, subcmd.specs)
} else {
specs = append(specs, subcmd.specs...)
}
// capture environment vars for these new options
if !p.config.IgnoreEnv {

View File

@ -1614,3 +1614,79 @@ func TestTextMarshalerUnmarshalerEmptyPointer(t *testing.T) {
require.NoError(t, err)
assert.Nil(t, args.Config)
}
func TestSubcommandGlobalFlag_Before(t *testing.T) {
var args struct {
Global bool `arg:"-g"`
Sub *struct {
} `arg:"subcommand"`
}
p, err := NewParser(Config{StrictSubcommands: false}, &args)
require.NoError(t, err)
err = p.Parse([]string{"-g", "sub"})
assert.NoError(t, err)
assert.True(t, args.Global)
}
func TestSubcommandGlobalFlag_InCommand(t *testing.T) {
var args struct {
Global bool `arg:"-g"`
Sub *struct {
} `arg:"subcommand"`
}
p, err := NewParser(Config{StrictSubcommands: false}, &args)
require.NoError(t, err)
err = p.Parse([]string{"sub", "-g"})
assert.NoError(t, err)
assert.True(t, args.Global)
}
func TestSubcommandGlobalFlag_Before_Strict(t *testing.T) {
var args struct {
Global bool `arg:"-g"`
Sub *struct {
} `arg:"subcommand"`
}
p, err := NewParser(Config{StrictSubcommands: true}, &args)
require.NoError(t, err)
err = p.Parse([]string{"-g", "sub"})
assert.NoError(t, err)
assert.True(t, args.Global)
}
func TestSubcommandGlobalFlag_InCommand_Strict(t *testing.T) {
var args struct {
Global bool `arg:"-g"`
Sub *struct {
} `arg:"subcommand"`
}
p, err := NewParser(Config{StrictSubcommands: true}, &args)
require.NoError(t, err)
err = p.Parse([]string{"sub", "-g"})
assert.Error(t, err)
}
func TestSubcommandGlobalFlag_InCommand_Strict_Inner(t *testing.T) {
var args struct {
Global bool `arg:"-g"`
Sub *struct {
Guard bool `arg:"-g"`
} `arg:"subcommand"`
}
p, err := NewParser(Config{StrictSubcommands: true}, &args)
require.NoError(t, err)
err = p.Parse([]string{"sub", "-g"})
assert.NoError(t, err)
assert.False(t, args.Global)
assert.True(t, args.Sub.Guard)
}