dirsync icon indicating copy to clipboard operation
dirsync copied to clipboard

sync with purge keeps orphan destination directory having read-only file

Open jokram opened this issue 2 years ago • 0 comments

Description

When calling sync with purge set to True and having a directory only in the destination with one read-only file then the sync removes the read-only file (OK), but the directory remains (Not OK).

Note that sometimes it works fine, but sometimes it fails. :confused: For cleaning up the read-only file there was another issue #25 implemented (and this works fine), but here the remaining empty directory is still in the destination.

Environment

  • Windows 10 Enterprise Build 10.0.19044
  • dirsync 2.2.5

Code to reproduce the error

Run the code several times, because sometimes it works, sometimes it gets an error!

import os
import shutil
import stat
from pathlib import Path
from dirsync import sync

test_dir = Path("D:/tmp/sync_test")
test_file = "test1.txt"
src_dir = test_dir / "src"
dst_dir = test_dir / "dst"
if src_dir.is_dir():
    shutil.rmtree(src_dir, onerror=lambda func, path, _: (os.chmod(path, stat.S_IWRITE), func(path)))
if dst_dir.is_dir():
    shutil.rmtree(dst_dir, onerror=lambda func, path, _: (os.chmod(path, stat.S_IWRITE), func(path)))
dst_dir.mkdir(parents=True, exist_ok=True)
# Build up a directory structure where all the files are read-only:
# +---[sub1]
#     +---test1.txt
# +---[sub2]
#     +---test1.txt
# +---[sub3]
#     +---test1.txt
for folder in ("sub1", "sub2", "sub3"):
    cur_dir = src_dir / folder
    cur_dir.mkdir(parents=True, exist_ok=True)
    open(cur_dir / test_file, 'w').close()
    # Set the file to read-only, because only then the error occurs
    os.chmod(cur_dir / test_file, stat.S_IREAD)
# The first sync works fine
print(f"Mirror {src_dir} -> {dst_dir}")
sync(src_dir, dst_dir, "sync", purge=True, verbose=False)
src_sub2 = src_dir / "sub2"
print("Remove the sub2 directory from the source")
shutil.rmtree(src_sub2, onerror=lambda func, path, _: (os.chmod(path, stat.S_IWRITE), func(path)))
# Now the sync (with purge set to True) should also delete the sub2 directory in the destination
print(f"Mirror {src_dir} -> {dst_dir} (should remove the sub2 directory)")
sync(src_dir, dst_dir, "sync", purge=True, verbose=False)
# Very strange: Often I'll get an error, but sometimes it seems to work
dst_sub2 = dst_dir / "sub2"
if dst_sub2.is_dir():
    print(f"*** ERROR: {dst_sub2} still exists in destination")
else:
    print("OK")

jokram avatar Mar 10 '23 10:03 jokram