commands: Cleaned up argument validation
Matt Bell committed
Nov 3, 2014 at 18:34 UTC
bc6938dc0899c4f37b4afa1f7b32c8bc7cdfb618
1 file changed
+49
-26
commands/command.go
+49
-26
@@ -140,40 +140,37 @@ func (c *Command) GetOptions(path []string) (map[string]Option, error) {
140
}
141
142
func (c *Command) CheckArguments(req Request) error {
143
- var argDef Argument
143
args := req.Arguments()
144
+ argDefs := c.Arguments
145
146
- var length int
147
- if len(args) > len(c.Arguments) {
148
- length = len(args)
149
- } else {
150
- length = len(c.Arguments)
146
+ // if we have more arg values provided than argument definitions,
147
+ // and the last arg definition is not variadic (or there are no definitions), return an error
148
+ notVariadic := len(argDefs) == 0 || !argDefs[len(argDefs)-1].Variadic
149
+ if notVariadic && len(args) > len(argDefs) {
150
+ return fmt.Errorf("Expected %v arguments, got %v", len(argDefs), len(args))
151
}
152
153
- for i := 0; i < length; i++ {
154
- var arg interface{}
155
- if len(args) > i {
156
- arg = args[i]
157
- }
153
+ // iterate over the arg definitions
154
+ for i, argDef := range c.Arguments {
155
159
- if i < len(c.Arguments) {
160
- argDef = c.Arguments[i]
161
- } else if !argDef.Variadic {
162
- return fmt.Errorf("Expected %v arguments, got %v", len(c.Arguments), len(args))
156
+ // the value for this argument definition. can be nil if it wasn't provided by the caller
157
+ var v interface{}
158
+ if i < len(args) {
159
+ v = args[i]
160
}
161
165
- if argDef.Required && arg == nil {
166
- return fmt.Errorf("Argument '%s' is required", argDef.Name)
162
+ err := checkArgValue(v, argDef)
163
+ if err != nil {
164
+ return err
165
}
168
- if argDef.Type == ArgFile {
169
- _, ok := arg.(io.Reader)
170
- if !ok {
171
- return fmt.Errorf("Argument '%s' isn't valid", argDef.Name)
172
- }
173
- } else if argDef.Type == ArgString {
174
- _, ok := arg.(string)
175
- if !ok {
176
- return fmt.Errorf("Argument '%s' must be a string", argDef.Name)
166
+
167
+ // any additional values are for the variadic arg definition
168
+ if argDef.Variadic && i < len(args)-1 {
169
+ for _, val := range args[i+1:] {
170
+ err := checkArgValue(val, argDef)
171
+ if err != nil {
172
+ return err
173
+ }
174
}
175
}
176
}
@@ -185,3 +182,29 @@ func (c *Command) CheckArguments(req Request) error {
182
func (c *Command) Subcommand(id string) *Command {
183
return c.Subcommands[id]
184
}
185
+
186
+// checkArgValue returns an error if a given arg value is not valid for the given Argument
187
+func checkArgValue(v interface{}, def Argument) error {
188
+ if v == nil {
189
+ if def.Required {
190
+ return fmt.Errorf("Argument '%s' is required", def.Name)
191
+ }
192
+
193
+ return nil
194
+ }
195
+
196
+ if def.Type == ArgFile {
197
+ _, ok := v.(io.Reader)
198
+ if !ok {
199
+ return fmt.Errorf("Argument '%s' isn't valid", def.Name)
200
+ }
201
+
202
+ } else if def.Type == ArgString {
203
+ _, ok := v.(string)
204
+ if !ok {
205
+ return fmt.Errorf("Argument '%s' must be a string", def.Name)
206
+ }
207
+ }
208
+
209
+ return nil
210
+}