@cryptotaxi247 / kubo / commits / 75649f3d4

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