diff --git a/core/commands/filestore.go b/core/commands/filestore.go index 70c02a3a41e..798b0ec8e1d 100644 --- a/core/commands/filestore.go +++ b/core/commands/filestore.go @@ -203,18 +203,8 @@ var dupsFileStore = &cmds.Command{ return nil }, - Encoders: cmds.EncoderMap{ - cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *RefWrapper) error { - if out.Err != "" { - return fmt.Errorf(out.Err) - } - - fmt.Fprintln(w, out.Ref) - - return nil - }), - }, - Type: RefWrapper{}, + Encoders: refsEncoderMap, + Type: RefWrapper{}, } func getFilestore(env cmds.Environment) (*core.IpfsNode, *filestore.Filestore, error) { diff --git a/core/commands/refs.go b/core/commands/refs.go index 5f5260be5b8..710679b6fe0 100644 --- a/core/commands/refs.go +++ b/core/commands/refs.go @@ -1,22 +1,33 @@ package commands import ( - "bytes" "context" "errors" + "fmt" "io" "strings" - cmds "github.com/ipfs/go-ipfs/commands" - "github.com/ipfs/go-ipfs/core" - e "github.com/ipfs/go-ipfs/core/commands/e" + core "github.com/ipfs/go-ipfs/core" + cmdenv "github.com/ipfs/go-ipfs/core/commands/cmdenv" cid "gx/ipfs/QmR8BauakNcBa3RbE4nbQu76PDiJgoQgz8AJdhJuiU4TAw/go-cid" path "gx/ipfs/QmRG3XuGwT7GYuAqgWDJBKTzdaHMwAnc1x7J2KHEXNHxzG/go-path" + cmds "gx/ipfs/Qma6uuSyjkecGhMFFLfzyJDPyoDtNJSHJNweDccZhaWkgU/go-ipfs-cmds" ipld "gx/ipfs/QmcKKBwfz6FyQdHR2jsXrrF6XeSBXYL86anmWNewpFpoF5/go-ipld-format" cmdkit "gx/ipfs/Qmde5VP1qUkyQXKCfmEUA7bP64V2HAptbJ7phuPp7jXWwg/go-ipfs-cmdkit" ) +var refsEncoderMap = cmds.EncoderMap{ + cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *RefWrapper) error { + if out.Err != "" { + return fmt.Errorf(out.Err) + } + fmt.Fprintln(w, out.Ref) + + return nil + }), +} + // KeyList is a general type for outputting lists of keys type KeyList struct { Keys []cid.Cid @@ -30,25 +41,7 @@ const ( refsMaxDepthOptionName = "max-depth" ) -// KeyListTextMarshaler outputs a KeyList as plaintext, one key per line -func KeyListTextMarshaler(res cmds.Response) (io.Reader, error) { - out, err := unwrapOutput(res.Output()) - if err != nil { - return nil, err - } - - output, ok := out.(*KeyList) - if !ok { - return nil, e.TypeErr(output, out) - } - - buf := new(bytes.Buffer) - for _, key := range output.Keys { - buf.WriteString(key.String() + "\n") - } - return buf, nil -} - +// RefsCmd is the `ipfs refs` command var RefsCmd = &cmds.Command{ Helptext: cmdkit.HelpText{ Tagline: "List links (references) from an object.", @@ -74,91 +67,62 @@ NOTE: List all references recursively by using the flag '-r'. cmdkit.BoolOption(refsRecursiveOptionName, "r", "Recursively list links of child nodes."), cmdkit.IntOption(refsMaxDepthOptionName, "Only for recursive refs, limits fetch and listing to the given depth").WithDefault(-1), }, - Run: func(req cmds.Request, res cmds.Response) { - ctx := req.Context() - n, err := req.InvocContext().GetNode() + Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error { + err := req.ParseBodyArgs() if err != nil { - res.SetError(err, cmdkit.ErrNormal) - return + return err } - unique, _, err := req.Option(refsUniqueOptionName).Bool() + ctx := req.Context + n, err := cmdenv.GetNode(env) if err != nil { - res.SetError(err, cmdkit.ErrNormal) - return + return err } - recursive, _, err := req.Option(refsRecursiveOptionName).Bool() - if err != nil { - res.SetError(err, cmdkit.ErrNormal) - return - } - - maxDepth, _, err := req.Option(refsMaxDepthOptionName).Int() - if err != nil { - res.SetError(err, cmdkit.ErrNormal) - return - } + unique, _ := req.Options[refsUniqueOptionName].(bool) + recursive, _ := req.Options[refsRecursiveOptionName].(bool) + maxDepth, _ := req.Options[refsMaxDepthOptionName].(int) + edges, _ := req.Options[refsEdgesOptionName].(bool) + format, _ := req.Options[refsFormatOptionName].(string) if !recursive { maxDepth = 1 // write only direct refs } - format, _, err := req.Option(refsFormatOptionName).String() - if err != nil { - res.SetError(err, cmdkit.ErrNormal) - return - } - - edges, _, err := req.Option(refsEdgesOptionName).Bool() - if err != nil { - res.SetError(err, cmdkit.ErrNormal) - return - } if edges { if format != "" { - res.SetError(errors.New("using format argument with edges is not allowed"), - cmdkit.ErrClient) - return + return errors.New("using format argument with edges is not allowed") } format = " -> " } - objs, err := objectsForPaths(ctx, n, req.Arguments()) + objs, err := objectsForPaths(ctx, n, req.Arguments) if err != nil { - res.SetError(err, cmdkit.ErrNormal) - return + return err } - out := make(chan interface{}) - res.SetOutput((<-chan interface{})(out)) - - go func() { - defer close(out) - - rw := RefWriter{ - out: out, - DAG: n.DAG, - Ctx: ctx, - Unique: unique, - PrintFmt: format, - MaxDepth: maxDepth, - } + rw := RefWriter{ + res: res, + DAG: n.DAG, + Ctx: ctx, + Unique: unique, + PrintFmt: format, + MaxDepth: maxDepth, + } - for _, o := range objs { - if _, err := rw.WriteRefs(o); err != nil { - select { - case out <- &RefWrapper{Err: err.Error()}: - case <-ctx.Done(): - } - return + for _, o := range objs { + if _, err := rw.WriteRefs(o); err != nil { + if err := res.Emit(&RefWrapper{Err: err.Error()}); err != nil { + return err } } - }() + } + + return nil }, - Marshalers: refsMarshallerMap, - Type: RefWrapper{}, + Encoders: refsEncoderMap, + Type: RefWrapper{}, } var RefsLocalCmd = &cmds.Command{ @@ -169,58 +133,30 @@ Displays the hashes of all local objects. `, }, - Run: func(req cmds.Request, res cmds.Response) { - ctx := req.Context() - n, err := req.InvocContext().GetNode() + Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error { + ctx := req.Context + n, err := cmdenv.GetNode(env) if err != nil { - res.SetError(err, cmdkit.ErrNormal) - return + return err } // todo: make async allKeys, err := n.Blockstore.AllKeysChan(ctx) if err != nil { - res.SetError(err, cmdkit.ErrNormal) - return + return err } - out := make(chan interface{}) - res.SetOutput((<-chan interface{})(out)) - - go func() { - defer close(out) - - for k := range allKeys { - select { - case out <- &RefWrapper{Ref: k.String()}: - case <-req.Context().Done(): - return - } + for k := range allKeys { + err := res.Emit(&RefWrapper{Ref: k.String()}) + if err != nil { + return err } - }() - }, - Marshalers: refsMarshallerMap, - Type: RefWrapper{}, -} - -var refsMarshallerMap = cmds.MarshalerMap{ - cmds.Text: func(res cmds.Response) (io.Reader, error) { - v, err := unwrapOutput(res.Output()) - if err != nil { - return nil, err } - obj, ok := v.(*RefWrapper) - if !ok { - return nil, e.TypeErr(obj, v) - } - - if obj.Err != "" { - return nil, errors.New(obj.Err) - } - - return strings.NewReader(obj.Ref + "\n"), nil + return nil }, + Encoders: refsEncoderMap, + Type: RefWrapper{}, } func objectsForPaths(ctx context.Context, n *core.IpfsNode, paths []string) ([]ipld.Node, error) { @@ -246,7 +182,7 @@ type RefWrapper struct { } type RefWriter struct { - out chan interface{} + res cmds.ResponseEmitter DAG ipld.DAGService Ctx context.Context @@ -260,7 +196,6 @@ type RefWriter struct { // WriteRefs writes refs of the given object to the underlying writer. func (rw *RefWriter) WriteRefs(n ipld.Node) (int, error) { return rw.writeRefsRecursive(n, 0) - } func (rw *RefWriter) writeRefsRecursive(n ipld.Node, depth int) (int, error) { @@ -394,6 +329,5 @@ func (rw *RefWriter) WriteEdge(from, to cid.Cid, linkname string) error { s += to.String() } - rw.out <- &RefWrapper{Ref: s} - return nil + return rw.res.Emit(&RefWrapper{Ref: s}) } diff --git a/core/commands/root.go b/core/commands/root.go index 654b0b7279e..62f2edfabcc 100644 --- a/core/commands/root.go +++ b/core/commands/root.go @@ -138,7 +138,7 @@ var rootSubcommands = map[string]*cmds.Command{ "pin": lgc.NewCommand(PinCmd), "ping": PingCmd, "p2p": P2PCmd, - "refs": lgc.NewCommand(RefsCmd), + "refs": RefsCmd, "resolve": ResolveCmd, "swarm": SwarmCmd, "tar": TarCmd, @@ -155,7 +155,8 @@ var RootRO = &cmds.Command{} var CommandsDaemonROCmd = CommandsCmd(RootRO) -var RefsROCmd = &oldcmds.Command{} +// RefsROCmd is `ipfs refs` command +var RefsROCmd = &cmds.Command{} var rootROSubcommands = map[string]*cmds.Command{ "commands": CommandsDaemonROCmd, @@ -198,12 +199,12 @@ func init() { // sanitize readonly refs command *RefsROCmd = *RefsCmd - RefsROCmd.Subcommands = map[string]*oldcmds.Command{} + RefsROCmd.Subcommands = map[string]*cmds.Command{} // this was in the big map definition above before, // but if we leave it there lgc.NewCommand will be executed // before the value is updated (:/sanitize readonly refs command/) - rootROSubcommands["refs"] = lgc.NewCommand(RefsROCmd) + rootROSubcommands["refs"] = RefsROCmd Root.Subcommands = rootSubcommands