commands: Moved argument checking into a Command method, fail early when parsing commands
Matt Bell committed
Nov 3, 2014 at 14:12 UTC
75649f3d4979a6a5746cfc47c7dcc7a60d6b914f
4 files changed
+60
-49
commands/cli/parse.go
+8
-3
@@ -45,7 +45,14 @@ func Parse(input []string, roots ...*cmds.Command) (cmds.Request, *cmds.Command,
45
return nil, nil, err
46
}
47
48
- return cmds.NewRequest(path, opts, args, cmd), root, nil
48
+ req := cmds.NewRequest(path, opts, args, cmd)
49
+
50
+ err = cmd.CheckArguments(req)
51
+ if err != nil {
52
+ return nil, nil, err
53
+ }
54
+
55
+ return req, root, nil
56
}
57
58
// parsePath gets the command path from the command line input
@@ -108,8 +115,6 @@ func parseOptions(input []string) (map[string]interface{}, []string, error) {
115
return opts, args, nil
116
}
117
111
-// Note that the argument handling here is dumb, it does not do any error-checking.
112
-// (Arguments are further processed when the request is passed to the command to run)
118
func parseArgs(stringArgs []string, cmd *cmds.Command) ([]interface{}, error) {
119
var argDef cmds.Argument
120
args := make([]interface{}, len(stringArgs))
commands/command.go
+44
-1
@@ -3,6 +3,7 @@ package commands
3
import (
4
"errors"
5
"fmt"
6
+ "io"
7
"strings"
8
9
u "github.com/jbenet/go-ipfs/util"
@@ -58,7 +59,7 @@ func (c *Command) Call(req Request) Response {
59
return res
60
}
61
61
- err = req.CheckArguments(cmd.Arguments)
62
+ err = cmd.CheckArguments(req)
63
if err != nil {
64
res.SetError(err, ErrClient)
65
return res
@@ -138,6 +139,48 @@ func (c *Command) GetOptions(path []string) (map[string]Option, error) {
139
return optionsMap, nil
140
}
141
142
+func (c *Command) CheckArguments(req Request) error {
143
+ var argDef Argument
144
+ args := req.Arguments()
145
+
146
+ var length int
147
+ if len(args) > len(c.Arguments) {
148
+ length = len(args)
149
+ } else {
150
+ length = len(c.Arguments)
151
+ }
152
+
153
+ for i := 0; i < length; i++ {
154
+ var arg interface{}
155
+ if len(args) > i {
156
+ arg = args[i]
157
+ }
158
+
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))
163
+ }
164
+
165
+ if argDef.Required && arg == nil {
166
+ return fmt.Errorf("Argument '%s' is required", argDef.Name)
167
+ }
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)
177
+ }
178
+ }
179
+ }
180
+
181
+ return nil
182
+}
183
+
184
// Subcommand returns the subcommand with the given id
185
func (c *Command) Subcommand(id string) *Command {
186
return c.Subcommands[id]
commands/http/parse.go
+8
-1
@@ -51,7 +51,14 @@ func Parse(r *http.Request, root *cmds.Command) (cmds.Request, error) {
51
}
52
}
53
54
- return cmds.NewRequest(path, opts, args, cmd), nil
54
+ req := cmds.NewRequest(path, opts, args, cmd)
55
+
56
+ err = cmd.CheckArguments(req)
57
+ if err != nil {
58
+ return nil, err
59
+ }
60
+
61
+ return req, nil
62
}
63
64
func parseOptions(r *http.Request) (map[string]interface{}, []string) {
commands/request.go
-44
@@ -2,7 +2,6 @@ package commands
2
3
import (
4
"fmt"
5
- "io"
5
"reflect"
6
"strconv"
7
@@ -29,7 +28,6 @@ type Request interface {
28
SetContext(Context)
29
Command() *Command
30
32
- CheckArguments(args []Argument) error
31
ConvertOptions(options map[string]Option) error
32
}
33
@@ -103,48 +101,6 @@ var converters = map[reflect.Kind]converter{
101
},
102
}
103
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
- var length int
111
- if len(r.arguments) > len(args) {
112
- length = len(r.arguments)
113
- } else {
114
- length = len(args)
115
- }
116
-
117
- for i := 0; i < length; i++ {
118
- var arg interface{}
119
- if len(r.arguments) > i {
120
- arg = r.arguments[i]
121
- }
122
-
123
- if i < len(args) {
124
- argDef = args[i]
125
- } else if !argDef.Variadic {
126
- return fmt.Errorf("Expected %v arguments, got %v", len(args), len(r.arguments))
127
- }
128
-
129
- if argDef.Required && arg == nil {
130
- return fmt.Errorf("Argument '%s' is required", argDef.Name)
131
- }
132
- if argDef.Type == ArgFile {
133
- _, ok := arg.(io.Reader)
134
- if !ok {
135
- return fmt.Errorf("Argument '%s' isn't valid", argDef.Name)
136
- }
137
- } else if argDef.Type == ArgString {
138
- _, ok := arg.(string)
139
- if !ok {
140
- return fmt.Errorf("Argument '%s' must be a string", argDef.Name)
141
- }
142
- }
143
- }
144
-
145
- return nil
146
-}
147
-
104
func (r *request) ConvertOptions(options map[string]Option) error {
105
converted := make(map[string]interface{})
106