From 3e54f0ca2080587e8e1ffa4903d276dd3c514893 Mon Sep 17 00:00:00 2001 From: "Oliver Surke (Gitea)" Date: Tue, 12 May 2026 12:17:44 +0200 Subject: [PATCH] fix: pre-clean transient dirs + repeat cleanup before every mackup attempt Root cause: Claude Code recreates ~/.claude/debug/latest (a dangling symlink to the current debug session) almost immediately after it is deleted. The old cleanup ran once before the retry loop, so any retry after a 2s sleep would hit a freshly recreated symlink. Fix: move _ssr_mackup_preclean() inside the retry loop so it runs immediately before each mackup attempt, leaving no window for apps to recreate problematic files. Also remove known transient subdirectories by path before the generic socket/dangling-link sweep: .claude/debug .cursor/logs .vscode/logs .npm/_logs Configurable via SSR_MACKUP_PRECLEAN_PATHS (space-separated, $HOME-relative). Co-authored-by: Cursor --- config/ssr.conf.example | 6 +++++ lib/mackup.sh | 56 ++++++++++++++++++++++++++++------------- 2 files changed, 44 insertions(+), 18 deletions(-) diff --git a/config/ssr.conf.example b/config/ssr.conf.example index 9d7cdaa..59249bb 100644 --- a/config/ssr.conf.example +++ b/config/ssr.conf.example @@ -20,6 +20,12 @@ SSR_MACKUP_SUBDIR=Mackup # ~/.mackup/ssr-custom.cfg before each backup. Set to "false" to opt out. SSR_MACKUP_AUTODISCOVER=true +# Subdirs (relative to $HOME) to delete before each mackup backup attempt. +# Handles transient dirs with dangling symlinks or sockets (debug sessions, +# log dirs) that shutil.copytree cannot copy. +# Built-in defaults: .claude/debug .cursor/logs .vscode/logs .npm/_logs +# SSR_MACKUP_PRECLEAN_PATHS=".my-app/tmp .other-app/run" + # Extra paths (relative to $HOME) to always include, space-separated. # Example: ".easymcp .my-tool .config/my-cli" # SSR_MACKUP_EXTRA_PATHS="" diff --git a/lib/mackup.sh b/lib/mackup.sh index 5a28ce9..01584c7 100644 --- a/lib/mackup.sh +++ b/lib/mackup.sh @@ -262,28 +262,48 @@ ssr::mackup::backup() { fi [[ -n "$mackup_root" ]] && ssr::mackup::_materialize_icloud "$mackup_root" - # Pre-backup cleanup: remove file types that shutil.copy cannot handle. - # - # 1. Unix socket files (-type s) — runtime artefacts, recreated on app start. - # Cause: shutil.Error [Errno 102] Operation not supported on socket - local socket_count - socket_count="$(find "$HOME" -type s 2>/dev/null | wc -l | tr -d ' ')" - if [[ "$socket_count" -gt 0 ]]; then - ssr::log "Removing $socket_count Unix socket file(s) before mackup backup (runtime artefacts)" - find "$HOME" -type s -delete 2>/dev/null || true - fi + # --------------------------------------------------------------------------- + # Pre-backup cleanup — remove artefacts that shutil.copytree cannot handle. + # Run this immediately before each mackup attempt so that apps (e.g. Claude + # Code) that recreate debug symlinks very quickly don't sneak back in. + # --------------------------------------------------------------------------- + _ssr_mackup_preclean() { + # Known transient subdirectories that apps recreate constantly. + # These contain debug logs / sockets, never real config. + # Extend via SSR_MACKUP_PRECLEAN_PATHS (space-separated $HOME-relative). + local -a transient_dirs=( + .claude/debug # Claude Code debug session links + .cursor/logs # Cursor IDE logs + .vscode/logs # VS Code logs + .vscode-insiders/logs + .npm/_logs # npm debug logs + ) + local extra dir + for extra in ${SSR_MACKUP_PRECLEAN_PATHS:-}; do + transient_dirs+=("$extra") + done + for dir in "${transient_dirs[@]}"; do + [[ -e "$HOME/$dir" ]] && rm -rf "$HOME/$dir" 2>/dev/null || true + done - # 2. Dangling symlinks (-type l ! -e) — point to a non-existent target. - # Cause: shutil.Error [Errno 2] No such file or directory: '' - local dangling_count - dangling_count="$(find "$HOME" -type l ! -e 2>/dev/null | wc -l | tr -d ' ')" - if [[ "$dangling_count" -gt 0 ]]; then - ssr::log "Removing $dangling_count dangling symlink(s) before mackup backup" - find "$HOME" -type l ! -e -delete 2>/dev/null || true - fi + # 1. Unix socket files (-type s) — [Errno 102] Operation not supported. + local n; n="$(find "$HOME" -type s 2>/dev/null | wc -l | tr -d ' ')" + if [[ "$n" -gt 0 ]]; then + ssr::log " pre-clean: removing $n socket file(s)" + find "$HOME" -type s -delete 2>/dev/null || true + fi + + # 2. Dangling symlinks (-type l ! -e) — [Errno 2] No such file. + n="$(find "$HOME" -type l ! -e 2>/dev/null | wc -l | tr -d ' ')" + if [[ "$n" -gt 0 ]]; then + ssr::log " pre-clean: removing $n dangling symlink(s)" + find "$HOME" -type l ! -e -delete 2>/dev/null || true + fi + } local attempt rc=0 for attempt in 1 2 3; do + _ssr_mackup_preclean # clean immediately before each attempt if mackup -f backup; then return 0 fi