mirror of
https://github.com/ipfs/kubo.git
synced 2025-06-27 07:57:30 +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:
@ -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
|
||||
}
|
@ -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,
|
||||
}
|
||||
|
@ -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")
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
Reference in New Issue
Block a user