diff --git a/migrations/1788996284.sh b/migrations/1788996284.sh index 5a943728..f2326812 100644 --- a/migrations/1788996284.sh +++ b/migrations/1788996284.sh @@ -3,6 +3,18 @@ echo "Repair remote Neovim clipboard yanks and paste" nvim_provider="$HOME/.config/nvim/lua/config/remote_clipboard.lua" provider_source="/usr/share/omarchy-nvim/config/lua/config/remote_clipboard.lua" +# Dotfile managers may own either the file or a parent directory through a +# symlink. Preserve that layout rather than detaching or editing its target. +provider_path="$nvim_provider" +while [[ $provider_path != "$HOME" && $provider_path != / ]]; do + if [[ -L $provider_path ]]; then + echo "Preserving symlink-managed Neovim provider: $nvim_provider" + echo "Review remote clipboard settings in your dotfile configuration manually." + exit 0 + fi + provider_path=$(dirname "$provider_path") +done + [[ -f $nvim_provider ]] || exit 0 # Replace only known Omarchy versions, including the June file-backed provider @@ -30,5 +42,10 @@ fi provider_backup=$(mktemp "$nvim_provider.bak.XXXXXX") cp -p "$nvim_provider" "$provider_backup" -install -m 0644 "$provider_source" "$nvim_provider" +provider_staged=$(mktemp "$nvim_provider.new.XXXXXX") +trap 'rm -f -- "$provider_staged"' EXIT +install -m 0644 "$provider_source" "$provider_staged" +# A failed write leaves the recognized original live, so retries can repair it. +# The temporary file is on the same filesystem for an atomic replacement. +mv -fT -- "$provider_staged" "$nvim_provider" echo "Previous Neovim provider saved to $provider_backup" diff --git a/test/shell.d/neovim-remote-yanks-test.sh b/test/shell.d/neovim-remote-yanks-test.sh index d96e4621..84a0c721 100755 --- a/test/shell.d/neovim-remote-yanks-test.sh +++ b/test/shell.d/neovim-remote-yanks-test.sh @@ -58,3 +58,54 @@ mv "$test_home/package.lua" "$test_home/package.saved" if run_migration; then fail "missing package source leaves migration pending"; fi cmp "$provider" "$SHELL_TEST_DIR/fixtures/neovim-clipboard/june.lua" || fail "missing source leaves provider unchanged" pass "old or missing package cannot mark an unrepaired provider complete" + +mv "$test_home/package.saved" "$test_home/package.lua" +# A write that fails after producing partial output must never damage the live +# provider. Exercise the real install destination with a failing replacement. +cat >"$test_home/bin/install" <<'STUB' +#!/bin/bash +printf '%s' '-- truncated replacement' >"${@: -1}" +exit 1 +STUB +chmod +x "$test_home/bin/install" +if run_migration; then fail "failed staging write leaves migration pending"; fi +cmp "$provider" "$SHELL_TEST_DIR/fixtures/neovim-clipboard/june.lua" || fail "failed write preserves live provider" +if compgen -G "$provider.new.*" >/dev/null; then fail "failed staging file is cleaned up"; fi +rm "$test_home/bin/install" +run_migration +cmp "$provider" "$test_home/package.lua" || fail "retry repairs the recognized original" +pass "failed write preserves original and retry succeeds" + +# Also fail the final rename, after successful staging. +cp "$SHELL_TEST_DIR/fixtures/neovim-clipboard/july.lua" "$provider" +printf '#!/bin/bash\nexit 1\n' >"$test_home/bin/mv" +chmod +x "$test_home/bin/mv" +if run_migration; then fail "failed rename leaves migration pending"; fi +cmp "$provider" "$SHELL_TEST_DIR/fixtures/neovim-clipboard/july.lua" || fail "failed rename preserves original" +if compgen -G "$provider.new.*" >/dev/null; then fail "failed rename staging file is cleaned up"; fi +rm "$test_home/bin/mv" +run_migration +cmp "$provider" "$test_home/package.lua" || fail "retry after rename failure succeeds" +pass "failed rename preserves original and retry succeeds" + +cp "$SHELL_TEST_DIR/fixtures/neovim-clipboard/july.lua" "$test_home/dotfile.lua" +rm "$provider" +ln -s "$test_home/dotfile.lua" "$provider" +run_migration >"$test_home/output" +[[ -L $provider ]] || fail "provider symlink is preserved" +cmp "$test_home/dotfile.lua" "$SHELL_TEST_DIR/fixtures/neovim-clipboard/july.lua" || fail "symlink target is preserved" +grep -q 'symlink-managed' "$test_home/output" || fail "linked provider receives guidance" +rm "$provider" +ln -s "$test_home/absent.lua" "$provider" +run_migration +[[ -L $provider && ! -e $provider ]] || fail "dangling symlink is preserved" +rm "$provider" + +mkdir "$test_home/dotfiles" +mv "$test_home/.config/nvim/lua/config" "$test_home/dotfiles/config" +ln -s "$test_home/dotfiles/config" "$test_home/.config/nvim/lua/config" +cp "$SHELL_TEST_DIR/fixtures/neovim-clipboard/july.lua" "$provider" +run_migration +[[ -L $test_home/.config/nvim/lua/config ]] || fail "linked config directory is preserved" +cmp "$provider" "$SHELL_TEST_DIR/fixtures/neovim-clipboard/july.lua" || fail "provider in linked directory is preserved" +pass "linked files, dangling links and linked directories are preserved"