#!/usr/bin/env bash set -euo pipefail # 一键把源码同步到开发机测试目录:Memind / memind_adm / Plaza # 适用:更新基于源码的开发机器环境。goose 不在本流程内。 HOST="${DEPLOY_HOST:-192.168.1.9}" USER="${DEPLOY_USER:-john}" TARGET="${DEPLOY_USER_HOST:-${USER}@${HOST}}" ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)" EXCLUDE_FILE="${ROOT_DIR}/scripts/.rsync-exclude-test-host" MEMIND_SRC="${MEMIND_SRC:-${ROOT_DIR}}" ADM_SRC="${ADM_SRC:-${ROOT_DIR}/../memind_adm}" PLAZA_SRC="${PLAZA_SRC:-${ROOT_DIR}/../memind_plaza}" MEMIND_DST="${MEMIND_DST:-/Users/john/Project/Memind}" ADM_DST="${ADM_DST:-/Users/john/Project/memind_adm}" PLAZA_DST="${PLAZA_DST:-/Users/john/Project/memind_plaza}" RSYNC_OPTS=( -az --delete --exclude-from="${EXCLUDE_FILE}" ) DRY_RUN=0 CHECK_ONLY=0 ONLY_MEMIND=0 ONLY_ADM=0 ONLY_PLAZA=0 SKIP_MV=0 AUTO_YES=0 usage() { cat <&2 usage exit 1 ;; esac shift done if [[ "${ONLY_MEMIND}" -eq 1 && ("${ONLY_ADM}" -eq 1 || "${ONLY_PLAZA}" -eq 1) ]] || [[ "${ONLY_ADM}" -eq 1 && "${ONLY_PLAZA}" -eq 1 ]]; then echo "错误: --only-* 只能选一个" >&2 exit 1 fi if [[ "${SKIP_MV}" -eq 1 ]]; then RSYNC_OPTS=( -az --exclude-from="${EXCLUDE_FILE}" ) fi if [[ ! -f "${EXCLUDE_FILE}" ]]; then echo "错误: 未找到排除规则文件 ${EXCLUDE_FILE}" >&2 exit 1 fi SSH_OPTS=(-o BatchMode=yes -o ConnectTimeout=12) log() { printf '%s\n' "$*"; } err() { printf '%s\n' "$*" >&2; } fail() { err "✗ $*"; exit 1; } ok() { printf '%s\n' "✓ $*"; } ssh_to_host() { ssh "${SSH_OPTS[@]}" "${TARGET}" "$*" } preflight_local() { local src=$1 [[ -d "$src" ]] || fail "本地源目录不存在: $src" [[ -f "$src/.gitignore" ]] || true ok "本地源目录存在: $src" } preflight_remote() { local dst=$1 local label=$2 ssh_to_host "mkdir -p '${dst}'" >/dev/null if ! ssh_to_host "test -w '${dst}'" >/dev/null 2>&1; then fail "远端目标不可写: ${label} -> ${TARGET}:${dst}" fi ok "远端目录可写: ${label} -> ${dst}" } ensure_host() { log "检查 SSH: ${TARGET}" ssh_to_host "echo connected" >/dev/null || fail "SSH 连接失败:${TARGET}" ok "SSH 连接成功: ${TARGET}" } need_confirm() { local target=$1 [[ "${AUTO_YES}" -eq 1 ]] && return 0 read -r -p "确认同步 ${target}?[y/N] " input [[ "$input" == "y" || "$input" == "Y" ]] } do_sync() { local label=$1 local src=$2 local dst=$3 local flags=("${RSYNC_OPTS[@]}") preflight_local "$src" preflight_remote "$dst" "$label" if [[ "${DRY_RUN}" -eq 1 ]]; then flags+=(--dry-run --itemize-changes) log "[预览] ${label}: ${src} -> ${TARGET}:${dst}" rsync "${flags[@]}" "${src}/" "${TARGET}:${dst}/" | head -80 return 0 fi if ! need_confirm "$label"; then fail "用户取消:${label}" fi log "同步中 ${label}: ${src} -> ${TARGET}:${dst}" rsync "${flags[@]}" "${src}/" "${TARGET}:${dst}/" ok "同步完成 ${label}" } health_check() { local label=$1 local url=$2 if [[ -z "${url}" ]]; then return 0 fi if ssh_to_host "command -v curl >/dev/null && curl -fsS '${url}' >/dev/null" >/dev/null 2>&1; then ok "${label} 健康检查通过:${url}" else log "⚠ ${label} 健康检查失败:${url}(仅提示)" fi } export MEMIND_STATUS_URL="${MEMIND_STATUS_URL:-http://127.0.0.1:18081/api/status}" export ADMIN_STATUS_URL="${ADMIN_STATUS_URL:-http://127.0.0.1:18082/healthz}" export PLAZA_URL="${PLAZA_URL:-http://127.0.0.1:13001/plaza}" ensure_host if [[ "${CHECK_ONLY}" -eq 1 ]]; then preflight_remote "${MEMIND_DST}" "Memind" preflight_remote "${ADM_DST}" "memind_adm" preflight_remote "${PLAZA_DST}" "Plaza" ok "检查通过:远端目录可用" health_check "Memind" "${MEMIND_STATUS_URL}" health_check "memind_adm" "${ADMIN_STATUS_URL}" health_check "Plaza" "${PLAZA_URL}" exit 0 fi TARGETS=() if [[ "${ONLY_MEMIND}" -eq 1 ]]; then TARGETS+=("memind") elif [[ "${ONLY_ADM}" -eq 1 ]]; then TARGETS+=("adm") elif [[ "${ONLY_PLAZA}" -eq 1 ]]; then TARGETS+=("plaza") else TARGETS+=("memind" "adm" "plaza") fi for t in "${TARGETS[@]}"; do case "$t" in memind) do_sync "Memind" "${MEMIND_SRC}" "${MEMIND_DST}" ;; adm) do_sync "memind_adm" "${ADM_SRC}" "${ADM_DST}" ;; plaza) do_sync "Plaza" "${PLAZA_SRC}" "${PLAZA_DST}" ;; esac done log "同步完成。建议检查:" log " Memind: ${MEMIND_STATUS_URL}" log " memind_adm: ${ADMIN_STATUS_URL}" log " Plaza: ${PLAZA_URL}" echo "\n可在远端执行 restart(不包含 goose)" echo " ssh ${TARGET}" echo " cd ${MEMIND_DST} && pnpm install && pnpm dev:server 或 pm2 reload memind" echo " cd ${ADM_DST} && pnpm install && pnpm start:??" echo " cd ${PLAZA_DST} && pnpm install && pnpm dev:plaza" echo "" echo "如果需要,我也可以把 restart 命令固定成你们当前启动脚架构(例如 launchctl/systemd/pm2/nodemon)。"