platform: modularize api/gui, add docs-tests-web foundation, and refresh root config
This commit is contained in:
153
scripts/transport-packaging/rollback.sh
Executable file
153
scripts/transport-packaging/rollback.sh
Executable file
@@ -0,0 +1,153 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
BIN_ROOT="/opt/selective-vpn/bin"
|
||||
COMPONENTS_RAW=""
|
||||
DRY_RUN=0
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
Usage:
|
||||
rollback.sh [--bin-root DIR] [--component NAME[,NAME...]] [--dry-run]
|
||||
|
||||
Description:
|
||||
Rolls back transport companion binaries by one history step.
|
||||
Uses history files created by update.sh in BIN_ROOT/.packaging/*.history.
|
||||
|
||||
Examples:
|
||||
./scripts/transport-packaging/rollback.sh --component singbox
|
||||
./scripts/transport-packaging/rollback.sh --bin-root /tmp/svpn-bin --dry-run
|
||||
EOF
|
||||
}
|
||||
|
||||
require_cmd() {
|
||||
local cmd="$1"
|
||||
if ! command -v "$cmd" >/dev/null 2>&1; then
|
||||
echo "[transport-rollback] missing required command: ${cmd}" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
collect_components() {
|
||||
local state_dir="$1"
|
||||
local out=()
|
||||
if [[ -n "$COMPONENTS_RAW" ]]; then
|
||||
IFS=',' read -r -a out <<< "$COMPONENTS_RAW"
|
||||
else
|
||||
if [[ -d "$state_dir" ]]; then
|
||||
while IFS= read -r file; do
|
||||
local base
|
||||
base="$(basename "$file")"
|
||||
out+=("${base%.history}")
|
||||
done < <(find "$state_dir" -maxdepth 1 -type f -name '*.history' | sort)
|
||||
fi
|
||||
fi
|
||||
printf '%s\n' "${out[@]}"
|
||||
}
|
||||
|
||||
rollback_component() {
|
||||
local component="$1"
|
||||
local state_dir="$2"
|
||||
local history_file="${state_dir}/${component}.history"
|
||||
|
||||
if [[ ! -f "$history_file" ]]; then
|
||||
echo "[transport-rollback] ${component}: history file not found (${history_file})" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
mapfile -t lines < "$history_file"
|
||||
if [[ "${#lines[@]}" -lt 2 ]]; then
|
||||
echo "[transport-rollback] ${component}: not enough history entries to rollback" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
local current_line prev_line
|
||||
current_line="${lines[${#lines[@]}-1]}"
|
||||
prev_line="${lines[${#lines[@]}-2]}"
|
||||
|
||||
IFS='|' read -r _ts_curr bin_curr version_curr target_curr <<< "$current_line"
|
||||
IFS='|' read -r _ts_prev bin_prev version_prev target_prev <<< "$prev_line"
|
||||
local binary_name="${bin_curr:-$bin_prev}"
|
||||
local active_link="${BIN_ROOT}/${binary_name}"
|
||||
|
||||
if [[ -z "$binary_name" || -z "$target_prev" ]]; then
|
||||
echo "[transport-rollback] ${component}: invalid history lines" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ ! -e "$target_prev" ]]; then
|
||||
echo "[transport-rollback] ${component}: previous target does not exist: ${target_prev}" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "[transport-rollback] ${component}: ${binary_name} ${version_curr} -> ${version_prev}"
|
||||
if [[ "$DRY_RUN" -eq 1 ]]; then
|
||||
echo "[transport-rollback] DRY-RUN ${component}: switch ${active_link} -> ${target_prev}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
ln -sfn "$target_prev" "$active_link"
|
||||
|
||||
if [[ "${#lines[@]}" -eq 2 ]]; then
|
||||
printf '%s\n' "${lines[0]}" > "$history_file"
|
||||
else
|
||||
printf '%s\n' "${lines[@]:0:${#lines[@]}-1}" > "$history_file"
|
||||
fi
|
||||
echo "[transport-rollback] ${component}: active -> ${target_prev}"
|
||||
}
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--bin-root)
|
||||
BIN_ROOT="${2:-}"
|
||||
shift 2
|
||||
;;
|
||||
--component)
|
||||
COMPONENTS_RAW="${2:-}"
|
||||
shift 2
|
||||
;;
|
||||
--dry-run)
|
||||
DRY_RUN=1
|
||||
shift
|
||||
;;
|
||||
-h|--help)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
echo "[transport-rollback] unknown argument: $1" >&2
|
||||
usage >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
require_cmd ln
|
||||
require_cmd find
|
||||
require_cmd basename
|
||||
|
||||
state_dir="${BIN_ROOT}/.packaging"
|
||||
mapfile -t components < <(collect_components "$state_dir")
|
||||
|
||||
if [[ "${#components[@]}" -eq 0 ]]; then
|
||||
echo "[transport-rollback] no components selected/found" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "[transport-rollback] bin_root=${BIN_ROOT}"
|
||||
if [[ -n "$COMPONENTS_RAW" ]]; then
|
||||
echo "[transport-rollback] components=${COMPONENTS_RAW}"
|
||||
fi
|
||||
if [[ "$DRY_RUN" -eq 1 ]]; then
|
||||
echo "[transport-rollback] mode=dry-run"
|
||||
fi
|
||||
|
||||
for component in "${components[@]}"; do
|
||||
component="$(echo "$component" | xargs)"
|
||||
if [[ -z "$component" ]]; then
|
||||
continue
|
||||
fi
|
||||
rollback_component "$component" "$state_dir"
|
||||
done
|
||||
|
||||
echo "[transport-rollback] done"
|
||||
Reference in New Issue
Block a user