fmt, lint, + vet commands/
Juan Batiz-Benet committed
Oct 20, 2014 at 07:31 UTC
7673ce6f65ce84179f4a65f40c6516b335f6eefd
6 files changed
+130
-117
commands/cli/parse.go
+52
-50
@@ -1,81 +1,83 @@
1
package cli
2
3
import (
4
- "fmt"
5
- "strings"
4
+ "fmt"
5
+ "strings"
6
7
- "github.com/jbenet/go-ipfs/commands"
7
+ "github.com/jbenet/go-ipfs/commands"
8
)
9
10
+// Parse parses the input commandline string (cmd, flags, and args).
11
+// returns the corresponding command Request object.
12
func Parse(input []string, root *commands.Command) (*commands.Request, error) {
11
- path, input, err := parsePath(input, root)
12
- if err != nil {
13
- return nil, err
14
- }
13
+ path, input, err := parsePath(input, root)
14
+ if err != nil {
15
+ return nil, err
16
+ }
17
16
- opts, args, err := parseOptions(input)
17
- if err != nil {
18
- return nil, err
19
- }
18
+ opts, args, err := parseOptions(input)
19
+ if err != nil {
20
+ return nil, err
21
+ }
22
21
- return commands.NewRequest(path, opts, args), nil
23
+ return commands.NewRequest(path, opts, args), nil
24
}
25
26
// parsePath gets the command path from the command line input
27
func parsePath(input []string, root *commands.Command) ([]string, []string, error) {
26
- cmd := root
27
- i := 0
28
+ cmd := root
29
+ i := 0
30
29
- for _, blob := range input {
30
- if strings.HasPrefix(blob, "-") {
31
- break
32
- }
31
+ for _, blob := range input {
32
+ if strings.HasPrefix(blob, "-") {
33
+ break
34
+ }
35
34
- cmd := cmd.Sub(blob)
35
- if cmd == nil {
36
- break
37
- }
36
+ cmd := cmd.Sub(blob)
37
+ if cmd == nil {
38
+ break
39
+ }
40
39
- i++
40
- }
41
+ i++
42
+ }
43
42
- return input[:i], input[i:], nil
44
+ return input[:i], input[i:], nil
45
}
46
47
// parseOptions parses the raw string values of the given options
48
// returns the parsed options as strings, along with the CLI args
49
func parseOptions(input []string) (map[string]interface{}, []string, error) {
48
- opts := make(map[string]interface{})
49
- args := make([]string, 0)
50
+ opts := make(map[string]interface{})
51
+ args := []string{}
52
51
- for i := 0; i < len(input); i++ {
52
- blob := input[i]
53
+ for i := 0; i < len(input); i++ {
54
+ blob := input[i]
55
54
- if strings.HasPrefix(blob, "-") {
55
- name := blob[1:]
56
- value := ""
56
+ if strings.HasPrefix(blob, "-") {
57
+ name := blob[1:]
58
+ value := ""
59
58
- // support single and double dash
59
- if strings.HasPrefix(name, "-") {
60
- name = name[1:]
61
- }
60
+ // support single and double dash
61
+ if strings.HasPrefix(name, "-") {
62
+ name = name[1:]
63
+ }
64
63
- if strings.Contains(name, "=") {
64
- split := strings.SplitN(name, "=", 2)
65
- name = split[0]
66
- value = split[1]
67
- }
65
+ if strings.Contains(name, "=") {
66
+ split := strings.SplitN(name, "=", 2)
67
+ name = split[0]
68
+ value = split[1]
69
+ }
70
69
- if _, ok := opts[name]; ok {
70
- return nil, nil, fmt.Errorf("Duplicate values for option '%s'", name)
71
- }
71
+ if _, ok := opts[name]; ok {
72
+ return nil, nil, fmt.Errorf("Duplicate values for option '%s'", name)
73
+ }
74
73
- opts[name] = value
75
+ opts[name] = value
76
75
- } else {
76
- args = append(args, blob)
77
- }
78
- }
77
+ } else {
78
+ args = append(args, blob)
79
+ }
80
+ }
81
80
- return opts, args, nil
82
+ return opts, args, nil
83
}
commands/cli/parse_test.go
+37
-37
@@ -1,48 +1,48 @@
1
package cli
2
3
import (
4
- //"fmt"
5
- "testing"
4
+ //"fmt"
5
+ "testing"
6
7
- "github.com/jbenet/go-ipfs/commands"
7
+ "github.com/jbenet/go-ipfs/commands"
8
)
9
10
func TestOptionParsing(t *testing.T) {
11
- cmd := &commands.Command{
12
- Options: []commands.Option{
13
- commands.Option{ []string{"b"}, commands.String },
14
- },
15
- }
16
- cmd.Register("test", &commands.Command{})
11
+ cmd := &commands.Command{
12
+ Options: []commands.Option{
13
+ commands.Option{Names: []string{"b"}, Type: commands.String},
14
+ },
15
+ }
16
+ cmd.Register("test", &commands.Command{})
17
18
- opts, input, err := parseOptions([]string{ "--beep", "-boop=lol", "test2", "-c", "beep", "--foo=5" })
19
- /*for k, v := range opts {
20
- fmt.Printf("%s: %s\n", k, v)
21
- }
22
- fmt.Printf("%s\n", input)*/
23
- if err != nil {
24
- t.Error("Should have passed")
25
- }
26
- if len(opts) != 4 || opts["beep"] != "" || opts["boop"] != "lol" || opts["c"] != "" || opts["foo"] != "5" {
27
- t.Error("Returned options were defferent than expected: %v", opts)
28
- }
29
- if len(input) != 2 || input[0] != "test2" || input[1] != "beep" {
30
- t.Error("Returned input was different than expected: %v", input)
31
- }
18
+ opts, input, err := parseOptions([]string{"--beep", "-boop=lol", "test2", "-c", "beep", "--foo=5"})
19
+ /*for k, v := range opts {
20
+ fmt.Printf("%s: %s\n", k, v)
21
+ }
22
+ fmt.Printf("%s\n", input)*/
23
+ if err != nil {
24
+ t.Error("Should have passed")
25
+ }
26
+ if len(opts) != 4 || opts["beep"] != "" || opts["boop"] != "lol" || opts["c"] != "" || opts["foo"] != "5" {
27
+ t.Error("Returned options were defferent than expected: %v", opts)
28
+ }
29
+ if len(input) != 2 || input[0] != "test2" || input[1] != "beep" {
30
+ t.Error("Returned input was different than expected: %v", input)
31
+ }
32
33
- _, _, err = parseOptions([]string{ "-beep=1", "-boop=2", "-beep=3" })
34
- if err == nil {
35
- t.Error("Should have failed (duplicate option name)")
36
- }
33
+ _, _, err = parseOptions([]string{"-beep=1", "-boop=2", "-beep=3"})
34
+ if err == nil {
35
+ t.Error("Should have failed (duplicate option name)")
36
+ }
37
38
- path, args, err := parsePath([]string{ "test", "beep", "boop" }, cmd)
39
- if err != nil {
40
- t.Error("Should have passed")
41
- }
42
- if len(path) != 1 || path[0] != "test" {
43
- t.Error("Returned path was defferent than expected: %v", path)
44
- }
45
- if len(args) != 2 || args[0] != "beep" || args[1] != "boop" {
46
- t.Error("Returned args were different than expected: %v", args)
47
- }
38
+ path, args, err := parsePath([]string{"test", "beep", "boop"}, cmd)
39
+ if err != nil {
40
+ t.Error("Should have passed")
41
+ }
42
+ if len(path) != 1 || path[0] != "test" {
43
+ t.Error("Returned path was defferent than expected: %v", path)
44
+ }
45
+ if len(args) != 2 || args[0] != "beep" || args[1] != "boop" {
46
+ t.Error("Returned args were different than expected: %v", args)
47
+ }
48
}
commands/command.go
+8
-5
@@ -6,6 +6,7 @@ import (
6
"strings"
7
)
8
9
+// Command is an object that defines a command.
10
type Command struct {
11
Help string
12
Options []Option
@@ -13,7 +14,8 @@ type Command struct {
14
subcommands map[string]*Command
15
}
16
16
-var NotCallableError = errors.New("This command can't be called directly. Try one of its subcommands.")
17
+// ErrNotCallable signals a command that cannot be called.
18
+var ErrNotCallable = errors.New("This command can't be called directly. Try one of its subcommands.")
19
20
// Register adds a subcommand
21
func (c *Command) Register(id string, sub *Command) error {
@@ -44,25 +46,25 @@ func (c *Command) Call(req *Request) *Response {
46
47
cmds, err := c.Resolve(req.path)
48
if err != nil {
47
- res.SetError(err, Client)
49
+ res.SetError(err, ErrClient)
50
return res
51
}
52
cmd := cmds[len(cmds)-1]
53
54
if cmd.f == nil {
53
- res.SetError(NotCallableError, Client)
55
+ res.SetError(ErrNotCallable, ErrClient)
56
return res
57
}
58
59
options, err := c.GetOptions(req.path)
60
if err != nil {
59
- res.SetError(err, Client)
61
+ res.SetError(err, ErrClient)
62
return res
63
}
64
65
err = req.convertOptions(options)
66
if err != nil {
65
- res.SetError(err, Client)
67
+ res.SetError(err, ErrClient)
68
return res
69
}
70
@@ -91,6 +93,7 @@ func (c *Command) Resolve(path []string) ([]*Command, error) {
93
return cmds, nil
94
}
95
96
+// Get resolves and returns the Command addressed by path
97
func (c *Command) Get(path []string) (*Command, error) {
98
cmds, err := c.Resolve(path)
99
if err != nil {
commands/option.go
+3
-2
@@ -2,6 +2,7 @@ package commands
2
3
import "reflect"
4
5
+// Types of Command options
6
const (
7
Invalid = reflect.Invalid
8
Bool = reflect.Bool
@@ -22,11 +23,11 @@ type Option struct {
23
}
24
25
// options that are used by this package
25
-var globalOptions []Option = []Option{
26
+var globalOptions = []Option{
27
Option{[]string{"enc", "encoding"}, String},
28
}
29
30
// the above array of Options, wrapped in a Command
30
-var globalCommand *Command = &Command{
31
+var globalCommand = &Command{
32
Options: globalOptions,
33
}
commands/response.go
+28
-21
@@ -7,11 +7,13 @@ import (
7
"strings"
8
)
9
10
+// ErrorType signfies a category of errors
11
type ErrorType uint
12
13
+// ErrorTypes convey what category of error ocurred
14
const (
13
- Normal ErrorType = iota // general errors
14
- Client // error was caused by the client, (e.g. invalid CLI usage)
15
+ ErrNormal ErrorType = iota // general errors
16
+ ErrClient // error was caused by the client, (e.g. invalid CLI usage)
17
// TODO: add more types of errors for better error-specific handling
18
)
19
@@ -21,37 +23,44 @@ type Error struct {
23
Code ErrorType
24
}
25
26
+func (e *Error) Error() string {
27
+ return fmt.Sprintf("%d error: %s", e.Code, e.Message)
28
+}
29
+
30
+// EncodingType defines a supported encoding
31
type EncodingType string
32
33
+// Supported EncodingType constants.
34
const (
27
- Json = "json"
28
- Xml = "xml"
35
+ JSON = "json"
36
+ XML = "xml"
37
// TODO: support more encoding types
38
)
39
40
+// Marshaller is a function used by coding types.
41
+// TODO this should just be a `coding.Codec`
42
type Marshaller func(v interface{}) ([]byte, error)
43
44
var marshallers = map[EncodingType]Marshaller{
35
- Json: json.Marshal,
36
- Xml: xml.Marshal,
45
+ JSON: json.Marshal,
46
+ XML: xml.Marshal,
47
}
48
49
+// Response is the result of a command request. Handlers write to the response,
50
+// setting Error or Value. Response is returned to the client.
51
type Response struct {
40
- req *Request
41
- Error error
42
- ErrorType ErrorType
43
- Value interface{}
44
-}
45
-
46
-func (r *Response) SetError(err error, errType ErrorType) {
47
- r.Error = err
48
- r.ErrorType = errType
52
+ req *Request
53
+ Error *Error
54
+ Value interface{}
55
}
56
51
-func (r *Response) FormatError() Error {
52
- return Error{r.Error.Error(), r.ErrorType}
57
+// SetError updates the response Error.
58
+func (r *Response) SetError(err error, code ErrorType) {
59
+ r.Error = &Error{Message: err.Error(), Code: code}
60
}
61
62
+// Marshal marshals out the response into a buffer. It uses the EncodingType
63
+// on the Request to chose a Marshaller (Codec).
64
func (r *Response) Marshal() ([]byte, error) {
65
if r.Error == nil && r.Value == nil {
66
return nil, fmt.Errorf("No error or value set, there is nothing to marshal")
@@ -69,9 +78,7 @@ func (r *Response) Marshal() ([]byte, error) {
78
}
79
80
if r.Error != nil {
72
- err := r.FormatError()
73
- return marshaller(err)
74
- } else {
75
- return marshaller(r.Value)
81
+ return marshaller(r.Error)
82
}
83
+ return marshaller(r.Value)
84
}
commands/response_test.go
+2
-2
@@ -30,7 +30,7 @@ func TestMarshalling(t *testing.T) {
30
t.Error("Should have failed (no encoding type specified in request)")
31
}
32
33
- req.SetOption("enc", Json)
33
+ req.SetOption("enc", JSON)
34
req.convertOptions(options)
35
36
bytes, err := res.Marshal()
@@ -42,7 +42,7 @@ func TestMarshalling(t *testing.T) {
42
t.Error("Incorrect JSON output")
43
}
44
45
- res.SetError(fmt.Errorf("You broke something!"), Client)
45
+ res.SetError(fmt.Errorf("You broke something!"), ErrClient)
46
bytes, err = res.Marshal()
47
if err != nil {
48
t.Error("Should have passed")