1
0
mirror of https://github.com/ipfs/kubo.git synced 2025-05-30 14:43:45 +08:00
Files
W. Trevor King b304eef2d3 core/commands/unixfs/ls: Drop multi-column example from --help
The old text belonged to an earlier iteration that didn't land in the
rebased 434871ba (core/commands/unixfs: Add 'ipfs unixfs ls ...',
2015-06-09).
2015-07-06 09:15:13 -07:00

202 lines
4.5 KiB
Go

package unixfs
import (
"bytes"
"fmt"
"io"
"sort"
"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"
path "github.com/ipfs/go-ipfs/path"
unixfs "github.com/ipfs/go-ipfs/unixfs"
unixfspb "github.com/ipfs/go-ipfs/unixfs/pb"
)
type LsLink struct {
Name, Hash string
Size uint64
Type string
}
type LsObject struct {
Hash string
Size uint64
Type string
Links []LsLink
}
type LsOutput struct {
Arguments map[string]string
Objects map[string]*LsObject
}
var LsCmd = &cmds.Command{
Helptext: cmds.HelpText{
Tagline: "List directory contents for Unix-filesystem objects",
ShortDescription: `
Retrieves the object named by <ipfs-or-ipns-path> and displays the
contents.
The JSON output contains size information. For files, the child size
is the total size of the file contents. For directories, the child
size is the IPFS link size.
`,
},
Arguments: []cmds.Argument{
cmds.StringArg("ipfs-path", true, true, "The path to the IPFS object(s) to list links from").EnableStdin(),
},
Run: func(req cmds.Request, res cmds.Response) {
node, err := req.Context().GetNode()
if err != nil {
res.SetError(err, cmds.ErrNormal)
return
}
paths := req.Arguments()
output := LsOutput{
Arguments: map[string]string{},
Objects: map[string]*LsObject{},
}
for _, fpath := range paths {
ctx := req.Context().Context
merkleNode, err := core.Resolve(ctx, node, path.Path(fpath))
if err != nil {
res.SetError(err, cmds.ErrNormal)
return
}
key, err := merkleNode.Key()
if err != nil {
res.SetError(err, cmds.ErrNormal)
return
}
hash := key.B58String()
output.Arguments[fpath] = hash
if _, ok := output.Objects[hash]; ok {
// duplicate argument for an already-listed node
continue
}
unixFSNode, err := unixfs.FromBytes(merkleNode.Data)
if err != nil {
res.SetError(err, cmds.ErrNormal)
return
}
t := unixFSNode.GetType()
output.Objects[hash] = &LsObject{
Hash: key.String(),
Type: t.String(),
Size: unixFSNode.GetFilesize(),
}
switch t {
default:
res.SetError(fmt.Errorf("unrecognized type: %s", t), cmds.ErrImplementation)
return
case unixfspb.Data_File:
break
case unixfspb.Data_Directory:
links := make([]LsLink, len(merkleNode.Links))
output.Objects[hash].Links = links
for i, link := range merkleNode.Links {
getCtx, cancel := context.WithTimeout(ctx, time.Minute)
defer cancel()
link.Node, err = link.GetNode(getCtx, 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
}
t := d.GetType()
lsLink := LsLink{
Name: link.Name,
Hash: link.Hash.B58String(),
Type: t.String(),
}
if t == unixfspb.Data_File {
lsLink.Size = d.GetFilesize()
} else {
lsLink.Size = link.Size
}
links[i] = lsLink
}
}
}
res.SetOutput(&output)
},
Marshalers: cmds.MarshalerMap{
cmds.Text: func(res cmds.Response) (io.Reader, error) {
output := res.Output().(*LsOutput)
buf := new(bytes.Buffer)
w := tabwriter.NewWriter(buf, 1, 2, 1, ' ', 0)
nonDirectories := []string{}
directories := []string{}
for argument, hash := range output.Arguments {
object, ok := output.Objects[hash]
if !ok {
return nil, fmt.Errorf("unresolved hash: %s", hash)
}
if object.Type == "Directory" {
directories = append(directories, argument)
} else {
nonDirectories = append(nonDirectories, argument)
}
}
sort.Strings(nonDirectories)
sort.Strings(directories)
for _, argument := range nonDirectories {
fmt.Fprintf(w, "%s\n", argument)
}
seen := map[string]bool{}
for i, argument := range directories {
hash := output.Arguments[argument]
if _, ok := seen[hash]; ok {
continue
}
seen[hash] = true
object := output.Objects[hash]
if i > 0 || len(nonDirectories) > 0 {
fmt.Fprintln(w)
}
if len(output.Arguments) > 1 {
for _, arg := range directories[i:] {
if output.Arguments[arg] == hash {
fmt.Fprintf(w, "%s:\n", arg)
}
}
}
for _, link := range object.Links {
fmt.Fprintf(w, "%s\n", link.Name)
}
}
w.Flush()
return buf, nil
},
},
Type: LsOutput{},
}