diff --git a/vault_sync_daemon.py b/vault_sync_daemon.py index a0ffbdc..7c23578 100644 --- a/vault_sync_daemon.py +++ b/vault_sync_daemon.py @@ -482,6 +482,29 @@ def _nearest_archive_note(archive_data_path): return note if os.path.exists(note) else None +def _prune_deleted_plain_folder(vault_path, rel, data_path): + """ + A non-ID folder vanished from /vault (typically a sync client applying + a rename as delete+create, so the old name's /data mirror is orphaned). + Remove the /data mirror only if its whole tree holds no files; if it + holds any, leave it and ping instead. + """ + if rel.split(os.sep)[0] == vl.SYSTEM_META or _under_archive(rel): + return + if os.path.exists(vault_path) or not os.path.isdir(data_path): + return + if any(files for _, _, files in os.walk(data_path)): + log(f"KEPT /data mirror of deleted vault folder (has files): {rel}") + ntfy_post( + "Vault sync: deleted folder has blobs", + f"Folder removed from /vault but /data/{rel} contains files. Left in place.", + tags="warning", + ) + return + shutil.rmtree(data_path) + log(f"PRUNED empty /data mirror of deleted vault folder: {rel}") + + def handle_vault_deleted(path): """ An ID-shaped folder disappeared from /vault. Per design this normally @@ -509,9 +532,10 @@ def handle_vault_deleted(path): return rel = os.path.relpath(path, VAULT) base = os.path.basename(path) - if not ID_RE.match(base): - return # only care about ID-folder deletions data_path = os.path.join(DATA, rel) + if not ID_RE.match(base): + _prune_deleted_plain_folder(path, rel, data_path) + return if not os.path.isdir(data_path): return # already handled (duplicate event) or no /data counterpart ever existed id_code = vl.id_code(base)