Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 33 additions & 16 deletions flag_mutex.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,32 +17,49 @@ type MutuallyExclusiveFlags struct {
}

func (grp MutuallyExclusiveFlags) check(_ *Command) error {
oneSet := false
e := &mutuallyExclusiveGroup{}

for _, grpf := range grp.Flags {
for _, f := range grpf {
if f.IsSet() {
if oneSet {
e.flag2Name = f.Names()[0]
return e
}
e.flag1Name = f.Names()[0]
oneSet = true
break
}
if oneSet {
break
}
// Check for the use of a mutually-exclusive flag, starting at
// the first group.
name, i, ok := grp.findSetFlag(0)
if ok {
e.flag1Name = name
i++

// Check for the use of a flag in a mutually exclusive
// relationship with the one we just found.
if name2, _, ok := grp.findSetFlag(i); ok {
e.flag2Name = name2
return e
}
}

if !oneSet && grp.Required {
if !ok && grp.Required {
return &mutuallyExclusiveGroupRequiredFlag{flags: &grp}
}

return nil
}

// findSetFlag is used in [MutuallyExclusiveFlags.check] to find
// whether at least one flag inside a mutually exclusive flag group is
// set. If so, return the flag name, position at which it's set, and
// Boolean true (indicating that a flag was found.) Else, return all
// zero values.
func (grp MutuallyExclusiveFlags) findSetFlag(startIdx int) (string, int, bool) {
for i := startIdx; i < len(grp.Flags); i++ {
flags := grp.Flags[i]

for _, flg := range flags {
if flg.IsSet() {
return flg.Names()[0], i, true
}
}
}

return "", 0, false
}

func (grp MutuallyExclusiveFlags) propagateCategory() {
for _, grpf := range grp.Flags {
for _, f := range grpf {
Expand Down
9 changes: 9 additions & 0 deletions flag_mutex_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ func newCommand() *Command {
Aliases: []string{"ai"},
Sources: EnvVars("T_VAR"),
},
&BoolFlag{
Name: "q",
},
},
},
},
Expand Down Expand Up @@ -73,6 +76,12 @@ func TestFlagMutuallyExclusiveFlags(t *testing.T) {
errStr: "option i cannot be set along with option ai",
required: true,
},
{
name: "required both set second member",
args: []string{"--i", "11", "--q"},
errStr: "option i cannot be set along with option q",
required: true,
},
{
name: "set env var",
required: true,
Expand Down