#!/usr/bin/env sh set -eu COMMAND="${1:-help}" ENV_FILE="${ENV_FILE:-.env}" BACKUP_ROOT="${BACKUP_ROOT:-backups}" RETENTION_DAYS="${RETENTION_DAYS:-14}" TIMESTAMP="${BACKUP_TIMESTAMP:-$(date +%Y%m%d_%H%M%S)}" log() { printf '[backup] %s\n' "$*" } fail() { printf '[backup] %s\n' "$*" >&2 exit 1 } require_command() { command -v "$1" >/dev/null 2>&1 || fail "Required command not found: $1" } has_command() { command -v "$1" >/dev/null 2>&1 } load_env() { [ -f "$ENV_FILE" ] || fail "Env file not found: $ENV_FILE" case "$ENV_FILE" in */*) env_path="$ENV_FILE" ;; *) env_path="./$ENV_FILE" ;; esac set -a # shellcheck disable=SC1090 . "$env_path" set +a : "${DB_HOST:?DB_HOST is required in $ENV_FILE}" : "${DB_PORT:=3306}" : "${DB_USER:?DB_USER is required in $ENV_FILE}" : "${DB_PASS:?DB_PASS is required in $ENV_FILE}" : "${DB_NAME:?DB_NAME is required in $ENV_FILE}" } db_dump() { require_command gzip load_env mkdir -p "$BACKUP_ROOT/db" output_path="$BACKUP_ROOT/db/${DB_NAME}_${TIMESTAMP}.sql.gz" log "Creating DB dump: $output_path" if has_command mysqldump; then MYSQL_PWD="$DB_PASS" mysqldump \ --host="$DB_HOST" \ --port="$DB_PORT" \ --user="$DB_USER" \ --single-transaction \ --quick \ --routines \ --triggers \ "$DB_NAME" | gzip > "$output_path" elif has_command docker; then docker exec itam-backend sh -lc "MYSQL_PWD=\"$DB_PASS\" exec mysqldump --host=\"$DB_HOST\" --port=\"$DB_PORT\" --user=\"$DB_USER\" --single-transaction --quick --routines --triggers \"$DB_NAME\"" | gzip > "$output_path" else fail "Required command not found: mysqldump (and docker fallback unavailable)" fi log "DB dump completed: $output_path" } files_backup() { require_command tar mkdir -p "$BACKUP_ROOT/files" archive_path="$BACKUP_ROOT/files/runtime_${TIMESTAMP}.tar.gz" set -- [ -f "$ENV_FILE" ] && set -- "$@" "$ENV_FILE" [ -d "uploads" ] && set -- "$@" "uploads" [ -f "map_config.json" ] && set -- "$@" "map_config.json" [ "$#" -gt 0 ] || fail "No runtime files found to archive" log "Creating runtime archive: $archive_path" tar -czf "$archive_path" "$@" log "Runtime archive completed: $archive_path" } cleanup_backups() { require_command find [ -d "$BACKUP_ROOT" ] || { log "Backup root does not exist, skipping cleanup: $BACKUP_ROOT" return 0 } log "Deleting backup files older than ${RETENTION_DAYS} days from $BACKUP_ROOT" find "$BACKUP_ROOT" -type f -mtime "+$RETENTION_DAYS" -print -delete } case "$COMMAND" in db) db_dump ;; files) files_backup ;; full) db_dump files_backup ;; cleanup) cleanup_backups ;; help|--help|-h) log "Commands: db | files | full | cleanup" ;; *) fail "Unknown command: $COMMAND" ;; esac