#!/usr/bin/env bash # # Short Track Dashboard — Linux 自动部署脚本 # 替代 deploy_all.ps1,适用于 PRoot/aarch64 Linux 环境 # # 用法: # ./deploy.sh # 完整部署(保留服务器数据库) # ./deploy.sh --force-data # 强制同步本地数据库到服务器 # ./deploy.sh --apk-only # 仅构建并上传 APK # set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" cd "$SCRIPT_DIR" SERVER="ubuntu@122.51.80.140" REMOTE_DIR="~/short_track_dashboard" APK_SRC="static/app-debug-latest.apk" BUILD_LOG="/tmp/deploy_$(date +%Y%m%d_%H%M%S).log" FORCE_DATA=false APK_ONLY=false for arg in "$@"; do case "$arg" in --force-data) FORCE_DATA=true ;; --apk-only) APK_ONLY=true ;; *) echo "未知参数: $arg"; exit 1 ;; esac done # ── Color helpers ────────────────────────────────────────────── red() { echo -e "\033[31m$1\033[0m"; } green() { echo -e "\033[32m$1\033[0m"; } yellow() { echo -e "\033[33m$1\033[0m"; } cyan() { echo -e "\033[36m$1\033[0m"; } step() { echo ""; yellow "[$1/$2] $3"; } ok() { green " ✓ $1"; } warn() { yellow " ⚠ $1"; } fail() { red " ✗ $1"; exit 1; } echo "" cyan "========================================" cyan " Short Track Dashboard Deploy" cyan "========================================" echo "" # ── Step 1: Check / Build APK ────────────────────────────────── step 1 3 "检查 APK..." NEED_APK_BUILD=true # ── Step 2: Web 部署 (if not APK-only) ──────────────────────── if [ "$APK_ONLY" = false ]; then step 2 3 "打包项目..." PACK_FILE="$SCRIPT_DIR/deploy_tmp.tar.gz" rm -f "$PACK_FILE" # 排除列表 EXCLUDES=( 'node_modules' '__pycache__' '.git' '.codebuddy' 'deploy_tmp.tar.gz' 'android' 'wechat_decrypted' 'wx_key_tool' 'dist' 'deploy*.ps1' 'deploy_guide.md' 'deploy.sh' '.venv' 'venv' '.pytest_cache' 'hf-space' 'data' # 保护服务器数据库 ← 重要! ) # 构建 tar exclude 参数 TAR_EXCLUDE="" for ex in "${EXCLUDES[@]}"; do TAR_EXCLUDE="$TAR_EXCLUDE --exclude=$ex" done # 打包(包含 data/ 目录下的 .db 但不覆盖服务器数据) tar czf "$PACK_FILE" $TAR_EXCLUDE \ --exclude='check_*.py' --exclude='debug_*.py' \ --exclude='decrypt*.py' --exclude='export_competition.py' \ --exclude='export_training.py' --exclude='_*' \ -C "$SCRIPT_DIR" . PACK_SIZE=$(du -h "$PACK_FILE" | cut -f1) ok "打包完成 ($PACK_SIZE)" step 3 3 "上传项目到服务器..." scp -o StrictHostKeyChecking=no "$PACK_FILE" "${SERVER}:~/deploy_tmp.tar.gz" || fail "上传失败" rm -f "$PACK_FILE" ok "上传完成" echo "" echo " 远程部署中..." echo "" # 数据库备份(部署前自动备份,防止数据丢失) BACKUP_CMD="mkdir -p $REMOTE_DIR/db_backups && cp $REMOTE_DIR/data/short_track.db $REMOTE_DIR/db_backups/short_track_\$(date +%Y%m%d_%H%M%S).db 2>/dev/null || true" # 构建远程命令(tar 的非致命权限错误用 sed 过滤) if [ "$FORCE_DATA" = true ]; then warn "ForceData 模式:将覆盖服务器数据库" REMOTE_CMD="$BACKUP_CMD && cd $REMOTE_DIR && tar xzf ~/deploy_tmp.tar.gz --no-same-permissions 2>&1 | sed '/Cannot/d' && rm ~/deploy_tmp.tar.gz && sudo docker compose down && sudo docker compose up -d --build && sleep 8 && sudo docker compose ps" else ok "保留服务器数据库(已备份)" REMOTE_CMD="$BACKUP_CMD && cd $REMOTE_DIR && tar xzf ~/deploy_tmp.tar.gz --no-same-permissions 2>&1 | sed '/Cannot/d' && rm ~/deploy_tmp.tar.gz && sudo docker compose down && sudo docker compose up -d --build && sleep 8 && sudo docker compose ps" fi ssh -o StrictHostKeyChecking=no "$SERVER" "$REMOTE_CMD" || fail "远程部署失败" ok "Docker 容器已重启" fi # ── Step 3: APK 上传 ─────────────────────────────────────────── if [ "$NEED_APK_BUILD" = true ] || [ "$APK_ONLY" = true ]; then echo "" yellow "[APK] 构建 Android APK..." python3 build_mobile.py android || fail "APK 构建失败" ok "APK 构建完成" fi echo "" echo " 上传 APK 到服务器..." scp -o StrictHostKeyChecking=no "$APK_SRC" "${SERVER}:~/app-debug.apk" || fail "APK 上传失败" ok "APK 已上传" # 安装 APK 到 static/ 目录 ssh -o StrictHostKeyChecking=no "$SERVER" \ "cp ~/app-debug.apk $REMOTE_DIR/static/app-debug-latest.apk && cp ~/app-debug.apk $REMOTE_DIR/static/app-debug-v\$(python3 -c \"import re, os; print(re.search(r'APP_VERSION\s*=\s*\\\"([^\\\"]+)\\\"', open(os.path.join(os.path.expanduser('~'), 'short_track_dashboard/app.py')).read()).group(1))\").apk && rm ~/app-debug.apk && ls -lh $REMOTE_DIR/static/app-debug-*.apk" || warn "APK 安装到 static/ 失败(可能版本号提取异常)" ok "APK 已部署到服务器" # ── Done ─────────────────────────────────────────────────────── echo "" cyan "========================================" green " 部署完成!" cyan "========================================" echo "" echo " Web: http://122.51.80.140:5000" echo " APK: http://122.51.80.140:5000/static/app-debug-latest.apk" echo " Ping: http://122.51.80.140:5000/api/ping" echo ""