#!/usr/bin/env bash set -euo pipefail # === METADATA === SCRIPT_NAME="$(basename "$0")" SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" SKILL_ROOT="$(dirname "$SCRIPT_DIR")" # === CONFIGURATION === : "${OUTPUT_DIR:=$SKILL_ROOT/outputs}" : "${BACKUP_SOURCES:=}" : "${BACKUP_EXCLUDES:=.git,node_modules,target,dist,outputs}" # === FUNCTIONS === log_info() { echo "[INFO] $(date -Iseconds) $*"; } log_warn() { echo "[WARN] $(date -Iseconds) $*" >&2; } log_error() { echo "[ERROR] $(date -Iseconds) $*" >&2; } die() { log_error "$@"; exit 1; } check_tool() { local tool="$1" if command -v "$tool" &>/dev/null; then log_info "Found: $tool ($(command -v "$tool"))" return 0 else log_warn "Missing: $tool" return 1 fi } check_b3sum() { if command -v b3sum &>/dev/null; then log_info "Found: b3sum ($(command -v b3sum))" return 0 elif command -v blake3 &>/dev/null; then log_info "Found: blake3 ($(command -v blake3))" return 0 else log_warn "Missing: b3sum or blake3" return 1 fi } main() { log_info "Starting $SCRIPT_NAME..." mkdir -p "$OUTPUT_DIR" local missing=0 log_info "=== Required Tools ===" check_tool tar || ((missing++)) check_tool gzip || ((missing++)) check_tool age || ((missing++)) check_b3sum || ((missing++)) check_tool stat || ((missing++)) check_tool find || ((missing++)) log_info "=== Backup Sources ===" if [[ -z "$BACKUP_SOURCES" ]]; then log_warn "BACKUP_SOURCES not set (required for backup)" else IFS=',' read -r -a sources <<< "$BACKUP_SOURCES" for src in "${sources[@]}"; do # Expand ~ if present src="${src/#\~/$HOME}" if [[ -e "$src" ]]; then log_info "Source exists: $src" else log_warn "Source missing: $src" fi done fi log_info "=== Encryption Files ===" if [[ -n "${AGE_RECIPIENT_FILE:-}" ]]; then if [[ -f "$AGE_RECIPIENT_FILE" ]]; then log_info "AGE_RECIPIENT_FILE exists: $AGE_RECIPIENT_FILE" else log_warn "AGE_RECIPIENT_FILE missing: $AGE_RECIPIENT_FILE" fi else log_warn "AGE_RECIPIENT_FILE not set (required for encryption)" fi if [[ -n "${AGE_IDENTITY_FILE:-}" ]]; then if [[ -f "$AGE_IDENTITY_FILE" ]]; then log_info "AGE_IDENTITY_FILE exists: $AGE_IDENTITY_FILE" else log_warn "AGE_IDENTITY_FILE missing: $AGE_IDENTITY_FILE" fi else log_warn "AGE_IDENTITY_FILE not set (required for restore drill)" fi log_info "=== Disk Space ===" local avail avail=$(df -P "$OUTPUT_DIR" | awk 'NR==2 {print $4}') log_info "Available space in $OUTPUT_DIR: $((avail / 1024)) MB" log_info "=== Parameters ===" log_info "NODE_NAME=${NODE_NAME:-node-a}" log_info "BACKUP_LABEL=${BACKUP_LABEL:-manual}" log_info "BACKUP_EXCLUDES=$BACKUP_EXCLUDES" log_info "DRY_RUN=${DRY_RUN:-1} (apply scripts require DRY_RUN=0)" if [[ $missing -gt 0 ]]; then die "Missing $missing required tools. Install them before proceeding." fi log_info "Preflight OK." log_info "Completed $SCRIPT_NAME" } [[ "${BASH_SOURCE[0]}" == "$0" ]] && main "$@"