cat.go 1.94 KB
Newer Older
1 2 3 4 5
package commands

import (
	"io"

Matt Bell's avatar
Matt Bell committed
6
	cmds "github.com/jbenet/go-ipfs/commands"
7
	core "github.com/jbenet/go-ipfs/core"
Jeromy's avatar
Jeromy committed
8
	path "github.com/jbenet/go-ipfs/path"
9
	uio "github.com/jbenet/go-ipfs/unixfs/io"
10 11

	"github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/cheggaaa/pb"
12 13
)

14 15
const progressBarMinSize = 1024 * 1024 * 8 // show progress bar for outputs > 8MiB

16
var CatCmd = &cmds.Command{
17 18 19 20
	Helptext: cmds.HelpText{
		Tagline: "Show IPFS object data",
		ShortDescription: `
Retrieves the object named by <ipfs-path> and outputs the data
21
it contains.
22 23
`,
	},
24 25

	Arguments: []cmds.Argument{
26
		cmds.StringArg("ipfs-path", true, true, "The path to the IPFS object(s) to be outputted").EnableStdin(),
27
	},
28
	Run: func(req cmds.Request, res cmds.Response) {
29 30
		node, err := req.Context().GetNode()
		if err != nil {
31 32
			res.SetError(err, cmds.ErrNormal)
			return
33 34
		}

Matt Bell's avatar
Matt Bell committed
35
		readers := make([]io.Reader, 0, len(req.Arguments()))
36

37
		readers, length, err := cat(node, req.Arguments())
38
		if err != nil {
39 40
			res.SetError(err, cmds.ErrNormal)
			return
41
		}
Matt Bell's avatar
Matt Bell committed
42

43 44
		res.SetLength(length)

Matt Bell's avatar
Matt Bell committed
45
		reader := io.MultiReader(readers...)
46
		res.SetOutput(reader)
Matt Bell's avatar
Matt Bell committed
47
	},
48
	PostRun: func(req cmds.Request, res cmds.Response) {
49 50 51 52 53
		if res.Length() < progressBarMinSize {
			return
		}

		bar := pb.New(int(res.Length())).SetUnits(pb.U_BYTES)
54
		bar.Output = res.Stderr()
55 56 57 58 59
		bar.Start()

		reader := bar.NewProxyReader(res.Output().(io.Reader))
		res.SetOutput(reader)
	},
60
}
61

62
func cat(node *core.IpfsNode, paths []string) ([]io.Reader, uint64, error) {
63
	readers := make([]io.Reader, 0, len(paths))
64
	length := uint64(0)
Jeromy's avatar
Jeromy committed
65 66
	for _, fpath := range paths {
		dagnode, err := node.Resolver.ResolvePath(path.Path(fpath))
67
		if err != nil {
68 69 70 71 72 73
			return nil, 0, err
		}

		nodeLength, err := dagnode.Size()
		if err != nil {
			return nil, 0, err
74
		}
75 76
		length += nodeLength

Jeromy's avatar
Jeromy committed
77
		read, err := uio.NewDagReader(node.Context(), dagnode, node.DAG)
78
		if err != nil {
79
			return nil, 0, err
80 81 82
		}
		readers = append(readers, read)
	}
83
	return readers, length, nil
84
}