summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexey Trofimov <[email protected]>2023-01-18 11:50:50 +0300
committerAlexey Trofimov <[email protected]>2023-01-18 11:50:50 +0300
commitcef66fd2f6e0e061ade3778d3d3868032e4f0a32 (patch)
tree17ecbe31d927fd13e6454487ad62388abb2d4281
parent727f8533acca70ca429dce4bfea729a6af75c3f7 (diff)
add strict subcommand parsing
-rw-r--r--go.sum2
-rw-r--r--parse.go11
-rw-r--r--parse_test.go82
3 files changed, 89 insertions, 6 deletions
diff --git a/go.sum b/go.sum
index 5b536f9..385ca8f 100644
--- a/go.sum
+++ b/go.sum
@@ -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=
diff --git a/parse.go b/parse.go
index 6ac5e99..3efe858 100644
--- a/parse.go
+++ b/parse.go
@@ -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
- specs = append(specs, subcmd.specs...)
+ 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 {
diff --git a/parse_test.go b/parse_test.go
index 5d38306..64119a8 100644
--- a/parse_test.go
+++ b/parse_test.go
@@ -98,9 +98,9 @@ func TestInt(t *testing.T) {
func TestHexOctBin(t *testing.T) {
var args struct {
- Hex int
- Oct int
- Bin int
+ Hex int
+ Oct int
+ Bin int
Underscored int
}
err := parse("--hex 0xA --oct 0o10 --bin 0b101 --underscored 123_456", &args)
@@ -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)
+}