提交 3e507f7c 作者: Matt Bell 提交者: Juan Batiz-Benet

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

上级 20591c7e
......@@ -20,30 +20,28 @@ var initCmd = &cmds.Command{
`,
Options: []cmds.Option{
cmds.IntOption("bits", "b", "Number of bits to use in the generated RSA private key (defaults to 4096)"),
cmds.UintOption("bits", "b", "Number of bits to use in the generated RSA private key (defaults to 4096)"),
cmds.StringOption("passphrase", "p", "Passphrase for encrypting the private key"),
cmds.BoolOption("force", "f", "Overwrite existing config (if it exists)"),
cmds.StringOption("datastore", "d", "Location for the IPFS data store"),
},
Run: func(req cmds.Request) (interface{}, error) {
arg, found := req.Option("d")
dspath, ok := arg.(string)
if found && !ok {
return nil, errors.New("failed to parse datastore flag")
dspath, err := req.Option("d").String()
if err != nil {
return nil, err
}
arg, found = req.Option("f")
force, ok := arg.(bool) // TODO param
if found && !ok {
return nil, errors.New("failed to parse force flag")
force, err := req.Option("f").Bool()
if err != nil {
return nil, err
}
arg, found = req.Option("b")
nBitsForKeypair, ok := arg.(int) // TODO param
if found && !ok {
return nil, errors.New("failed to get bits flag")
} else if !found {
nBitsForKeypair, err := req.Option("b").Int()
if err != nil {
return nil, err
}
if !req.Option("b").Found() {
nBitsForKeypair = 4096
}
......
......@@ -66,10 +66,7 @@ func createRequest(args []string) (cmds.Request, *cmds.Command) {
// or if a path was returned (user specified a valid subcommand), show the error message
// (this means there was an option or argument error)
if path != nil && len(path) > 0 {
help := false
opt, _ := req.Option("help")
help, _ = opt.(bool)
help, _ := req.Option("help").Bool()
if !help {
fmt.Printf(errorFormat, err)
}
......@@ -108,7 +105,7 @@ func createRequest(args []string) (cmds.Request, *cmds.Command) {
ctx.ConfigRoot = configPath
ctx.Config = conf
if _, found := req.Option("encoding"); !found {
if !req.Option("encoding").Found() {
if req.Command().Marshallers != nil && req.Command().Marshallers[cmds.Text] != nil {
req.SetOption("encoding", cmds.Text)
} else {
......@@ -120,30 +117,25 @@ func createRequest(args []string) (cmds.Request, *cmds.Command) {
}
func handleOptions(req cmds.Request, root *cmds.Command) {
if help, found := req.Option("help"); found {
if helpBool, ok := help.(bool); helpBool && ok {
helpText, err := cmdsCli.HelpText("ipfs", root, req.Path())
if err != nil {
fmt.Println(err.Error())
} else {
fmt.Println(helpText)
}
exit(0)
} else if !ok {
fmt.Println("error: expected 'help' option to be a bool")
exit(1)
if help, err := req.Option("help").Bool(); help && err == nil {
helpText, err := cmdsCli.HelpText("ipfs", root, req.Path())
if err != nil {
fmt.Println(err.Error())
} else {
fmt.Println(helpText)
}
exit(0)
} else if err != nil {
fmt.Println(err)
exit(1)
}
if debug, found := req.Option("debug"); found {
if debugBool, ok := debug.(bool); debugBool && ok {
u.Debug = true
u.SetAllLoggers(logging.DEBUG)
} else if !ok {
fmt.Println("error: expected 'debug' option to be a bool")
exit(1)
}
if debug, err := req.Option("debug").Bool(); debug && err == nil {
u.Debug = true
u.SetAllLoggers(logging.DEBUG)
} else if err != nil {
fmt.Println(err)
exit(1)
}
}
......@@ -154,19 +146,13 @@ func callCommand(req cmds.Request, root *cmds.Command) cmds.Response {
res = root.Call(req)
} else {
var found bool
var local interface{}
localBool := false
if local, found = req.Option("local"); found {
var ok bool
localBool, ok = local.(bool)
if !ok {
fmt.Println("error: expected 'local' option to be a bool")
exit(1)
}
local, err := req.Option("local").Bool()
if err != nil {
fmt.Println(err)
exit(1)
}
if (!found || !localBool) && daemon.Locked(req.Context().ConfigRoot) {
if (!req.Option("local").Found() || !local) && daemon.Locked(req.Context().ConfigRoot) {
addr, err := ma.NewMultiaddr(req.Context().Config.Addresses.API)
if err != nil {
fmt.Println(err)
......@@ -229,12 +215,12 @@ func outputResponse(res cmds.Response, root *cmds.Command) {
}
func getConfigRoot(req cmds.Request) (string, error) {
if opt, found := req.Option("config"); found {
if optStr, ok := opt.(string); ok {
return optStr, nil
} else {
return "", fmt.Errorf("Expected 'config' option to be a string")
}
configOpt, err := req.Option("config").String()
if err != nil {
return "", err
}
if configOpt != "" {
return configOpt, nil
}
configPath, err := config.PathRoot()
......
......@@ -66,13 +66,7 @@ func (c *Command) Call(req Request) Response {
return res
}
options, err := c.GetOptions(req.Path())
if err != nil {
res.SetError(err, ErrClient)
return res
}
err = req.ConvertOptions(options)
err = req.ConvertOptions()
if err != nil {
res.SetError(err, ErrClient)
return res
......
......@@ -15,29 +15,23 @@ func TestOptionValidation(t *testing.T) {
Run: noop,
}
req := NewEmptyRequest()
req.SetOption("beep", 5)
req.SetOption("b", 10)
res := cmd.Call(req)
if res.Error() == nil {
t.Error("Should have failed (duplicate options)")
}
opts, _ := cmd.GetOptions(nil)
req = NewEmptyRequest()
req.SetOption("beep", "foo")
res = cmd.Call(req)
req := NewRequest(nil, nil, nil, nil, opts)
req.SetOption("beep", true)
res := cmd.Call(req)
if res.Error() == nil {
t.Error("Should have failed (incorrect type)")
}
req = NewEmptyRequest()
req = NewRequest(nil, nil, nil, nil, opts)
req.SetOption("beep", 5)
res = cmd.Call(req)
if res.Error() != nil {
t.Error(res.Error(), "Should have passed")
}
req = NewEmptyRequest()
req = NewRequest(nil, nil, nil, nil, opts)
req.SetOption("beep", 5)
req.SetOption("boop", "test")
res = cmd.Call(req)
......@@ -45,7 +39,7 @@ func TestOptionValidation(t *testing.T) {
t.Error("Should have passed")
}
req = NewEmptyRequest()
req = NewRequest(nil, nil, nil, nil, opts)
req.SetOption("b", 5)
req.SetOption("B", "test")
res = cmd.Call(req)
......@@ -53,32 +47,32 @@ func TestOptionValidation(t *testing.T) {
t.Error("Should have passed")
}
req = NewEmptyRequest()
req = NewRequest(nil, nil, nil, nil, opts)
req.SetOption("foo", 5)
res = cmd.Call(req)
if res.Error() != nil {
t.Error("Should have passed")
}
req = NewEmptyRequest()
req = NewRequest(nil, nil, nil, nil, opts)
req.SetOption(EncShort, "json")
res = cmd.Call(req)
if res.Error() != nil {
t.Error("Should have passed")
}
req = NewEmptyRequest()
req = NewRequest(nil, nil, nil, nil, opts)
req.SetOption("b", "100")
res = cmd.Call(req)
if res.Error() != nil {
t.Error("Should have passed")
}
req = NewEmptyRequest()
req = NewRequest(nil, nil, nil, nil, opts)
req.SetOption("b", ":)")
res = cmd.Call(req)
if res.Error() == nil {
t.Error(res.Error(), "Should have failed (string value not convertible to int)")
t.Error("Should have failed (string value not convertible to int)")
}
}
......@@ -107,13 +101,14 @@ func TestRegistration(t *testing.T) {
Run: noop,
}
res := cmdB.Call(NewRequest([]string{"a"}, nil, nil, nil, nil))
if res.Error() == nil {
path := []string{"a"}
_, err := cmdB.GetOptions(path)
if err == nil {
t.Error("Should have failed (option name collision)")
}
res = cmdC.Call(NewEmptyRequest())
if res.Error() == nil {
_, err = cmdC.GetOptions(nil)
if err == nil {
t.Error("Should have failed (option name collision with global options)")
}
}
......
......@@ -34,23 +34,8 @@ func NewClient(address string) Client {
}
func (c *client) Send(req cmds.Request) (cmds.Response, error) {
var userEncoding string
if enc, found := req.Option(cmds.EncShort); found {
var ok bool
userEncoding, ok = enc.(string)
if !ok {
return nil, castError
}
req.SetOption(cmds.EncShort, cmds.JSON)
} else {
var ok bool
enc, _ := req.Option(cmds.EncLong)
userEncoding, ok = enc.(string)
if !ok {
return nil, castError
}
req.SetOption(cmds.EncLong, cmds.JSON)
}
userEncoding, _ := req.Option(cmds.EncShort).String()
req.SetOption(cmds.EncShort, cmds.JSON)
query, inputStream, err := getQuery(req)
if err != nil {
......@@ -72,7 +57,6 @@ func (c *client) Send(req cmds.Request) (cmds.Response, error) {
if len(userEncoding) > 0 {
req.SetOption(cmds.EncShort, userEncoding)
req.SetOption(cmds.EncLong, userEncoding)
}
return res, nil
......
......@@ -57,13 +57,12 @@ func (i Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
w.Header().Set(streamHeader, "1")
} else {
enc, _ := req.Option(cmds.EncShort)
encStr, ok := enc.(string)
if !ok {
enc, err := req.Option(cmds.EncShort).String()
if err != nil || len(enc) == 0 {
w.WriteHeader(http.StatusInternalServerError)
return
}
mime := mimeTypes[encStr]
mime := mimeTypes[enc]
w.Header().Set("Content-Type", mime)
}
......
package commands
import "reflect"
import (
"errors"
"reflect"
)
// Types of Command options
const (
......@@ -30,7 +33,7 @@ func NewOption(kind reflect.Kind, names ...string) Option {
}
desc := names[len(names)-1]
names = names[:len(names)-2]
names = names[:len(names)-1]
return Option{
Names: names,
......@@ -55,6 +58,73 @@ func StringOption(names ...string) Option {
return NewOption(String, names...)
}
type OptionValue struct {
value interface{}
found bool
}
// Found returns true if the option value was provided by the user (not a default value)
func (ov OptionValue) Found() bool {
return ov.found
}
// value accessor methods, gets the value as a certain type
func (ov OptionValue) Bool() (bool, error) {
val, ok := ov.value.(bool)
if !ok {
var err error
if ov.value != nil {
err = errors.New("error casting to bool")
}
return false, err
}
return val, nil
}
func (ov OptionValue) Int() (int, error) {
val, ok := ov.value.(int)
if !ok {
var err error
if ov.value != nil {
err = errors.New("error casting to int")
}
return 0, err
}
return val, nil
}
func (ov OptionValue) Uint() (uint, error) {
val, ok := ov.value.(uint)
if !ok {
var err error
if ov.value != nil {
err = errors.New("error casting to uint")
}
return 0, err
}
return val, nil
}
func (ov OptionValue) Float() (float64, error) {
val, ok := ov.value.(float64)
if !ok {
var err error
if ov.value != nil {
err = errors.New("error casting to float64")
}
return 0.0, err
}
return val, nil
}
func (ov OptionValue) String() (string, error) {
val, ok := ov.value.(string)
if !ok {
var err error
if ov.value != nil {
err = errors.New("error casting to string")
}
return "", err
}
return val, nil
}
// Flag names
const (
EncShort = "enc"
......
......@@ -21,15 +21,15 @@ type Context struct {
// Request represents a call to a command from a consumer
type Request interface {
Path() []string
Option(name string) (interface{}, bool)
Options() map[string]interface{}
Option(name string) *OptionValue
Options() optMap
SetOption(name string, val interface{})
Arguments() []interface{} // TODO: make argument value type instead of using interface{}
Context() *Context
SetContext(Context)
Command() *Command
ConvertOptions(options map[string]Option) error
ConvertOptions() error
}
type request struct {
......@@ -47,31 +47,34 @@ func (r *request) Path() []string {
}
// Option returns the value of the option for given name.
func (r *request) Option(name string) (interface{}, bool) {
func (r *request) Option(name string) *OptionValue {
val, found := r.options[name]
if found {
return val, found
return &OptionValue{val, found}
}
// if a value isn't defined for that name, we will try to look it up by its aliases
// find the option with the specified name
option, found := r.optionDefs[name]
if found {
// try all the possible names, break if we find a value
for _, n := range option.Names {
val, found := r.options[n]
if found {
return val, found
}
if !found {
return nil
}
// try all the possible names, break if we find a value
for _, n := range option.Names {
val, found = r.options[n]
if found {
return &OptionValue{val, found}
}
}
return nil, false
// MAYBE_TODO: use default value instead of nil
return &OptionValue{nil, false}
}
// Options returns a copy of the option map
func (r *request) Options() map[string]interface{} {
func (r *request) Options() optMap {
output := make(optMap)
for k, v := range r.options {
output[k] = v
......@@ -136,11 +139,11 @@ var converters = map[reflect.Kind]converter{
},
}
func (r *request) ConvertOptions(options map[string]Option) error {
func (r *request) ConvertOptions() error {
converted := make(map[string]interface{})
for k, v := range r.options {
opt, ok := options[k]
opt, ok := r.optionDefs[k]
if !ok {
continue
}
......@@ -203,5 +206,9 @@ func NewRequest(path []string, opts optMap, args []interface{}, cmd *Command, op
if optDefs == nil {
optDefs = make(map[string]Option)
}
return &request{path, opts, args, cmd, Context{}, optDefs}
req := &request{path, opts, args, cmd, Context{}, optDefs}
req.ConvertOptions()
return req
}
......@@ -108,18 +108,22 @@ func (r *response) Marshal() ([]byte, error) {
return []byte{}, nil
}
enc, found := r.req.Option(EncShort)
encStr, ok := enc.(string)
if !found || !ok || encStr == "" {
fmt.Println(r.req, r.req.Option(EncShort))
if !r.req.Option(EncShort).Found() {
return nil, fmt.Errorf("No encoding type was specified")
}
encType := EncodingType(strings.ToLower(encStr))
enc, err := r.req.Option(EncShort).String()
if err != nil {
return nil, err
}
encType := EncodingType(strings.ToLower(enc))
var marshaller Marshaller
if r.req.Command() != nil && r.req.Command().Marshallers != nil {
marshaller = r.req.Command().Marshallers[encType]
}
if marshaller == nil {
var ok bool
marshaller, ok = marshallers[encType]
if !ok {
return nil, fmt.Errorf("No marshaller found for encoding type '%s'", enc)
......
......@@ -12,25 +12,20 @@ type TestOutput struct {
}
func TestMarshalling(t *testing.T) {
req := NewEmptyRequest()
cmd := &Command{}
opts, _ := cmd.GetOptions(nil)
req := NewRequest(nil, nil, nil, nil, opts)
res := NewResponse(req)
res.SetOutput(TestOutput{"beep", "boop", 1337})
// get command global options so we can set the encoding option
cmd := Command{}
options, err := cmd.GetOptions(nil)
if err != nil {
t.Error(err)
}
_, err = res.Marshal()
_, err := res.Marshal()
if err == nil {
t.Error("Should have failed (no encoding type specified in request)")
}
req.SetOption(EncShort, JSON)
req.ConvertOptions(options)
bytes, err := res.Marshal()
if err != nil {
......
......@@ -44,17 +44,15 @@ not be listable, as it is virtual. Accessing known paths directly.
// update fsdir with flag.
fsdir := ctx.Config.Mounts.IPFS
opt, _ := req.Option("f")
if val, ok := opt.(string); ok && val != "" {
fsdir = val
if req.Option("f").Found() {
fsdir, _ = req.Option("f").String()
}
fsdone := mountIpfs(ctx.Node, fsdir)
// get default mount points
nsdir := ctx.Config.Mounts.IPNS
opt, _ = req.Option("f")
if val, ok := opt.(string); ok && val != "" {
nsdir = val
if req.Option("n").Found() {
nsdir, _ = req.Option("n").String()
}
nsdone := mountIpns(ctx.Node, nsdir, fsdir)
......
......@@ -35,8 +35,7 @@ on disk.
n := req.Context().Node
// set recursive flag
opt, _ := req.Option("recursive")
recursive, _ := opt.(bool) // false if cast fails.
recursive, _ := req.Option("recursive").Bool() // false if cast fails.
paths, err := internal.CastToStrings(req.Arguments())
if err != nil {
......@@ -70,8 +69,7 @@ collected if needed.
n := req.Context().Node
// set recursive flag
opt, _ := req.Option("recursive")
recursive, _ := opt.(bool) // false if cast fails.
recursive, _ := req.Option("recursive").Bool() // false if cast fails.
paths, err := internal.CastToStrings(req.Arguments())
if err != nil {
......
......@@ -35,17 +35,8 @@ Note: list all refs recursively with -r.`,
Run: func(req cmds.Request) (interface{}, error) {
n := req.Context().Node
opt, found := req.Option("unique")
unique, ok := opt.(bool)
if !ok && found {
unique = false
}
opt, found = req.Option("recursive")
recursive, ok := opt.(bool)
if !ok && found {
recursive = false
}
unique, _ := req.Option("unique").Bool()
recursive, _ := req.Option("recursive").Bool()
paths, err := internal.CastToStrings(req.Arguments())
if err != nil {
......
package commands
import (
"errors"
cmds "github.com/jbenet/go-ipfs/commands"
config "github.com/jbenet/go-ipfs/config"
)
......@@ -29,11 +27,7 @@ var versionCmd = &cmds.Command{
v := res.Output().(*VersionOutput)
s := ""
opt, found := res.Request().Option("number")
number, ok := opt.(bool)
if found && !ok {
return nil, errors.New("cast error")
}
number, _ := res.Request().Option("number").Bool()
if !number {
s += "ipfs version "
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论