#!/bin/bash set -euo pipefail RESTORE_TESTS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" BORG_CONTAINER="${BORG_CONTAINER:-borg-ui}" BORG_RESTORE_HOST_ROOT="${BORG_RESTORE_HOST_ROOT:-/mnt/user/appdata/borg-ui/restore}" BORG_PASSPHRASE_FILE_DEFAULT="${BORG_PASSPHRASE_FILE_DEFAULT:-/mnt/user/appdata/secrets/borg_repo_passphrase.txt}" require_cmd() { command -v "$1" >/dev/null 2>&1 || { echo "Missing command: $1" >&2 exit 1 } } require_path() { [ -e "$1" ] || { echo "Missing path: $1" >&2 exit 1 } } latest_archive_name() { docker exec "$BORG_CONTAINER" python3 - <<'PY' import sqlite3 conn = sqlite3.connect('/data/borg.db') cur = conn.cursor() cur.execute("select archive_name from backup_jobs where status in ('completed', 'completed_with_warnings') order by created_at desc limit 1") row = cur.fetchone() if not row: raise SystemExit("No completed borg archive found") print(row[0]) PY } borg_repo_url() { docker exec "$BORG_CONTAINER" python3 - <<'PY' import sqlite3 conn = sqlite3.connect('/data/borg.db') cur = conn.cursor() cur.execute("select path from repositories where path is not null and path != '' order by id asc limit 1") row = cur.fetchone() if not row: raise SystemExit("No borg repository configured") print(row[0]) PY } borg_extract() { local extract_dir="$1" shift local paths=("$@") docker exec -i "$BORG_CONTAINER" python3 - "$extract_dir" "${paths[@]}" <<'PY' import os, sys, subprocess extract_dir = sys.argv[1] paths = sys.argv[2:] import sqlite3 conn = sqlite3.connect('/data/borg.db') cur = conn.cursor() cur.execute("select path from repositories where path is not null and path != '' order by id asc limit 1") repo = cur.fetchone()[0] cur.execute("select archive_name from backup_jobs where status in ('completed', 'completed_with_warnings') order by created_at desc limit 1") archive = cur.fetchone()[0] with open('/local/secrets/borg_repo_passphrase.txt', 'r', encoding='utf-8') as f: os.environ['BORG_PASSPHRASE'] = f.read().strip() known_hosts = '/data/known_hosts' if os.path.exists(known_hosts): os.environ.setdefault( 'BORG_RSH', f'ssh -o UserKnownHostsFile={known_hosts} -o StrictHostKeyChecking=yes', ) os.makedirs(extract_dir, exist_ok=True) os.chdir(extract_dir) subprocess.run(['borg', 'extract', f'{repo}::{archive}', *paths], check=True) PY } write_report() { local report_file="$1" shift mkdir -p "$(dirname "$report_file")" cat > "$report_file" } cleanup_compose() { local compose_file="$1" if [ -f "$compose_file" ]; then docker compose -f "$compose_file" down >/dev/null 2>&1 || true fi }