Complete Linux backup manager with Whiptail TUI and CLI interface. Adapted from gniza4cp (cPanel backup tool) with target/profile-based system replacing cPanel-specific features. - 14 core engine modules (backup, restore, targets, remotes, transfer, etc.) - 11 Whiptail TUI screens (full CRUD for targets/remotes/schedules) - CLI entrypoint with subcommands for scripting/cron - Support for SSH, local, S3, and Google Drive remotes - rsync --link-dest incremental snapshots - Root and user mode (XDG paths) - 70 passing tests - Config templates, installer, uninstaller Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
76 lines
3.0 KiB
Bash
76 lines
3.0 KiB
Bash
#!/usr/bin/env bash
|
|
# gniza4linux/lib/retention.sh — Delete old snapshots beyond RETENTION_COUNT on remote
|
|
|
|
[[ -n "${_GNIZA4LINUX_RETENTION_LOADED:-}" ]] && return 0
|
|
_GNIZA4LINUX_RETENTION_LOADED=1
|
|
|
|
enforce_retention() {
|
|
local target_name="$1"
|
|
local keep="${RETENTION_COUNT:-$DEFAULT_RETENTION_COUNT}"
|
|
|
|
log_debug "Enforcing retention for $target_name: keeping $keep snapshots"
|
|
|
|
# Get completed snapshots sorted newest first
|
|
local snapshots; snapshots=$(list_remote_snapshots "$target_name")
|
|
if [[ -z "$snapshots" ]]; then
|
|
log_debug "No snapshots found for $target_name, nothing to prune"
|
|
return 0
|
|
fi
|
|
|
|
local count=0
|
|
local pruned=0
|
|
while IFS= read -r snap; do
|
|
[[ -z "$snap" ]] && continue
|
|
((count++)) || true
|
|
if (( count > keep )); then
|
|
# Skip pinned snapshots
|
|
local is_pinned=false
|
|
if _is_rclone_mode; then
|
|
local meta; meta=$(rclone_cat "targets/${target_name}/snapshots/${snap}/meta.json" 2>/dev/null) || true
|
|
if [[ -n "$meta" ]] && echo "$meta" | grep -q '"pinned":\s*true'; then
|
|
is_pinned=true
|
|
fi
|
|
elif [[ "${REMOTE_TYPE:-ssh}" == "local" ]]; then
|
|
local snap_dir; snap_dir=$(get_snapshot_dir "$target_name")
|
|
local meta_file="$snap_dir/$snap/meta.json"
|
|
if [[ -f "$meta_file" ]] && grep -q '"pinned":\s*true' "$meta_file" 2>/dev/null; then
|
|
is_pinned=true
|
|
fi
|
|
else
|
|
local snap_dir; snap_dir=$(get_snapshot_dir "$target_name")
|
|
local meta_content; meta_content=$(remote_exec "cat '$snap_dir/$snap/meta.json' 2>/dev/null" 2>/dev/null) || true
|
|
if [[ -n "$meta_content" ]] && echo "$meta_content" | grep -q '"pinned":\s*true'; then
|
|
is_pinned=true
|
|
fi
|
|
fi
|
|
|
|
if [[ "$is_pinned" == "true" ]]; then
|
|
log_info "Skipping pinned snapshot for $target_name: $snap"
|
|
continue
|
|
fi
|
|
|
|
log_info "Pruning old snapshot for $target_name: $snap"
|
|
if _is_rclone_mode; then
|
|
rclone_purge "targets/${target_name}/snapshots/${snap}" || {
|
|
log_warn "Failed to purge snapshot: $snap"
|
|
}
|
|
elif [[ "${REMOTE_TYPE:-ssh}" == "local" ]]; then
|
|
local snap_dir; snap_dir=$(get_snapshot_dir "$target_name")
|
|
rm -rf "$snap_dir/$snap" || {
|
|
log_warn "Failed to prune snapshot: $snap_dir/$snap"
|
|
}
|
|
else
|
|
local snap_dir; snap_dir=$(get_snapshot_dir "$target_name")
|
|
remote_exec "rm -rf '$snap_dir/$snap'" || {
|
|
log_warn "Failed to prune snapshot: $snap_dir/$snap"
|
|
}
|
|
fi
|
|
((pruned++)) || true
|
|
fi
|
|
done <<< "$snapshots"
|
|
|
|
if (( pruned > 0 )); then
|
|
log_info "Pruned $pruned old snapshot(s) for $target_name"
|
|
fi
|
|
}
|