Skip to content

Commit c021846

Browse files
committed
Error with sync_tree when source top is a symlink
The call to `sync_tree` should be doing the same as `rsync -rlpgoD --update`. When the top-level source element is a symbolic link, `rsync` creates a true folder as the target top-level element, then synchronizes the content. The `sync_tree` function create a symbolic link instead, which may lead to errors when trying to copy symbolic links. The `sync_tree` now uses the real path of the top-level source element, preventing this kind of error. Closes #45+
1 parent 6f597b3 commit c021846

File tree

2 files changed

+38
-0
lines changed

2 files changed

+38
-0
lines changed

src/e3/fs.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1054,6 +1054,10 @@ def walk(
10541054
if not os.path.exists(source):
10551055
raise FSError(origin="sync_tree", message=f"{source} does not exist")
10561056

1057+
# Use realpath here, or a FileNotFoundError is raised instead of an FSError
1058+
# if source does not exist.
1059+
source_top = os.path.realpath(source_top, strict=True)
1060+
10571061
# Keep track of deleted and updated files
10581062
deleted_list: list[str] = []
10591063
updated_list: list[str] = []

tests/tests_e3/fs/main_test.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,40 @@ def test_sync_tree_links():
433433
assert f.read() == "content"
434434

435435

436+
def test_sync_tree_top_source_is_link():
437+
"""Check handling of source top is a link."""
438+
e3.fs.mkdir("a")
439+
with open("a/content", "w") as f:
440+
f.write("content")
441+
442+
try:
443+
# Symlinks are supported on Windows, but the user must have sufficient
444+
# permissions.
445+
os.symlink(
446+
os.path.join(os.getcwd(), "a"),
447+
os.path.join(os.getcwd(), "b"),
448+
target_is_directory=True,
449+
)
450+
except Exception as e:
451+
if sys.platform == "win32":
452+
pytest.skip("Insufficient permissions to create symbolic links on Windows")
453+
else:
454+
raise e
455+
456+
# Sync tree in "c", source top is "b", which is a symlink to "a".
457+
e3.fs.mkdir("c")
458+
e3.fs.sync_tree(
459+
os.path.join(os.getcwd(), "b"),
460+
os.path.join(os.getcwd(), "c", "a"),
461+
preserve_timestamps=False,
462+
)
463+
464+
# Make sure "c/a" is not a symlink
465+
assert not os.path.islink(os.path.join(os.getcwd(), "c", "a"))
466+
with open("c/a/content") as f:
467+
assert f.read() == "content"
468+
469+
436470
def test_sync_tree_does_not_exist():
437471
"""Check error message when sync_tree source does not exist."""
438472
with pytest.raises(e3.fs.FSError) as err:

0 commit comments

Comments
 (0)