github.com/keltia/go-ipfs@v0.3.8-0.20150909044612-210793031c63/core/commands/cat.go (about)

     1  package commands
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  
     7  	cmds "github.com/ipfs/go-ipfs/commands"
     8  	core "github.com/ipfs/go-ipfs/core"
     9  	path "github.com/ipfs/go-ipfs/path"
    10  	uio "github.com/ipfs/go-ipfs/unixfs/io"
    11  
    12  	"github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/cheggaaa/pb"
    13  	context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
    14  )
    15  
    16  const progressBarMinSize = 1024 * 1024 * 8 // show progress bar for outputs > 8MiB
    17  
    18  type clearlineReader struct {
    19  	io.Reader
    20  	out io.Writer
    21  }
    22  
    23  var CatCmd = &cmds.Command{
    24  	Helptext: cmds.HelpText{
    25  		Tagline: "Show IPFS object data",
    26  		ShortDescription: `
    27  Retrieves the object named by <ipfs-or-ipns-path> and outputs the data
    28  it contains.
    29  `,
    30  	},
    31  
    32  	Arguments: []cmds.Argument{
    33  		cmds.StringArg("ipfs-path", true, true, "The path to the IPFS object(s) to be outputted").EnableStdin(),
    34  	},
    35  	Run: func(req cmds.Request, res cmds.Response) {
    36  		node, err := req.InvocContext().GetNode()
    37  		if err != nil {
    38  			res.SetError(err, cmds.ErrNormal)
    39  			return
    40  		}
    41  
    42  		readers, length, err := cat(req.Context(), node, req.Arguments())
    43  		if err != nil {
    44  			res.SetError(err, cmds.ErrNormal)
    45  			return
    46  		}
    47  
    48  		res.SetLength(length)
    49  
    50  		reader := io.MultiReader(readers...)
    51  		res.SetOutput(reader)
    52  	},
    53  	PostRun: func(req cmds.Request, res cmds.Response) {
    54  		if res.Length() < progressBarMinSize {
    55  			return
    56  		}
    57  
    58  		bar := pb.New(int(res.Length())).SetUnits(pb.U_BYTES)
    59  		bar.Output = res.Stderr()
    60  		bar.Start()
    61  
    62  		reader := bar.NewProxyReader(res.Output().(io.Reader))
    63  		res.SetOutput(&clearlineReader{reader, res.Stderr()})
    64  	},
    65  }
    66  
    67  func cat(ctx context.Context, node *core.IpfsNode, paths []string) ([]io.Reader, uint64, error) {
    68  	readers := make([]io.Reader, 0, len(paths))
    69  	length := uint64(0)
    70  	for _, fpath := range paths {
    71  		dagnode, err := core.Resolve(ctx, node, path.Path(fpath))
    72  		if err != nil {
    73  			return nil, 0, err
    74  		}
    75  
    76  		read, err := uio.NewDagReader(ctx, dagnode, node.DAG)
    77  		if err != nil {
    78  			return nil, 0, err
    79  		}
    80  		readers = append(readers, read)
    81  		length += uint64(read.Size())
    82  	}
    83  	return readers, length, nil
    84  }
    85  
    86  func (r *clearlineReader) Read(p []byte) (n int, err error) {
    87  	n, err = r.Reader.Read(p)
    88  	if err == io.EOF {
    89  		fmt.Fprintf(r.out, "\033[2K\r") // clear progress bar line on EOF
    90  	}
    91  	return
    92  }