主要变更: - 添加完整的项目结构和模块(admin、articles、comments、users、session、oauth2、email、moderation、analytics、jobs 等) - 实现系统初始化 API(/init/status 和 /init/run) - 重写部署流程:迁移到 package.json scripts,删除 Makefile - 优化部署脚本:deploy.sh、healthcheck.sh、backup.sh、restore.sh、verify-env.sh - 更新 README.md:简化文档,整合部署指南 - 优化 AGENTS.md:精简到约 150 行,包含完整的代码规范和命令速查 - 配置 Docker Compose 自动化部署(prisma migrate deploy + seed) - 生成 OAuth2 RSA 密钥对支持 - 添加环境变量验证和数据库备份恢复功能
166 lines
4.1 KiB
Bash
166 lines
4.1 KiB
Bash
#!/bin/bash
|
|
|
|
# ============================================
|
|
# LinkShare Blog - 数据库恢复脚本
|
|
# ============================================
|
|
# 用途: 从备份恢复 PostgreSQL 数据库
|
|
# 用法: ./scripts/restore.sh <backup_file> [options]
|
|
# 示例: ./scripts/restore.sh daily_20260328.sql.gz
|
|
|
|
set -e
|
|
|
|
# 配置
|
|
DB_CONTAINER="blog-postgres"
|
|
DB_NAME="linkshare"
|
|
DB_USER="blog"
|
|
|
|
# 颜色定义
|
|
GREEN='\033[0;32m'
|
|
RED='\033[0;31m'
|
|
YELLOW='\033[1;33m'
|
|
NC='\033[0m'
|
|
|
|
log_info() {
|
|
echo -e "${GREEN}[INFO]${NC} $1"
|
|
}
|
|
|
|
log_error() {
|
|
echo -e "${RED}[ERROR]${NC} $1"
|
|
}
|
|
|
|
log_warn() {
|
|
echo -e "${YELLOW}[WARN]${NC} $1"
|
|
}
|
|
|
|
# 显示用法
|
|
show_usage() {
|
|
echo "用法: $0 <backup_file> [options]"
|
|
echo ""
|
|
echo "参数:"
|
|
echo " backup_file 备份文件路径 (必需)"
|
|
echo ""
|
|
echo "选项:"
|
|
echo " --drop 恢复前删除现有数据库 (危险!)"
|
|
echo " --dry-run 仅验证备份文件,不执行恢复"
|
|
echo " --help 显示此帮助信息"
|
|
echo ""
|
|
echo "示例:"
|
|
echo " $0 daily_20260328.sql.gz # 恢复备份"
|
|
echo " $0 daily_20260328.sql.gz --drop # 删除并恢复"
|
|
echo " $0 daily_20260328.sql.gz --dry-run # 验证备份"
|
|
echo ""
|
|
echo "可用备份:"
|
|
ls -1 backups/*.sql.gz 2>/dev/null || echo " (无备份文件)"
|
|
}
|
|
|
|
# 检查参数
|
|
if [ $# -lt 1 ] || [ "$1" = "--help" ]; then
|
|
show_usage
|
|
exit 1
|
|
fi
|
|
|
|
BACKUP_FILE=$1
|
|
shift
|
|
|
|
# 解析选项
|
|
DROP_DB=false
|
|
DRY_RUN=false
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case $1 in
|
|
--drop)
|
|
DROP_DB=true
|
|
shift
|
|
;;
|
|
--dry-run)
|
|
DRY_RUN=true
|
|
shift
|
|
;;
|
|
*)
|
|
log_error "未知选项: $1"
|
|
show_usage
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
|
|
# 检查备份文件
|
|
if [ ! -f "$BACKUP_FILE" ]; then
|
|
log_error "备份文件不存在: $BACKUP_FILE"
|
|
exit 1
|
|
fi
|
|
|
|
# 验证备份文件
|
|
log_info "验证备份文件..."
|
|
if gzip -t "$BACKUP_FILE" 2>/dev/null; then
|
|
log_info "✓ 备份文件完整性检查通过"
|
|
else
|
|
log_error "备份文件损坏或不是有效的 gzip 文件"
|
|
exit 1
|
|
fi
|
|
|
|
# dry-run 模式
|
|
if [ "$DRY_RUN" = true ]; then
|
|
log_info "Dry-run 模式: 不执行恢复"
|
|
log_info "备份信息:"
|
|
ls -lh "$BACKUP_FILE"
|
|
gzip -dc "$BACKUP_FILE" | head -n 20
|
|
log_info "备份文件前20行预览完成"
|
|
exit 0
|
|
fi
|
|
|
|
# 检查数据库容器
|
|
if ! docker ps | grep -q "$DB_CONTAINER"; then
|
|
log_error "数据库容器 '$DB_CONTAINER' 未运行"
|
|
exit 1
|
|
fi
|
|
|
|
# 警告确认
|
|
echo ""
|
|
log_warn "即将执行数据库恢复!"
|
|
log_warn "备份文件: $BACKUP_FILE"
|
|
log_warn "数据库: $DB_NAME"
|
|
if [ "$DROP_DB" = true ]; then
|
|
log_warn "警告: 将删除现有数据库!"
|
|
fi
|
|
echo ""
|
|
read -p "确认继续? (yes/no): " CONFIRM
|
|
if [ "$CONFIRM" != "yes" ]; then
|
|
log_info "操作已取消"
|
|
exit 0
|
|
fi
|
|
|
|
# 执行恢复
|
|
log_info "开始恢复数据库..."
|
|
|
|
if [ "$DROP_DB" = true ]; then
|
|
log_info "删除现有数据库..."
|
|
docker exec "$DB_CONTAINER" psql -U "$DB_USER" -c "DROP DATABASE IF EXISTS $DB_NAME;"
|
|
docker exec "$DB_CONTAINER" psql -U "$DB_USER" -c "CREATE DATABASE $DB_NAME;"
|
|
log_info "数据库已重建"
|
|
fi
|
|
|
|
# 恢复数据
|
|
if gzip -dc "$BACKUP_FILE" | docker exec -i "$DB_CONTAINER" psql -U "$DB_USER" "$DB_NAME"; then
|
|
log_info "✓ 数据库恢复成功!"
|
|
|
|
# 验证恢复
|
|
log_info "验证恢复结果..."
|
|
TABLE_COUNT=$(gzip -dc "$BACKUP_FILE" | grep -c "^CREATE TABLE" || echo "0")
|
|
log_info "备份中发现的表数量: $TABLE_COUNT"
|
|
|
|
ACTUAL_COUNT=$(docker exec "$DB_CONTAINER" psql -U "$DB_USER" -d "$DB_NAME" -t -c "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='public';" 2>/dev/null | tr -d '[:space:]')
|
|
log_info "恢复后的表数量: $ACTUAL_COUNT"
|
|
|
|
if [ "$TABLE_COUNT" -eq "$ACTUAL_COUNT" ] || [ "$ACTUAL_COUNT" -gt 0 ]; then
|
|
log_info "✓ 验证通过"
|
|
exit 0
|
|
else
|
|
log_warn "表数量不匹配,请手动验证数据完整性"
|
|
exit 0
|
|
fi
|
|
else
|
|
log_error "数据库恢复失败"
|
|
exit 1
|
|
fi
|