Skip to content

Commit

Permalink
core/commands/unixfs/ls: Don't recurse into chunked files
Browse files Browse the repository at this point in the history
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
  QmW1HetBAhJPQgLMpYXyRb8JV4AU8d8WFvK9wkiNc4ki31 File 262144
  QmcG1bJ3dtKdEqKv4pyzNZaNdFGb4eS4TYP3MNXyj1K4sD File 262144
  QmYuAwy4tEeRkWe2BG8CAUW6amjgDQAQXJ2Efikqip2r66 File 262144
  QmccDNKasKMBZ7jRGfYwUwqaQrHu2GMUaD9pdYcAVjzfKV File 262144
  QmYHZJzWo4UTTtsbFJU6Ls79tp8t1AxsRsG6siNefVCf17 File 262144
  QmXWXzjBB9i9NkpUEausaWPE1UoZhMfhyjVeUhZAFoHmr6 File 262144
  Qmasn9Hzj5PsMXoy7bnu7WVXMLq1jYg7uTs2eWoyVbyiE3 File 262144
  QmTwygpqpUkCq68YLPuzwVVW2QWkt7StAPW6DvK3aQTL5v File 112616

And with this commit we have:

  $ ipfs unixfs ls /ipfs/QmSRCHG21Sbqm3EJG9aEBo4vS7Fqu86pAjqf99MyCdNxZ4/busybox
  QmPbjmmci73roXf9VijpyQGgRJZthiQfnEetaMRGoGYV5a File 1947624 /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:
  QmPbjmmci73roXf9VijpyQGgRJZthiQfnEetaMRGoGYV5a File 1947624 /ipfs/QmSRCHG21Sbqm3EJG9aEBo4vS7Fqu86pAjqf99MyCdNxZ4/busybox

As a side-effect of this rework, we no longer have the trialing blank
line that we used to have after the final directory listing.

I also dropped the minute-timeout context which landed in 'ipfs ls
...' with 0a6b880, fix for #1008 and other pinning fixes, #1010).
Instead, I just pass through this command's context.

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 <[email protected]>
  • Loading branch information
wking committed Jun 9, 2015
1 parent d0ce146 commit bdefbbb
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 35 deletions.
5 changes: 3 additions & 2 deletions commands/response.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@ type ErrorType uint

// ErrorTypes convey what category of error ocurred
const (
ErrNormal ErrorType = iota // general errors
ErrClient // error was caused by the client, (e.g. invalid CLI usage)
ErrNormal ErrorType = iota // general errors
ErrClient // error was caused by the client, (e.g. invalid CLI usage)
ErrImplementation // programmer error in the server
// TODO: add more types of errors for better error-specific handling
)

Expand Down
90 changes: 59 additions & 31 deletions core/commands/unixfs/ls.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,6 @@ import (
"fmt"
"io"
"text/tabwriter"
"time"

context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"

cmds "github.com/ipfs/go-ipfs/commands"
core "github.com/ipfs/go-ipfs/core"
Expand Down Expand Up @@ -68,40 +65,64 @@ directories, the child size is the IPFS link size.

output := make([]*LsObject, len(paths))
for i, fpath := range paths {
dagnode, err := core.Resolve(req.Context().Context, node, path.Path(fpath))
ctx := req.Context().Context
merkleNode, err := core.Resolve(ctx, node, path.Path(fpath))
if err != nil {
res.SetError(err, cmds.ErrNormal)
return
}

output[i] = &LsObject{
Argument: paths[i],
Links: make([]LsLink, len(dagnode.Links)),
unixFSNode, err := unixfs.FromBytes(merkleNode.Data)
if err != nil {
res.SetError(err, cmds.ErrNormal)
return
}
for j, link := range dagnode.Links {
ctx, cancel := context.WithTimeout(context.TODO(), time.Minute)
defer cancel()
link.Node, err = link.GetNode(ctx, node.DAG)
if err != nil {
res.SetError(err, cmds.ErrNormal)
return
}
d, err := unixfs.FromBytes(link.Node.Data)

output[i] = &LsObject{}

t := unixFSNode.GetType()
switch t {
default:
res.SetError(fmt.Errorf("unrecognized type: %s", t), cmds.ErrImplementation)
return
case unixfspb.Data_File:
key, err := merkleNode.Key()
if err != nil {
res.SetError(err, cmds.ErrNormal)
return
}
lsLink := LsLink{
Name: link.Name,
Hash: link.Hash.B58String(),
Type: d.GetType(),
output[i].Links = []LsLink{LsLink{
Name: paths[i],
Hash: key.String(),
Type: t,
Size: unixFSNode.GetFilesize(),
}}
case unixfspb.Data_Directory:
output[i].Argument = paths[i]
output[i].Links = make([]LsLink, len(merkleNode.Links))
for j, link := range merkleNode.Links {
link.Node, err = link.GetNode(ctx, node.DAG)
if err != nil {
res.SetError(err, cmds.ErrNormal)
return
}
d, err := unixfs.FromBytes(link.Node.Data)
if err != nil {
res.SetError(err, cmds.ErrNormal)
return
}
lsLink := LsLink{
Name: link.Name,
Hash: link.Hash.B58String(),
Type: d.GetType(),
}
if lsLink.Type == unixfspb.Data_File {
lsLink.Size = d.GetFilesize()
} else {
lsLink.Size = link.Size
}
output[i].Links[j] = lsLink
}
if lsLink.Type == unixfspb.Data_File {
lsLink.Size = d.GetFilesize()
} else {
lsLink.Size = link.Size
}
output[i].Links[j] = lsLink
}
}

Expand All @@ -114,9 +135,19 @@ directories, the child size is the IPFS link size.
output := res.Output().(*LsOutput)
buf := new(bytes.Buffer)
w := tabwriter.NewWriter(buf, 1, 2, 1, ' ', 0)
for _, object := range output.Objects {
if len(output.Objects) > 1 {
lastObjectDirHeader := false
for i, object := range output.Objects {
if len(output.Objects) > 1 && object.Argument != "" {
if i > 0 {
fmt.Fprintln(w)
}
fmt.Fprintf(w, "%s:\n", object.Argument)
lastObjectDirHeader = true
} else {
if lastObjectDirHeader {
fmt.Fprintln(w)
}
lastObjectDirHeader = false
}
if headers {
fmt.Fprintln(w, "Hash\tType\tSize\tName")
Expand All @@ -125,9 +156,6 @@ directories, the child size is the IPFS link size.
fmt.Fprintf(w, "%s\t%s\t%v\t%s\n",
link.Hash, link.Type.String(), link.Size, link.Name)
}
if len(output.Objects) > 1 {
fmt.Fprintln(w)
}
}
w.Flush()

Expand Down
14 changes: 12 additions & 2 deletions test/sharness/t0200-unixfs-ls.sh
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ test_ls_cmd() {
QmSix55yz8CzWXf5ZVM9vgEvijnEeeXiTSarVtsqiiCJss:
QmQNd6ubRXaNG6Prov8o6vk3bn6eWsj9FxLGrAVDUAGkGe File 128 128
QmZULkCELmmk5XNfCgTnCyFgAVxBRBXyDHGGMVoLFLiXEN File 6 a
EOF
test_cmp expected_ls actual_ls
'
Expand All @@ -84,10 +83,21 @@ test_ls_cmd() {
Hash Type Size Name
QmQNd6ubRXaNG6Prov8o6vk3bn6eWsj9FxLGrAVDUAGkGe File 128 128
QmZULkCELmmk5XNfCgTnCyFgAVxBRBXyDHGGMVoLFLiXEN File 6 a
EOF
test_cmp expected_ls_headers actual_ls_headers
'

test_expect_success "'ipfs unixfs ls <file hashes>' succeeds" '
ipfs unixfs ls /ipfs/QmR3jhV4XpxxPjPT3Y8vNnWvWNvakdcT3H6vqpRBsX1MLy/1024 QmQNd6ubRXaNG6Prov8o6vk3bn6eWsj9FxLGrAVDUAGkGe >actual_ls_file
'

test_expect_success "'ipfs unixfs ls <file hashes>' output looks good" '
cat <<-\EOF >expected_ls_file &&
QmbQBUSRL9raZtNXfpTDeaxQapibJEG6qEY8WqAN22aUzd File 1024 /ipfs/QmR3jhV4XpxxPjPT3Y8vNnWvWNvakdcT3H6vqpRBsX1MLy/1024
QmQNd6ubRXaNG6Prov8o6vk3bn6eWsj9FxLGrAVDUAGkGe File 128 QmQNd6ubRXaNG6Prov8o6vk3bn6eWsj9FxLGrAVDUAGkGe
EOF
test_cmp expected_ls_file actual_ls_file
'
}

# should work offline
Expand Down

0 comments on commit bdefbbb

Please sign in to comment.