mirror of
https://github.com/RsyncProject/rsync.git
synced 2026-06-08 14:15:46 -04:00
79 lines
3.1 KiB
Python
79 lines
3.1 KiB
Python
#!/usr/bin/env python3
|
|
"""Coverage of -u (--update) and --force at depth.
|
|
|
|
-u skips any destination file that is newer than the source. --force lets rsync
|
|
delete a non-empty destination directory when it must be replaced by a
|
|
non-directory. Both decide a per-entry action on a name whose parent chain the
|
|
resolver restructure rewrites, so check them several levels deep.
|
|
"""
|
|
|
|
import os
|
|
|
|
from rsyncfns import (
|
|
FROMDIR, TODIR,
|
|
assert_same, make_tree, makepath, rmtree, run_rsync, test_fail,
|
|
)
|
|
|
|
src = FROMDIR
|
|
deep = os.path.join('d1', 'd2', 'd3', 'f3')
|
|
|
|
|
|
# --- -u keeps a newer destination file, updates an older one ----------------
|
|
rmtree(src)
|
|
rmtree(TODIR)
|
|
make_tree(src, depth=3)
|
|
run_rsync('-a', f'{src}/', f'{TODIR}/')
|
|
|
|
# Make the deep source newer in content, but the DEST copy newer in time.
|
|
(src / deep).write_text("new source content\n")
|
|
keep = "destination is newer - keep me\n"
|
|
(TODIR / deep).write_text(keep)
|
|
st = os.stat(src / deep)
|
|
os.utime(TODIR / deep, (st.st_atime, st.st_mtime + 100)) # dest mtime newer
|
|
|
|
run_rsync('-a', '-u', f'{src}/', f'{TODIR}/')
|
|
if (TODIR / deep).read_text() != keep:
|
|
test_fail("-u overwrote a destination file that was newer than the source")
|
|
|
|
# An older destination file IS updated under -u.
|
|
os.utime(TODIR / deep, (st.st_atime, st.st_mtime - 100)) # dest mtime older
|
|
run_rsync('-a', '-u', f'{src}/', f'{TODIR}/')
|
|
assert_same(TODIR / deep, src / deep, label='-u updated an older dest file')
|
|
|
|
# A newer destination symlink is still replaced by a source regular file
|
|
# because a file-format difference is always important enough to update.
|
|
rmtree(src)
|
|
rmtree(TODIR)
|
|
makepath(src, TODIR)
|
|
(src / 'foo').write_text("regular source file\n")
|
|
os.symlink('/should/not/exist', TODIR / 'foo')
|
|
st = os.stat(src / 'foo')
|
|
os.utime(TODIR / 'foo', (st.st_atime, st.st_mtime + 100),
|
|
follow_symlinks=False)
|
|
run_rsync('-a', '-u', f'{src}/', f'{TODIR}/')
|
|
if os.path.islink(TODIR / 'foo'):
|
|
test_fail("-u skipped a source file over a newer destination symlink")
|
|
assert_same(TODIR / 'foo', src / 'foo',
|
|
label='-u replaced a newer dest symlink with a regular file')
|
|
|
|
# --- --force replaces a non-empty dest directory with a file at depth -------
|
|
rmtree(src)
|
|
rmtree(TODIR)
|
|
makepath(src / 'd1' / 'd2' / 'd3')
|
|
(src / deep).write_text("now a regular file\n") # src: d1/d2/d3/f3 = file
|
|
makepath(TODIR / 'd1' / 'd2' / 'd3' / 'f3') # dest: f3 = non-empty dir
|
|
(TODIR / 'd1' / 'd2' / 'd3' / 'f3' / 'occupant').write_text("blocker\n")
|
|
|
|
# Without --force the non-empty directory can't be replaced.
|
|
proc = run_rsync('-a', f'{src}/', f'{TODIR}/', check=False)
|
|
if proc.returncode == 0 and (TODIR / deep).is_file():
|
|
test_fail("a non-empty directory was replaced by a file without --force")
|
|
|
|
# With --force the directory is removed and the file takes its place.
|
|
run_rsync('-a', '--force', f'{src}/', f'{TODIR}/')
|
|
if not (TODIR / deep).is_file():
|
|
test_fail("--force did not replace the directory with the file at depth")
|
|
assert_same(TODIR / deep, src / deep, label='--force replacement content')
|
|
|
|
print("update: -u keeps newer dest / updates older; --force replaces a dir at depth")
|