#!/usr/bin/env bash set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" source "$SCRIPT_DIR/.env" # --- Argument validation --- if [ $# -lt 1 ]; then echo "Usage: $0 " >&2 exit 1 fi DUMP_ZIP="$(realpath "$1")" if [ ! -f "$DUMP_ZIP" ]; then echo "Error: dump file not found: $DUMP_ZIP" >&2 exit 1 fi if ! docker info > /dev/null 2>&1; then echo "Error: Docker is not accessible" >&2 exit 1 fi # --- Cleanup trap: always bring services back up --- cleanup() { echo "Starting all services..." docker compose -f "$SCRIPT_DIR/docker-compose.yml" up -d } trap cleanup EXIT # --- Stop everything --- echo "Stopping all services..." docker compose -f "$SCRIPT_DIR/docker-compose.yml" down # --- Start only the database --- echo "Starting database only..." docker compose -f "$SCRIPT_DIR/docker-compose.yml" up -d db echo "Waiting for database to be ready..." for i in $(seq 1 30); do if docker compose -f "$SCRIPT_DIR/docker-compose.yml" exec -T db \ pg_isready -U "$DB_USER" -d "$DB_NAME" > /dev/null 2>&1; then break fi if [ "$i" -eq 30 ]; then echo "Error: database not ready after 30 seconds" >&2 exit 1 fi sleep 1 done # --- Restore database --- echo "Restoring database..." docker compose -f "$SCRIPT_DIR/docker-compose.yml" exec -T db \ psql -U "$DB_USER" -d postgres -c "DROP DATABASE IF EXISTS \"$DB_NAME\";" docker compose -f "$SCRIPT_DIR/docker-compose.yml" exec -T db \ psql -U "$DB_USER" -d postgres -c "CREATE DATABASE \"$DB_NAME\" OWNER \"$DB_USER\";" unzip -p "$DUMP_ZIP" gitea-db.sql | \ docker compose -f "$SCRIPT_DIR/docker-compose.yml" exec -T db \ psql -U "$DB_USER" -d "$DB_NAME" # --- Restore data files --- echo "Restoring data files..." docker run --rm \ -v "${GITEA_DATA}:/data" \ -v "${DUMP_ZIP}:/backup/dump.zip:ro" \ docker.gitea.com/gitea:1.25.3 \ /bin/sh -c ' set -e apk add --no-cache unzip > /dev/null 2>&1 || true mkdir -p /tmp/restore unzip -o /backup/dump.zip -d /tmp/restore # Clear old data rm -rf /data/gitea/attachments /data/gitea/avatars /data/gitea/jwt \ /data/gitea/indexers /data/gitea/queues /data/gitea/lfs \ /data/gitea/packages /data/gitea/tmp rm -rf /data/git/repositories/* # Restore data directory contents if [ -d /tmp/restore/data ]; then cp -a /tmp/restore/data/* /data/gitea/ 2>/dev/null || true fi # Restore repositories if [ -d /tmp/restore/repos ]; then cp -a /tmp/restore/repos/* /data/git/repositories/ 2>/dev/null || true fi # Restore app.ini if [ -f /tmp/restore/app.ini ]; then mkdir -p /data/gitea/conf cp -a /tmp/restore/app.ini /data/gitea/conf/app.ini fi # Fix ownership chown -R 1001:1001 /data rm -rf /tmp/restore ' # --- Bring everything up (trap will handle this) --- # Trap fires on exit, which starts all services. # After services are up, regenerate hooks. trap - EXIT echo "Starting all services..." docker compose -f "$SCRIPT_DIR/docker-compose.yml" up -d echo "Waiting for Gitea to start..." for i in $(seq 1 60); do if docker exec gitea curl -sf http://localhost:3000/ > /dev/null 2>&1; then break fi if [ "$i" -eq 60 ]; then echo "Warning: Gitea not responding after 60s, attempting hook regeneration anyway" >&2 break fi sleep 1 done echo "Regenerating git hooks..." docker exec gitea gitea admin regenerate hooks echo "Restore completed successfully"