From c24a08be2ebb91d1c472442561b5369583c1177f Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Fri, 16 Mar 2018 11:00:49 -0700 Subject: [PATCH] delete dead code This code was making it *really* hard to understand the commands code. License: MIT Signed-off-by: Steven Allen --- commands/channelmarshaler.go | 44 ----- commands/command.go | 228 ------------------------- commands/command_test.go | 200 ---------------------- commands/legacy/request.go | 26 --- commands/request.go | 319 ----------------------------------- commands/response.go | 181 -------------------- commands/response_test.go | 70 -------- 7 files changed, 1068 deletions(-) delete mode 100644 commands/channelmarshaler.go delete mode 100644 commands/command_test.go delete mode 100644 commands/response_test.go diff --git a/commands/channelmarshaler.go b/commands/channelmarshaler.go deleted file mode 100644 index 4564b537b..000000000 --- a/commands/channelmarshaler.go +++ /dev/null @@ -1,44 +0,0 @@ -package commands - -import ( - "io" -) - -type ChannelMarshaler struct { - Channel <-chan interface{} - Marshaler func(interface{}) (io.Reader, error) - Res Response - - reader io.Reader -} - -func (cr *ChannelMarshaler) Read(p []byte) (int, error) { - if cr.reader == nil { - val, more := <-cr.Channel - if !more { - //check error in response - if cr.Res.Error() != nil { - return 0, cr.Res.Error() - } - return 0, io.EOF - } - - r, err := cr.Marshaler(val) - if err != nil { - return 0, err - } - if r == nil { - return 0, nil - } - cr.reader = r - } - - n, err := cr.reader.Read(p) - if err != nil && err != io.EOF { - return n, err - } - if n == 0 { - cr.reader = nil - } - return n, nil -} diff --git a/commands/command.go b/commands/command.go index 8d40a27c0..a0cb945b2 100644 --- a/commands/command.go +++ b/commands/command.go @@ -9,15 +9,9 @@ output to the user, including text, JSON, and XML marshallers. package commands import ( - "errors" - "fmt" "io" - "reflect" - - "github.com/ipfs/go-ipfs/path" logging "gx/ipfs/QmRb5jh8z2E8hMGN2tkvs1yHynUanqnZ3UeKwgN1i9P1F8/go-log" - cmds "gx/ipfs/QmabLouZTZwhfALuBcssPvkzhbYGMb4394huT7HY4LQ6d3/go-ipfs-cmds" cmdkit "gx/ipfs/QmceUdzxkimdYsgtX733uNgzf1DLHyBKN6ehGSp85ayppM/go-ipfs-cmdkit" ) @@ -64,233 +58,11 @@ type Command struct { Subcommands map[string]*Command } -// ErrNotCallable signals a command that cannot be called. -var ErrNotCallable = ClientError("This command can't be called directly. Try one of its subcommands.") - -var ErrNoFormatter = ClientError("This command cannot be formatted to plain text") - -var ErrIncorrectType = errors.New("The command returned a value with a different type than expected") - -// Call invokes the command for the given Request -func (c *Command) Call(req Request) Response { - res := NewResponse(req) - - cmds, err := c.Resolve(req.Path()) - if err != nil { - res.SetError(err, cmdkit.ErrClient) - return res - } - cmd := cmds[len(cmds)-1] - - if cmd.Run == nil { - res.SetError(ErrNotCallable, cmdkit.ErrClient) - return res - } - - err = cmd.CheckArguments(req) - if err != nil { - res.SetError(err, cmdkit.ErrClient) - return res - } - - err = req.ConvertOptions() - if err != nil { - res.SetError(err, cmdkit.ErrClient) - return res - } - - cmd.Run(req, res) - if res.Error() != nil { - return res - } - - output := res.Output() - isChan := false - actualType := reflect.TypeOf(output) - if actualType != nil { - if actualType.Kind() == reflect.Ptr { - actualType = actualType.Elem() - } - - // test if output is a channel - isChan = actualType.Kind() == reflect.Chan - } - - // If the command specified an output type, ensure the actual value - // returned is of that type - if cmd.Type != nil && !isChan { - expectedType := reflect.TypeOf(cmd.Type) - - if actualType != expectedType { - res.SetError(ErrIncorrectType, cmdkit.ErrNormal) - return res - } - } - - return res -} - -// Resolve returns the subcommands at the given path -func (c *Command) Resolve(pth []string) ([]*Command, error) { - cmds := make([]*Command, len(pth)+1) - cmds[0] = c - - cmd := c - for i, name := range pth { - cmd = cmd.Subcommand(name) - - if cmd == nil { - pathS := path.Join(pth[:i]) - return nil, fmt.Errorf("Undefined command: '%s'", pathS) - } - - cmds[i+1] = cmd - } - - return cmds, nil -} - -// Get resolves and returns the Command addressed by path -func (c *Command) Get(path []string) (*Command, error) { - cmds, err := c.Resolve(path) - if err != nil { - return nil, err - } - return cmds[len(cmds)-1], nil -} - -// GetOptions returns the options in the given path of commands -func (c *Command) GetOptions(path []string) (map[string]cmdkit.Option, error) { - options := make([]cmdkit.Option, 0, len(c.Options)) - - cmds, err := c.Resolve(path) - if err != nil { - return nil, err - } - cmds = append(cmds, globalCommand) - - for _, cmd := range cmds { - options = append(options, cmd.Options...) - } - - optionsMap := make(map[string]cmdkit.Option) - for _, opt := range options { - for _, name := range opt.Names() { - if _, found := optionsMap[name]; found { - return nil, fmt.Errorf("Option name '%s' used multiple times", name) - } - - optionsMap[name] = opt - } - } - - return optionsMap, nil -} - -func (c *Command) CheckArguments(req Request) error { - args := req.(*request).arguments - - // count required argument definitions - numRequired := 0 - for _, argDef := range c.Arguments { - if argDef.Required { - numRequired++ - } - } - - // iterate over the arg definitions - valueIndex := 0 // the index of the current value (in `args`) - for i, argDef := range c.Arguments { - // skip optional argument definitions if there aren't - // sufficient remaining values - if len(args)-valueIndex <= numRequired && !argDef.Required || - argDef.Type == cmdkit.ArgFile { - continue - } - - // the value for this argument definition. can be nil if it - // wasn't provided by the caller - v, found := "", false - if valueIndex < len(args) { - v = args[valueIndex] - found = true - valueIndex++ - } - - // in the case of a non-variadic required argument that supports stdin - if !found && len(c.Arguments)-1 == i && argDef.SupportsStdin { - found = true - } - - err := checkArgValue(v, found, argDef) - if err != nil { - return err - } - - // any additional values are for the variadic arg definition - if argDef.Variadic && valueIndex < len(args)-1 { - for _, val := range args[valueIndex:] { - err := checkArgValue(val, true, argDef) - if err != nil { - return err - } - } - } - } - - return nil -} - // Subcommand returns the subcommand with the given id func (c *Command) Subcommand(id string) *Command { return c.Subcommands[id] } -type CommandVisitor func(*Command) - -// Walks tree of all subcommands (including this one) -func (c *Command) Walk(visitor CommandVisitor) { - visitor(c) - for _, cm := range c.Subcommands { - cm.Walk(visitor) - } -} - -func (c *Command) ProcessHelp() { - c.Walk(func(cm *Command) { - ht := &cm.Helptext - if len(ht.LongDescription) == 0 { - ht.LongDescription = ht.ShortDescription - } - }) -} - -// checkArgValue returns an error if a given arg value is not valid for the -// given Argument -func checkArgValue(v string, found bool, def cmdkit.Argument) error { - if def.Variadic && def.SupportsStdin { - return nil - } - - if !found && def.Required { - return fmt.Errorf("Argument '%s' is required", def.Name) - } - - return nil -} - func ClientError(msg string) error { return &cmdkit.Error{Code: cmdkit.ErrClient, Message: msg} } - -// global options, added to every command -var globalOptions = []cmdkit.Option{ - cmds.OptionEncodingType, - cmds.OptionStreamChannels, - cmds.OptionTimeout, -} - -// the above array of Options, wrapped in a Command -var globalCommand = &Command{ - Options: globalOptions, -} diff --git a/commands/command_test.go b/commands/command_test.go deleted file mode 100644 index ee7a37574..000000000 --- a/commands/command_test.go +++ /dev/null @@ -1,200 +0,0 @@ -package commands - -import ( - "testing" - - cmds "gx/ipfs/QmabLouZTZwhfALuBcssPvkzhbYGMb4394huT7HY4LQ6d3/go-ipfs-cmds" - cmdkit "gx/ipfs/QmceUdzxkimdYsgtX733uNgzf1DLHyBKN6ehGSp85ayppM/go-ipfs-cmdkit" -) - -func noop(req Request, res Response) { -} - -func TestOptionValidation(t *testing.T) { - cmd := Command{ - Options: []cmdkit.Option{ - cmdkit.IntOption("b", "beep", "enables beeper"), - cmdkit.StringOption("B", "boop", "password for booper"), - }, - Run: noop, - } - - opts, _ := cmd.GetOptions(nil) - - req, _ := NewRequest(nil, 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, _ = NewRequest(nil, 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, _ = NewRequest(nil, nil, nil, nil, nil, opts) - req.SetOption("beep", 5) - req.SetOption("boop", "test") - res = cmd.Call(req) - if res.Error() != nil { - t.Error("Should have passed") - } - - req, _ = NewRequest(nil, nil, nil, nil, nil, opts) - req.SetOption("b", 5) - req.SetOption("B", "test") - res = cmd.Call(req) - if res.Error() != nil { - t.Error("Should have passed") - } - - req, _ = NewRequest(nil, nil, nil, nil, nil, opts) - req.SetOption("foo", 5) - res = cmd.Call(req) - if res.Error() != nil { - t.Error("Should have passed") - } - - req, _ = NewRequest(nil, nil, nil, nil, nil, opts) - req.SetOption(cmds.EncLong, "json") - res = cmd.Call(req) - if res.Error() != nil { - t.Error("Should have passed") - } - - req, _ = NewRequest(nil, nil, nil, nil, nil, opts) - req.SetOption("b", "100") - res = cmd.Call(req) - if res.Error() != nil { - t.Error("Should have passed") - } - - req, _ = NewRequest(nil, nil, nil, nil, &cmd, opts) - req.SetOption("b", ":)") - res = cmd.Call(req) - if res.Error() == nil { - t.Error("Should have failed (string value not convertible to int)") - } - - err := req.SetOptions(map[string]interface{}{ - "b": 100, - }) - if err != nil { - t.Error("Should have passed") - } - - err = req.SetOptions(map[string]interface{}{ - "b": ":)", - }) - if err == nil { - t.Error("Should have failed (string value not convertible to int)") - } -} - -func TestRegistration(t *testing.T) { - cmdA := &Command{ - Options: []cmdkit.Option{ - cmdkit.IntOption("beep", "number of beeps"), - }, - Run: noop, - } - - cmdB := &Command{ - Options: []cmdkit.Option{ - cmdkit.IntOption("beep", "number of beeps"), - }, - Run: noop, - Subcommands: map[string]*Command{ - "a": cmdA, - }, - } - - cmdC := &Command{ - Options: []cmdkit.Option{ - cmdkit.StringOption("encoding", "data encoding type"), - }, - Run: noop, - } - - path := []string{"a"} - _, err := cmdB.GetOptions(path) - if err == nil { - t.Error("Should have failed (option name collision)") - } - - _, err = cmdC.GetOptions(nil) - if err == nil { - t.Error("Should have failed (option name collision with global options)") - } -} - -func TestResolving(t *testing.T) { - cmdC := &Command{} - cmdB := &Command{ - Subcommands: map[string]*Command{ - "c": cmdC, - }, - } - cmdB2 := &Command{} - cmdA := &Command{ - Subcommands: map[string]*Command{ - "b": cmdB, - "B": cmdB2, - }, - } - cmd := &Command{ - Subcommands: map[string]*Command{ - "a": cmdA, - }, - } - - cmds, err := cmd.Resolve([]string{"a", "b", "c"}) - if err != nil { - t.Error(err) - } - if len(cmds) != 4 || cmds[0] != cmd || cmds[1] != cmdA || cmds[2] != cmdB || cmds[3] != cmdC { - t.Error("Returned command path is different than expected", cmds) - } -} - -func TestWalking(t *testing.T) { - cmdA := &Command{ - Subcommands: map[string]*Command{ - "b": &Command{}, - "B": &Command{}, - }, - } - i := 0 - cmdA.Walk(func(c *Command) { - i = i + 1 - }) - if i != 3 { - t.Error("Command tree walk didn't work, expected 3 got:", i) - } -} - -func TestHelpProcessing(t *testing.T) { - cmdB := &Command{ - Helptext: cmdkit.HelpText{ - ShortDescription: "This is other short", - }, - } - cmdA := &Command{ - Helptext: cmdkit.HelpText{ - ShortDescription: "This is short", - }, - Subcommands: map[string]*Command{ - "a": cmdB, - }, - } - cmdA.ProcessHelp() - if len(cmdA.Helptext.LongDescription) == 0 { - t.Error("LongDescription was not set on basis of ShortDescription") - } - if len(cmdB.Helptext.LongDescription) == 0 { - t.Error("LongDescription was not set on basis of ShortDescription") - } -} diff --git a/commands/legacy/request.go b/commands/legacy/request.go index cd353d9b7..01a8d5a71 100644 --- a/commands/legacy/request.go +++ b/commands/legacy/request.go @@ -147,32 +147,6 @@ func (r *requestWrapper) Values() map[string]interface{} { return nil } -func (r *requestWrapper) VarArgs(f func(string) error) error { - if len(r.req.Arguments) >= len(r.req.Command.Arguments) { - for _, arg := range r.req.Arguments { - err := f(arg) - if err != nil { - return err - } - } - return nil - } - - s, err := r.req.BodyArgs() - if err != nil { - return err - } - - for s.Scan() { - err = f(s.Text()) - if err != nil { - return err - } - } - - return nil -} - // copied from go-ipfs-cmds/request.go func convertOptions(req *cmds.Request) error { optDefSlice := req.Command.Options diff --git a/commands/request.go b/commands/request.go index 4711024ad..ebacbd677 100644 --- a/commands/request.go +++ b/commands/request.go @@ -1,20 +1,13 @@ package commands import ( - "bufio" "context" "errors" - "fmt" - "io" - "os" - "reflect" - "strconv" "strings" "time" "github.com/ipfs/go-ipfs/core" "github.com/ipfs/go-ipfs/repo/config" - u "gx/ipfs/QmNiJuT8Ja3hMVpBHXv3Q6dwmperaQ6JjLtpMQgMCD7xvx/go-ipfs-util" "gx/ipfs/QmabLouZTZwhfALuBcssPvkzhbYGMb4394huT7HY4LQ6d3/go-ipfs-cmds" "gx/ipfs/QmceUdzxkimdYsgtX733uNgzf1DLHyBKN6ehGSp85ayppM/go-ipfs-cmdkit" @@ -59,12 +52,6 @@ func (c *Context) GetNode() (*core.IpfsNode, error) { return c.node, err } -// NodeWithoutConstructing returns the underlying node variable -// so that clients may close it. -func (c *Context) NodeWithoutConstructing() *core.IpfsNode { - return c.node -} - // Context returns the node's context. func (c *Context) Context() context.Context { n, err := c.GetNode() @@ -112,316 +99,10 @@ type Request interface { Path() []string Option(name string) *cmdkit.OptionValue Options() cmdkit.OptMap - SetOption(name string, val interface{}) - SetOptions(opts cmdkit.OptMap) error Arguments() []string StringArguments() []string - SetArguments([]string) Files() files.File - SetFiles(files.File) Context() context.Context InvocContext() *Context - SetInvocContext(Context) Command() *Command - Values() map[string]interface{} - Stdin() io.Reader - VarArgs(func(string) error) error - - ConvertOptions() error -} - -type request struct { - path []string - options cmdkit.OptMap - arguments []string - files files.File - cmd *Command - ctx Context - rctx context.Context - optionDefs map[string]cmdkit.Option - values map[string]interface{} - stdin io.Reader -} - -// Path returns the command path of this request -func (r *request) Path() []string { - return r.path -} - -// Option returns the value of the option for given name. -func (r *request) Option(name string) *cmdkit.OptionValue { - // find the option with the specified name - option, found := r.optionDefs[name] - 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 &cmdkit.OptionValue{ - Value: val, - ValueFound: found, - Def: option, - } - } - } - - return &cmdkit.OptionValue{ - Value: option.Default(), - ValueFound: false, - Def: option, - } -} - -// Options returns a copy of the option map -func (r *request) Options() cmdkit.OptMap { - output := make(cmdkit.OptMap) - for k, v := range r.options { - output[k] = v - } - return output -} - -// SetOption sets the value of the option for given name. -func (r *request) SetOption(name string, val interface{}) { - // find the option with the specified name - option, found := r.optionDefs[name] - if !found { - return - } - - // try all the possible names, if we already have a value then set over it - for _, n := range option.Names() { - _, found := r.options[n] - if found { - r.options[n] = val - return - } - } - - r.options[name] = val -} - -// SetOptions sets the option values, unsetting any values that were previously set -func (r *request) SetOptions(opts cmdkit.OptMap) error { - r.options = opts - return r.ConvertOptions() -} - -func (r *request) StringArguments() []string { - return r.arguments -} - -// Arguments returns the arguments slice -func (r *request) Arguments() []string { - if r.haveVarArgsFromStdin() { - err := r.VarArgs(func(s string) error { - r.arguments = append(r.arguments, s) - return nil - }) - if err != nil && err != io.EOF { - log.Error(err) - } - } - - return r.arguments -} - -func (r *request) SetArguments(args []string) { - r.arguments = args -} - -func (r *request) Files() files.File { - return r.files -} - -func (r *request) SetFiles(f files.File) { - r.files = f -} - -func (r *request) Context() context.Context { - return r.rctx -} - -func (r *request) haveVarArgsFromStdin() bool { - // we expect varargs if we have a string argument that supports stdin - // and not arguments to satisfy it - if len(r.cmd.Arguments) == 0 { - return false - } - - last := r.cmd.Arguments[len(r.cmd.Arguments)-1] - return last.SupportsStdin && last.Type == cmdkit.ArgString && (last.Required || last.Variadic) && - len(r.arguments) < len(r.cmd.Arguments) -} - -// VarArgs can be used when you want string arguments as input -// and also want to be able to handle them in a streaming fashion -func (r *request) VarArgs(f func(string) error) error { - if len(r.arguments) >= len(r.cmd.Arguments) { - for _, arg := range r.arguments[len(r.cmd.Arguments)-1:] { - err := f(arg) - if err != nil { - return err - } - } - - return nil - } - - if r.files == nil { - log.Warning("expected more arguments from stdin") - return nil - } - - fi, err := r.files.NextFile() - if err != nil { - return err - } - - var any bool - scan := bufio.NewScanner(fi) - for scan.Scan() { - any = true - err := f(scan.Text()) - if err != nil { - return err - } - } - if !any { - return f("") - } - - return nil -} - -func (r *request) InvocContext() *Context { - return &r.ctx -} - -func (r *request) SetInvocContext(ctx Context) { - r.ctx = ctx -} - -func (r *request) Command() *Command { - return r.cmd -} - -type converter func(string) (interface{}, error) - -var converters = map[reflect.Kind]converter{ - cmdkit.Bool: func(v string) (interface{}, error) { - if v == "" { - return true, nil - } - return strconv.ParseBool(v) - }, - cmdkit.Int: func(v string) (interface{}, error) { - val, err := strconv.ParseInt(v, 0, 32) - if err != nil { - return nil, err - } - return int(val), err - }, - cmdkit.Uint: func(v string) (interface{}, error) { - val, err := strconv.ParseUint(v, 0, 32) - if err != nil { - return nil, err - } - return int(val), err - }, - cmdkit.Float: func(v string) (interface{}, error) { - return strconv.ParseFloat(v, 64) - }, -} - -func (r *request) Values() map[string]interface{} { - return r.values -} - -func (r *request) Stdin() io.Reader { - return r.stdin -} - -func (r *request) ConvertOptions() error { - for k, v := range r.options { - opt, ok := r.optionDefs[k] - if !ok { - continue - } - - kind := reflect.TypeOf(v).Kind() - if kind != opt.Type() { - if kind == cmdkit.String { - convert := converters[opt.Type()] - str, ok := v.(string) - if !ok { - return u.ErrCast() - } - val, err := convert(str) - if err != nil { - value := fmt.Sprintf("value '%v'", v) - if len(str) == 0 { - value = "empty value" - } - return fmt.Errorf("Could not convert %s to type '%s' (for option '-%s')", - value, opt.Type().String(), k) - } - r.options[k] = val - - } else { - return fmt.Errorf("Option '%s' should be type '%s', but got type '%s'", - k, opt.Type().String(), kind.String()) - } - } else { - r.options[k] = v - } - - for _, name := range opt.Names() { - if _, ok := r.options[name]; name != k && ok { - return fmt.Errorf("Duplicate command options were provided ('%s' and '%s')", - k, name) - } - } - } - - return nil -} - -// NewEmptyRequest initializes an empty request -func NewEmptyRequest() (Request, error) { - return NewRequest(nil, nil, nil, nil, nil, nil) -} - -// NewRequest returns a request initialized with given arguments -// An non-nil error will be returned if the provided option values are invalid -func NewRequest(path []string, opts cmdkit.OptMap, args []string, file files.File, cmd *Command, optDefs map[string]cmdkit.Option) (Request, error) { - if opts == nil { - opts = make(cmdkit.OptMap) - } - if optDefs == nil { - optDefs = make(map[string]cmdkit.Option) - } - - ctx := Context{} - values := make(map[string]interface{}) - req := &request{ - path: path, - options: opts, - arguments: args, - files: file, - cmd: cmd, - ctx: ctx, - optionDefs: optDefs, - values: values, - stdin: os.Stdin, - } - err := req.ConvertOptions() - if err != nil { - return nil, err - } - - return req, nil } diff --git a/commands/response.go b/commands/response.go index ef4e11af0..159a52c1f 100644 --- a/commands/response.go +++ b/commands/response.go @@ -1,15 +1,8 @@ package commands import ( - "bytes" - "encoding/json" - "encoding/xml" - "fmt" "io" - "os" - "strings" - cmds "gx/ipfs/QmabLouZTZwhfALuBcssPvkzhbYGMb4394huT7HY4LQ6d3/go-ipfs-cmds" cmdkit "gx/ipfs/QmceUdzxkimdYsgtX733uNgzf1DLHyBKN6ehGSp85ayppM/go-ipfs-cmdkit" ) @@ -28,50 +21,6 @@ const ( // TODO: support more encoding types ) -func marshalJson(value interface{}) (io.Reader, error) { - b, err := json.Marshal(value) - if err != nil { - return nil, err - } - b = append(b, '\n') - return bytes.NewReader(b), nil -} - -var marshallers = map[EncodingType]Marshaler{ - JSON: func(res Response) (io.Reader, error) { - ch, ok := res.Output().(<-chan interface{}) - if ok { - return &ChannelMarshaler{ - Channel: ch, - Marshaler: marshalJson, - Res: res, - }, nil - } - - var value interface{} - if res.Error() != nil { - value = res.Error() - } else { - value = res.Output() - } - return marshalJson(value) - }, - XML: func(res Response) (io.Reader, error) { - var value interface{} - if res.Error() != nil { - value = res.Error() - } else { - value = res.Output() - } - - b, err := xml.Marshal(value) - if err != nil { - return nil, err - } - return bytes.NewReader(b), nil - }, -} - // Response is the result of a command request. Handlers write to the response, // setting Error or Value. Response is returned to the client. type Response interface { @@ -104,133 +53,3 @@ type Response interface { Stdout() io.Writer Stderr() io.Writer } - -type response struct { - req Request - err *cmdkit.Error - value interface{} - out io.Reader - length uint64 - stdout io.Writer - stderr io.Writer - closer io.Closer -} - -func (r *response) Request() Request { - return r.req -} - -func (r *response) Output() interface{} { - return r.value -} - -func (r *response) SetOutput(v interface{}) { - r.value = v -} - -func (r *response) Length() uint64 { - return r.length -} - -func (r *response) SetLength(l uint64) { - r.length = l -} - -func (r *response) Error() *cmdkit.Error { - return r.err -} - -func (r *response) SetError(err error, code cmdkit.ErrorType) { - r.err = &cmdkit.Error{Message: err.Error(), Code: code} -} - -func (r *response) Marshal() (io.Reader, error) { - if r.err == nil && r.value == nil { - return bytes.NewReader([]byte{}), nil - } - - enc, found, err := r.req.Option(cmds.EncLong).String() - if err != nil { - return nil, err - } - if !found { - return nil, fmt.Errorf("No encoding type was specified") - } - encType := EncodingType(strings.ToLower(enc)) - - // Special case: if text encoding and an error, just print it out. - if encType == Text && r.Error() != nil { - return strings.NewReader(r.Error().Error()), nil - } - - var marshaller Marshaler - if r.req.Command() != nil && r.req.Command().Marshalers != nil { - marshaller = r.req.Command().Marshalers[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) - } - } - - output, err := marshaller(r) - if err != nil { - return nil, err - } - if output == nil { - return bytes.NewReader([]byte{}), nil - } - return output, nil -} - -// Reader returns an `io.Reader` representing marshalled output of this Response -// Note that multiple calls to this will return a reference to the same io.Reader -func (r *response) Reader() (io.Reader, error) { - if r.out == nil { - if out, ok := r.value.(io.Reader); ok { - // if command returned a io.Reader, use that as our reader - r.out = out - - } else { - // otherwise, use the response marshaler output - marshalled, err := r.Marshal() - if err != nil { - return nil, err - } - - r.out = marshalled - } - } - - return r.out, nil -} - -func (r *response) Close() error { - if r.closer != nil { - return r.closer.Close() - } - return nil -} - -func (r *response) SetCloser(c io.Closer) { - r.closer = c -} - -func (r *response) Stdout() io.Writer { - return r.stdout -} - -func (r *response) Stderr() io.Writer { - return r.stderr -} - -// NewResponse returns a response to match given Request -func NewResponse(req Request) Response { - return &response{ - req: req, - stdout: os.Stdout, - stderr: os.Stderr, - } -} diff --git a/commands/response_test.go b/commands/response_test.go deleted file mode 100644 index 300ded7a7..000000000 --- a/commands/response_test.go +++ /dev/null @@ -1,70 +0,0 @@ -package commands - -import ( - "bytes" - "fmt" - "strings" - "testing" - - cmds "gx/ipfs/QmabLouZTZwhfALuBcssPvkzhbYGMb4394huT7HY4LQ6d3/go-ipfs-cmds" - cmdkit "gx/ipfs/QmceUdzxkimdYsgtX733uNgzf1DLHyBKN6ehGSp85ayppM/go-ipfs-cmdkit" -) - -type TestOutput struct { - Foo, Bar string - Baz int -} - -func TestMarshalling(t *testing.T) { - cmd := &Command{} - opts, _ := cmd.GetOptions(nil) - - req, _ := NewRequest(nil, nil, nil, nil, nil, opts) - - res := NewResponse(req) - res.SetOutput(TestOutput{"beep", "boop", 1337}) - - _, err := res.Marshal() - if err == nil { - t.Error("Should have failed (no encoding type specified in request)") - } - - req.SetOption(cmds.EncLong, JSON) - - reader, err := res.Marshal() - if err != nil { - t.Error(err, "Should have passed") - } - buf := new(bytes.Buffer) - buf.ReadFrom(reader) - output := buf.String() - if removeWhitespace(output) != "{\"Foo\":\"beep\",\"Bar\":\"boop\",\"Baz\":1337}" { - t.Error("Incorrect JSON output") - } - - res.SetError(fmt.Errorf("Oops!"), cmdkit.ErrClient) - reader, err = res.Marshal() - if err != nil { - t.Error("Should have passed") - } - buf.Reset() - buf.ReadFrom(reader) - output = buf.String() - fmt.Println(removeWhitespace(output)) - if removeWhitespace(output) != `{"Message":"Oops!","Code":1,"Type":"error"}` { - t.Error("Incorrect JSON output") - } -} - -func TestErrTypeOrder(t *testing.T) { - if cmdkit.ErrNormal != 0 || cmdkit.ErrClient != 1 || cmdkit.ErrImplementation != 2 || cmdkit.ErrNotFound != 3 { - t.Fatal("ErrType order is wrong") - } -} - -func removeWhitespace(input string) string { - input = strings.Replace(input, " ", "", -1) - input = strings.Replace(input, "\t", "", -1) - input = strings.Replace(input, "\n", "", -1) - return strings.Replace(input, "\r", "", -1) -}