diff --git a/mmv.go b/mmv.go index 58b58bd..28140ff 100644 --- a/mmv.go +++ b/mmv.go @@ -14,13 +14,31 @@ func Rename(files map[string]string) error { return err } for _, r := range rs { - if err := os.Rename(r.src, r.dst); err != nil { + if err := doRename(r.src, r.dst); err != nil { return err } } return nil } +// rename with creating the destination directory +func doRename(src, dst string) (err error) { + // first of all, try renaming the file, which will succeed in most cases + if err = os.Rename(src, dst); err != nil && os.IsNotExist(err) { + // check the source file existence to exit without creating the destination + // directory when the both source file and destination directory do not exist + if _, err := os.Stat(src); err == nil { + // create the destination directory + if err := os.MkdirAll(filepath.Dir(dst), 0755); err != nil { + return err + } + // try renaming again + return os.Rename(src, dst) + } + } + return +} + type rename struct { src, dst string } diff --git a/mmv_test.go b/mmv_test.go index 46809e0..e98fdc1 100644 --- a/mmv_test.go +++ b/mmv_test.go @@ -233,6 +233,25 @@ func TestRename(t *testing.T) { }, err: &sameDestinationError{"foo"}, }, + { + name: "create destination directory", + files: map[string]string{ + "foo": "x/foo", + "bar": "x/bar", + "baz": "a/b/c/baz", + }, + count: 3, + contents: map[string]string{ + "foo": "0", + "bar": "1", + "baz": "2", + }, + expected: map[string]string{ + "x/foo": "0", + "x/bar": "1", + "a/b/c/baz": "2", + }, + }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) {