From 9c242edc10c403761b7ae94268af6c670523e1be Mon Sep 17 00:00:00 2001 From: lewapm <32110057+lewapm@users.noreply.github.com> Date: Wed, 13 Dec 2017 11:23:54 +0100 Subject: [PATCH] rmdirs: add --leave-root flag - fixes #1874 --- cmd/rmdirs/rmdirs.go | 9 ++++++++- docs/content/docs.md | 4 ++++ fs/operations.go | 6 +++--- fs/operations_test.go | 40 ++++++++++++++++++++++++++++++++++++++-- 4 files changed, 53 insertions(+), 6 deletions(-) diff --git a/cmd/rmdirs/rmdirs.go b/cmd/rmdirs/rmdirs.go index 5309c850b..735ef1769 100644 --- a/cmd/rmdirs/rmdirs.go +++ b/cmd/rmdirs/rmdirs.go @@ -6,8 +6,13 @@ import ( "github.com/spf13/cobra" ) +var ( + leaveRoot = false +) + func init() { cmd.Root.AddCommand(rmdirsCmd) + rmdirsCmd.Flags().BoolVarP(&leaveRoot, "leave-root", "", leaveRoot, "Do not remove root directory if empty") } var rmdirsCmd = &cobra.Command{ @@ -17,6 +22,8 @@ var rmdirsCmd = &cobra.Command{ empty directories) under the path that it finds, including the path if it has nothing in. +If you supply the --leave-root flag, it will not remove the root directory. + This is useful for tidying up remotes that rclone has left a lot of empty directories in. @@ -25,7 +32,7 @@ empty directories in. cmd.CheckArgs(1, 1, command, args) fdst := cmd.NewFsDst(args) cmd.Run(true, false, command, func() error { - return fs.Rmdirs(fdst, "") + return fs.Rmdirs(fdst, "", leaveRoot) }) }, } diff --git a/docs/content/docs.md b/docs/content/docs.md index 6e30fba7f..fa9f7c385 100644 --- a/docs/content/docs.md +++ b/docs/content/docs.md @@ -457,6 +457,10 @@ This can be useful as an additional layer of protection for immutable or append-only data sets (notably backup archives), where modification implies corruption and should not be propagated. +## --leave-root ### + +During rmdirs it will not remove root directory, even if it's empty. + ### --log-file=FILE ### Log all of rclone's output to FILE. This is not active by default. diff --git a/fs/operations.go b/fs/operations.go index 2a76bf100..11fc15a36 100644 --- a/fs/operations.go +++ b/fs/operations.go @@ -1183,7 +1183,7 @@ func Purge(f Fs) error { if err != nil { return err } - err = Rmdirs(f, "") + err = Rmdirs(f, "", false) } if err != nil { Stats.Error(err) @@ -1672,9 +1672,9 @@ func Rcat(fdst Fs, dstFileName string, in io.ReadCloser, modTime time.Time) (dst // Rmdirs removes any empty directories (or directories only // containing empty directories) under f, including f. -func Rmdirs(f Fs, dir string) error { +func Rmdirs(f Fs, dir string, leaveRoot bool) error { dirEmpty := make(map[string]bool) - dirEmpty[""] = true + dirEmpty[""] = !leaveRoot err := Walk(f, dir, true, Config.MaxDepth, func(dirPath string, entries DirEntries, err error) error { if err != nil { Stats.Error(err) diff --git a/fs/operations_test.go b/fs/operations_test.go index 58782f578..b95acb0d0 100644 --- a/fs/operations_test.go +++ b/fs/operations_test.go @@ -522,7 +522,7 @@ func TestRcat(t *testing.T) { check(false) } -func TestRmdirs(t *testing.T) { +func TestRmdirsNoLeaveRoot(t *testing.T) { r := fstest.NewRun(t) defer r.Finalise() r.Mkdir(r.Fremote) @@ -562,7 +562,7 @@ func TestRmdirs(t *testing.T) { fs.Config.ModifyWindow, ) - require.NoError(t, fs.Rmdirs(r.Fremote, "")) + require.NoError(t, fs.Rmdirs(r.Fremote, "", false)) fstest.CheckListingWithPrecision( t, @@ -580,6 +580,42 @@ func TestRmdirs(t *testing.T) { } +func TestRmdirsLeaveRoot(t *testing.T) { + r := fstest.NewRun(t) + defer r.Finalise() + r.Mkdir(r.Fremote) + + r.ForceMkdir(r.Fremote) + + require.NoError(t, fs.Mkdir(r.Fremote, "A1")) + require.NoError(t, fs.Mkdir(r.Fremote, "A1/B1")) + require.NoError(t, fs.Mkdir(r.Fremote, "A1/B1/C1")) + + fstest.CheckListingWithPrecision( + t, + r.Fremote, + []fstest.Item{}, + []string{ + "A1", + "A1/B1", + "A1/B1/C1", + }, + fs.Config.ModifyWindow, + ) + + require.NoError(t, fs.Rmdirs(r.Fremote, "/A1", true)) + + fstest.CheckListingWithPrecision( + t, + r.Fremote, + []fstest.Item{}, + []string{ + "A1", + }, + fs.Config.ModifyWindow, + ) +} + func TestMoveFile(t *testing.T) { r := fstest.NewRun(t) defer r.Finalise()