diff --git a/matchers.go b/matchers.go index 30c36ae..11a8efc 100644 --- a/matchers.go +++ b/matchers.go @@ -86,10 +86,6 @@ func (o *optMatcher) match(args []string, c *parseContext) (bool, []string) { idx += consumed default: - if o.theOne.valueSetFromEnv { - // exclude opt - c.excludedOpts[o.theOne] = struct{}{} - } return o.theOne.valueSetFromEnv, args } } @@ -235,7 +231,10 @@ func (om optsMatcher) try(args []string, c *parseContext) (bool, []string) { continue } if ok, nargs := (&optMatcher{theOne: o, optionsIdx: om.optionsIndex}).match(args, c); ok { - return ok, nargs + if o.valueSetFromEnv { + c.excludedOpts[o] = struct{}{} + } + return true, nargs } } return false, args diff --git a/matchers_test.go b/matchers_test.go index 552752d..999b78c 100644 --- a/matchers_test.go +++ b/matchers_test.go @@ -3,6 +3,8 @@ package cli import ( "testing" + "time" + "github.com/stretchr/testify/require" ) @@ -192,3 +194,34 @@ func TestOptsMatcher(t *testing.T) { require.False(t, nok, "opts shouldn't match when rejectOptions flag is set") } } + +// Issue 55 +func TestOptsMatcherInfiniteLoop(t *testing.T) { + opts := optsMatcher{ + options: []*opt{ + {names: []string{"-g"}, value: newStringValue(new(string), ""), valueSetFromEnv: true}, + }, + optionsIndex: map[string]*opt{}, + } + + for _, o := range opts.options { + for _, n := range o.names { + opts.optionsIndex[n] = o + } + } + + done := make(chan struct{}, 1) + pc := newParseContext() + go func() { + opts.match([]string{"-x"}, &pc) + done <- struct{}{} + }() + + select { + case <-done: + // nop, everything is good + case <-time.After(5 * time.Second): + t.Fatalf("Timed out after 5 seconds. Infinite loop in optsMatcher.") + } + +}