add.go 2.74 KB
Newer Older
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
1 2 3 4
package main

import (
	"fmt"
5 6 7 8
	"io/ioutil"
	"os"
	"path/filepath"

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
9 10 11 12
	"github.com/gonuts/flag"
	"github.com/jbenet/commander"
	core "github.com/jbenet/go-ipfs/core"
	importer "github.com/jbenet/go-ipfs/importer"
13
	dag "github.com/jbenet/go-ipfs/merkledag"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
14 15 16
	u "github.com/jbenet/go-ipfs/util"
)

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
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
	}

44
	n, err := localNode(false)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
45 46 47 48 49 50 51 52 53 54 55 56 57
	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
func addDir(n *core.IpfsNode, fpath string, depth int) (*dag.Node, error) {
88
	tree := &dag.Node{Data: dag.FolderPBData()}
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
	err := n.DAG.AddRecursive(nd)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
124 125 126 127
	if err != nil {
		return err
	}

128
	u.POut("added %s\n", fpath)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
129 130

	// ensure we keep it. atm no-op
131
	return n.PinDagNode(nd)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
132
}