@cryptotaxi247 / kubo / commits / 434871ba1

core/commands/unixfs: Add 'ipfs unixfs ls ...'

This is similar to 'ipfs ls ...', but it: * Lists file sizes that match the content size: $ ipfs --encoding=json unixfs ls /ipfs/QmSRCHG21Sbqm3EJG9aEBo4vS7Fqu86pAjqf99MyCdNxZ4 { "Objects": [ { "Argument": "/ipfs/QmSRCHG21Sbqm3EJG9aEBo4vS7Fqu86pAjqf99MyCdNxZ4", "Links": [ { "Name": "busybox", "Hash": "QmPbjmmci73roXf9VijpyQGgRJZthiQfnEetaMRGoGYV5a", "Size": 1947624, "Type": 2 } ] } ] } $ ipfs cat /ipfs/QmSRCHG21Sbqm3EJG9aEBo4vS7Fqu86pAjqf99MyCdNxZ4/busybox | wc -c 1947624 'ipfs ls ...', on the other hand, is using the Merkle-descendant size, which also includes fanout links and the typing information unixfs objects store in their Data: $ ipfs --encoding=json ls /ipfs/QmSRCHG21Sbqm3EJG9aEBo4vS7Fqu86pAjqf99MyCdNxZ4 { "Objects": [ { "Hash": "/ipfs/QmSRCHG21Sbqm3EJG9aEBo4vS7Fqu86pAjqf99MyCdNxZ4", "Links": [ { "Name": "busybox", "Hash": "QmPbjmmci73roXf9VijpyQGgRJZthiQfnEetaMRGoGYV5a", "Size": 1948128, "Type": 2 } ] } ] } * Has a simpler text output corresponding to POSIX ls [1]: $ ipfs unixfs ls /ipfs/QmV2FrBtvue5ve7vxbAzKz3mTdWq8wfMNPwYd8d9KHksCF/gentoo/stage3/amd64/2015-04-02 bin dev etc proc run sys $ ipfs ls /ipfs/QmV2FrBtvue5ve7vxbAzKz3mTdWq8wfMNPwYd8d9KHksCF/gentoo/stage3/amd64/2015-04-02 QmSRCHG21Sbqm3EJG9aEBo4vS7Fqu86pAjqf99MyCdNxZ4 1948183 bin/ QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn 4 dev/ QmUz1Z5jnQEjwr78fiMk5babwjJBDmhN5sx5HvPiTGGGjM 1207 etc/ QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn 4 proc/ QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn 4 run/ QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn 4 sys/ The minimal output allows us to start off with POSIX compliance and then add options (which may or may not be POSIX compatible) to adjust the output format as we get a better feel for what we need ([2] through [3]). [1]: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ls.html [2]: https://botbot.me/freenode/ipfs/2015-06-12/?msg=41724727&page=5 [3]: https://botbot.me/freenode/ipfs/2015-06-12/?msg=41725146&page=5 License: MIT Signed-off-by: W. Trevor King <wking@tremily.us>

W. Trevor King committed Jun 9, 2015 at 10:03 UTC 434871ba18662db366907e358654728a357f9c0e
4 files changed +223
core/commands/root.go
+3
@@ -5,6 +5,7 @@ import (
5 "strings"
6
7 cmds "github.com/ipfs/go-ipfs/commands"
8 + unixfs "github.com/ipfs/go-ipfs/core/commands/unixfs"
9 evlog "github.com/ipfs/go-ipfs/thirdparty/eventlog"
10 )
11
@@ -35,6 +36,7 @@ DATA STRUCTURE COMMANDS
36
37 block Interact with raw blocks in the datastore
38 object Interact with raw dag nodes
39 + unixfs Interact with Unix filesystem objects
40
41 ADVANCED COMMANDS
42
@@ -102,6 +104,7 @@ var rootSubcommands = map[string]*cmds.Command{
104 "stats": StatsCmd,
105 "swarm": SwarmCmd,
106 "tour": tourCmd,
107 + "unixfs": unixfs.UnixFSCmd,
108 "update": UpdateCmd,
109 "version": VersionCmd,
110 "bitswap": BitswapCmd,
core/commands/unixfs/ls.go new
+124
@@ -0,0 +1,124 @@
1 +package unixfs
2 +
3 +import (
4 + "bytes"
5 + "fmt"
6 + "io"
7 + "text/tabwriter"
8 + "time"
9 +
10 + context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
11 +
12 + cmds "github.com/ipfs/go-ipfs/commands"
13 + core "github.com/ipfs/go-ipfs/core"
14 + path "github.com/ipfs/go-ipfs/path"
15 + unixfs "github.com/ipfs/go-ipfs/unixfs"
16 + unixfspb "github.com/ipfs/go-ipfs/unixfs/pb"
17 +)
18 +
19 +type LsLink struct {
20 + Name, Hash string
21 + Size uint64
22 + Type unixfspb.Data_DataType
23 +}
24 +
25 +type LsObject struct {
26 + Argument string
27 + Links []LsLink
28 +}
29 +
30 +type LsOutput struct {
31 + Objects []*LsObject
32 +}
33 +
34 +var LsCmd = &cmds.Command{
35 + Helptext: cmds.HelpText{
36 + Tagline: "List directory contents for Unix-filesystem objects",
37 + ShortDescription: `
38 +Retrieves the object named by <ipfs-or-ipns-path> and displays the
39 +contents with the following format:
40 +
41 + <hash> <type> <size> <name>
42 +
43 +For files, the child size is the total size of the file contents. For
44 +directories, the child size is the IPFS link size.
45 +`,
46 + },
47 +
48 + Arguments: []cmds.Argument{
49 + cmds.StringArg("ipfs-path", true, true, "The path to the IPFS object(s) to list links from").EnableStdin(),
50 + },
51 + Run: func(req cmds.Request, res cmds.Response) {
52 + node, err := req.Context().GetNode()
53 + if err != nil {
54 + res.SetError(err, cmds.ErrNormal)
55 + return
56 + }
57 +
58 + paths := req.Arguments()
59 +
60 + output := make([]*LsObject, len(paths))
61 + for i, fpath := range paths {
62 + dagnode, err := core.Resolve(req.Context().Context, node, path.Path(fpath))
63 + if err != nil {
64 + res.SetError(err, cmds.ErrNormal)
65 + return
66 + }
67 +
68 + output[i] = &LsObject{
69 + Argument: fpath,
70 + Links: make([]LsLink, len(dagnode.Links)),
71 + }
72 + for j, link := range dagnode.Links {
73 + ctx, cancel := context.WithTimeout(context.TODO(), time.Minute)
74 + defer cancel()
75 + link.Node, err = link.GetNode(ctx, node.DAG)
76 + if err != nil {
77 + res.SetError(err, cmds.ErrNormal)
78 + return
79 + }
80 + d, err := unixfs.FromBytes(link.Node.Data)
81 + if err != nil {
82 + res.SetError(err, cmds.ErrNormal)
83 + return
84 + }
85 + lsLink := LsLink{
86 + Name: link.Name,
87 + Hash: link.Hash.B58String(),
88 + Type: d.GetType(),
89 + }
90 + if lsLink.Type == unixfspb.Data_File {
91 + lsLink.Size = d.GetFilesize()
92 + } else {
93 + lsLink.Size = link.Size
94 + }
95 + output[i].Links[j] = lsLink
96 + }
97 + }
98 +
99 + res.SetOutput(&LsOutput{Objects: output})
100 + },
101 + Marshalers: cmds.MarshalerMap{
102 + cmds.Text: func(res cmds.Response) (io.Reader, error) {
103 +
104 + output := res.Output().(*LsOutput)
105 + buf := new(bytes.Buffer)
106 + w := tabwriter.NewWriter(buf, 1, 2, 1, ' ', 0)
107 + for _, object := range output.Objects {
108 + if len(output.Objects) > 1 {
109 + fmt.Fprintf(w, "%s:\n", object.Argument)
110 + }
111 + for _, link := range object.Links {
112 + fmt.Fprintf(w, "%s\n", link.Name)
113 + }
114 + if len(output.Objects) > 1 {
115 + fmt.Fprintln(w)
116 + }
117 + }
118 + w.Flush()
119 +
120 + return buf, nil
121 + },
122 + },
123 + Type: LsOutput{},
124 +}
core/commands/unixfs/unixfs.go new
+21
@@ -0,0 +1,21 @@
1 +package unixfs
2 +
3 +import cmds "github.com/ipfs/go-ipfs/commands"
4 +
5 +var UnixFSCmd = &cmds.Command{
6 + Helptext: cmds.HelpText{
7 + Tagline: "Interact with ipfs objects representing Unix filesystems",
8 + ShortDescription: `
9 +'ipfs unixfs' provides a familar interface to filesystems represtented
10 +by IPFS objects that hides IPFS-implementation details like layout
11 +objects (e.g. fanout and chunking).
12 +`,
13 + Synopsis: `
14 +ipfs unixfs ls <path>... - List directory contents for <path>...
15 +`,
16 + },
17 +
18 + Subcommands: map[string]*cmds.Command{
19 + "ls": LsCmd,
20 + },
21 +}
test/sharness/t0200-unixfs-ls.sh new
+75
@@ -0,0 +1,75 @@
1 +#!/bin/sh
2 +#
3 +# Copyright (c) 2014 Christian Couder
4 +# MIT Licensed; see the LICENSE file in this repository.
5 +#
6 +
7 +test_description="Test unixfs ls command"
8 +
9 +. lib/test-lib.sh
10 +
11 +test_init_ipfs
12 +
13 +test_ls_cmd() {
14 +
15 + test_expect_success "'ipfs add -r testData' succeeds" '
16 + mkdir -p testData testData/d1 testData/d2 &&
17 + echo "test" >testData/f1 &&
18 + echo "data" >testData/f2 &&
19 + echo "hello" >testData/d1/a &&
20 + random 128 42 >testData/d1/128 &&
21 + echo "world" >testData/d2/a &&
22 + random 1024 42 >testData/d2/1024 &&
23 + ipfs add -r testData >actual_add
24 + '
25 +
26 + test_expect_success "'ipfs add' output looks good" '
27 + cat <<-\EOF >expected_add &&
28 + added QmQNd6ubRXaNG6Prov8o6vk3bn6eWsj9FxLGrAVDUAGkGe testData/d1/128
29 + added QmZULkCELmmk5XNfCgTnCyFgAVxBRBXyDHGGMVoLFLiXEN testData/d1/a
30 + added QmSix55yz8CzWXf5ZVM9vgEvijnEeeXiTSarVtsqiiCJss testData/d1
31 + added QmbQBUSRL9raZtNXfpTDeaxQapibJEG6qEY8WqAN22aUzd testData/d2/1024
32 + added QmaRGe7bVmVaLmxbrMiVNXqW4pRNNp3xq7hFtyRKA3mtJL testData/d2/a
33 + added QmR3jhV4XpxxPjPT3Y8vNnWvWNvakdcT3H6vqpRBsX1MLy testData/d2
34 + added QmeomffUNfmQy76CQGy9NdmqEnnHU9soCexBnGU3ezPHVH testData/f1
35 + added QmNtocSs7MoDkJMc1RkyisCSKvLadujPsfJfSdJ3e1eA1M testData/f2
36 + added QmfNy183bXiRVyrhyWtq3TwHn79yHEkiAGFr18P7YNzESj testData
37 + EOF
38 + test_cmp expected_add actual_add
39 + '
40 +
41 + test_expect_success "'ipfs unixfs ls <three dir hashes>' succeeds" '
42 + ipfs unixfs ls QmfNy183bXiRVyrhyWtq3TwHn79yHEkiAGFr18P7YNzESj QmR3jhV4XpxxPjPT3Y8vNnWvWNvakdcT3H6vqpRBsX1MLy QmSix55yz8CzWXf5ZVM9vgEvijnEeeXiTSarVtsqiiCJss >actual_ls
43 + '
44 +
45 + test_expect_success "'ipfs unixfs ls <three dir hashes>' output looks good" '
46 + cat <<-\EOF >expected_ls &&
47 + QmfNy183bXiRVyrhyWtq3TwHn79yHEkiAGFr18P7YNzESj:
48 + d1
49 + d2
50 + f1
51 + f2
52 +
53 + QmR3jhV4XpxxPjPT3Y8vNnWvWNvakdcT3H6vqpRBsX1MLy:
54 + 1024
55 + a
56 +
57 + QmSix55yz8CzWXf5ZVM9vgEvijnEeeXiTSarVtsqiiCJss:
58 + 128
59 + a
60 +
61 + EOF
62 + test_cmp expected_ls actual_ls
63 + '
64 +}
65 +
66 +
67 +# should work offline
68 +test_ls_cmd
69 +
70 +# should work online
71 +test_launch_ipfs_daemon
72 +test_ls_cmd
73 +test_kill_ipfs_daemon
74 +
75 +test_done