diff --git a/core/commands/object.go b/core/commands/object.go index a93f32346..fb510012e 100644 --- a/core/commands/object.go +++ b/core/commands/object.go @@ -602,36 +602,75 @@ func addLinkCaller(req cmds.Request, root *dag.Node) (key.Key, error) { return "", err } - name := req.Arguments()[2] + path := req.Arguments()[2] childk := key.B58KeyDecode(req.Arguments()[3]) - newkey, err := addLink(req.Context().Context, nd.DAG, root, name, childk) + parts := strings.Split(path, "/") + + nnode, err := insertNodeAtPath(req.Context().Context, nd.DAG, root, parts, childk) if err != nil { return "", err } - - return newkey, nil + return nnode.Key() } -func addLink(ctx context.Context, ds dag.DAGService, root *dag.Node, childname string, childk key.Key) (key.Key, error) { +func addLink(ctx context.Context, ds dag.DAGService, root *dag.Node, childname string, childk key.Key) (*dag.Node, error) { ctx, cancel := context.WithTimeout(ctx, time.Second*30) childnd, err := ds.Get(ctx, childk) if err != nil { cancel() - return "", err + return nil, err } cancel() err = root.AddNodeLinkClean(childname, childnd) if err != nil { - return "", err + return nil, err } - newkey, err := ds.Add(root) + _, err = ds.Add(root) if err != nil { - return "", err + return nil, err } - return newkey, nil + return root, nil +} + +func insertNodeAtPath(ctx context.Context, ds dag.DAGService, root *dag.Node, path []string, toinsert key.Key) (*dag.Node, error) { + if len(path) == 1 { + return addLink(ctx, ds, root, path[0], toinsert) + } + + child, err := root.GetNodeLink(path[0]) + if err != nil { + return nil, err + } + + nd, err := child.GetNode(ctx, ds) + if err != nil { + return nil, err + } + + ndprime, err := insertNodeAtPath(ctx, ds, nd, path[1:], toinsert) + if err != nil { + return nil, err + } + + err = root.RemoveNodeLink(path[0]) + if err != nil { + return nil, err + } + + err = root.AddNodeLinkClean(path[0], ndprime) + if err != nil { + return nil, err + } + + _, err = ds.Add(root) + if err != nil { + return nil, err + } + + return root, nil } func nodeFromTemplate(template string) (*dag.Node, error) { diff --git a/test/sharness/t0051-object.sh b/test/sharness/t0051-object.sh index 4ab822dbc..c41dd621f 100755 --- a/test/sharness/t0051-object.sh +++ b/test/sharness/t0051-object.sh @@ -100,6 +100,20 @@ test_object_cmd() { OUTPUT=$(ipfs object patch $EMPTY_DIR add-link foo $EMPTY_DIR) ' + test_expect_success "multilayer ipfs patch works" ' + echo "hello world" > hwfile && + FILE=$(ipfs add -q hwfile) && + EMPTY=$(ipfs object new unixfs-dir) && + ONE=$(ipfs object patch $EMPTY add-link b $EMPTY) && + TWO=$(ipfs object patch $EMPTY add-link a $ONE) && + ipfs object patch $TWO add-link a/b/c $FILE > multi_patch + ' + + test_expect_success "output looks good" ' + ipfs cat $(cat multi_patch)/a/b/c > hwfile_out && + test_cmp hwfile hwfile_out + ' + test_expect_success "should have created dir within a dir" ' ipfs ls $OUTPUT > patched_output '