add.go 2.79 KB
Newer Older
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
1 2 3 4 5 6 7 8
package main

import (
	"fmt"
	"github.com/gonuts/flag"
	"github.com/jbenet/commander"
	core "github.com/jbenet/go-ipfs/core"
	importer "github.com/jbenet/go-ipfs/importer"
9
	dag "github.com/jbenet/go-ipfs/merkledag"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
10 11
	u "github.com/jbenet/go-ipfs/util"
	mh "github.com/jbenet/go-multihash"
12
	"io/ioutil"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
13
	"os"
14
	"path/filepath"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
15 16
)

Juan Batiz-Benet's avatar
go lint  
Juan Batiz-Benet committed
17 18
// Error indicating the max depth has been exceded.
var ErrDepthLimitExceeded = fmt.Errorf("depth limit exceeded")
19

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
var cmdIpfsAdd = &commander.Command{
	UsageLine: "add",
	Short:     "Add an object to ipfs.",
	Long: `ipfs add <path>... - Add objects to ipfs.

    Adds contents of <path> to ipfs. Use -r to add directories.
    Note that directories are added recursively, to form the ipfs
    MerkleDAG. A smarter partial add with a staging area (like git)
    remains to be implemented.
`,
	Run:  addCmd,
	Flag: *flag.NewFlagSet("ipfs-add", flag.ExitOnError),
}

func init() {
	cmdIpfsAdd.Flag.Bool("r", false, "add objects recursively")
}

func addCmd(c *commander.Command, inp []string) error {
	if len(inp) < 1 {
		u.POut(c.Long)
		return nil
	}

	n, err := localNode()
	if err != nil {
		return err
	}

	recursive := c.Flag.Lookup("r").Value.Get().(bool)
	var depth int
	if recursive {
		depth = -1
	} else {
		depth = 1
	}

	for _, fpath := range inp {
58
		_, err := addPath(n, fpath, depth)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
59
		if err != nil {
60
			if !recursive {
Juan Batiz-Benet's avatar
go lint  
Juan Batiz-Benet committed
61
				return fmt.Errorf("%s is a directory. Use -r to add recursively", fpath)
62
			}
Juan Batiz-Benet's avatar
go lint  
Juan Batiz-Benet committed
63 64

			u.PErr("error adding %s: %v\n", fpath, err)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
65 66 67 68 69
		}
	}
	return err
}

70 71
func addPath(n *core.IpfsNode, fpath string, depth int) (*dag.Node, error) {
	if depth == 0 {
Juan Batiz-Benet's avatar
go lint  
Juan Batiz-Benet committed
72
		return nil, ErrDepthLimitExceeded
73 74
	}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
75 76
	fi, err := os.Stat(fpath)
	if err != nil {
77
		return nil, err
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
78 79 80 81 82
	}

	if fi.IsDir() {
		return addDir(n, fpath, depth)
	}
Juan Batiz-Benet's avatar
go lint  
Juan Batiz-Benet committed
83 84

	return addFile(n, fpath, depth)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
85 86
}

87 88
func addDir(n *core.IpfsNode, fpath string, depth int) (*dag.Node, error) {
	tree := &dag.Node{}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
89

90
	files, err := ioutil.ReadDir(fpath)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
91
	if err != nil {
92
		return nil, err
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
93 94
	}

95 96 97 98 99 100 101
	// construct nodes for containing files.
	for _, f := range files {
		fp := filepath.Join(fpath, f.Name())
		nd, err := addPath(n, fp, depth-1)
		if err != nil {
			return nil, err
		}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
102

103 104 105
		if err = tree.AddNodeLink(f.Name(), nd); err != nil {
			return nil, err
		}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
106 107
	}

108 109 110 111 112
	return tree, addNode(n, tree, fpath)
}

func addFile(n *core.IpfsNode, fpath string, depth int) (*dag.Node, error) {
	root, err := importer.NewDagFromFile(fpath)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
113
	if err != nil {
114
		return nil, err
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
115 116
	}

117 118 119 120 121
	return root, addNode(n, root, fpath)
}

// addNode adds the node to the graph + local storage
func addNode(n *core.IpfsNode, nd *dag.Node, fpath string) error {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
122
	// add the file to the graph + local storage
123
	k, err := n.DAG.Put(nd)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
124 125 126 127 128 129 130 131 132 133
	if err != nil {
		return err
	}

	u.POut("added %s %s\n", fpath, mh.Multihash(k).B58String())
	return nil

	// ensure we keep it. atm no-op
	// return n.PinDagNode(root)
}