add.go 3.07 KB
Newer Older
1 2 3
package commands

import (
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
4
	"errors"
5
	"fmt"
6
	"io"
7 8 9 10 11 12
	"io/ioutil"
	"os"
	"path/filepath"

	"github.com/jbenet/go-ipfs/core"
	"github.com/jbenet/go-ipfs/importer"
Jeromy's avatar
Jeromy committed
13
	"github.com/jbenet/go-ipfs/importer/chunk"
14
	dag "github.com/jbenet/go-ipfs/merkledag"
Jeromy's avatar
Jeromy committed
15
	"github.com/jbenet/go-ipfs/pin"
16
	ft "github.com/jbenet/go-ipfs/unixfs"
Jeromy's avatar
Jeromy committed
17
	uio "github.com/jbenet/go-ipfs/unixfs/io"
18 19 20 21 22
)

// Error indicating the max depth has been exceded.
var ErrDepthLimitExceeded = fmt.Errorf("depth limit exceeded")

23
// Add is a command that imports files and directories -- given as arguments -- into ipfs.
24 25
func Add(n *core.IpfsNode, args []string, opts map[string]interface{}, out io.Writer) error {
	depth := 1
26 27

	// if recursive, set depth to reflect so
28 29 30
	if r, ok := opts["r"].(bool); r && ok {
		depth = -1
	}
31 32

	// add every path in args
33
	for _, path := range args {
34 35

		// Add the file
36
		_, err := AddPath(n, path, depth, out)
37
		if err != nil {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
38
			if err == ErrDepthLimitExceeded && depth == 1 {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
39
				err = errors.New("use -r to recursively add directories")
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
40
			}
41 42 43 44 45 46 47
			return fmt.Errorf("addFile error: %v", err)
		}

	}
	return nil
}

48
// AddPath adds a particular path to ipfs.
49
func AddPath(n *core.IpfsNode, fpath string, depth int, out io.Writer) (*dag.Node, error) {
50 51 52 53 54 55 56 57 58 59
	if depth == 0 {
		return nil, ErrDepthLimitExceeded
	}

	fi, err := os.Stat(fpath)
	if err != nil {
		return nil, err
	}

	if fi.IsDir() {
60
		return addDir(n, fpath, depth, out)
61 62
	}

63
	return addFile(n, fpath, depth, out)
64 65
}

66
func addDir(n *core.IpfsNode, fpath string, depth int, out io.Writer) (*dag.Node, error) {
67
	tree := &dag.Node{Data: ft.FolderPBData()}
68 69 70 71 72 73 74 75 76

	files, err := ioutil.ReadDir(fpath)
	if err != nil {
		return nil, err
	}

	// construct nodes for containing files.
	for _, f := range files {
		fp := filepath.Join(fpath, f.Name())
77
		nd, err := AddPath(n, fp, depth-1, out)
78 79 80 81 82 83 84 85 86
		if err != nil {
			return nil, err
		}

		if err = tree.AddNodeLink(f.Name(), nd); err != nil {
			return nil, err
		}
	}

87 88 89
	log.Info("adding dir: %s", fpath)

	return tree, addNode(n, tree, fpath, out)
90 91
}

92
func addFile(n *core.IpfsNode, fpath string, depth int, out io.Writer) (*dag.Node, error) {
Jeromy's avatar
Jeromy committed
93 94 95 96 97 98 99 100
	dw := uio.NewDagWriter(n.DAG, chunk.DefaultSplitter)
	mp, ok := n.Pinning.(pin.ManualPinner)
	if !ok {
		return nil, errors.New("invalid pinner type! expected manual pinner")
	}
	dw.Pinner = mp

	root, err := importer.ImportFileDag(fpath, dw)
101 102 103 104
	if err != nil {
		return nil, err
	}

105
	log.Info("adding file: %s", fpath)
Jeromy's avatar
Jeromy committed
106 107

	for _, l := range root.Links {
108
		log.Info("adding subblock: %s %s", l.Name, l.Hash.B58String())
Jeromy's avatar
Jeromy committed
109 110
	}

111 112 113 114 115 116 117 118
	k, err := root.Key()
	if err != nil {
		return nil, err
	}

	// output that we've added this node
	fmt.Fprintf(out, "added %s %s\n", k, fpath)

119
	return root, nil
120 121 122
}

// addNode adds the node to the graph + local storage
123
func addNode(n *core.IpfsNode, nd *dag.Node, fpath string, out io.Writer) error {
124 125 126 127 128 129
	// add the file to the graph + local storage
	err := n.DAG.AddRecursive(nd)
	if err != nil {
		return err
	}

130 131 132 133 134 135 136 137
	k, err := nd.Key()
	if err != nil {
		return err
	}

	// output that we've added this node
	fmt.Fprintf(out, "added %s %s\n", k, fpath)

Jeromy's avatar
Jeromy committed
138 139
	// ensure we keep it
	return n.Pinning.Pin(nd, true)
140
}