#!/usr/bin/env bash # 一键更新:git pull -> pip install -> 前端构建(可选)-> 重启后端 set -euo pipefail PROJECT_ROOT="$(cd "$(dirname "$0")" && pwd)" BACKEND_DIR="$PROJECT_ROOT/backend" FRONTEND_DIR="$PROJECT_ROOT/frontend" SSL_DIR="$PROJECT_ROOT/ssl" PID_FILE="$BACKEND_DIR/backend.pid" PORT="${PORT:-8775}" HOST="${HOST:-0.0.0.0}" echo "==> [1/4] git pull" cd "$PROJECT_ROOT" git pull --ff-only echo "==> [2/4] 后端依赖" cd "$BACKEND_DIR" if [ ! -d ".venv" ]; then echo " 创建虚拟环境 .venv" python3 -m venv .venv fi # shellcheck disable=SC1091 source .venv/bin/activate pip install --upgrade pip setuptools wheel >/dev/null pip install -e . echo "==> [3/4] 前端构建" if [ -d "$FRONTEND_DIR" ] && command -v npm >/dev/null 2>&1; then cd "$FRONTEND_DIR" npm install --no-audit --no-fund npm run build rm -rf "$BACKEND_DIR/dist" cp -r "$FRONTEND_DIR/dist" "$BACKEND_DIR/dist" echo " frontend/dist -> backend/dist 完成" else echo " 跳过(未装 npm 或无 frontend 目录)" fi echo "==> [4/4] 重启后端" cd "$BACKEND_DIR" # 停旧进程 if [ -f "$PID_FILE" ] && kill -0 "$(cat "$PID_FILE")" 2>/dev/null; then echo " 停旧进程 PID=$(cat "$PID_FILE")" kill "$(cat "$PID_FILE")" || true sleep 1 fi pkill -f 'uvicorn.*app.main:app' 2>/dev/null || true sleep 1 # 校验证书 if [ ! -f "$SSL_DIR/finai.ctc-zc.com.pem" ] || [ ! -f "$SSL_DIR/finai.ctc-zc.com.key" ]; then echo "!! 证书不存在于 $SSL_DIR,退出" >&2 exit 1 fi # 启新进程 nohup .venv/bin/python -m uvicorn app.main:app \ --host "$HOST" --port "$PORT" \ --ssl-certfile "$SSL_DIR/finai.ctc-zc.com.pem" \ --ssl-keyfile "$SSL_DIR/finai.ctc-zc.com.key" \ > "$BACKEND_DIR/backend.out.log" 2> "$BACKEND_DIR/backend.err.log" & echo $! > "$PID_FILE" sleep 2 NEW_PID="$(cat "$PID_FILE")" if kill -0 "$NEW_PID" 2>/dev/null; then echo "OK 启动成功 PID=$NEW_PID https://$HOST:$PORT" else echo "!! 启动失败,查看 $BACKEND_DIR/backend.err.log" >&2 tail -n 20 "$BACKEND_DIR/backend.err.log" >&2 || true exit 1 fi