126 lines
3.4 KiB
Bash
126 lines
3.4 KiB
Bash
#!/usr/bin/env bash
|
|
set -Eeuo pipefail
|
|
|
|
if [ "${EUID}" -ne 0 ]; then echo "需要 root 权限"; exit 1; fi
|
|
|
|
SRC_DIR=$(cd "$(dirname "$0")" && pwd)
|
|
DEST_DIR=/srv/taiko-web
|
|
SONGS_DIR="$DEST_DIR/public/songs"
|
|
BACKUP_DIR="$DEST_DIR/.backup_songs_$(date +%Y%m%d_%H%M%S)"
|
|
|
|
echo "正在检测部署模式..."
|
|
|
|
MODE="unknown"
|
|
if [ -f "$DEST_DIR/docker-compose.yml" ]; then
|
|
MODE="docker"
|
|
elif systemctl list-unit-files | grep -q '^taiko-web\.service'; then
|
|
MODE="direct"
|
|
fi
|
|
|
|
echo "部署模式: $MODE"
|
|
|
|
# Function: Common Backup
|
|
backup_songs() {
|
|
if [ -d "$SONGS_DIR" ]; then
|
|
echo "备份歌曲目录..."
|
|
mkdir -p "$BACKUP_DIR"
|
|
rsync -a "$SONGS_DIR/" "$BACKUP_DIR/" || cp -a "$SONGS_DIR/." "$BACKUP_DIR/"
|
|
fi
|
|
}
|
|
|
|
restore_songs() {
|
|
if [ -d "$BACKUP_DIR" ]; then
|
|
echo "恢复歌曲目录..."
|
|
mkdir -p "$SONGS_DIR"
|
|
rsync -a "$BACKUP_DIR/" "$SONGS_DIR/" || cp -a "$BACKUP_DIR/." "$SONGS_DIR/"
|
|
fi
|
|
}
|
|
|
|
sync_files() {
|
|
echo "同步文件到 $DEST_DIR..."
|
|
mkdir -p "$DEST_DIR"
|
|
# Sync but exclude data directories and config
|
|
rsync -a --delete \
|
|
--exclude '.git' \
|
|
--exclude '.venv' \
|
|
--exclude 'public/songs' \
|
|
--exclude 'mongo-data' \
|
|
--exclude 'redis-data' \
|
|
--exclude 'config.py' \
|
|
--exclude 'docker-compose.yml' \
|
|
"$SRC_DIR/" "$DEST_DIR/"
|
|
|
|
# If config.py missing in dest, copy example (only for first time, but update shouldn't overwrite)
|
|
if [ ! -f "$DEST_DIR/config.py" ] && [ -f "$SRC_DIR/config.example.py" ]; then
|
|
cp "$SRC_DIR/config.example.py" "$DEST_DIR/config.py"
|
|
fi
|
|
|
|
# If docker mode, explicit check for docker-compose.yml?
|
|
# Usually setup.sh generates it only.
|
|
# If we updated setup.sh (like I just did), we might want to update docker-compose.yml?
|
|
# No, user config might be there. Better leave it unless missing.
|
|
# However, if setup.sh changed docker-compose template, existing one might be stale.
|
|
# But usually docker-compose.yml is static enough.
|
|
}
|
|
|
|
if [ "$MODE" == "docker" ]; then
|
|
echo "=== 更新 Docker 部署 ==="
|
|
|
|
# Backup
|
|
backup_songs
|
|
|
|
# Stop containers
|
|
cd "$DEST_DIR"
|
|
if command -v docker-compose >/dev/null 2>&1; then
|
|
docker-compose down
|
|
else
|
|
docker compose down
|
|
fi
|
|
|
|
# Sync
|
|
sync_files
|
|
|
|
# Restore (if needed, though rsync exclude should handle it, double safety)
|
|
restore_songs
|
|
|
|
# Rebuild and Start
|
|
echo "重建并启动容器..."
|
|
if command -v docker-compose >/dev/null 2>&1; then
|
|
docker-compose up -d --build --remove-orphans
|
|
else
|
|
docker compose up -d --build --remove-orphans
|
|
fi
|
|
|
|
echo "清理旧镜像..."
|
|
docker image prune -f || true
|
|
|
|
echo "=== Docker 更新完成 ==="
|
|
|
|
elif [ "$MODE" == "direct" ]; then
|
|
echo "=== 更新直接部署 ==="
|
|
|
|
systemctl stop taiko-web || true
|
|
|
|
backup_songs
|
|
sync_files
|
|
|
|
# Update venv
|
|
if [ -x "$DEST_DIR/.venv/bin/pip" ]; then
|
|
echo "更新依赖..."
|
|
"$DEST_DIR/.venv/bin/pip" install -U pip
|
|
"$DEST_DIR/.venv/bin/pip" install -r "$DEST_DIR/requirements.txt"
|
|
fi
|
|
|
|
chown -R www-data:www-data "$DEST_DIR"
|
|
restore_songs
|
|
|
|
systemctl daemon-reload || true
|
|
systemctl restart taiko-web || systemctl start taiko-web || true
|
|
|
|
systemctl is-active --quiet taiko-web
|
|
echo "=== 直接部署更新完成 ==="
|
|
|
|
else
|
|
echo "未检测到已知部署 (Docker 或 Systemd)。请先运行 setup.sh 进行安装。"
|
|
exit 1
|
|
fi |