diff --git a/core/coreunix/add.go b/core/coreunix/add.go index ade57652b..629696a7e 100644 --- a/core/coreunix/add.go +++ b/core/coreunix/add.go @@ -1,11 +1,18 @@ package coreunix import ( + "errors" "io" + "os" + "path" + "github.com/jbenet/go-ipfs/commands/files" core "github.com/jbenet/go-ipfs/core" importer "github.com/jbenet/go-ipfs/importer" chunk "github.com/jbenet/go-ipfs/importer/chunk" + merkledag "github.com/jbenet/go-ipfs/merkledag" + "github.com/jbenet/go-ipfs/pin" + unixfs "github.com/jbenet/go-ipfs/unixfs" u "github.com/jbenet/go-ipfs/util" ) @@ -22,5 +29,107 @@ func Add(n *core.IpfsNode, r io.Reader) (u.Key, error) { if err != nil { return "", err } + // TODO(btc): is it necessary to flush the pinner? return dagNode.Key() } + +// AddR recursively adds files in |path|. +func AddR(n *core.IpfsNode, root string) (key string, err error) { + f, err := os.Open(root) + if err != nil { + return "", err + } + defer f.Close() + ff, err := files.NewSerialFile(root, f) + if err != nil { + return "", err + } + dagnode, err := addFile(n, ff) + if err != nil { + return "", err + } + k, err := dagnode.Key() + if err != nil { + return "", err + } + return k.String(), nil +} + +func add(n *core.IpfsNode, readers []io.Reader) ([]*merkledag.Node, error) { + mp, ok := n.Pinning.(pin.ManualPinner) + if !ok { + return nil, errors.New("invalid pinner type! expected manual pinner") + } + dagnodes := make([]*merkledag.Node, 0) + for _, reader := range readers { + node, err := importer.BuildDagFromReader(reader, n.DAG, mp, chunk.DefaultSplitter) + if err != nil { + return nil, err + } + dagnodes = append(dagnodes, node) + } + err := n.Pinning.Flush() + if err != nil { + return nil, err + } + return dagnodes, nil +} + +func addNode(n *core.IpfsNode, node *merkledag.Node) error { + err := n.DAG.AddRecursive(node) // add the file to the graph + local storage + if err != nil { + return err + } + err = n.Pinning.Pin(node, true) // ensure we keep it + if err != nil { + return err + } + return nil +} + +func addFile(n *core.IpfsNode, file files.File) (*merkledag.Node, error) { + if file.IsDirectory() { + return addDir(n, file) + } + + dns, err := add(n, []io.Reader{file}) + if err != nil { + return nil, err + } + + return dns[len(dns)-1], nil // last dag node is the file. +} + +func addDir(n *core.IpfsNode, dir files.File) (*merkledag.Node, error) { + + tree := &merkledag.Node{Data: unixfs.FolderPBData()} + +Loop: + for { + file, err := dir.NextFile() + switch { + case err != nil && err != io.EOF: + return nil, err + case err == io.EOF: + break Loop + } + + node, err := addFile(n, file) + if err != nil { + return nil, err + } + + _, name := path.Split(file.FileName()) + + err = tree.AddNodeLink(name, node) + if err != nil { + return nil, err + } + } + + err := addNode(n, tree) + if err != nil { + return nil, err + } + return tree, nil +} diff --git a/core/coreunix/add_test.go b/core/coreunix/add_test.go new file mode 100644 index 000000000..5987f47fe --- /dev/null +++ b/core/coreunix/add_test.go @@ -0,0 +1,37 @@ +package coreunix + +import ( + "os" + "path" + "testing" + + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context" + "github.com/jbenet/go-ipfs/core" + "github.com/jbenet/go-ipfs/repo" + "github.com/jbenet/go-ipfs/repo/config" + "github.com/jbenet/go-ipfs/util/testutil" +) + +func TestAddRecursive(t *testing.T) { + here, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + r := &repo.Mock{ + C: config.Config{ + Identity: config.Identity{ + PeerID: "Qmfoo", // required by offline node + }, + }, + D: testutil.ThreadSafeCloserMapDatastore(), + } + node, err := core.NewIPFSNode(context.Background(), core.Offline(r)) + if err != nil { + t.Fatal(err) + } + if k, err := AddR(node, path.Join(here, "test_data")); err != nil { + t.Fatal(err) + } else if k != "QmWCCga8AbTyfAQ7pTnGT6JgmRMAB3Qp8ZmTEFi5q5o8jC" { + t.Fatal("keys do not match") + } +} diff --git a/core/coreunix/test_data/colors/orange b/core/coreunix/test_data/colors/orange new file mode 100644 index 000000000..f8c1e5ce5 Binary files /dev/null and b/core/coreunix/test_data/colors/orange differ diff --git a/core/coreunix/test_data/corps/apple b/core/coreunix/test_data/corps/apple new file mode 100644 index 000000000..4c479deff Binary files /dev/null and b/core/coreunix/test_data/corps/apple differ diff --git a/core/coreunix/test_data/fruits/apple b/core/coreunix/test_data/fruits/apple new file mode 100644 index 000000000..4c479deff Binary files /dev/null and b/core/coreunix/test_data/fruits/apple differ diff --git a/core/coreunix/test_data/fruits/orange b/core/coreunix/test_data/fruits/orange new file mode 100644 index 000000000..f8c1e5ce5 Binary files /dev/null and b/core/coreunix/test_data/fruits/orange differ