#!/usr/bin/env bash set -euo pipefail ROOT="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" KEEP_RELEASES=3 KEEP_BACKUPS=3 prune_directories() { local base="$1" local keep="$2" local protected="${3:-}" local kept=0 local entry local name [[ -d "$base" ]] || return 0 if [[ -L "$base" ]]; then printf 'WARNING: retention cleanup skipped for symlink: %s\n' "$base" >&2 return 0 fi if [[ -n "$protected" && -d "$base/$protected" && ! -L "$base/$protected" ]]; then kept=1 fi while IFS= read -r -d '' entry; do name="${entry##*/}" if [[ -n "$protected" && "$name" == "$protected" ]]; then continue fi if (( kept < keep )); then kept=$((kept + 1)) continue fi printf 'Removing old retained item: %s\n' "$entry" rm -rf -- "$entry" done < <( find "$base" \ -mindepth 1 \ -maxdepth 1 \ -type d \ -printf '%T@ %p\0' | sort -z -nr ) } cleanup_installed_releases() { local prefix="$1" local releases="$prefix/releases" local backups="$prefix/backups" local current="$prefix/current" local releases_real local current_real local current_release prune_directories "$backups" "$KEEP_BACKUPS" [[ -d "$releases" && ! -L "$releases" ]] || return 0 if [[ ! -L "$current" ]]; then printf 'WARNING: release cleanup skipped: %s is not a symlink\n' "$current" >&2 return 0 fi releases_real="$(readlink -f -- "$releases" || true)" current_real="$(readlink -f -- "$current" || true)" if [[ -z "$releases_real" || -z "$current_real" ]]; then printf 'WARNING: release cleanup skipped: cannot resolve current release\n' >&2 return 0 fi case "$current_real" in "$releases_real"/*) current_release="${current_real##*/}" ;; *) printf 'WARNING: release cleanup skipped: current points outside %s\n' \ "$releases" >&2 return 0 ;; esac prune_directories "$releases" "$KEEP_RELEASES" "$current_release" } cleanup_source_backups() { local target="$1" local backup_dir target="$(cd -- "$target" 2>/dev/null && pwd -P)" || return 0 backup_dir="$target/.upgrade-backup" prune_directories "$backup_dir" "$KEEP_BACKUPS" } if [[ "${1:-}" == "--source-tree" ]]; then shift if (($# == 0)); then exec python3 "$ROOT/scripts/deploy/upgrade.py" fi source_target="$1" python3 "$ROOT/scripts/deploy/upgrade.py" "$@" cleanup_source_backups "$source_target" exit 0 fi prefix="/opt/rustproxy" plan=0 args=("$@") for ((i = 0; i < ${#args[@]}; i++)); do case "${args[i]}" in --prefix) if ((i + 1 < ${#args[@]})); then prefix="${args[i + 1]}" i=$((i + 1)) fi ;; --prefix=*) prefix="${args[i]#--prefix=}" ;; --plan) plan=1 ;; esac done python3 "$ROOT/scripts/deploy/deploy.py" update "$@" if ((plan)); then exit 0 fi if command -v flock >/dev/null 2>&1; then exec {cleanup_lock_fd}>>"$prefix/.deploy.lock" flock -x "$cleanup_lock_fd" cleanup_installed_releases "$prefix" flock -u "$cleanup_lock_fd" exec {cleanup_lock_fd}>&- else printf 'WARNING: flock unavailable; retention cleanup skipped\n' >&2 fi