github.com/zignig/go-ipfs@v0.0.0-20141111235910-c9e5fdf55a52/core/commands/add.go (about) 1 package commands 2 3 import ( 4 "errors" 5 "fmt" 6 "io" 7 "io/ioutil" 8 "os" 9 "path/filepath" 10 11 "github.com/jbenet/go-ipfs/core" 12 "github.com/jbenet/go-ipfs/importer" 13 dag "github.com/jbenet/go-ipfs/merkledag" 14 "github.com/jbenet/go-ipfs/pin" 15 ft "github.com/jbenet/go-ipfs/unixfs" 16 ) 17 18 // Error indicating the max depth has been exceded. 19 var ErrDepthLimitExceeded = fmt.Errorf("depth limit exceeded") 20 21 // Add is a command that imports files and directories -- given as arguments -- into ipfs. 22 func Add(n *core.IpfsNode, args []string, opts map[string]interface{}, out io.Writer) error { 23 depth := 1 24 25 // if recursive, set depth to reflect so 26 if r, ok := opts["r"].(bool); r && ok { 27 depth = -1 28 } 29 30 // add every path in args 31 for _, path := range args { 32 33 // Add the file 34 _, err := AddPath(n, path, depth, out) 35 if err != nil { 36 if err == ErrDepthLimitExceeded && depth == 1 { 37 err = errors.New("use -r to recursively add directories") 38 } 39 return fmt.Errorf("addFile error: %v", err) 40 } 41 42 } 43 return nil 44 } 45 46 // AddPath adds a particular path to ipfs. 47 func AddPath(n *core.IpfsNode, fpath string, depth int, out io.Writer) (*dag.Node, error) { 48 if depth == 0 { 49 return nil, ErrDepthLimitExceeded 50 } 51 52 fi, err := os.Stat(fpath) 53 if err != nil { 54 return nil, err 55 } 56 57 if fi.IsDir() { 58 return addDir(n, fpath, depth, out) 59 } 60 61 return addFile(n, fpath, depth, out) 62 } 63 64 func addDir(n *core.IpfsNode, fpath string, depth int, out io.Writer) (*dag.Node, error) { 65 tree := &dag.Node{Data: ft.FolderPBData()} 66 67 files, err := ioutil.ReadDir(fpath) 68 if err != nil { 69 return nil, err 70 } 71 72 // construct nodes for containing files. 73 for _, f := range files { 74 fp := filepath.Join(fpath, f.Name()) 75 nd, err := AddPath(n, fp, depth-1, out) 76 if err != nil { 77 return nil, err 78 } 79 80 if err = tree.AddNodeLink(f.Name(), nd); err != nil { 81 return nil, err 82 } 83 } 84 85 log.Infof("adding dir: %s", fpath) 86 87 return tree, addNode(n, tree, fpath, out) 88 } 89 90 func addFile(n *core.IpfsNode, fpath string, depth int, out io.Writer) (*dag.Node, error) { 91 mp, ok := n.Pinning.(pin.ManualPinner) 92 if !ok { 93 return nil, errors.New("invalid pinner type! expected manual pinner") 94 } 95 96 root, err := importer.BuildDagFromFile(fpath, n.DAG, mp) 97 if err != nil { 98 return nil, err 99 } 100 101 log.Infof("adding file: %s", fpath) 102 103 for _, l := range root.Links { 104 log.Infof("adding subblock: '%s' %s", l.Name, l.Hash.B58String()) 105 } 106 107 k, err := root.Key() 108 if err != nil { 109 return nil, err 110 } 111 112 // output that we've added this node 113 fmt.Fprintf(out, "added %s %s\n", k, fpath) 114 115 return root, nil 116 } 117 118 // addNode adds the node to the graph + local storage 119 func addNode(n *core.IpfsNode, nd *dag.Node, fpath string, out io.Writer) error { 120 // add the file to the graph + local storage 121 err := n.DAG.AddRecursive(nd) 122 if err != nil { 123 return err 124 } 125 126 k, err := nd.Key() 127 if err != nil { 128 return err 129 } 130 131 // output that we've added this node 132 fmt.Fprintf(out, "added %s %s\n", k, fpath) 133 134 // ensure we keep it 135 return n.Pinning.Pin(nd, true) 136 }