@cryptotaxi247 / kubo / commits / 3e507f7c9

commands: Changed option accessor API (Request#Option now returns an OptionValue)

Matt Bell committed Nov 10, 2014 at 21:30 UTC 3e507f7c9f5488e69aafb9be7f5da00702bfeafb
14 files changed +182 -169
cmd/ipfs2/init.go
+12 -14
@@ -20,30 +20,28 @@ var initCmd = &cmds.Command{
20 `,
21
22 Options: []cmds.Option{
23 - cmds.IntOption("bits", "b", "Number of bits to use in the generated RSA private key (defaults to 4096)"),
23 + cmds.UintOption("bits", "b", "Number of bits to use in the generated RSA private key (defaults to 4096)"),
24 cmds.StringOption("passphrase", "p", "Passphrase for encrypting the private key"),
25 cmds.BoolOption("force", "f", "Overwrite existing config (if it exists)"),
26 cmds.StringOption("datastore", "d", "Location for the IPFS data store"),
27 },
28 Run: func(req cmds.Request) (interface{}, error) {
29
30 - arg, found := req.Option("d")
31 - dspath, ok := arg.(string)
32 - if found && !ok {
33 - return nil, errors.New("failed to parse datastore flag")
30 + dspath, err := req.Option("d").String()
31 + if err != nil {
32 + return nil, err
33 }
34
36 - arg, found = req.Option("f")
37 - force, ok := arg.(bool) // TODO param
38 - if found && !ok {
39 - return nil, errors.New("failed to parse force flag")
35 + force, err := req.Option("f").Bool()
36 + if err != nil {
37 + return nil, err
38 }
39
42 - arg, found = req.Option("b")
43 - nBitsForKeypair, ok := arg.(int) // TODO param
44 - if found && !ok {
45 - return nil, errors.New("failed to get bits flag")
46 - } else if !found {
40 + nBitsForKeypair, err := req.Option("b").Int()
41 + if err != nil {
42 + return nil, err
43 + }
44 + if !req.Option("b").Found() {
45 nBitsForKeypair = 4096
46 }
47
cmd/ipfs2/main.go
+29 -43
@@ -66,10 +66,7 @@ func createRequest(args []string) (cmds.Request, *cmds.Command) {
66 // or if a path was returned (user specified a valid subcommand), show the error message
67 // (this means there was an option or argument error)
68 if path != nil && len(path) > 0 {
69 - help := false
70 - opt, _ := req.Option("help")
71 - help, _ = opt.(bool)
72 -
69 + help, _ := req.Option("help").Bool()
70 if !help {
71 fmt.Printf(errorFormat, err)
72 }
@@ -108,7 +105,7 @@ func createRequest(args []string) (cmds.Request, *cmds.Command) {
105 ctx.ConfigRoot = configPath
106 ctx.Config = conf
107
111 - if _, found := req.Option("encoding"); !found {
108 + if !req.Option("encoding").Found() {
109 if req.Command().Marshallers != nil && req.Command().Marshallers[cmds.Text] != nil {
110 req.SetOption("encoding", cmds.Text)
111 } else {
@@ -120,30 +117,25 @@ func createRequest(args []string) (cmds.Request, *cmds.Command) {
117 }
118
119 func handleOptions(req cmds.Request, root *cmds.Command) {
123 - if help, found := req.Option("help"); found {
124 - if helpBool, ok := help.(bool); helpBool && ok {
125 - helpText, err := cmdsCli.HelpText("ipfs", root, req.Path())
126 - if err != nil {
127 - fmt.Println(err.Error())
128 - } else {
129 - fmt.Println(helpText)
130 - }
131 - exit(0)
132 - } else if !ok {
133 - fmt.Println("error: expected 'help' option to be a bool")
134 - exit(1)
120 + if help, err := req.Option("help").Bool(); help && err == nil {
121 + helpText, err := cmdsCli.HelpText("ipfs", root, req.Path())
122 + if err != nil {
123 + fmt.Println(err.Error())
124 + } else {
125 + fmt.Println(helpText)
126 }
127 + exit(0)
128 + } else if err != nil {
129 + fmt.Println(err)
130 + exit(1)
131 }
132
138 - if debug, found := req.Option("debug"); found {
139 - if debugBool, ok := debug.(bool); debugBool && ok {
140 - u.Debug = true
141 -
142 - u.SetAllLoggers(logging.DEBUG)
143 - } else if !ok {
144 - fmt.Println("error: expected 'debug' option to be a bool")
145 - exit(1)
146 - }
133 + if debug, err := req.Option("debug").Bool(); debug && err == nil {
134 + u.Debug = true
135 + u.SetAllLoggers(logging.DEBUG)
136 + } else if err != nil {
137 + fmt.Println(err)
138 + exit(1)
139 }
140 }
141
@@ -154,19 +146,13 @@ func callCommand(req cmds.Request, root *cmds.Command) cmds.Response {
146 res = root.Call(req)
147
148 } else {
157 - var found bool
158 - var local interface{}
159 - localBool := false
160 - if local, found = req.Option("local"); found {
161 - var ok bool
162 - localBool, ok = local.(bool)
163 - if !ok {
164 - fmt.Println("error: expected 'local' option to be a bool")
165 - exit(1)
166 - }
149 + local, err := req.Option("local").Bool()
150 + if err != nil {
151 + fmt.Println(err)
152 + exit(1)
153 }
154
169 - if (!found || !localBool) && daemon.Locked(req.Context().ConfigRoot) {
155 + if (!req.Option("local").Found() || !local) && daemon.Locked(req.Context().ConfigRoot) {
156 addr, err := ma.NewMultiaddr(req.Context().Config.Addresses.API)
157 if err != nil {
158 fmt.Println(err)
@@ -229,12 +215,12 @@ func outputResponse(res cmds.Response, root *cmds.Command) {
215 }
216
217 func getConfigRoot(req cmds.Request) (string, error) {
232 - if opt, found := req.Option("config"); found {
233 - if optStr, ok := opt.(string); ok {
234 - return optStr, nil
235 - } else {
236 - return "", fmt.Errorf("Expected 'config' option to be a string")
237 - }
218 + configOpt, err := req.Option("config").String()
219 + if err != nil {
220 + return "", err
221 + }
222 + if configOpt != "" {
223 + return configOpt, nil
224 }
225
226 configPath, err := config.PathRoot()
commands/command.go
+1 -7
@@ -66,13 +66,7 @@ func (c *Command) Call(req Request) Response {
66 return res
67 }
68
69 - options, err := c.GetOptions(req.Path())
70 - if err != nil {
71 - res.SetError(err, ErrClient)
72 - return res
73 - }
74 -
75 - err = req.ConvertOptions(options)
69 + err = req.ConvertOptions()
70 if err != nil {
71 res.SetError(err, ErrClient)
72 return res
commands/command_test.go
+17 -22
@@ -15,29 +15,23 @@ func TestOptionValidation(t *testing.T) {
15 Run: noop,
16 }
17
18 - req := NewEmptyRequest()
19 - req.SetOption("beep", 5)
20 - req.SetOption("b", 10)
21 - res := cmd.Call(req)
22 - if res.Error() == nil {
23 - t.Error("Should have failed (duplicate options)")
24 - }
18 + opts, _ := cmd.GetOptions(nil)
19
26 - req = NewEmptyRequest()
27 - req.SetOption("beep", "foo")
28 - res = cmd.Call(req)
20 + req := NewRequest(nil, nil, nil, nil, opts)
21 + req.SetOption("beep", true)
22 + res := cmd.Call(req)
23 if res.Error() == nil {
24 t.Error("Should have failed (incorrect type)")
25 }
26
33 - req = NewEmptyRequest()
27 + req = NewRequest(nil, nil, nil, nil, opts)
28 req.SetOption("beep", 5)
29 res = cmd.Call(req)
30 if res.Error() != nil {
31 t.Error(res.Error(), "Should have passed")
32 }
33
40 - req = NewEmptyRequest()
34 + req = NewRequest(nil, nil, nil, nil, opts)
35 req.SetOption("beep", 5)
36 req.SetOption("boop", "test")
37 res = cmd.Call(req)
@@ -45,7 +39,7 @@ func TestOptionValidation(t *testing.T) {
39 t.Error("Should have passed")
40 }
41
48 - req = NewEmptyRequest()
42 + req = NewRequest(nil, nil, nil, nil, opts)
43 req.SetOption("b", 5)
44 req.SetOption("B", "test")
45 res = cmd.Call(req)
@@ -53,32 +47,32 @@ func TestOptionValidation(t *testing.T) {
47 t.Error("Should have passed")
48 }
49
56 - req = NewEmptyRequest()
50 + req = NewRequest(nil, nil, nil, nil, opts)
51 req.SetOption("foo", 5)
52 res = cmd.Call(req)
53 if res.Error() != nil {
54 t.Error("Should have passed")
55 }
56
63 - req = NewEmptyRequest()
57 + req = NewRequest(nil, nil, nil, nil, opts)
58 req.SetOption(EncShort, "json")
59 res = cmd.Call(req)
60 if res.Error() != nil {
61 t.Error("Should have passed")
62 }
63
70 - req = NewEmptyRequest()
64 + req = NewRequest(nil, nil, nil, nil, opts)
65 req.SetOption("b", "100")
66 res = cmd.Call(req)
67 if res.Error() != nil {
68 t.Error("Should have passed")
69 }
70
77 - req = NewEmptyRequest()
71 + req = NewRequest(nil, nil, nil, nil, opts)
72 req.SetOption("b", ":)")
73 res = cmd.Call(req)
74 if res.Error() == nil {
81 - t.Error(res.Error(), "Should have failed (string value not convertible to int)")
75 + t.Error("Should have failed (string value not convertible to int)")
76 }
77 }
78
@@ -107,13 +101,14 @@ func TestRegistration(t *testing.T) {
101 Run: noop,
102 }
103
110 - res := cmdB.Call(NewRequest([]string{"a"}, nil, nil, nil, nil))
111 - if res.Error() == nil {
104 + path := []string{"a"}
105 + _, err := cmdB.GetOptions(path)
106 + if err == nil {
107 t.Error("Should have failed (option name collision)")
108 }
109
115 - res = cmdC.Call(NewEmptyRequest())
116 - if res.Error() == nil {
110 + _, err = cmdC.GetOptions(nil)
111 + if err == nil {
112 t.Error("Should have failed (option name collision with global options)")
113 }
114 }
commands/http/client.go
+2 -18
@@ -34,23 +34,8 @@ func NewClient(address string) Client {
34 }
35
36 func (c *client) Send(req cmds.Request) (cmds.Response, error) {
37 - var userEncoding string
38 - if enc, found := req.Option(cmds.EncShort); found {
39 - var ok bool
40 - userEncoding, ok = enc.(string)
41 - if !ok {
42 - return nil, castError
43 - }
44 - req.SetOption(cmds.EncShort, cmds.JSON)
45 - } else {
46 - var ok bool
47 - enc, _ := req.Option(cmds.EncLong)
48 - userEncoding, ok = enc.(string)
49 - if !ok {
50 - return nil, castError
51 - }
52 - req.SetOption(cmds.EncLong, cmds.JSON)
53 - }
37 + userEncoding, _ := req.Option(cmds.EncShort).String()
38 + req.SetOption(cmds.EncShort, cmds.JSON)
39
40 query, inputStream, err := getQuery(req)
41 if err != nil {
@@ -72,7 +57,6 @@ func (c *client) Send(req cmds.Request) (cmds.Response, error) {
57
58 if len(userEncoding) > 0 {
59 req.SetOption(cmds.EncShort, userEncoding)
75 - req.SetOption(cmds.EncLong, userEncoding)
60 }
61
62 return res, nil
commands/http/handler.go
+3 -4
@@ -57,13 +57,12 @@ func (i Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
57 w.Header().Set(streamHeader, "1")
58
59 } else {
60 - enc, _ := req.Option(cmds.EncShort)
61 - encStr, ok := enc.(string)
62 - if !ok {
60 + enc, err := req.Option(cmds.EncShort).String()
61 + if err != nil || len(enc) == 0 {
62 w.WriteHeader(http.StatusInternalServerError)
63 return
64 }
66 - mime := mimeTypes[encStr]
65 + mime := mimeTypes[enc]
66 w.Header().Set("Content-Type", mime)
67 }
68
commands/option.go
+72 -2
@@ -1,6 +1,9 @@
1 package commands
2
3 -import "reflect"
3 +import (
4 + "errors"
5 + "reflect"
6 +)
7
8 // Types of Command options
9 const (
@@ -30,7 +33,7 @@ func NewOption(kind reflect.Kind, names ...string) Option {
33 }
34
35 desc := names[len(names)-1]
33 - names = names[:len(names)-2]
36 + names = names[:len(names)-1]
37
38 return Option{
39 Names: names,
@@ -55,6 +58,73 @@ func StringOption(names ...string) Option {
58 return NewOption(String, names...)
59 }
60
61 +type OptionValue struct {
62 + value interface{}
63 + found bool
64 +}
65 +
66 +// Found returns true if the option value was provided by the user (not a default value)
67 +func (ov OptionValue) Found() bool {
68 + return ov.found
69 +}
70 +
71 +// value accessor methods, gets the value as a certain type
72 +func (ov OptionValue) Bool() (bool, error) {
73 + val, ok := ov.value.(bool)
74 + if !ok {
75 + var err error
76 + if ov.value != nil {
77 + err = errors.New("error casting to bool")
78 + }
79 + return false, err
80 + }
81 + return val, nil
82 +}
83 +func (ov OptionValue) Int() (int, error) {
84 + val, ok := ov.value.(int)
85 + if !ok {
86 + var err error
87 + if ov.value != nil {
88 + err = errors.New("error casting to int")
89 + }
90 + return 0, err
91 + }
92 + return val, nil
93 +}
94 +func (ov OptionValue) Uint() (uint, error) {
95 + val, ok := ov.value.(uint)
96 + if !ok {
97 + var err error
98 + if ov.value != nil {
99 + err = errors.New("error casting to uint")
100 + }
101 + return 0, err
102 + }
103 + return val, nil
104 +}
105 +func (ov OptionValue) Float() (float64, error) {
106 + val, ok := ov.value.(float64)
107 + if !ok {
108 + var err error
109 + if ov.value != nil {
110 + err = errors.New("error casting to float64")
111 + }
112 + return 0.0, err
113 + }
114 + return val, nil
115 +}
116 +func (ov OptionValue) String() (string, error) {
117 + val, ok := ov.value.(string)
118 + if !ok {
119 + var err error
120 + if ov.value != nil {
121 + err = errors.New("error casting to string")
122 + }
123 + return "", err
124 + }
125 + return val, nil
126 +}
127 +
128 // Flag names
129 const (
130 EncShort = "enc"
commands/request.go
+24 -17
@@ -21,15 +21,15 @@ type Context struct {
21 // Request represents a call to a command from a consumer
22 type Request interface {
23 Path() []string
24 - Option(name string) (interface{}, bool)
25 - Options() map[string]interface{}
24 + Option(name string) *OptionValue
25 + Options() optMap
26 SetOption(name string, val interface{})
27 Arguments() []interface{} // TODO: make argument value type instead of using interface{}
28 Context() *Context
29 SetContext(Context)
30 Command() *Command
31
32 - ConvertOptions(options map[string]Option) error
32 + ConvertOptions() error
33 }
34
35 type request struct {
@@ -47,31 +47,34 @@ func (r *request) Path() []string {
47 }
48
49 // Option returns the value of the option for given name.
50 -func (r *request) Option(name string) (interface{}, bool) {
50 +func (r *request) Option(name string) *OptionValue {
51 val, found := r.options[name]
52 if found {
53 - return val, found
53 + return &OptionValue{val, found}
54 }
55
56 // if a value isn't defined for that name, we will try to look it up by its aliases
57
58 // find the option with the specified name
59 option, found := r.optionDefs[name]
60 - if found {
61 - // try all the possible names, break if we find a value
62 - for _, n := range option.Names {
63 - val, found := r.options[n]
64 - if found {
65 - return val, found
66 - }
60 + if !found {
61 + return nil
62 + }
63 +
64 + // try all the possible names, break if we find a value
65 + for _, n := range option.Names {
66 + val, found = r.options[n]
67 + if found {
68 + return &OptionValue{val, found}
69 }
70 }
71
70 - return nil, false
72 + // MAYBE_TODO: use default value instead of nil
73 + return &OptionValue{nil, false}
74 }
75
76 // Options returns a copy of the option map
74 -func (r *request) Options() map[string]interface{} {
77 +func (r *request) Options() optMap {
78 output := make(optMap)
79 for k, v := range r.options {
80 output[k] = v
@@ -136,11 +139,11 @@ var converters = map[reflect.Kind]converter{
139 },
140 }
141
139 -func (r *request) ConvertOptions(options map[string]Option) error {
142 +func (r *request) ConvertOptions() error {
143 converted := make(map[string]interface{})
144
145 for k, v := range r.options {
143 - opt, ok := options[k]
146 + opt, ok := r.optionDefs[k]
147 if !ok {
148 continue
149 }
@@ -203,5 +206,9 @@ func NewRequest(path []string, opts optMap, args []interface{}, cmd *Command, op
206 if optDefs == nil {
207 optDefs = make(map[string]Option)
208 }
206 - return &request{path, opts, args, cmd, Context{}, optDefs}
209 +
210 + req := &request{path, opts, args, cmd, Context{}, optDefs}
211 + req.ConvertOptions()
212 +
213 + return req
214 }
commands/response.go
+8 -4
@@ -108,18 +108,22 @@ func (r *response) Marshal() ([]byte, error) {
108 return []byte{}, nil
109 }
110
111 - enc, found := r.req.Option(EncShort)
112 - encStr, ok := enc.(string)
113 - if !found || !ok || encStr == "" {
111 + fmt.Println(r.req, r.req.Option(EncShort))
112 + if !r.req.Option(EncShort).Found() {
113 return nil, fmt.Errorf("No encoding type was specified")
114 }
116 - encType := EncodingType(strings.ToLower(encStr))
115 + enc, err := r.req.Option(EncShort).String()
116 + if err != nil {
117 + return nil, err
118 + }
119 + encType := EncodingType(strings.ToLower(enc))
120
121 var marshaller Marshaller
122 if r.req.Command() != nil && r.req.Command().Marshallers != nil {
123 marshaller = r.req.Command().Marshallers[encType]
124 }
125 if marshaller == nil {
126 + var ok bool
127 marshaller, ok = marshallers[encType]
128 if !ok {
129 return nil, fmt.Errorf("No marshaller found for encoding type '%s'", enc)
commands/response_test.go
+5 -10
@@ -12,25 +12,20 @@ type TestOutput struct {
12 }
13
14 func TestMarshalling(t *testing.T) {
15 - req := NewEmptyRequest()
15 + cmd := &Command{}
16 + opts, _ := cmd.GetOptions(nil)
17 +
18 + req := NewRequest(nil, nil, nil, nil, opts)
19
20 res := NewResponse(req)
21 res.SetOutput(TestOutput{"beep", "boop", 1337})
22
20 - // get command global options so we can set the encoding option
21 - cmd := Command{}
22 - options, err := cmd.GetOptions(nil)
23 - if err != nil {
24 - t.Error(err)
25 - }
26 -
27 - _, err = res.Marshal()
23 + _, err := res.Marshal()
24 if err == nil {
25 t.Error("Should have failed (no encoding type specified in request)")
26 }
27
28 req.SetOption(EncShort, JSON)
33 - req.ConvertOptions(options)
29
30 bytes, err := res.Marshal()
31 if err != nil {
core/commands2/mount_unix.go
+4 -6
@@ -44,17 +44,15 @@ not be listable, as it is virtual. Accessing known paths directly.
44
45 // update fsdir with flag.
46 fsdir := ctx.Config.Mounts.IPFS
47 - opt, _ := req.Option("f")
48 - if val, ok := opt.(string); ok && val != "" {
49 - fsdir = val
47 + if req.Option("f").Found() {
48 + fsdir, _ = req.Option("f").String()
49 }
50 fsdone := mountIpfs(ctx.Node, fsdir)
51
52 // get default mount points
53 nsdir := ctx.Config.Mounts.IPNS
55 - opt, _ = req.Option("f")
56 - if val, ok := opt.(string); ok && val != "" {
57 - nsdir = val
54 + if req.Option("n").Found() {
55 + nsdir, _ = req.Option("n").String()
56 }
57 nsdone := mountIpns(ctx.Node, nsdir, fsdir)
58
core/commands2/pin.go
+2 -4
@@ -35,8 +35,7 @@ on disk.
35 n := req.Context().Node
36
37 // set recursive flag
38 - opt, _ := req.Option("recursive")
39 - recursive, _ := opt.(bool) // false if cast fails.
38 + recursive, _ := req.Option("recursive").Bool() // false if cast fails.
39
40 paths, err := internal.CastToStrings(req.Arguments())
41 if err != nil {
@@ -70,8 +69,7 @@ collected if needed.
69 n := req.Context().Node
70
71 // set recursive flag
73 - opt, _ := req.Option("recursive")
74 - recursive, _ := opt.(bool) // false if cast fails.
72 + recursive, _ := req.Option("recursive").Bool() // false if cast fails.
73
74 paths, err := internal.CastToStrings(req.Arguments())
75 if err != nil {
core/commands2/refs.go
+2 -11
@@ -35,17 +35,8 @@ Note: list all refs recursively with -r.`,
35 Run: func(req cmds.Request) (interface{}, error) {
36 n := req.Context().Node
37
38 - opt, found := req.Option("unique")
39 - unique, ok := opt.(bool)
40 - if !ok && found {
41 - unique = false
42 - }
43 -
44 - opt, found = req.Option("recursive")
45 - recursive, ok := opt.(bool)
46 - if !ok && found {
47 - recursive = false
48 - }
38 + unique, _ := req.Option("unique").Bool()
39 + recursive, _ := req.Option("recursive").Bool()
40
41 paths, err := internal.CastToStrings(req.Arguments())
42 if err != nil {
core/commands2/version.go
+1 -7
@@ -1,8 +1,6 @@
1 package commands
2
3 import (
4 - "errors"
5 -
4 cmds "github.com/jbenet/go-ipfs/commands"
5 config "github.com/jbenet/go-ipfs/config"
6 )
@@ -29,11 +27,7 @@ var versionCmd = &cmds.Command{
27 v := res.Output().(*VersionOutput)
28 s := ""
29
32 - opt, found := res.Request().Option("number")
33 - number, ok := opt.(bool)
34 - if found && !ok {
35 - return nil, errors.New("cast error")
36 - }
30 + number, _ := res.Request().Option("number").Bool()
31
32 if !number {
33 s += "ipfs version "