@cryptotaxi247 / kubo / commits / 663f37cb9

core/commands/unixfs/ls: Don't recurse into chunked files

Folks operating at the Unix-filesystem level shouldn't care about that level of Merkle-DAG detail. Before this commit we had: $ ipfs unixfs ls /ipfs/QmSRCHG21Sbqm3EJG9aEBo4vS7Fqu86pAjqf99MyCdNxZ4/busybox /ipfs/QmSRCHG21Sbqm3EJG9aEBo4vS7Fqu86pAjqf99MyCdNxZ4/busybox: ... several lines of empty-string names ... And with this commit we have: $ ipfs unixfs ls /ipfs/QmSRCHG21Sbqm3EJG9aEBo4vS7Fqu86pAjqf99MyCdNxZ4/busybox /ipfs/QmSRCHG21Sbqm3EJG9aEBo4vS7Fqu86pAjqf99MyCdNxZ4/busybox I also reworked the argument-prefixing (object.Argument) in the output marshaller to avoid redundancies like: $ ipfs unixfs ls /ipfs/QmSRCHG21Sbqm3EJG9aEBo4vS7Fqu86pAjqf99MyCdNxZ4/busybox /ipfs/QmSRCHG21Sbqm3EJG9aEBo4vS7Fqu86pAjqf99MyCdNxZ4/busybox: /ipfs/QmSRCHG21Sbqm3EJG9aEBo4vS7Fqu86pAjqf99MyCdNxZ4/busybox As a side-effect of this rework, we no longer have the trailing blank line that we used to have after the final directory listing. The new ErrImplementation is like Python's NotImplementedError, and is mostly a way to guard against external changes that would need associated updates in this code. For example, once we see something that's neither a file nor a directory, we'll have to update the switch statement to handle those objects. License: MIT Signed-off-by: W. Trevor King <wking@tremily.us>

W. Trevor King committed Jun 9, 2015 at 14:06 UTC 663f37cb999f55cc18cc27b71c4df83afdc8fa10
3 files changed +76 -31
commands/response.go
+3 -2
@@ -15,8 +15,9 @@ type ErrorType uint
15
16 // ErrorTypes convey what category of error ocurred
17 const (
18 - ErrNormal ErrorType = iota // general errors
19 - ErrClient // error was caused by the client, (e.g. invalid CLI usage)
18 + ErrNormal ErrorType = iota // general errors
19 + ErrClient // error was caused by the client, (e.g. invalid CLI usage)
20 + ErrImplementation // programmer error in the server
21 // TODO: add more types of errors for better error-specific handling
22 )
23
core/commands/unixfs/ls.go
+61 -28
@@ -59,40 +59,66 @@ directories, the child size is the IPFS link size.
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))
62 + ctx := req.Context().Context
63 + merkleNode, err := core.Resolve(ctx, node, path.Path(fpath))
64 if err != nil {
65 res.SetError(err, cmds.ErrNormal)
66 return
67 }
68
68 - output[i] = &LsObject{
69 - Argument: fpath,
70 - Links: make([]LsLink, len(dagnode.Links)),
69 + unixFSNode, err := unixfs.FromBytes(merkleNode.Data)
70 + if err != nil {
71 + res.SetError(err, cmds.ErrNormal)
72 + return
73 }
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)
74 +
75 + output[i] = &LsObject{}
76 +
77 + t := unixFSNode.GetType()
78 + switch t {
79 + default:
80 + res.SetError(fmt.Errorf("unrecognized type: %s", t), cmds.ErrImplementation)
81 + return
82 + case unixfspb.Data_File:
83 + key, err := merkleNode.Key()
84 if err != nil {
85 res.SetError(err, cmds.ErrNormal)
86 return
87 }
85 - lsLink := LsLink{
86 - Name: link.Name,
87 - Hash: link.Hash.B58String(),
88 - Type: d.GetType(),
88 + output[i].Links = []LsLink{LsLink{
89 + Name: fpath,
90 + Hash: key.String(),
91 + Type: t,
92 + Size: unixFSNode.GetFilesize(),
93 + }}
94 + case unixfspb.Data_Directory:
95 + output[i].Argument = fpath
96 + output[i].Links = make([]LsLink, len(merkleNode.Links))
97 + for j, link := range merkleNode.Links {
98 + getCtx, cancel := context.WithTimeout(context.TODO(), time.Minute)
99 + defer cancel()
100 + link.Node, err = link.GetNode(getCtx, node.DAG)
101 + if err != nil {
102 + res.SetError(err, cmds.ErrNormal)
103 + return
104 + }
105 + d, err := unixfs.FromBytes(link.Node.Data)
106 + if err != nil {
107 + res.SetError(err, cmds.ErrNormal)
108 + return
109 + }
110 + lsLink := LsLink{
111 + Name: link.Name,
112 + Hash: link.Hash.B58String(),
113 + Type: d.GetType(),
114 + }
115 + if lsLink.Type == unixfspb.Data_File {
116 + lsLink.Size = d.GetFilesize()
117 + } else {
118 + lsLink.Size = link.Size
119 + }
120 + output[i].Links[j] = lsLink
121 }
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
122 }
123 }
124
@@ -104,16 +130,23 @@ directories, the child size is the IPFS link size.
130 output := res.Output().(*LsOutput)
131 buf := new(bytes.Buffer)
132 w := tabwriter.NewWriter(buf, 1, 2, 1, ' ', 0)
107 - for _, object := range output.Objects {
108 - if len(output.Objects) > 1 {
133 + lastObjectDirHeader := false
134 + for i, object := range output.Objects {
135 + if len(output.Objects) > 1 && object.Argument != "" {
136 + if i > 0 {
137 + fmt.Fprintln(w)
138 + }
139 fmt.Fprintf(w, "%s:\n", object.Argument)
140 + lastObjectDirHeader = true
141 + } else {
142 + if lastObjectDirHeader {
143 + fmt.Fprintln(w)
144 + }
145 + lastObjectDirHeader = false
146 }
147 for _, link := range object.Links {
148 fmt.Fprintf(w, "%s\n", link.Name)
149 }
114 - if len(output.Objects) > 1 {
115 - fmt.Fprintln(w)
116 - }
150 }
151 w.Flush()
152
test/sharness/t0200-unixfs-ls.sh
+12 -1
@@ -57,10 +57,21 @@ test_ls_cmd() {
57 QmSix55yz8CzWXf5ZVM9vgEvijnEeeXiTSarVtsqiiCJss:
58 128
59 a
60 -
60 EOF
61 test_cmp expected_ls actual_ls
62 '
63 +
64 + test_expect_success "'ipfs unixfs ls <file hashes>' succeeds" '
65 + ipfs unixfs ls /ipfs/QmR3jhV4XpxxPjPT3Y8vNnWvWNvakdcT3H6vqpRBsX1MLy/1024 QmQNd6ubRXaNG6Prov8o6vk3bn6eWsj9FxLGrAVDUAGkGe >actual_ls_file
66 + '
67 +
68 + test_expect_success "'ipfs unixfs ls <file hashes>' output looks good" '
69 + cat <<-\EOF >expected_ls_file &&
70 + /ipfs/QmR3jhV4XpxxPjPT3Y8vNnWvWNvakdcT3H6vqpRBsX1MLy/1024
71 + QmQNd6ubRXaNG6Prov8o6vk3bn6eWsj9FxLGrAVDUAGkGe
72 + EOF
73 + test_cmp expected_ls_file actual_ls_file
74 + '
75 }
76
77