From e8d0cbff1dfa4fc964eb7345cf36192a476ce26d Mon Sep 17 00:00:00 2001 From: Matt Bell Date: Sun, 2 Nov 2014 20:26:27 -0800 Subject: [PATCH] commands: Check argument validity when running commands --- commands/command.go | 12 ++++++++++++ commands/request.go | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/commands/command.go b/commands/command.go index cf10c63b6..ea3dc2e5d 100644 --- a/commands/command.go +++ b/commands/command.go @@ -19,6 +19,12 @@ type Function func(Response, Request) // MAYBE_TODO: maybe this should be a io.Reader instead of a string? type Formatter func(Response) (string, error) +// TODO: check Argument definitions when creating a Command +// (might need to use a Command constructor) +// * make sure any variadic args are at the end +// * make sure there aren't duplicate names +// * make sure optional arguments aren't followed by required arguments + // Command is a runnable command, with input arguments and options (flags). // It can also have Subcommands, to group units of work into sets. type Command struct { @@ -52,6 +58,12 @@ func (c *Command) Call(req Request) Response { return res } + err = req.CheckArguments(cmd.Arguments) + if err != nil { + res.SetError(err, ErrClient) + return res + } + options, err := c.GetOptions(req.Path()) if err != nil { res.SetError(err, ErrClient) diff --git a/commands/request.go b/commands/request.go index c26f1773b..974f97ff3 100644 --- a/commands/request.go +++ b/commands/request.go @@ -2,6 +2,7 @@ package commands import ( "fmt" + "io" "reflect" "strconv" @@ -28,6 +29,7 @@ type Request interface { SetContext(Context) Command() *Command + CheckArguments(args []Argument) error ConvertOptions(options map[string]Option) error } @@ -101,6 +103,36 @@ var converters = map[reflect.Kind]converter{ }, } +// MAYBE_TODO: maybe this should be a Command method? (taking a Request as a param) +func (r *request) CheckArguments(args []Argument) error { + var argDef Argument + + for i, arg := range r.arguments { + if i < len(args) { + argDef = args[i] + } else if !argDef.Variadic { + return fmt.Errorf("Expected %v arguments, got %v", len(args), len(r.arguments)) + } + + if argDef.Required && arg == nil { + return fmt.Errorf("Argument '%s' is required", argDef.Name) + } + if argDef.Type == ArgFile { + _, ok := arg.(io.Reader) + if !ok { + return fmt.Errorf("Argument '%s' isn't valid", argDef.Name) + } + } else if argDef.Type == ArgString { + _, ok := arg.(string) + if !ok { + return fmt.Errorf("Argument '%s' must be a string", argDef.Name) + } + } + } + + return nil +} + func (r *request) ConvertOptions(options map[string]Option) error { converted := make(map[string]interface{})