commands: Check argument validity when running commands
Matt Bell committed
Nov 2, 2014 at 20:26 UTC
e8d0cbff1dfa4fc964eb7345cf36192a476ce26d
2 files changed
+44
commands/command.go
+12
@@ -19,6 +19,12 @@ type Function func(Response, Request)
19
// MAYBE_TODO: maybe this should be a io.Reader instead of a string?
20
type Formatter func(Response) (string, error)
21
22
+// TODO: check Argument definitions when creating a Command
23
+// (might need to use a Command constructor)
24
+// * make sure any variadic args are at the end
25
+// * make sure there aren't duplicate names
26
+// * make sure optional arguments aren't followed by required arguments
27
+
28
// Command is a runnable command, with input arguments and options (flags).
29
// It can also have Subcommands, to group units of work into sets.
30
type Command struct {
@@ -52,6 +58,12 @@ func (c *Command) Call(req Request) Response {
58
return res
59
}
60
61
+ err = req.CheckArguments(cmd.Arguments)
62
+ if err != nil {
63
+ res.SetError(err, ErrClient)
64
+ return res
65
+ }
66
+
67
options, err := c.GetOptions(req.Path())
68
if err != nil {
69
res.SetError(err, ErrClient)
commands/request.go
+32
@@ -2,6 +2,7 @@ package commands
2
3
import (
4
"fmt"
5
+ "io"
6
"reflect"
7
"strconv"
8
@@ -28,6 +29,7 @@ type Request interface {
29
SetContext(Context)
30
Command() *Command
31
32
+ CheckArguments(args []Argument) error
33
ConvertOptions(options map[string]Option) error
34
}
35
@@ -101,6 +103,36 @@ var converters = map[reflect.Kind]converter{
103
},
104
}
105
106
+// MAYBE_TODO: maybe this should be a Command method? (taking a Request as a param)
107
+func (r *request) CheckArguments(args []Argument) error {
108
+ var argDef Argument
109
+
110
+ for i, arg := range r.arguments {
111
+ if i < len(args) {
112
+ argDef = args[i]
113
+ } else if !argDef.Variadic {
114
+ return fmt.Errorf("Expected %v arguments, got %v", len(args), len(r.arguments))
115
+ }
116
+
117
+ if argDef.Required && arg == nil {
118
+ return fmt.Errorf("Argument '%s' is required", argDef.Name)
119
+ }
120
+ if argDef.Type == ArgFile {
121
+ _, ok := arg.(io.Reader)
122
+ if !ok {
123
+ return fmt.Errorf("Argument '%s' isn't valid", argDef.Name)
124
+ }
125
+ } else if argDef.Type == ArgString {
126
+ _, ok := arg.(string)
127
+ if !ok {
128
+ return fmt.Errorf("Argument '%s' must be a string", argDef.Name)
129
+ }
130
+ }
131
+ }
132
+
133
+ return nil
134
+}
135
+
136
func (r *request) ConvertOptions(options map[string]Option) error {
137
converted := make(map[string]interface{})
138