#!/usr/bin/env sh set -eu if [ "$#" -lt 1 ]; then echo "Usage: $0 " exit 1 fi dump_file="$1" COMPOSE_FILE="${COMPOSE_FILE:-docker-compose.production.yml}" ENV_FILE="${ENV_FILE:-.env.production}" SYNOLOGY_BACKUP_DIR="${SYNOLOGY_BACKUP_DIR:-}" if [ ! -f "${dump_file}" ]; then echo "Backup file not found: ${dump_file}" exit 1 fi backup_dir="$(dirname "${dump_file}")" backup_name="$(basename "${dump_file}")" timestamp="$(printf '%s' "${backup_name}" | sed -n 's/^postgres-\([0-9]\{8\}-[0-9]\{6\}\)\.dump$/\1/p')" uploads_file="" config_file="" # If SYNOLOGY_BACKUP_DIR wasn't exported in the shell, read it from ENV_FILE. if [ -z "${SYNOLOGY_BACKUP_DIR}" ] && [ -f "${ENV_FILE}" ]; then SYNOLOGY_BACKUP_DIR="$( sed -n 's/^SYNOLOGY_BACKUP_DIR=//p' "${ENV_FILE}" | tail -n 1 )" fi if [ -n "${timestamp}" ]; then # Legacy local full-archive naming. candidate_uploads="${backup_dir}/uploads-${timestamp}.tar.gz" candidate_config="${backup_dir}/config-${timestamp}.tar.gz" if [ -f "${candidate_uploads}" ]; then uploads_file="${candidate_uploads}" fi if [ -f "${candidate_config}" ]; then config_file="${candidate_config}" fi fi docker compose --env-file "${ENV_FILE}" -f "${COMPOSE_FILE}" exec -T postgres sh -lc \ "PGPASSWORD=\"\$POSTGRES_PASSWORD\" psql -U \"\$POSTGRES_USER\" -d postgres -c \"DROP DATABASE IF EXISTS \\\"\$POSTGRES_DB\\\";\"" docker compose --env-file "${ENV_FILE}" -f "${COMPOSE_FILE}" exec -T postgres sh -lc \ "PGPASSWORD=\"\$POSTGRES_PASSWORD\" psql -U \"\$POSTGRES_USER\" -d postgres -c \"CREATE DATABASE \\\"\$POSTGRES_DB\\\";\"" cat "${dump_file}" | docker compose --env-file "${ENV_FILE}" -f "${COMPOSE_FILE}" exec -T postgres sh -lc \ "PGPASSWORD=\"\$POSTGRES_PASSWORD\" pg_restore -U \"\$POSTGRES_USER\" -d \"\$POSTGRES_DB\" --clean --if-exists --no-owner --no-privileges" if [ -n "${SYNOLOGY_BACKUP_DIR}" ] && [ -d "${SYNOLOGY_BACKUP_DIR}/uploads" ]; then docker compose --env-file "${ENV_FILE}" -f "${COMPOSE_FILE}" run --rm --no-deps \ -v "${SYNOLOGY_BACKUP_DIR}:/backup" \ --entrypoint sh app -lc \ "mkdir -p /app/uploads/documents /app/uploads/photos && \ find /app/uploads/documents -mindepth 1 -delete && \ find /app/uploads/photos -mindepth 1 -delete && \ if [ -d /backup/uploads/documents ]; then cp -a /backup/uploads/documents/. /app/uploads/documents/; fi && \ if [ -d /backup/uploads/photos ]; then cp -a /backup/uploads/photos/. /app/uploads/photos/; fi && \ if [ -f /backup/uploads/homepage.md ]; then cp /backup/uploads/homepage.md /app/uploads/homepage.md; else rm -f /app/uploads/homepage.md; fi" elif [ -n "${uploads_file}" ]; then # Legacy local full-archive restore. cat "${uploads_file}" | docker compose --env-file "${ENV_FILE}" -f "${COMPOSE_FILE}" run --rm --no-deps --entrypoint sh app -lc \ "mkdir -p /app/uploads && find /app/uploads -mindepth 1 -delete && tar -xzf - -C /app/uploads" fi if [ -n "${SYNOLOGY_BACKUP_DIR}" ] && [ -n "${timestamp}" ] && [ -f "${SYNOLOGY_BACKUP_DIR}/config-${timestamp}.tar.gz" ]; then tar -xzf "${SYNOLOGY_BACKUP_DIR}/config-${timestamp}.tar.gz" -C . elif [ -n "${config_file}" ]; then # Legacy local full-archive restore. tar -xzf "${config_file}" -C . fi echo "Restore complete from: ${dump_file}" if [ -n "${SYNOLOGY_BACKUP_DIR}" ] && [ -d "${SYNOLOGY_BACKUP_DIR}/uploads" ]; then echo "Restored uploads mirror from: ${SYNOLOGY_BACKUP_DIR}/uploads" elif [ -n "${uploads_file}" ]; then echo "Restored uploads archive: ${uploads_file}" fi if [ -n "${SYNOLOGY_BACKUP_DIR}" ] && [ -n "${timestamp}" ] && [ -f "${SYNOLOGY_BACKUP_DIR}/config-${timestamp}.tar.gz" ]; then echo "Restored config archive: ${SYNOLOGY_BACKUP_DIR}/config-${timestamp}.tar.gz" elif [ -n "${config_file}" ]; then echo "Restored config archive: ${config_file}" fi