@cryptotaxi247 / kubo / commits / 84fa7bc46

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 }