diff --git a/core/commands/object.go b/core/commands/object.go index e522a1eb29e01c7cd3d51943e42c65f67b215566..75e6c52978e585d7b53e18bfbd1c98f8487bcd7d 100644 --- a/core/commands/object.go +++ b/core/commands/object.go @@ -582,36 +582,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 4ab822dbc200449fc444a8d2749cb9fa17ef0491..c41dd621f39de986d118714046bcabd27687da9d 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 '