@cryptotaxi247 / kubo / commits / b32d0ef15

implement 'editor' abstraction

License: MIT Signed-off-by: Jeromy <jeromyj@gmail.com>

Jeromy committed Jul 28, 2015 at 14:12 UTC b32d0ef15325a44861ec58cadf3e8d3286a32815
4 files changed +127 -55
core/commands/object.go
+19 -5
@@ -587,13 +587,17 @@ func rmLinkCaller(req cmds.Request, root *dag.Node) (key.Key, error) {
587 return "", err
588 }
589
590 - path := strings.Split(req.Arguments()[2], "/")
590 + path := req.Arguments()[2]
591 +
592 + e := dagutils.NewDagEditor(nd.DAG, root)
593
592 - nnode, err := dagutils.RmLink(req.Context(), nd.DAG, root, path)
594 + err = e.RmLink(req.Context(), path)
595 if err != nil {
596 return "", err
597 }
598
599 + nnode := e.GetNode()
600 +
601 return nnode.Key()
602 }
603
@@ -610,17 +614,27 @@ func addLinkCaller(req cmds.Request, root *dag.Node) (key.Key, error) {
614 path := req.Arguments()[2]
615 childk := key.B58KeyDecode(req.Arguments()[3])
616
613 - parts := strings.Split(path, "/")
614 -
617 create, _, err := req.Option("create").Bool()
618 if err != nil {
619 return "", err
620 }
621
620 - nnode, err := dagutils.InsertNodeAtPath(req.Context(), nd.DAG, root, parts, childk, create)
622 + var createfunc func() *dag.Node
623 + if create {
624 + createfunc = func() *dag.Node {
625 + return &dag.Node{Data: ft.FolderPBData()}
626 + }
627 + }
628 +
629 + e := dagutils.NewDagEditor(nd.DAG, root)
630 +
631 + err = e.InsertNodeAtPath(req.Context(), path, childk, createfunc)
632 if err != nil {
633 return "", err
634 }
635 +
636 + nnode := e.GetNode()
637 +
638 return nnode.Key()
639 }
640
merkledag/node.go
+15 -5
@@ -129,13 +129,23 @@ func (n *Node) AddRawLink(name string, l *Link) error {
129 // Remove a link on this node by the given name
130 func (n *Node) RemoveNodeLink(name string) error {
131 n.encoded = nil
132 - for i, l := range n.Links {
133 - if l.Name == name {
134 - n.Links = append(n.Links[:i], n.Links[i+1:]...)
135 - return nil
132 + good := make([]*Link, 0, len(n.Links))
133 + var found bool
134 +
135 + for _, l := range n.Links {
136 + if l.Name != name {
137 + good = append(good, l)
138 + } else {
139 + found = true
140 }
141 }
138 - return ErrNotFound
142 + n.Links = good
143 +
144 + if !found {
145 + return ErrNotFound
146 + }
147 +
148 + return nil
149 }
150
151 // Return a copy of the link with given name
merkledag/utils/utils.go
+54 -12
@@ -2,22 +2,44 @@ package dagutils
2
3 import (
4 "errors"
5 - "time"
5 + "strings"
6
7 context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
8
9 key "github.com/ipfs/go-ipfs/blocks/key"
10 dag "github.com/ipfs/go-ipfs/merkledag"
11 - ft "github.com/ipfs/go-ipfs/unixfs"
11 )
12
14 -func AddLink(ctx context.Context, ds dag.DAGService, root *dag.Node, childname string, childk key.Key) (*dag.Node, error) {
13 +type Editor struct {
14 + root *dag.Node
15 + ds dag.DAGService
16 +}
17 +
18 +func NewDagEditor(ds dag.DAGService, root *dag.Node) *Editor {
19 + return &Editor{
20 + root: root,
21 + ds: ds,
22 + }
23 +}
24 +
25 +func (e *Editor) GetNode() *dag.Node {
26 + return e.root.Copy()
27 +}
28 +
29 +func (e *Editor) AddLink(ctx context.Context, childname string, childk key.Key) error {
30 + nd, err := addLink(ctx, e.ds, e.root, childname, childk)
31 + if err != nil {
32 + return err
33 + }
34 + e.root = nd
35 + return nil
36 +}
37 +
38 +func addLink(ctx context.Context, ds dag.DAGService, root *dag.Node, childname string, childk key.Key) (*dag.Node, error) {
39 if childname == "" {
40 return nil, errors.New("cannot create link with no name!")
41 }
42
19 - ctx, cancel := context.WithTimeout(ctx, time.Second*30)
20 - defer cancel()
43 childnd, err := ds.Get(ctx, childk)
44 if err != nil {
45 return nil, err
@@ -38,22 +60,32 @@ func AddLink(ctx context.Context, ds dag.DAGService, root *dag.Node, childname s
60 return root, nil
61 }
62
41 -func InsertNodeAtPath(ctx context.Context, ds dag.DAGService, root *dag.Node, path []string, toinsert key.Key, create bool) (*dag.Node, error) {
63 +func (e *Editor) InsertNodeAtPath(ctx context.Context, path string, toinsert key.Key, create func() *dag.Node) error {
64 + splpath := strings.Split(path, "/")
65 + nd, err := insertNodeAtPath(ctx, e.ds, e.root, splpath, toinsert, create)
66 + if err != nil {
67 + return err
68 + }
69 + e.root = nd
70 + return nil
71 +}
72 +
73 +func insertNodeAtPath(ctx context.Context, ds dag.DAGService, root *dag.Node, path []string, toinsert key.Key, create func() *dag.Node) (*dag.Node, error) {
74 if len(path) == 1 {
43 - return AddLink(ctx, ds, root, path[0], toinsert)
75 + return addLink(ctx, ds, root, path[0], toinsert)
76 }
77
78 nd, err := root.GetLinkedNode(ctx, ds, path[0])
79 if err != nil {
80 // if 'create' is true, we create directories on the way down as needed
49 - if err == dag.ErrNotFound && create {
50 - nd = &dag.Node{Data: ft.FolderPBData()}
81 + if err == dag.ErrNotFound && create != nil {
82 + nd = create()
83 } else {
84 return nil, err
85 }
86 }
87
56 - ndprime, err := InsertNodeAtPath(ctx, ds, nd, path[1:], toinsert, create)
88 + ndprime, err := insertNodeAtPath(ctx, ds, nd, path[1:], toinsert, create)
89 if err != nil {
90 return nil, err
91 }
@@ -72,7 +104,17 @@ func InsertNodeAtPath(ctx context.Context, ds dag.DAGService, root *dag.Node, pa
104 return root, nil
105 }
106
75 -func RmLink(ctx context.Context, ds dag.DAGService, root *dag.Node, path []string) (*dag.Node, error) {
107 +func (e *Editor) RmLink(ctx context.Context, path string) error {
108 + splpath := strings.Split(path, "/")
109 + nd, err := rmLink(ctx, e.ds, e.root, splpath)
110 + if err != nil {
111 + return err
112 + }
113 + e.root = nd
114 + return nil
115 +}
116 +
117 +func rmLink(ctx context.Context, ds dag.DAGService, root *dag.Node, path []string) (*dag.Node, error) {
118 if len(path) == 1 {
119 // base case, remove node in question
120 err := root.RemoveNodeLink(path[0])
@@ -93,7 +135,7 @@ func RmLink(ctx context.Context, ds dag.DAGService, root *dag.Node, path []strin
135 return nil, err
136 }
137
96 - nnode, err := RmLink(ctx, ds, nd, path[1:])
138 + nnode, err := rmLink(ctx, ds, nd, path[1:])
139 if err != nil {
140 return nil, err
141 }
merkledag/utils/utils_test.go
+39 -33
@@ -1,6 +1,7 @@
1 package dagutils
2
3 import (
4 + "strings"
5 "testing"
6
7 key "github.com/ipfs/go-ipfs/blocks/key"
@@ -22,7 +23,7 @@ func TestAddLink(t *testing.T) {
23 }
24
25 nd := new(dag.Node)
25 - nnode, err := AddLink(context.Background(), ds, nd, "fish", fk)
26 + nnode, err := addLink(context.Background(), ds, nd, "fish", fk)
27 if err != nil {
28 t.Fatal(err)
29 }
@@ -42,9 +43,10 @@ func TestAddLink(t *testing.T) {
43 }
44 }
45
45 -func assertNodeAtPath(t *testing.T, ds dag.DAGService, root *dag.Node, path []string, exp key.Key) {
46 +func assertNodeAtPath(t *testing.T, ds dag.DAGService, root *dag.Node, path string, exp key.Key) {
47 + parts := strings.Split(path, "/")
48 cur := root
47 - for _, e := range path {
49 + for _, e := range parts {
50 nxt, err := cur.GetLinkedNode(context.Background(), ds, e)
51 if err != nil {
52 t.Fatal(err)
@@ -66,53 +68,57 @@ func assertNodeAtPath(t *testing.T, ds dag.DAGService, root *dag.Node, path []st
68 func TestInsertNode(t *testing.T) {
69 ds := mdtest.Mock(t)
70 root := new(dag.Node)
71 + e := NewDagEditor(ds, root)
72
70 - childa := &dag.Node{
71 - Data: []byte("This is child A"),
72 - }
73 - ak, err := ds.Add(childa)
73 + testInsert(t, e, "a", "anodefortesting", false, "")
74 + testInsert(t, e, "a/b", "data", false, "")
75 + testInsert(t, e, "a/b/c/d/e", "blah", false, "merkledag: not found")
76 + testInsert(t, e, "a/b/c/d/e", "foo", true, "")
77 + testInsert(t, e, "a/b/c/d/f", "baz", true, "")
78 + testInsert(t, e, "a/b/c/d/f", "bar", true, "")
79 +
80 + testInsert(t, e, "", "bar", true, "cannot create link with no name!")
81 + testInsert(t, e, "////", "slashes", true, "cannot create link with no name!")
82 +
83 + k, err := e.GetNode().Key()
84 if err != nil {
85 t.Fatal(err)
86 }
87
78 - path := []string{"a", "b", "c", "d"}
79 - root_a, err := InsertNodeAtPath(context.Background(), ds, root, path, ak, true)
80 - if err != nil {
81 - t.Fatal(err)
88 + if k.B58String() != "QmThorWojP6YzLJwDukxiYCoKQSwyrMCvdt4WZ6rPm221t" {
89 + t.Fatal("output was different than expected")
90 }
83 - assertNodeAtPath(t, ds, root_a, path, ak)
91 +}
92
85 - childb := &dag.Node{Data: []byte("this is the second child")}
86 - bk, err := ds.Add(childb)
93 +func testInsert(t *testing.T, e *Editor, path, data string, create bool, experr string) {
94 + child := &dag.Node{Data: []byte(data)}
95 + ck, err := e.ds.Add(child)
96 if err != nil {
97 t.Fatal(err)
98 }
99
91 - // this one should fail, we are specifying a non-existant path
92 - // with create == false
93 - path2 := []string{"a", "b", "e", "f"}
94 - _, err = InsertNodeAtPath(context.Background(), ds, root_a, path2, bk, false)
95 - if err == nil {
96 - t.Fatal("that shouldnt have worked")
97 - }
98 - if err != dag.ErrNotFound {
99 - t.Fatal("expected this to fail with 'not found'")
100 + var c func() *dag.Node
101 + if create {
102 + c = func() *dag.Node {
103 + return &dag.Node{}
104 + }
105 }
106
102 - // inserting a path of length one should work with create == false
103 - path3 := []string{"x"}
104 - root_b, err := InsertNodeAtPath(context.Background(), ds, root_a, path3, bk, false)
105 - if err != nil {
106 - t.Fatal(err)
107 + err = e.InsertNodeAtPath(context.TODO(), path, ck, c)
108 + if experr != "" {
109 + var got string
110 + if err != nil {
111 + got = err.Error()
112 + }
113 + if got != experr {
114 + t.Fatalf("expected '%s' but got '%s'", experr, got)
115 + }
116 + return
117 }
118
109 - assertNodeAtPath(t, ds, root_b, path3, bk)
110 -
111 - // now try overwriting a path
112 - root_c, err := InsertNodeAtPath(context.Background(), ds, root_b, path, bk, false)
119 if err != nil {
120 t.Fatal(err)
121 }
122
117 - assertNodeAtPath(t, ds, root_c, path, bk)
123 + assertNodeAtPath(t, e.ds, e.root, path, ck)
124 }