@cryptotaxi247 / kubo / commits / e8d0cbff1

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