Skip to content

Commit 863a61e

Browse files
committed
Optimize alt linking to avoid redundant operations
This change reduces unnecessary filesystem operations and preserves user‑created symlinks when no alternate is tracked. Stale links are still removed (#236). Added two tests.
1 parent bbb58e6 commit 863a61e

File tree

2 files changed

+65
-4
lines changed

2 files changed

+65
-4
lines changed

test/test_alt.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,3 +442,58 @@ def setup_standard_yadm_dir(paths):
442442
std_yadm_data.join("repo.git").mksymlinkto(paths.repo, absolute=1)
443443
std_yadm_dir.join("encrypt").mksymlinkto(paths.encrypt, absolute=1)
444444
return std_yadm_dir, std_yadm_data
445+
446+
447+
@pytest.mark.usefixtures("ds1_copy")
448+
def test_alt_preserves_user_symlink_until_alt_tracked(runner, paths):
449+
"""yadm alt should preserve user-created symlinks when no alternate is tracked,
450+
but replaces them once the alternate is added to the repository."""
451+
yadm_dir, yadm_data = setup_standard_yadm_dir(paths)
452+
# Create a user symlink (not managed by yadm)
453+
user_target = paths.work.join("user_target")
454+
user_target.write("user-data")
455+
link_file = paths.work.join(utils.ALT_FILE1)
456+
link_file.mksymlinkto(user_target)
457+
assert link_file.islink()
458+
# Create a yadm alt file, but do not add it yet
459+
alt_file = yadm_dir.join("alt").join(f"{utils.ALT_FILE1}##default")
460+
alt_file.write("alt-data", ensure=True)
461+
# Run yadm alt (should not replace user symlink)
462+
run = runner([paths.pgm, "-Y", yadm_dir, "--yadm-data", yadm_data, "alt"])
463+
assert run.success
464+
# The symlink should still point to user_target
465+
assert link_file.islink()
466+
assert os.path.realpath(str(link_file)) == str(user_target)
467+
# Now add the alt file and run yadm alt again
468+
run = runner([paths.pgm, "-Y", yadm_dir, "--yadm-data", yadm_data, "add", alt_file])
469+
assert run.success
470+
run = runner([paths.pgm, "-Y", yadm_dir, "--yadm-data", yadm_data, "alt"])
471+
assert run.success
472+
# Now the symlink should be replaced and point to the alt file
473+
assert link_file.islink()
474+
assert os.path.realpath(str(link_file)) == str(alt_file)
475+
476+
477+
@pytest.mark.usefixtures("ds1_copy")
478+
def test_alt_skips_correct_symlink_without_touching(runner, paths):
479+
"""yadm alt should skip already-correct symlinks without any filesystem operations (no remove/recreate)."""
480+
yadm_dir, yadm_data = setup_standard_yadm_dir(paths)
481+
# Create and add a yadm alt file
482+
alt_file = yadm_dir.join("alt").join(f"{utils.ALT_FILE1}##default")
483+
alt_file.write("alt-data", ensure=True)
484+
run = runner([paths.pgm, "-Y", yadm_dir, "--yadm-data", yadm_data, "add", alt_file])
485+
assert run.success
486+
# Run yadm alt to create the symlink
487+
run = runner([paths.pgm, "-Y", yadm_dir, "--yadm-data", yadm_data, "alt"])
488+
assert run.success
489+
link_file = paths.work.join(utils.ALT_FILE1)
490+
assert link_file.islink()
491+
assert os.path.realpath(str(link_file)) == str(alt_file)
492+
# Get the symlink's mtime
493+
mtime_before = link_file.lstat().mtime
494+
# Run yadm alt again (should not touch the symlink)
495+
run = runner([paths.pgm, "-Y", yadm_dir, "--yadm-data", yadm_data, "alt"])
496+
assert run.success
497+
mtime_after = link_file.lstat().mtime
498+
# The mtime should not change
499+
assert mtime_before == mtime_after

yadm

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -603,12 +603,12 @@ function alt() {
603603
target="$target$suffix"
604604
fi
605605

606-
# Remove target if it's a symlink pointing at source
607-
if [ -L "$target" ] && [ "$target" -ef "$source" ]; then
606+
score_file "$source" "$target" "$conditions"
607+
608+
# Remove target if it's a symlink pointing at source with score 0 (stale)
609+
if [ -L "$target" ] && [ "$target" -ef "$source" ] && [ "$score" -eq 0 ]; then
608610
rm -f "$target"
609611
fi
610-
611-
score_file "$source" "$target" "$conditions"
612612
done
613613

614614
local alt_linked=()
@@ -705,6 +705,12 @@ function alt_linking() {
705705
local source="${alt_sources[$index]}"
706706
local template_processor="${alt_template_processors[$index]}"
707707

708+
if [ -L "$target" ] && [ "$target" -ef "$source" ] && [ "$do_copy" -eq 0 ]; then
709+
$log "Keeping $target; already linked to $source"
710+
exclude+=("${target#"$YADM_WORK"}")
711+
continue
712+
fi
713+
708714
if [ -L "$target" ]; then
709715
rm -f "$target"
710716
elif [ -d "$target" ]; then

0 commit comments

Comments
 (0)