From 73f1e2dbf09f6ef094b73b280415392c78e9c88b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Sat, 2 Feb 2019 00:18:44 +0100 Subject: [PATCH] ls: use CoreAPI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit License: MIT Signed-off-by: Ɓukasz Magiera --- core/commands/ls.go | 192 +++++++---------------- core/coreapi/interface/options/unixfs.go | 7 +- core/coreapi/unixfs.go | 13 +- 3 files changed, 70 insertions(+), 142 deletions(-) diff --git a/core/commands/ls.go b/core/commands/ls.go index 6033b89fd..bf16280cc 100644 --- a/core/commands/ls.go +++ b/core/commands/ls.go @@ -8,18 +8,12 @@ import ( cmdenv "github.com/ipfs/go-ipfs/core/commands/cmdenv" iface "github.com/ipfs/go-ipfs/core/coreapi/interface" + options "github.com/ipfs/go-ipfs/core/coreapi/interface/options" unixfs "gx/ipfs/QmQ1JnYpnzkaurjW1yxkQxC2w3K1PorNE1nv1vaP5Le7sq/go-unixfs" - uio "gx/ipfs/QmQ1JnYpnzkaurjW1yxkQxC2w3K1PorNE1nv1vaP5Le7sq/go-unixfs/io" unixfspb "gx/ipfs/QmQ1JnYpnzkaurjW1yxkQxC2w3K1PorNE1nv1vaP5Le7sq/go-unixfs/pb" cmds "gx/ipfs/QmR77mMvvh8mJBBWQmBfQBu8oD38NUN4KE9SL2gDgAQNc6/go-ipfs-cmds" - cid "gx/ipfs/QmR8BauakNcBa3RbE4nbQu76PDiJgoQgz8AJdhJuiU4TAw/go-cid" - ipld "gx/ipfs/QmRL22E4paat7ky7vx9MLpR97JHHbFPrg3ytFQw6qp1y1s/go-ipld-format" - blockservice "gx/ipfs/QmVKQHuzni68SWByzJgBUCwHvvr4TWiXfutNWWwpZpp4rE/go-blockservice" - offline "gx/ipfs/QmYZwey1thDTynSrvd6qQkX24UpTka6TFhQ2v569UpoqxD/go-ipfs-exchange-offline" - merkledag "gx/ipfs/Qmb2UEG2TAeVrEJSjqsZF7Y2he7wRDkrdt6c3bECxwZf4k/go-merkledag" - cidenc "gx/ipfs/QmdPQx9fvN5ExVwMhRmh7YpCQJzJrFhd1AjVBwJmRMFJeX/go-cidutil/cidenc" - "gx/ipfs/Qmde5VP1qUkyQXKCfmEUA7bP64V2HAptbJ7phuPp7jXWwg/go-ipfs-cmdkit" + cmdkit "gx/ipfs/Qmde5VP1qUkyQXKCfmEUA7bP64V2HAptbJ7phuPp7jXWwg/go-ipfs-cmdkit" ) // LsLink contains printable data for a single ipld link in ls output @@ -72,11 +66,6 @@ The JSON output contains type information. cmdkit.BoolOption(lsStreamOptionName, "s", "Enable exprimental streaming of directory entries as they are traversed."), }, Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error { - nd, err := cmdenv.GetNode(env) - if err != nil { - return err - } - api, err := cmdenv.GetApi(env, req) if err != nil { return err @@ -84,12 +73,7 @@ The JSON output contains type information. resolveType, _ := req.Options[lsResolveTypeOptionName].(bool) resolveSize, _ := req.Options[lsSizeOptionName].(bool) - dserv := nd.DAG - if !resolveType && !resolveSize { - offlineexch := offline.Exchange(nd.Blockstore) - bserv := blockservice.New(nd.Blockstore, offlineexch) - dserv = merkledag.NewDAGService(bserv) - } + stream, _ := req.Options[lsStreamOptionName].(bool) err = req.ParseBodyArgs() if err != nil { @@ -102,90 +86,80 @@ The JSON output contains type information. return err } - var dagnodes []ipld.Node - for _, fpath := range paths { - p, err := iface.ParsePath(fpath) - if err != nil { - return err - } - dagnode, err := api.ResolveNode(req.Context, p) - if err != nil { - return err - } - dagnodes = append(dagnodes, dagnode) - } - ng := merkledag.NewSession(req.Context, nd.DAG) - ro := merkledag.NewReadOnlyDagService(ng) + var processLink func(path string, link LsLink) error + var dirDone func(i int) - stream, _ := req.Options[lsStreamOptionName].(bool) + processDir := func() (func(path string, link LsLink) error, func(i int)) { + return func(path string, link LsLink) error { + output := []LsObject{{ + Hash: path, + Links: []LsLink{link}, + }} + return res.Emit(&LsOutput{output}) + }, func(i int) {} + } + done := func() error { return nil } if !stream { output := make([]LsObject, len(req.Arguments)) - for i, dagnode := range dagnodes { - dir, err := uio.NewDirectoryFromNode(ro, dagnode) - if err != nil && err != uio.ErrNotADir { - return fmt.Errorf("the data in %s (at %q) is not a UnixFS directory: %s", dagnode.Cid(), paths[i], err) - } - - var links []*ipld.Link - if dir == nil { - links = dagnode.Links() - } else { - links, err = dir.Links(req.Context) - if err != nil { - return err + processDir = func() (func(path string, link LsLink) error, func(i int)) { + // for each dir + outputLinks := make([]LsLink, 0) + return func(path string, link LsLink) error { + // for each link + outputLinks = append(outputLinks, link) + return nil + }, func(i int) { + // after each dir + output[i] = LsObject{ + Hash: paths[i], + Links: outputLinks, + } } - } - outputLinks := make([]LsLink, len(links)) - for j, link := range links { - lsLink, err := makeLsLink(req, dserv, resolveType, resolveSize, link, enc) - if err != nil { - return err - } - outputLinks[j] = *lsLink - } - output[i] = LsObject{ - Hash: paths[i], - Links: outputLinks, - } } - return cmds.EmitOnce(res, &LsOutput{output}) + done = func() error { + return cmds.EmitOnce(res, &LsOutput{output}) + } } - for i, dagnode := range dagnodes { - dir, err := uio.NewDirectoryFromNode(ro, dagnode) - if err != nil && err != uio.ErrNotADir { - return fmt.Errorf("the data in %s (at %q) is not a UnixFS directory: %s", dagnode.Cid(), paths[i], err) + for i, fpath := range paths { + p, err := iface.ParsePath(fpath) + if err != nil { + return err } - var linkResults <-chan unixfs.LinkResult - if dir == nil { - linkResults = makeDagNodeLinkResults(req, dagnode) - } else { - linkResults = dir.EnumLinksAsync(req.Context) + results, err := api.Unixfs().Ls(req.Context, p, + options.Unixfs.Async(stream), + options.Unixfs.ResolveType(resolveType), + options.Unixfs.ResolveSize(resolveSize)) + if err != nil { + return err } - for linkResult := range linkResults { + processLink, dirDone = processDir() + for link := range results { + if link.Err != nil { + return link.Err + } + lsLink := LsLink{ + Name: link.Link.Name, + Hash: enc.Encode(link.Link.Cid), - if linkResult.Err != nil { - return linkResult.Err + Size: link.Size, + Type: link.Type, } - link := linkResult.Link - lsLink, err := makeLsLink(req, dserv, resolveType, resolveSize, link, enc) - if err != nil { - return err - } - output := []LsObject{{ - Hash: paths[i], - Links: []LsLink{*lsLink}, - }} - if err = res.Emit(&LsOutput{output}); err != nil { + if err := processLink(paths[i], lsLink); err != nil { return err } } + dirDone(i) } + if err := done(); err != nil { + return err + } + return nil }, PostRun: cmds.PostRunMap{ @@ -219,58 +193,6 @@ The JSON output contains type information. Type: LsOutput{}, } -func makeDagNodeLinkResults(req *cmds.Request, dagnode ipld.Node) <-chan unixfs.LinkResult { - links := dagnode.Links() - linkResults := make(chan unixfs.LinkResult, len(links)) - defer close(linkResults) - for _, l := range links { - linkResults <- unixfs.LinkResult{ - Link: l, - Err: nil, - } - } - return linkResults -} - -func makeLsLink(req *cmds.Request, dserv ipld.DAGService, resolveType bool, resolveSize bool, link *ipld.Link, enc cidenc.Encoder) (*LsLink, error) { - t := unixfspb.Data_DataType(-1) - var size uint64 - - switch link.Cid.Type() { - case cid.Raw: - // No need to check with raw leaves - t = unixfs.TFile - size = link.Size - case cid.DagProtobuf: - linkNode, err := link.GetNode(req.Context, dserv) - if err == ipld.ErrNotFound && !resolveType && !resolveSize { - // not an error - linkNode = nil - } else if err != nil { - return nil, err - } - - if pn, ok := linkNode.(*merkledag.ProtoNode); ok { - d, err := unixfs.FSNodeFromBytes(pn.Data()) - if err != nil { - return nil, err - } - if resolveType { - t = d.Type() - } - if d.Type() == unixfs.TFile && resolveSize { - size = d.FileSize() - } - } - } - return &LsLink{ - Name: link.Name, - Hash: enc.Encode(link.Cid), - Size: size, - Type: t, - }, nil -} - func tabularOutput(req *cmds.Request, w io.Writer, out *LsOutput, lastObjectHash string, ignoreBreaks bool) string { headers, _ := req.Options[lsHeadersOptionNameTime].(bool) stream, _ := req.Options[lsStreamOptionName].(bool) diff --git a/core/coreapi/interface/options/unixfs.go b/core/coreapi/interface/options/unixfs.go index 6dbab93b6..4ff5cdb3f 100644 --- a/core/coreapi/interface/options/unixfs.go +++ b/core/coreapi/interface/options/unixfs.go @@ -133,6 +133,9 @@ func UnixfsAddOptions(opts ...UnixfsAddOption) (*UnixfsAddSettings, cid.Prefix, func UnixfsLsOptions(opts ...UnixfsLsOption) (*UnixfsLsSettings, error) { options := &UnixfsLsSettings{ Async: true, + + ResolveSize: true, + ResolveType: true, } for _, opt := range opts { @@ -333,7 +336,7 @@ func (unixfsOpts) ResolveSize(resolve bool) UnixfsLsOption { func (unixfsOpts) ResolveType(resolve bool) UnixfsLsOption { return func(settings *UnixfsLsSettings) error { - settings.ResolveSize = resolve + settings.ResolveType = resolve return nil } -} \ No newline at end of file +} diff --git a/core/coreapi/unixfs.go b/core/coreapi/unixfs.go index 9a66de3ca..5a3802fea 100644 --- a/core/coreapi/unixfs.go +++ b/core/coreapi/unixfs.go @@ -151,24 +151,27 @@ func (api *UnixfsAPI) Ls(ctx context.Context, p coreiface.Path, opts ...options. return nil, err } - dagnode, err := api.core().ResolveNode(ctx, p) + ses := api.core().getSession(ctx) + uses := (*UnixfsAPI)(ses) + + dagnode, err := ses.ResolveNode(ctx, p) if err != nil { return nil, err } - dir, err := uio.NewDirectoryFromNode(api.dag, dagnode) + dir, err := uio.NewDirectoryFromNode(ses.dag, dagnode) if err == uio.ErrNotADir { - return api.lsFromLinks(ctx, dagnode.Links(), settings) + return uses.lsFromLinks(ctx, dagnode.Links(), settings) } if err != nil { return nil, err } if !settings.Async { - return api.lsFromDir(ctx, dir, settings) + return uses.lsFromDir(ctx, dir, settings) } - return api.lsFromLinksAsync(ctx, dir, settings) + return uses.lsFromLinksAsync(ctx, dir, settings) } func (api *UnixfsAPI) processLink(ctx context.Context, linkres ft.LinkResult, settings *options.UnixfsLsSettings) coreiface.LsLink {