#!/usr/bin/env bash set -euo pipefail # 快速更新脚本:适合已经完成首次部署后的日常代码更新。 # 只做 git 更新、前端 build、重启用户级服务;不检查/安装系统依赖。 # 如果 pyproject.toml 在本次更新中变化,会额外同步一次 Python 依赖。 # 如果本次改动包含依赖、systemd 模板或部署脚本变化,请使用 scripts/deploy-ubuntu.sh。 ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" ENV_FILE="${ROOT_DIR}/.env.deploy" DEPLOY_INSTANCE="${CLAW_DEPLOY_INSTANCE:-zk-data-agent}" BACKEND_SERVICE="${CLAW_BACKEND_SERVICE:-${DEPLOY_INSTANCE}-backend}" FRONTEND_SERVICE="${CLAW_FRONTEND_SERVICE:-${DEPLOY_INSTANCE}-frontend}" BRANCH="${1:-}" log() { printf "\n\033[1;34m==>\033[0m %s\n" "$1" } fail() { printf "\033[1;31mERROR\033[0m %s\n" "$1" >&2 exit 1 } configure_instance_names() { DEPLOY_INSTANCE="${CLAW_DEPLOY_INSTANCE:-${DEPLOY_INSTANCE:-zk-data-agent}}" BACKEND_SERVICE="${CLAW_BACKEND_SERVICE:-${DEPLOY_INSTANCE}-backend}" FRONTEND_SERVICE="${CLAW_FRONTEND_SERVICE:-${DEPLOY_INSTANCE}-frontend}" } resolve_npm_bin() { if [[ -f "${ENV_FILE}" ]]; then # shellcheck disable=SC1090 source "${ENV_FILE}" configure_instance_names fi if [[ -n "${CLAW_NODE_BIN_DIR:-}" ]]; then export PATH="${CLAW_NODE_BIN_DIR}:${PATH}" fi local npm_bin="${CLAW_NPM_BIN:-$(command -v npm || true)}" if [[ -z "${npm_bin}" || ! -x "${npm_bin}" ]]; then fail "缺少命令:npm。请先安装 Node.js 和 npm,或执行 bash scripts/deploy-ubuntu.sh 重新记录 Node.js 路径。" fi local node_bin_dir node_bin_dir="$(dirname "${npm_bin}")" export PATH="${node_bin_dir}:${PATH}" if ! "${npm_bin}" --version >/dev/null 2>&1; then fail "npm 不可用:${npm_bin}。请确认同目录下存在 node,或重新安装 Node.js/npm。" fi printf "%s\n" "${npm_bin}" } sync_python_dependencies_if_needed() { if [[ "${PYTHON_DEPS_CHANGED}" != "1" ]]; then return fi local python_bin="${ROOT_DIR}/.venv/bin/python" if [[ ! -x "${python_bin}" ]]; then fail "缺少项目 Python 虚拟环境:${python_bin}。请执行 bash scripts/deploy-ubuntu.sh。" fi log "检测到 pyproject.toml 变化,同步 Python 依赖" "${python_bin}" -m pip install -e . } cd "${ROOT_DIR}" [[ -d .git ]] || fail "${ROOT_DIR} 不是 git 仓库。" if [[ -f "${ENV_FILE}" ]]; then # shellcheck disable=SC1090 source "${ENV_FILE}" fi configure_instance_names if [[ -z "${BRANCH}" ]]; then BRANCH="$(git branch --show-current)" fi [[ -n "${BRANCH}" ]] || fail "无法判断当前分支,请显式传入分支名。" if [[ -n "$(git status --porcelain)" ]]; then fail "工作区有未提交改动。请先处理后再快速更新。" fi PYTHON_DEPS_CHANGED=0 before_rev="$(git rev-parse HEAD)" log "拉取代码:origin/${BRANCH}" git fetch origin git checkout "${BRANCH}" git pull --ff-only origin "${BRANCH}" after_rev="$(git rev-parse HEAD)" if [[ "${before_rev}" != "${after_rev}" ]] && ! git diff --quiet "${before_rev}" "${after_rev}" -- pyproject.toml; then PYTHON_DEPS_CHANGED=1 fi sync_python_dependencies_if_needed log "构建前端" cd "${ROOT_DIR}/frontend/app" npm_bin="$(resolve_npm_bin)" export PATH="$(dirname "${npm_bin}"):${PATH}" "${npm_bin}" run build log "重启用户服务" systemctl --user restart "${BACKEND_SERVICE}" "${FRONTEND_SERVICE}" log "健康检查" sleep 1 systemctl --user --no-pager --lines=0 status "${BACKEND_SERVICE}" "${FRONTEND_SERVICE}" echo echo "快速更新完成。"