1
0
mirror of https://github.com/ipfs/kubo.git synced 2025-06-28 00:39:31 +08:00

delete dead code

This code was making it *really* hard to understand the commands code.

License: MIT
Signed-off-by: Steven Allen <steven@stebalien.com>
This commit is contained in:
Steven Allen
2018-03-16 11:00:49 -07:00
parent 682b263f3a
commit c24a08be2e
7 changed files with 0 additions and 1068 deletions

View File

@ -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
}

View File

@ -9,15 +9,9 @@ output to the user, including text, JSON, and XML marshallers.
package commands package commands
import ( import (
"errors"
"fmt"
"io" "io"
"reflect"
"github.com/ipfs/go-ipfs/path"
logging "gx/ipfs/QmRb5jh8z2E8hMGN2tkvs1yHynUanqnZ3UeKwgN1i9P1F8/go-log" logging "gx/ipfs/QmRb5jh8z2E8hMGN2tkvs1yHynUanqnZ3UeKwgN1i9P1F8/go-log"
cmds "gx/ipfs/QmabLouZTZwhfALuBcssPvkzhbYGMb4394huT7HY4LQ6d3/go-ipfs-cmds"
cmdkit "gx/ipfs/QmceUdzxkimdYsgtX733uNgzf1DLHyBKN6ehGSp85ayppM/go-ipfs-cmdkit" cmdkit "gx/ipfs/QmceUdzxkimdYsgtX733uNgzf1DLHyBKN6ehGSp85ayppM/go-ipfs-cmdkit"
) )
@ -64,233 +58,11 @@ type Command struct {
Subcommands map[string]*Command 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 // Subcommand returns the subcommand with the given id
func (c *Command) Subcommand(id string) *Command { func (c *Command) Subcommand(id string) *Command {
return c.Subcommands[id] 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 { func ClientError(msg string) error {
return &cmdkit.Error{Code: cmdkit.ErrClient, Message: msg} 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,
}

View File

@ -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")
}
}

View File

@ -147,32 +147,6 @@ func (r *requestWrapper) Values() map[string]interface{} {
return nil 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 // copied from go-ipfs-cmds/request.go
func convertOptions(req *cmds.Request) error { func convertOptions(req *cmds.Request) error {
optDefSlice := req.Command.Options optDefSlice := req.Command.Options

View File

@ -1,20 +1,13 @@
package commands package commands
import ( import (
"bufio"
"context" "context"
"errors" "errors"
"fmt"
"io"
"os"
"reflect"
"strconv"
"strings" "strings"
"time" "time"
"github.com/ipfs/go-ipfs/core" "github.com/ipfs/go-ipfs/core"
"github.com/ipfs/go-ipfs/repo/config" "github.com/ipfs/go-ipfs/repo/config"
u "gx/ipfs/QmNiJuT8Ja3hMVpBHXv3Q6dwmperaQ6JjLtpMQgMCD7xvx/go-ipfs-util"
"gx/ipfs/QmabLouZTZwhfALuBcssPvkzhbYGMb4394huT7HY4LQ6d3/go-ipfs-cmds" "gx/ipfs/QmabLouZTZwhfALuBcssPvkzhbYGMb4394huT7HY4LQ6d3/go-ipfs-cmds"
"gx/ipfs/QmceUdzxkimdYsgtX733uNgzf1DLHyBKN6ehGSp85ayppM/go-ipfs-cmdkit" "gx/ipfs/QmceUdzxkimdYsgtX733uNgzf1DLHyBKN6ehGSp85ayppM/go-ipfs-cmdkit"
@ -59,12 +52,6 @@ func (c *Context) GetNode() (*core.IpfsNode, error) {
return c.node, err 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. // Context returns the node's context.
func (c *Context) Context() context.Context { func (c *Context) Context() context.Context {
n, err := c.GetNode() n, err := c.GetNode()
@ -112,316 +99,10 @@ type Request interface {
Path() []string Path() []string
Option(name string) *cmdkit.OptionValue Option(name string) *cmdkit.OptionValue
Options() cmdkit.OptMap Options() cmdkit.OptMap
SetOption(name string, val interface{})
SetOptions(opts cmdkit.OptMap) error
Arguments() []string Arguments() []string
StringArguments() []string StringArguments() []string
SetArguments([]string)
Files() files.File Files() files.File
SetFiles(files.File)
Context() context.Context Context() context.Context
InvocContext() *Context InvocContext() *Context
SetInvocContext(Context)
Command() *Command 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
} }

View File

@ -1,15 +1,8 @@
package commands package commands
import ( import (
"bytes"
"encoding/json"
"encoding/xml"
"fmt"
"io" "io"
"os"
"strings"
cmds "gx/ipfs/QmabLouZTZwhfALuBcssPvkzhbYGMb4394huT7HY4LQ6d3/go-ipfs-cmds"
cmdkit "gx/ipfs/QmceUdzxkimdYsgtX733uNgzf1DLHyBKN6ehGSp85ayppM/go-ipfs-cmdkit" cmdkit "gx/ipfs/QmceUdzxkimdYsgtX733uNgzf1DLHyBKN6ehGSp85ayppM/go-ipfs-cmdkit"
) )
@ -28,50 +21,6 @@ const (
// TODO: support more encoding types // 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, // Response is the result of a command request. Handlers write to the response,
// setting Error or Value. Response is returned to the client. // setting Error or Value. Response is returned to the client.
type Response interface { type Response interface {
@ -104,133 +53,3 @@ type Response interface {
Stdout() io.Writer Stdout() io.Writer
Stderr() 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,
}
}

View File

@ -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)
}