fs: Implement --no-update-dir-modtime to disable setting modification times on dirs

This commit is contained in:
Nick Craig-Wood 2024-03-07 16:13:36 +00:00
parent 99acee7ba0
commit 4e07a72dc7
7 changed files with 62 additions and 4 deletions

View File

@ -1809,6 +1809,11 @@ files if they are incorrect as it would normally.
This can be used if the remote is being synced with another tool also This can be used if the remote is being synced with another tool also
(e.g. the Google Drive client). (e.g. the Google Drive client).
### --no-update-dir-modtime ###
When using this flag, rclone won't update modification times of remote
directories if they are incorrect as it would normally.
### --order-by string ### ### --order-by string ###
The `--order-by` flag controls the order in which files in the backlog The `--order-by` flag controls the order in which files in the backlog

View File

@ -89,6 +89,7 @@ type ConfigInfo struct {
NoCheckDest bool NoCheckDest bool
NoUnicodeNormalization bool NoUnicodeNormalization bool
NoUpdateModTime bool NoUpdateModTime bool
NoUpdateDirModTime bool
DataRateUnit string DataRateUnit string
CompareDest []string CompareDest []string
CopyDest []string CopyDest []string

View File

@ -91,6 +91,7 @@ func AddFlags(ci *fs.ConfigInfo, flagSet *pflag.FlagSet) {
flags.BoolVarP(flagSet, &ci.NoCheckDest, "no-check-dest", "", ci.NoCheckDest, "Don't check the destination, copy regardless", "Copy") flags.BoolVarP(flagSet, &ci.NoCheckDest, "no-check-dest", "", ci.NoCheckDest, "Don't check the destination, copy regardless", "Copy")
flags.BoolVarP(flagSet, &ci.NoUnicodeNormalization, "no-unicode-normalization", "", ci.NoUnicodeNormalization, "Don't normalize unicode characters in filenames", "Config") flags.BoolVarP(flagSet, &ci.NoUnicodeNormalization, "no-unicode-normalization", "", ci.NoUnicodeNormalization, "Don't normalize unicode characters in filenames", "Config")
flags.BoolVarP(flagSet, &ci.NoUpdateModTime, "no-update-modtime", "", ci.NoUpdateModTime, "Don't update destination modtime if files identical", "Copy") flags.BoolVarP(flagSet, &ci.NoUpdateModTime, "no-update-modtime", "", ci.NoUpdateModTime, "Don't update destination modtime if files identical", "Copy")
flags.BoolVarP(flagSet, &ci.NoUpdateDirModTime, "no-update-dir-modtime", "", ci.NoUpdateModTime, "Don't update directory modification times", "Copy")
flags.StringArrayVarP(flagSet, &ci.CompareDest, "compare-dest", "", nil, "Include additional comma separated server-side paths during comparison", "Copy") flags.StringArrayVarP(flagSet, &ci.CompareDest, "compare-dest", "", nil, "Include additional comma separated server-side paths during comparison", "Copy")
flags.StringArrayVarP(flagSet, &ci.CopyDest, "copy-dest", "", nil, "Implies --compare-dest but also copies files from paths into destination", "Copy") flags.StringArrayVarP(flagSet, &ci.CopyDest, "copy-dest", "", nil, "Implies --compare-dest but also copies files from paths into destination", "Copy")
flags.StringVarP(flagSet, &ci.BackupDir, "backup-dir", "", ci.BackupDir, "Make backups into hierarchy based in DIR", "Sync") flags.StringVarP(flagSet, &ci.BackupDir, "backup-dir", "", ci.BackupDir, "Make backups into hierarchy based in DIR", "Sync")

View File

@ -2612,6 +2612,11 @@ func CopyDirMetadata(ctx context.Context, f fs.Fs, dst fs.Directory, dir string,
// It does not create the directory. // It does not create the directory.
func SetDirModTime(ctx context.Context, f fs.Fs, dst fs.Directory, dir string, modTime time.Time) (newDst fs.Directory, err error) { func SetDirModTime(ctx context.Context, f fs.Fs, dst fs.Directory, dir string, modTime time.Time) (newDst fs.Directory, err error) {
logName := dirName(f, dst, dir) logName := dirName(f, dst, dir)
ci := fs.GetConfig(ctx)
if ci.NoUpdateDirModTime {
fs.Debugf(logName, "Skipping set directory modification time as --no-update-dir-modtime is set")
return nil, nil
}
if SkipDestructive(ctx, logName, "set directory modification time") { if SkipDestructive(ctx, logName, "set directory modification time") {
return nil, nil return nil, nil
} }

View File

@ -1755,14 +1755,21 @@ func TestCopyDirMetadata(t *testing.T) {
func TestSetDirModTime(t *testing.T) { func TestSetDirModTime(t *testing.T) {
const name = "set modtime on existing directory" const name = "set modtime on existing directory"
ctx := context.Background() ctx, ci := fs.AddConfig(context.Background())
r := fstest.NewRun(t) r := fstest.NewRun(t)
if r.Fremote.Features().DirSetModTime == nil && !r.Fremote.Features().WriteDirSetModTime { if r.Fremote.Features().DirSetModTime == nil && !r.Fremote.Features().WriteDirSetModTime {
t.Skip("Skipping test as remote does not support DirSetModTime or WriteDirSetModTime") t.Skip("Skipping test as remote does not support DirSetModTime or WriteDirSetModTime")
} }
// First try with the directory not existing - should return an error // Check that we obey --no-update-dir-modtime - this should return nil, nil
ci.NoUpdateDirModTime = true
newDst, err := operations.SetDirModTime(ctx, r.Fremote, nil, "set modtime on non existent directory", t2) newDst, err := operations.SetDirModTime(ctx, r.Fremote, nil, "set modtime on non existent directory", t2)
require.NoError(t, err)
require.Nil(t, newDst)
ci.NoUpdateDirModTime = false
// First try with the directory not existing - should return an error
newDst, err = operations.SetDirModTime(ctx, r.Fremote, nil, "set modtime on non existent directory", t2)
require.Error(t, err) require.Error(t, err)
require.Nil(t, newDst) require.Nil(t, newDst)

View File

@ -154,8 +154,8 @@ func newSyncCopyMove(ctx context.Context, fdst, fsrc fs.Fs, deleteMode fs.Delete
trackRenamesCh: make(chan fs.Object, ci.Checkers), trackRenamesCh: make(chan fs.Object, ci.Checkers),
checkFirst: ci.CheckFirst, checkFirst: ci.CheckFirst,
setDirMetadata: ci.Metadata && fsrc.Features().ReadDirMetadata && fdst.Features().WriteDirMetadata, setDirMetadata: ci.Metadata && fsrc.Features().ReadDirMetadata && fdst.Features().WriteDirMetadata,
setDirModTime: fdst.Features().WriteDirSetModTime || fdst.Features().MkdirMetadata != nil || fdst.Features().DirSetModTime != nil, setDirModTime: !ci.NoUpdateDirModTime && (fdst.Features().WriteDirSetModTime || fdst.Features().MkdirMetadata != nil || fdst.Features().DirSetModTime != nil),
setDirModTimeAfter: fdst.Features().DirModTimeUpdatesOnWrite, setDirModTimeAfter: !ci.NoUpdateDirModTime && fdst.Features().DirModTimeUpdatesOnWrite,
modifiedDirs: make(map[string]struct{}), modifiedDirs: make(map[string]struct{}),
} }

View File

@ -344,6 +344,45 @@ func TestMoveEmptyDirectories(t *testing.T) {
fstest.CheckDirModTime(ctx, t, r.Fremote, got, subDirT) fstest.CheckDirModTime(ctx, t, r.Fremote, got, subDirT)
} }
// Test that --no-update-dir-modtime is working
func TestSyncNoUpdateDirModtime(t *testing.T) {
r := fstest.NewRun(t)
if r.Fremote.Features().DirSetModTime == nil {
t.Skip("Skipping test as backend does not support DirSetModTime")
}
ctx, ci := fs.AddConfig(context.Background())
ci.NoUpdateDirModTime = true
const name = "sub dir no update dir modtime"
// Set the modtime on name to something specific
_, err := operations.MkdirModTime(ctx, r.Flocal, name, t1)
require.NoError(t, err)
// Create the remote directory with the current time
require.NoError(t, r.Fremote.Mkdir(ctx, name))
// Read its modification time
wantT := fstest.NewDirectory(ctx, t, r.Fremote, name).ModTime(ctx)
ctx = predictDstFromLogger(ctx)
err = Sync(ctx, r.Fremote, r.Flocal, true)
require.NoError(t, err)
testLoggerVsLsf(ctx, r.Fremote, operations.GetLoggerOpt(ctx).JSON, t)
r.CheckRemoteListing(
t,
[]fstest.Item{},
[]string{
name,
},
)
// Read the new directory modification time - it should not have changed
gotT := fstest.NewDirectory(ctx, t, r.Fremote, name).ModTime(ctx)
fstest.AssertTimeEqualWithPrecision(t, name, wantT, gotT, r.Fremote.Precision())
}
// Test sync empty directories // Test sync empty directories
func TestSyncEmptyDirectories(t *testing.T) { func TestSyncEmptyDirectories(t *testing.T) {
ctx := context.Background() ctx := context.Background()