AddOptionNames func
Juan Batiz-Benet committed
Oct 20, 2014 at 07:52 UTC
84fa7bc46dd3821f1cee9166bfd4091748c2fdff
1 file changed
+32
-13
commands/command.go
+32
-13
@@ -30,15 +30,11 @@ func (c *Command) Register(id string, sub *Command) error {
30
}
31
32
// check for duplicate option names (only checks downwards)
33
- names := make(map[string]bool)
34
- globalCommand.checkOptions(names)
35
- c.checkOptions(names)
36
- err := sub.checkOptions(names)
37
- if err != nil {
33
+ if err := checkOptionClashes(globalCommand, c, sub); err != nil {
34
return err
35
}
36
41
- if _, ok := c.subcommands[id]; ok {
37
+ if _, found := c.subcommands[id]; found {
38
return fmt.Errorf("There is already a subcommand registered with id '%s'", id)
39
}
40
@@ -137,19 +133,42 @@ func (c *Command) Sub(id string) *Command {
133
return c.subcommands[id]
134
}
135
140
-func (c *Command) checkOptions(names map[string]bool) error {
136
+// AddOptionNames returns a map of all command options names, and the command
137
+// they belong to. Will error if names clash in the command hierarchy.
138
+func AddOptionNames(c *Command, names map[string]*Command) error {
139
+
140
for _, opt := range c.Options {
141
for _, name := range opt.Names {
143
- if _, ok := names[name]; ok {
144
- return fmt.Errorf("Multiple options are using the same name ('%s')", name)
142
+ if c2, found := names[name]; found {
143
+
144
+ // option can be reused in same command, but more often than not
145
+ // the clash will be across commands so error out with that, as
146
+ // commands tell us where the problem is
147
+ errstr := "Option name ('%s') used multiple times (%v, %v)"
148
+ return fmt.Errorf(errstr, c2, c)
149
}
146
- names[name] = true
150
+
151
+ // mark the name as in use
152
+ names[name] = c
153
+ }
154
+ }
155
+
156
+ // for every subcommand, recurse
157
+ for _, c2 := range c.subcommands {
158
+ if err := AddOptionNames(c2, names); err != nil {
159
+ return err
160
}
161
}
162
150
- for _, cmd := range c.subcommands {
151
- err := cmd.checkOptions(names)
152
- if err != nil {
163
+ return nil
164
+}
165
+
166
+// checkOptionClashes checks all command option names for clashes
167
+func checkOptionClashes(cmds ...*Command) error {
168
+ names := map[string]*Command{}
169
+
170
+ for _, c := range cmds {
171
+ if err := AddOptionNames(c, names); err != nil {
172
return err
173
}
174
}