#!/usr/bin/env bash set -Eeuo pipefail usage() { echo "Usage: $0 BACKUP.tar.gz" >&2 } if [[ "$#" -ne 1 ]]; then usage exit 2 fi ROOT_DIR="$(cd "$(dirname "$0")" && pwd)" INPUT="$1" if [[ "$INPUT" != /* ]]; then INPUT="$(cd "$(dirname "$INPUT")" && pwd)/$(basename "$INPUT")" fi test -f "$INPUT" || { echo "Archive not found: $INPUT" >&2; exit 1; } gzip -t "$INPUT" STAGE="$(mktemp -d "$ROOT_DIR/.data-switch.XXXXXX")" OLD="$(mktemp -d "$ROOT_DIR/.data-previous.XXXXXX")" COMMITTED=false cleanup() { rm -rf "$STAGE" if [[ "$COMMITTED" == false ]]; then if [[ -d "$OLD/public" ]]; then rm -rf "$ROOT_DIR/public" mv "$OLD/public" "$ROOT_DIR/public" fi if [[ -d "$OLD/dbs" ]]; then rm -rf "$ROOT_DIR/dbs" mv "$OLD/dbs" "$ROOT_DIR/dbs" fi fi rm -rf "$OLD" } trap cleanup EXIT tar -C "$STAGE" -xzf "$INPUT" test -d "$STAGE/public" || { echo "Archive has no public/ directory" >&2; exit 1; } test -d "$STAGE/dbs" || { echo "Archive has no dbs/ directory" >&2; exit 1; } mapfile -t DATABASES < <(find "$STAGE/dbs" -maxdepth 1 -type f -name '*.sqlite' -print) if [[ "${#DATABASES[@]}" -eq 0 ]]; then echo "Archive contains no SQLite databases" >&2 exit 1 fi for database in "${DATABASES[@]}"; do DB_FILE="$database" node <<'NODE' const Database = require("better-sqlite3"); const db = new Database(process.env.DB_FILE, { readonly: true }); const result = db.pragma("quick_check", { simple: true }); db.close(); if (result !== "ok") { console.error(`${process.env.DB_FILE}: quick_check returned ${result}`); process.exit(1); } NODE done for process_dir in /proc/[0-9]*; do PROCESS_CWD="$(readlink "$process_dir/cwd" 2>/dev/null || true)" PROCESS_CMD="$(tr '\0' ' ' < "$process_dir/cmdline" 2>/dev/null || true)" if [[ "$PROCESS_CWD" == "$ROOT_DIR" ]] && [[ "$PROCESS_CMD" =~ (^|[[:space:]])(\./)?index\.js([[:space:]]|$) ]]; then echo "Refusing to switch data while the local Bliss server is running." >&2 echo "Stop it first, then rerun this command." >&2 exit 1 fi done STAMP="$(date +%Y%m%d-%H%M%S)" PREVIOUS="$ROOT_DIR/backups/bliss-local-before-$STAMP.tar.gz" mkdir -p "$ROOT_DIR/backups" echo "Saving current local data to $PREVIOUS" tar -C "$ROOT_DIR" -czf "$PREVIOUS" public dbs gzip -t "$PREVIOUS" mv "$ROOT_DIR/public" "$OLD/public" mv "$ROOT_DIR/dbs" "$OLD/dbs" mv "$STAGE/public" "$ROOT_DIR/public" mv "$STAGE/dbs" "$ROOT_DIR/dbs" COMMITTED=true echo "Activated data from: $INPUT" echo "Previous local data: $PREVIOUS" echo "To switch back:" printf ' %q %q\n' "$0" "$PREVIOUS"