ls: use CoreAPI
License: MIT Signed-off-by: Łukasz Magiera <magik6k@gmail.com>
Łukasz Magiera committed
Feb 2, 2019 at 00:18 UTC
73f1e2dbf09f6ef094b73b280415392c78e9c88b
3 files changed
+70
-142
core/commands/ls.go
+57
-135
@@ -8,18 +8,12 @@ import (
8
9
cmdenv "github.com/ipfs/go-ipfs/core/commands/cmdenv"
10
iface "github.com/ipfs/go-ipfs/core/coreapi/interface"
11
+ options "github.com/ipfs/go-ipfs/core/coreapi/interface/options"
12
13
unixfs "gx/ipfs/QmQ1JnYpnzkaurjW1yxkQxC2w3K1PorNE1nv1vaP5Le7sq/go-unixfs"
13
- uio "gx/ipfs/QmQ1JnYpnzkaurjW1yxkQxC2w3K1PorNE1nv1vaP5Le7sq/go-unixfs/io"
14
unixfspb "gx/ipfs/QmQ1JnYpnzkaurjW1yxkQxC2w3K1PorNE1nv1vaP5Le7sq/go-unixfs/pb"
15
cmds "gx/ipfs/QmR77mMvvh8mJBBWQmBfQBu8oD38NUN4KE9SL2gDgAQNc6/go-ipfs-cmds"
16
- cid "gx/ipfs/QmR8BauakNcBa3RbE4nbQu76PDiJgoQgz8AJdhJuiU4TAw/go-cid"
17
- ipld "gx/ipfs/QmRL22E4paat7ky7vx9MLpR97JHHbFPrg3ytFQw6qp1y1s/go-ipld-format"
18
- blockservice "gx/ipfs/QmVKQHuzni68SWByzJgBUCwHvvr4TWiXfutNWWwpZpp4rE/go-blockservice"
19
- offline "gx/ipfs/QmYZwey1thDTynSrvd6qQkX24UpTka6TFhQ2v569UpoqxD/go-ipfs-exchange-offline"
20
- merkledag "gx/ipfs/Qmb2UEG2TAeVrEJSjqsZF7Y2he7wRDkrdt6c3bECxwZf4k/go-merkledag"
21
- cidenc "gx/ipfs/QmdPQx9fvN5ExVwMhRmh7YpCQJzJrFhd1AjVBwJmRMFJeX/go-cidutil/cidenc"
22
- "gx/ipfs/Qmde5VP1qUkyQXKCfmEUA7bP64V2HAptbJ7phuPp7jXWwg/go-ipfs-cmdkit"
16
+ cmdkit "gx/ipfs/Qmde5VP1qUkyQXKCfmEUA7bP64V2HAptbJ7phuPp7jXWwg/go-ipfs-cmdkit"
17
)
18
19
// LsLink contains printable data for a single ipld link in ls output
@@ -72,11 +66,6 @@ The JSON output contains type information.
66
cmdkit.BoolOption(lsStreamOptionName, "s", "Enable exprimental streaming of directory entries as they are traversed."),
67
},
68
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
75
- nd, err := cmdenv.GetNode(env)
76
- if err != nil {
77
- return err
78
- }
79
-
69
api, err := cmdenv.GetApi(env, req)
70
if err != nil {
71
return err
@@ -84,12 +73,7 @@ The JSON output contains type information.
73
74
resolveType, _ := req.Options[lsResolveTypeOptionName].(bool)
75
resolveSize, _ := req.Options[lsSizeOptionName].(bool)
87
- dserv := nd.DAG
88
- if !resolveType && !resolveSize {
89
- offlineexch := offline.Exchange(nd.Blockstore)
90
- bserv := blockservice.New(nd.Blockstore, offlineexch)
91
- dserv = merkledag.NewDAGService(bserv)
92
- }
76
+ stream, _ := req.Options[lsStreamOptionName].(bool)
77
78
err = req.ParseBodyArgs()
79
if err != nil {
@@ -102,90 +86,80 @@ The JSON output contains type information.
86
return err
87
}
88
105
- var dagnodes []ipld.Node
106
- for _, fpath := range paths {
107
- p, err := iface.ParsePath(fpath)
108
- if err != nil {
109
- return err
110
- }
111
- dagnode, err := api.ResolveNode(req.Context, p)
112
- if err != nil {
113
- return err
114
- }
115
- dagnodes = append(dagnodes, dagnode)
116
- }
117
- ng := merkledag.NewSession(req.Context, nd.DAG)
118
- ro := merkledag.NewReadOnlyDagService(ng)
89
+ var processLink func(path string, link LsLink) error
90
+ var dirDone func(i int)
91
120
- stream, _ := req.Options[lsStreamOptionName].(bool)
92
+ processDir := func() (func(path string, link LsLink) error, func(i int)) {
93
+ return func(path string, link LsLink) error {
94
+ output := []LsObject{{
95
+ Hash: path,
96
+ Links: []LsLink{link},
97
+ }}
98
+ return res.Emit(&LsOutput{output})
99
+ }, func(i int) {}
100
+ }
101
+ done := func() error { return nil }
102
103
if !stream {
104
output := make([]LsObject, len(req.Arguments))
105
125
- for i, dagnode := range dagnodes {
126
- dir, err := uio.NewDirectoryFromNode(ro, dagnode)
127
- if err != nil && err != uio.ErrNotADir {
128
- return fmt.Errorf("the data in %s (at %q) is not a UnixFS directory: %s", dagnode.Cid(), paths[i], err)
129
- }
130
-
131
- var links []*ipld.Link
132
- if dir == nil {
133
- links = dagnode.Links()
134
- } else {
135
- links, err = dir.Links(req.Context)
136
- if err != nil {
137
- return err
138
- }
139
- }
140
- outputLinks := make([]LsLink, len(links))
141
- for j, link := range links {
142
- lsLink, err := makeLsLink(req, dserv, resolveType, resolveSize, link, enc)
143
- if err != nil {
144
- return err
106
+ processDir = func() (func(path string, link LsLink) error, func(i int)) {
107
+ // for each dir
108
+ outputLinks := make([]LsLink, 0)
109
+ return func(path string, link LsLink) error {
110
+ // for each link
111
+ outputLinks = append(outputLinks, link)
112
+ return nil
113
+ }, func(i int) {
114
+ // after each dir
115
+ output[i] = LsObject{
116
+ Hash: paths[i],
117
+ Links: outputLinks,
118
+ }
119
}
146
- outputLinks[j] = *lsLink
147
- }
148
- output[i] = LsObject{
149
- Hash: paths[i],
150
- Links: outputLinks,
151
- }
120
}
121
154
- return cmds.EmitOnce(res, &LsOutput{output})
122
+ done = func() error {
123
+ return cmds.EmitOnce(res, &LsOutput{output})
124
+ }
125
}
126
157
- for i, dagnode := range dagnodes {
158
- dir, err := uio.NewDirectoryFromNode(ro, dagnode)
159
- if err != nil && err != uio.ErrNotADir {
160
- return fmt.Errorf("the data in %s (at %q) is not a UnixFS directory: %s", dagnode.Cid(), paths[i], err)
127
+ for i, fpath := range paths {
128
+ p, err := iface.ParsePath(fpath)
129
+ if err != nil {
130
+ return err
131
}
132
163
- var linkResults <-chan unixfs.LinkResult
164
- if dir == nil {
165
- linkResults = makeDagNodeLinkResults(req, dagnode)
166
- } else {
167
- linkResults = dir.EnumLinksAsync(req.Context)
133
+ results, err := api.Unixfs().Ls(req.Context, p,
134
+ options.Unixfs.Async(stream),
135
+ options.Unixfs.ResolveType(resolveType),
136
+ options.Unixfs.ResolveSize(resolveSize))
137
+ if err != nil {
138
+ return err
139
}
140
170
- for linkResult := range linkResults {
171
-
172
- if linkResult.Err != nil {
173
- return linkResult.Err
141
+ processLink, dirDone = processDir()
142
+ for link := range results {
143
+ if link.Err != nil {
144
+ return link.Err
145
}
175
- link := linkResult.Link
176
- lsLink, err := makeLsLink(req, dserv, resolveType, resolveSize, link, enc)
177
- if err != nil {
178
- return err
146
+ lsLink := LsLink{
147
+ Name: link.Link.Name,
148
+ Hash: enc.Encode(link.Link.Cid),
149
+
150
+ Size: link.Size,
151
+ Type: link.Type,
152
}
180
- output := []LsObject{{
181
- Hash: paths[i],
182
- Links: []LsLink{*lsLink},
183
- }}
184
- if err = res.Emit(&LsOutput{output}); err != nil {
153
+ if err := processLink(paths[i], lsLink); err != nil {
154
return err
155
}
156
}
157
+ dirDone(i)
158
}
159
+ if err := done(); err != nil {
160
+ return err
161
+ }
162
+
163
return nil
164
},
165
PostRun: cmds.PostRunMap{
@@ -219,58 +193,6 @@ The JSON output contains type information.
193
Type: LsOutput{},
194
}
195
222
-func makeDagNodeLinkResults(req *cmds.Request, dagnode ipld.Node) <-chan unixfs.LinkResult {
223
- links := dagnode.Links()
224
- linkResults := make(chan unixfs.LinkResult, len(links))
225
- defer close(linkResults)
226
- for _, l := range links {
227
- linkResults <- unixfs.LinkResult{
228
- Link: l,
229
- Err: nil,
230
- }
231
- }
232
- return linkResults
233
-}
234
-
235
-func makeLsLink(req *cmds.Request, dserv ipld.DAGService, resolveType bool, resolveSize bool, link *ipld.Link, enc cidenc.Encoder) (*LsLink, error) {
236
- t := unixfspb.Data_DataType(-1)
237
- var size uint64
238
-
239
- switch link.Cid.Type() {
240
- case cid.Raw:
241
- // No need to check with raw leaves
242
- t = unixfs.TFile
243
- size = link.Size
244
- case cid.DagProtobuf:
245
- linkNode, err := link.GetNode(req.Context, dserv)
246
- if err == ipld.ErrNotFound && !resolveType && !resolveSize {
247
- // not an error
248
- linkNode = nil
249
- } else if err != nil {
250
- return nil, err
251
- }
252
-
253
- if pn, ok := linkNode.(*merkledag.ProtoNode); ok {
254
- d, err := unixfs.FSNodeFromBytes(pn.Data())
255
- if err != nil {
256
- return nil, err
257
- }
258
- if resolveType {
259
- t = d.Type()
260
- }
261
- if d.Type() == unixfs.TFile && resolveSize {
262
- size = d.FileSize()
263
- }
264
- }
265
- }
266
- return &LsLink{
267
- Name: link.Name,
268
- Hash: enc.Encode(link.Cid),
269
- Size: size,
270
- Type: t,
271
- }, nil
272
-}
273
-
196
func tabularOutput(req *cmds.Request, w io.Writer, out *LsOutput, lastObjectHash string, ignoreBreaks bool) string {
197
headers, _ := req.Options[lsHeadersOptionNameTime].(bool)
198
stream, _ := req.Options[lsStreamOptionName].(bool)
core/coreapi/interface/options/unixfs.go
+5
-2
@@ -133,6 +133,9 @@ func UnixfsAddOptions(opts ...UnixfsAddOption) (*UnixfsAddSettings, cid.Prefix,
133
func UnixfsLsOptions(opts ...UnixfsLsOption) (*UnixfsLsSettings, error) {
134
options := &UnixfsLsSettings{
135
Async: true,
136
+
137
+ ResolveSize: true,
138
+ ResolveType: true,
139
}
140
141
for _, opt := range opts {
@@ -333,7 +336,7 @@ func (unixfsOpts) ResolveSize(resolve bool) UnixfsLsOption {
336
337
func (unixfsOpts) ResolveType(resolve bool) UnixfsLsOption {
338
return func(settings *UnixfsLsSettings) error {
336
- settings.ResolveSize = resolve
339
+ settings.ResolveType = resolve
340
return nil
341
}
339
-}
\ No newline at end of file
342
+}
core/coreapi/unixfs.go
+8
-5
@@ -151,24 +151,27 @@ func (api *UnixfsAPI) Ls(ctx context.Context, p coreiface.Path, opts ...options.
151
return nil, err
152
}
153
154
- dagnode, err := api.core().ResolveNode(ctx, p)
154
+ ses := api.core().getSession(ctx)
155
+ uses := (*UnixfsAPI)(ses)
156
+
157
+ dagnode, err := ses.ResolveNode(ctx, p)
158
if err != nil {
159
return nil, err
160
}
161
159
- dir, err := uio.NewDirectoryFromNode(api.dag, dagnode)
162
+ dir, err := uio.NewDirectoryFromNode(ses.dag, dagnode)
163
if err == uio.ErrNotADir {
161
- return api.lsFromLinks(ctx, dagnode.Links(), settings)
164
+ return uses.lsFromLinks(ctx, dagnode.Links(), settings)
165
}
166
if err != nil {
167
return nil, err
168
}
169
170
if !settings.Async {
168
- return api.lsFromDir(ctx, dir, settings)
171
+ return uses.lsFromDir(ctx, dir, settings)
172
}
173
171
- return api.lsFromLinksAsync(ctx, dir, settings)
174
+ return uses.lsFromLinksAsync(ctx, dir, settings)
175
}
176
177
func (api *UnixfsAPI) processLink(ctx context.Context, linkres ft.LinkResult, settings *options.UnixfsLsSettings) coreiface.LsLink {