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 <alex@achingbrain.net>
This commit is contained in:
achingbrain 2018-08-09 12:09:05 +01:00
parent 0e5ed59400
commit c97c44e8a4
2 changed files with 44 additions and 1 deletions

View File

@ -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, 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,19 @@ func getPrefix(req oldcmds.Request) (cid.Builder, error) {
return &prefix, nil
}
func ensureContainingDirectoryExists(r *mfs.Root, path string, builder cid.Builder) error {
dirtomake := gopath.Dir(path)
if dirtomake == "/" {
return nil
}
return mfs.Mkdir(r, dirtomake, mfs.MkdirOpts{
Mkparents: true,
CidBuilder: builder,
})
}
func getFileHandle(r *mfs.Root, path string, create bool, builder cid.Builder) (*mfs.File, error) {
target, err := mfs.Lookup(r, path)
switch err {

View File

@ -597,9 +597,29 @@ test_files_api() {
ipfs files ls /adir | grep foobar
'
test_expect_success "should fail to write file and create intermediate directories with no --parents flag set $EXTRA" '
echo "ipfs rocks" | test_must_fail 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 "can write another file in the same directory with -e -p $EXTRA" '
echo "ipfs rocks" | ipfs files write -e -p /parents/foo/bar/baz/qux/quux/garply/ipfs2.txt &&
ipfs files stat "/parents/foo/bar/baz/qux/quux/garply/ipfs2.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" '