From d46ccfc2762558f4f400cfd68067695c88bf44df Mon Sep 17 00:00:00 2001 From: cfdaily Date: Fri, 22 May 2026 18:26:19 +0800 Subject: [PATCH] auto-sync: 2026-05-22 18:26:19 --- scripts/backup.sh | 105 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 scripts/backup.sh diff --git a/scripts/backup.sh b/scripts/backup.sh new file mode 100644 index 0000000..f4fc7f5 --- /dev/null +++ b/scripts/backup.sh @@ -0,0 +1,105 @@ +#!/usr/bin/env bash +# backup.sh — 备份 moziplus v2 数据到 NAS +set -euo pipefail + +TARGET_DIR="$HOME/.sanguo_projects/sanguo_moziplus_v2" +NAS_BASE="/Volumes/stock" +BACKUP_SUBDIR="moziplus-v2-backups" +PM2_NAME="sanguo-moziplus-v2" +STOP_SERVICE=false + +usage() { + echo "Usage: $0 [options]" + echo "" + echo "Options:" + echo " --target=DIR 安装目录" + echo " --nas=DIR NAS 挂载点 (default: /Volumes/stock)" + echo " --stop 备份前停服务(确保数据一致性)" + echo " -h, --help 显示帮助" + echo "" + echo "Note: 如果不停服务,SQLite 可能有不一致的快照" + echo " 对于日常备份通常没问题,重要备份建议加 --stop" + exit 0 +} + +for arg in "$@"; do + case "$arg" in + --target=*) TARGET_DIR="${arg#*=}" ;; + --nas=*) NAS_BASE="${arg#*=}" ;; + --stop) STOP_SERVICE=true ;; + -h|--help) usage ;; + esac +done + +DATA_DIR="$TARGET_DIR/data" +CONFIG_DIR="$TARGET_DIR/config" + +if [ ! -d "$DATA_DIR" ]; then + echo "❌ Data directory not found: $DATA_DIR" && exit 1 +fi + +if [ ! -d "$NAS_BASE" ]; then + echo "❌ NAS not mounted: $NAS_BASE" + echo " Mount NAS first: open smb://192.168.2.154/" + exit 1 +fi + +BACKUP_DIR="$NAS_BASE/$BACKUP_SUBDIR" +TIMESTAMP=$(date +%Y%m%d-%H%M%S) +BACKUP_NAME="backup-$TIMESTAMP" + +echo "💾 Backing up moziplus v2" +echo " Data: $DATA_DIR" +echo " Config: $CONFIG_DIR" +echo " Target: $BACKUP_DIR/$BACKUP_NAME" + +mkdir -p "$BACKUP_DIR" + +# ── 停服务(可选)── +if [ "$STOP_SERVICE" = true ]; then + echo "" + echo "🛑 Stopping service for consistent backup..." + pm2 stop "$PM2_NAME" 2>/dev/null || true +fi + +# ── 备份 ── +echo "" +echo "📦 Copying data..." +mkdir -p "$BACKUP_DIR/$BACKUP_NAME" +rsync -a "$DATA_DIR/" "$BACKUP_DIR/$BACKUP_NAME/data/" +echo "📦 Copying config..." +rsync -a "$CONFIG_DIR/" "$BACKUP_DIR/$BACKUP_NAME/config/" + +# ── 记录元数据 ── +cat > "$BACKUP_DIR/$BACKUP_NAME/metadata.json" << EOF +{ + "timestamp": "$TIMESTAMP", + "date": "$(date -Iseconds)", + "source": "$TARGET_DIR", + "service_stopped": $STOP_SERVICE, + "version": "$(cd "$TARGET_DIR" && python3 -c 'import tomllib; print(tomllib.load(open("pyproject.toml","rb"))["project"]["version"])' 2>/dev/null || echo 'unknown')" +} +EOF + +# ── 计算大小 ── +BACKUP_SIZE=$(du -sh "$BACKUP_DIR/$BACKUP_NAME" | cut -f1) + +# ── 重启服务 ── +if [ "$STOP_SERVICE" = true ]; then + echo "" + echo "▶️ Restarting service..." + pm2 start "$PM2_NAME" 2>/dev/null || true +fi + +# ── 清理旧备份(保留最近 10 个)── +echo "" +echo "🧹 Cleaning old backups (keeping latest 10)..." +cd "$BACKUP_DIR" +ls -d backup-* 2>/dev/null | sort | head -n -10 | xargs rm -rf 2>/dev/null || true + +# ── 完成 ── +echo "" +echo "✅ Backup completed" +echo " Name: $BACKUP_NAME" +echo " Size: $BACKUP_SIZE" +echo " Path: $BACKUP_DIR/$BACKUP_NAME"