From e9bd6fbba3d8e5098009dc1ff72d1c82660c36fe Mon Sep 17 00:00:00 2001 From: achingbrain Date: Thu, 9 Aug 2018 12:09:05 +0100 Subject: [PATCH] Allow mfs files.write command to create parent directories Adds support for a `-p/--parents` flag to the `files.write` command similar to the one supported by the `files.mkdir` command. If this is true and the directory for the file is not `"/"`, try to create the containing directory before writing to the file. License: MIT Signed-off-by: Alex Potsides --- core/commands/files.go | 24 ++++++++++++++++++++++++ test/sharness/t0250-files-api.sh | 17 ++++++++++++++++- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/core/commands/files.go b/core/commands/files.go index f8db88402d93..b54a3e1515ed 100644 --- a/core/commands/files.go +++ b/core/commands/files.go @@ -721,6 +721,7 @@ stat' on the file or any of its ancestors. Options: []cmdkit.Option{ cmdkit.IntOption("offset", "o", "Byte offset to begin writing at."), cmdkit.BoolOption("create", "e", "Create the file if it does not exist."), + cmdkit.BoolOption("parents", "p", "Make parent directories as needed."), cmdkit.BoolOption("truncate", "t", "Truncate the file to size zero before writing."), cmdkit.IntOption("count", "n", "Maximum number of bytes to read."), cmdkit.BoolOption("raw-leaves", "Use raw blocks for newly created leaf nodes. (experimental)"), @@ -735,6 +736,7 @@ stat' on the file or any of its ancestors. } create, _ := req.Options["create"].(bool) + mkParents, _ := req.Options["parents"].(bool) trunc, _ := req.Options["truncate"].(bool) flush, _ := req.Options["flush"].(bool) rawLeaves, rawLeavesDef := req.Options["raw-leaves"].(bool) @@ -757,6 +759,14 @@ stat' on the file or any of its ancestors. return } + if mkParents { + err := ensureContainingDirectoryExists(nd.FilesRoot, path, flush, prefix) + if err != nil { + re.SetError(err, cmdkit.ErrNormal) + return + } + } + fi, err := getFileHandle(nd.FilesRoot, path, create, prefix) if err != nil { re.SetError(err, cmdkit.ErrNormal) @@ -1146,6 +1156,20 @@ func getPrefix(req oldcmds.Request) (*cid.Prefix, error) { return &prefix, nil } +func ensureContainingDirectoryExists(r *mfs.Root, path string, flush bool, prefix *cid.Prefix) (error) { + dirtomake := gopath.Dir(path) + + if dirtomake == "/" { + return nil + } + + return mfs.Mkdir(r, dirtomake, mfs.MkdirOpts{ + Mkparents: true, + Flush: flush, + Prefix: prefix, + }) +} + func getFileHandle(r *mfs.Root, path string, create bool, prefix *cid.Prefix) (*mfs.File, error) { target, err := mfs.Lookup(r, path) switch err { diff --git a/test/sharness/t0250-files-api.sh b/test/sharness/t0250-files-api.sh index 007bad12da44..37a649c16e31 100755 --- a/test/sharness/t0250-files-api.sh +++ b/test/sharness/t0250-files-api.sh @@ -597,9 +597,24 @@ test_files_api() { ipfs files ls /adir | grep foobar ' + test_expect_failure "should fail to write file and create intermediate directories with no --parents flag set $EXTRA" ' + echo "ipfs rocks" | ipfs files write --create /parents/foo/ipfs.txt + ' + + test_expect_success "can write file and create intermediate directories $EXTRA" ' + echo "ipfs rocks" | ipfs files write --create --parents /parents/foo/bar/baz/ipfs.txt && + ipfs files stat "/parents/foo/bar/baz/ipfs.txt" | grep -q "^Type: file" + ' + + test_expect_success "can write file and create intermediate directories with short flags $EXTRA" ' + echo "ipfs rocks" | ipfs files write -e -p /parents/foo/bar/baz/qux/quux/garply/ipfs.txt && + ipfs files stat "/parents/foo/bar/baz/qux/quux/garply/ipfs.txt" | grep -q "^Type: file" + ' + test_expect_success "clean up $EXTRA" ' ipfs files rm -r /foobar && - ipfs files rm -r /adir + ipfs files rm -r /adir && + ipfs files rm -r /parents ' test_expect_success "root mfs entry is empty $EXTRA" '