@cryptotaxi247 / kubo / commits / 69b8383e1

add a --with-local option to ipfs files stat

License: MIT Signed-off-by: Michael Muré <batolettre@gmail.com>

Michael Muré committed Feb 1, 2018 at 11:48 UTC 69b8383e1c6539a0833e4d0a44bb098cc2453f1d
1 file changed +88 -26
core/commands/files/files.go
+88 -26
@@ -10,10 +10,14 @@ import (
10 gopath "path"
11 "strings"
12
13 + "gx/ipfs/QmPSBJL4momYnE7DcUyk2DVhD6rH488ZmHBGLbxNdhU44K/go-humanize"
14 +
15 + bservice "github.com/ipfs/go-ipfs/blockservice"
16 oldcmds "github.com/ipfs/go-ipfs/commands"
17 lgc "github.com/ipfs/go-ipfs/commands/legacy"
18 core "github.com/ipfs/go-ipfs/core"
19 e "github.com/ipfs/go-ipfs/core/commands/e"
20 + "github.com/ipfs/go-ipfs/exchange/offline"
21 dag "github.com/ipfs/go-ipfs/merkledag"
22 mfs "github.com/ipfs/go-ipfs/mfs"
23 path "github.com/ipfs/go-ipfs/path"
@@ -69,6 +73,17 @@ var hashOption = cmdkit.StringOption("hash", "Hash function to use. Will set Cid
73
74 var formatError = errors.New("Format was set by multiple options. Only one format option is allowed")
75
76 +type StatOutput struct {
77 + Hash string
78 + Size uint64
79 + CumulativeSize uint64
80 + Blocks int
81 + Type string
82 + WithLocality bool
83 + Local bool `json:",omitempty"`
84 + SizeLocal uint64 `json:",omitempty"`
85 +}
86 +
87 const defaultStatFormat = `<hash>
88 Size: <size>
89 CumulativeSize: <cumulsize>
@@ -88,6 +103,7 @@ var filesStatCmd = &cmds.Command{
103 "<hash> <size> <cumulsize> <type> <childs>. Conflicts with other format options.").WithDefault(defaultStatFormat),
104 cmdkit.BoolOption("hash", "Print only hash. Implies '--format=<hash>'. Conflicts with other format options."),
105 cmdkit.BoolOption("size", "Print only size. Implies '--format=<cumulsize>'. Conflicts with other format options."),
106 + cmdkit.BoolOption("with-local", "Compute the amount of the dag that is local, and if possible the total size"),
107 },
108 Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) {
109
@@ -108,23 +124,41 @@ var filesStatCmd = &cmds.Command{
124 return
125 }
126
111 - fsn, err := mfs.Lookup(node.FilesRoot, path)
127 + nd, err := getNodeFromPath(req.Context, node, path)
128 if err != nil {
129 res.SetError(err, cmdkit.ErrNormal)
130 return
131 }
132
117 - o, err := statNode(fsn)
133 + o, err := statNode(nd)
134 if err != nil {
135 res.SetError(err, cmdkit.ErrNormal)
136 return
137 }
138
139 + withLocal, _ := req.Options["with-local"].(bool)
140 + if !withLocal {
141 + cmds.EmitOnce(res, o)
142 + return
143 + }
144 +
145 + // an offline DAGService will not fetch from the network
146 + dagserv := dag.NewDAGService(bservice.New(
147 + node.Blockstore,
148 + offline.Exchange(node.Blockstore),
149 + ))
150 +
151 + local, sizeLocal, err := walkBlock(req.Context, dagserv, nd)
152 +
153 + o.WithLocality = true
154 + o.Local = local
155 + o.SizeLocal = sizeLocal
156 +
157 cmds.EmitOnce(res, o)
158 },
159 Encoders: cmds.EncoderMap{
160 cmds.Text: cmds.MakeEncoder(func(req *cmds.Request, w io.Writer, v interface{}) error {
127 - out, ok := v.(*Object)
161 + out, ok := v.(*StatOutput)
162 if !ok {
163 return e.TypeErr(out, v)
164 }
@@ -136,11 +170,20 @@ var filesStatCmd = &cmds.Command{
170 s = strings.Replace(s, "<childs>", fmt.Sprintf("%d", out.Blocks), -1)
171 s = strings.Replace(s, "<type>", out.Type, -1)
172
139 - _, err := fmt.Fprintln(w, s)
140 - return err
173 + fmt.Fprintln(w, s)
174 +
175 + if out.WithLocality {
176 + fmt.Fprintf(w, "Local: %s of %s (%.2f%%)\n",
177 + humanize.Bytes(out.SizeLocal),
178 + humanize.Bytes(out.CumulativeSize),
179 + 100.0*float64(out.SizeLocal)/float64(out.CumulativeSize),
180 + )
181 + }
182 +
183 + return nil
184 }),
185 },
143 - Type: Object{},
186 + Type: StatOutput{},
187 }
188
189 func moreThanOne(a, b, c bool) bool {
@@ -166,12 +209,7 @@ func statGetFormatOptions(req *cmds.Request) (string, error) {
209 }
210 }
211
169 -func statNode(fsn mfs.FSNode) (*Object, error) {
170 - nd, err := fsn.GetNode()
171 - if err != nil {
172 - return nil, err
173 - }
174 -
212 +func statNode(nd ipld.Node) (*StatOutput, error) {
213 c := nd.Cid()
214
215 cumulsize, err := nd.Size()
@@ -187,16 +225,16 @@ func statNode(fsn mfs.FSNode) (*Object, error) {
225 }
226
227 var ndtype string
190 - switch fsn.Type() {
191 - case mfs.TDir:
228 + switch d.GetType() {
229 + case ft.TDirectory, ft.THAMTShard:
230 ndtype = "directory"
193 - case mfs.TFile:
231 + case ft.TFile, ft.TMetadata, ft.TRaw:
232 ndtype = "file"
233 default:
196 - return nil, fmt.Errorf("unrecognized node type: %s", fsn.Type())
234 + return nil, fmt.Errorf("unrecognized node type: %s", d.GetType())
235 }
236
199 - return &Object{
237 + return &StatOutput{
238 Hash: c.String(),
239 Blocks: len(nd.Links()),
240 Size: d.GetFilesize(),
@@ -204,7 +242,7 @@ func statNode(fsn mfs.FSNode) (*Object, error) {
242 Type: ndtype,
243 }, nil
244 case *dag.RawNode:
207 - return &Object{
245 + return &StatOutput{
246 Hash: c.String(),
247 Blocks: 0,
248 Size: cumulsize,
@@ -216,6 +254,38 @@ func statNode(fsn mfs.FSNode) (*Object, error) {
254 }
255 }
256
257 +func walkBlock(ctx context.Context, dagserv ipld.DAGService, nd ipld.Node) (bool, uint64, error) {
258 + // Start with the block data size
259 + sizeLocal := uint64(len(nd.RawData()))
260 +
261 + local := true
262 +
263 + for _, link := range nd.Links() {
264 + child, err := dagserv.Get(ctx, link.Cid)
265 +
266 + if err == ipld.ErrNotFound {
267 + local = false
268 + continue
269 + }
270 +
271 + if err != nil {
272 + return local, sizeLocal, err
273 + }
274 +
275 + childLocal, childLocalSize, err := walkBlock(ctx, dagserv, child)
276 +
277 + if err != nil {
278 + return local, sizeLocal, err
279 + }
280 +
281 + // Recursively add the child size
282 + local = local && childLocal
283 + sizeLocal += childLocalSize
284 + }
285 +
286 + return local, sizeLocal, nil
287 +}
288 +
289 var filesCpCmd = &oldcmds.Command{
290 Helptext: cmdkit.HelpText{
291 Tagline: "Copy files into mfs.",
@@ -298,14 +368,6 @@ func getNodeFromPath(ctx context.Context, node *core.IpfsNode, p string) (ipld.N
368 }
369 }
370
301 -type Object struct {
302 - Hash string
303 - Size uint64
304 - CumulativeSize uint64
305 - Blocks int
306 - Type string
307 -}
308 -
371 type filesLsOutput struct {
372 Entries []mfs.NodeListing
373 }