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  }