github.com/keltia/go-ipfs@v0.3.8-0.20150909044612-210793031c63/merkledag/utils/utils.go (about) 1 package dagutils 2 3 import ( 4 "errors" 5 "strings" 6 7 context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" 8 9 dag "github.com/ipfs/go-ipfs/merkledag" 10 ) 11 12 type Editor struct { 13 root *dag.Node 14 ds dag.DAGService 15 } 16 17 func NewDagEditor(ds dag.DAGService, root *dag.Node) *Editor { 18 return &Editor{ 19 root: root, 20 ds: ds, 21 } 22 } 23 24 func (e *Editor) GetNode() *dag.Node { 25 return e.root.Copy() 26 } 27 28 func (e *Editor) GetDagService() dag.DAGService { 29 return e.ds 30 } 31 32 func addLink(ctx context.Context, ds dag.DAGService, root *dag.Node, childname string, childnd *dag.Node) (*dag.Node, error) { 33 if childname == "" { 34 return nil, errors.New("cannot create link with no name!") 35 } 36 37 // ensure that the node we are adding is in the dagservice 38 _, err := ds.Add(childnd) 39 if err != nil { 40 return nil, err 41 } 42 43 // ensure no link with that name already exists 44 _ = root.RemoveNodeLink(childname) // ignore error, only option is ErrNotFound 45 46 if err := root.AddNodeLinkClean(childname, childnd); err != nil { 47 return nil, err 48 } 49 50 if _, err := ds.Add(root); err != nil { 51 return nil, err 52 } 53 return root, nil 54 } 55 56 func (e *Editor) InsertNodeAtPath(ctx context.Context, path string, toinsert *dag.Node, create func() *dag.Node) error { 57 splpath := strings.Split(path, "/") 58 nd, err := insertNodeAtPath(ctx, e.ds, e.root, splpath, toinsert, create) 59 if err != nil { 60 return err 61 } 62 e.root = nd 63 return nil 64 } 65 66 func insertNodeAtPath(ctx context.Context, ds dag.DAGService, root *dag.Node, path []string, toinsert *dag.Node, create func() *dag.Node) (*dag.Node, error) { 67 if len(path) == 1 { 68 return addLink(ctx, ds, root, path[0], toinsert) 69 } 70 71 nd, err := root.GetLinkedNode(ctx, ds, path[0]) 72 if err != nil { 73 // if 'create' is true, we create directories on the way down as needed 74 if err == dag.ErrNotFound && create != nil { 75 nd = create() 76 } else { 77 return nil, err 78 } 79 } 80 81 ndprime, err := insertNodeAtPath(ctx, ds, nd, path[1:], toinsert, create) 82 if err != nil { 83 return nil, err 84 } 85 86 _ = root.RemoveNodeLink(path[0]) 87 err = root.AddNodeLinkClean(path[0], ndprime) 88 if err != nil { 89 return nil, err 90 } 91 92 _, err = ds.Add(root) 93 if err != nil { 94 return nil, err 95 } 96 97 return root, nil 98 } 99 100 func (e *Editor) RmLink(ctx context.Context, path string) error { 101 splpath := strings.Split(path, "/") 102 nd, err := rmLink(ctx, e.ds, e.root, splpath) 103 if err != nil { 104 return err 105 } 106 e.root = nd 107 return nil 108 } 109 110 func rmLink(ctx context.Context, ds dag.DAGService, root *dag.Node, path []string) (*dag.Node, error) { 111 if len(path) == 1 { 112 // base case, remove node in question 113 err := root.RemoveNodeLink(path[0]) 114 if err != nil { 115 return nil, err 116 } 117 118 _, err = ds.Add(root) 119 if err != nil { 120 return nil, err 121 } 122 123 return root, nil 124 } 125 126 nd, err := root.GetLinkedNode(ctx, ds, path[0]) 127 if err != nil { 128 return nil, err 129 } 130 131 nnode, err := rmLink(ctx, ds, nd, path[1:]) 132 if err != nil { 133 return nil, err 134 } 135 136 _ = root.RemoveNodeLink(path[0]) 137 err = root.AddNodeLinkClean(path[0], nnode) 138 if err != nil { 139 return nil, err 140 } 141 142 _, err = ds.Add(root) 143 if err != nil { 144 return nil, err 145 } 146 147 return root, nil 148 } 149 150 func (e *Editor) WriteOutputTo(ds dag.DAGService) error { 151 return copyDag(e.GetNode(), e.ds, ds) 152 } 153 154 func copyDag(nd *dag.Node, from, to dag.DAGService) error { 155 _, err := to.Add(nd) 156 if err != nil { 157 return err 158 } 159 160 for _, lnk := range nd.Links { 161 child, err := lnk.GetNode(context.Background(), from) 162 if err != nil { 163 if err == dag.ErrNotFound { 164 // not found means we didnt modify it, and it should 165 // already be in the target datastore 166 continue 167 } 168 return err 169 } 170 171 err = copyDag(child, from, to) 172 if err != nil { 173 return err 174 } 175 } 176 return nil 177 }