#!/usr/bin/env bash # 本地编译 goosed(linux/amd64)并上传到 105,不在生产机 cargo build。 # # Mac / 非 x86_64 Linux:Docker --platform linux/amd64 # x86_64 Linux:本机 cargo,产物写入 deploy/.target-linux-amd64/ # # 用法: # ./deploy/deploy-goosed-105.sh # ./deploy/deploy-goosed-105.sh --skip-build # 只上传已有二进制 # ./deploy/deploy-goosed-105.sh --skip-source # 不上传 crates 源码 # ./deploy/deploy-goosed-105.sh --no-restart # ./rsync_to_server.sh goosed # ./rsync_to_server.sh all set -euo pipefail ROOT="$(cd "$(dirname "$0")/.." && pwd)" DEPLOY_ENV="${ROOT}/deploy/h5-105.env" BUILDER_DOCKERFILE="${ROOT}/deploy/Dockerfile.goosed-build" BUILDER_IMAGE="${GOOSED_BUILDER_IMAGE:-goose-goosed-builder:1.92-al8}" CARGO_HOME="${ROOT}/deploy/.cargo-linux-amd64" CARGO_HOME_CONTAINER="/cache/cargo" TARGET_DIR="${ROOT}/deploy/.target-linux-amd64" LOCAL_BIN="${TARGET_DIR}/release/goosed" H5_DEPLOY_HOST="${H5_DEPLOY_HOST:-root@120.26.184.105}" GOOSED_REMOTE_DIR="${GOOSED_REMOTE_DIR:-/root/tkmind_go}" GOOSED_REMOTE_BIN="${GOOSED_REMOTE_BIN:-${GOOSED_REMOTE_DIR}/target/release/goosed}" GOOSED_SYSTEMD_SERVICE="${GOOSED_SYSTEMD_SERVICE:-goosed-tkmind-go}" SKIP_BUILD=0 SKIP_SOURCE=0 NO_RESTART=0 for arg in "$@"; do case "$arg" in --skip-build) SKIP_BUILD=1 ;; --skip-source) SKIP_SOURCE=1 ;; --no-restart) NO_RESTART=1 ;; -h|--help) sed -n '2,13p' "$0" exit 0 ;; *) echo "未知参数: $arg(可用 --skip-build / --skip-source / --no-restart)" >&2 exit 1 ;; esac done if [[ -f "${DEPLOY_ENV}" ]]; then set -a # shellcheck disable=SC1090 source "${DEPLOY_ENV}" set +a fi ssh_cmd() { ssh -o ConnectTimeout=15 -o BatchMode=yes "${H5_DEPLOY_HOST}" "$@" } use_docker_build() { [[ "$(uname -s)" != "Linux" || "$(uname -m)" != "x86_64" ]] } ensure_builder_image() { if docker image inspect "${BUILDER_IMAGE}" >/dev/null 2>&1; then return fi echo "==> 构建 Docker 编译镜像 ${BUILDER_IMAGE}(AlmaLinux 8,兼容 105 glibc 2.32)..." docker build --platform linux/amd64 -f "${BUILDER_DOCKERFILE}" -t "${BUILDER_IMAGE}" "${ROOT}/deploy" } build_with_docker() { ensure_builder_image mkdir -p "${CARGO_HOME}" "${TARGET_DIR}" echo "==> Docker 编译 goosed (linux/amd64) ..." docker run --rm \ --platform linux/amd64 \ -v "${ROOT}:/build:ro" \ -v "${CARGO_HOME}:${CARGO_HOME_CONTAINER}" \ -v "${TARGET_DIR}:/build/target" \ -e CARGO_HOME="${CARGO_HOME_CONTAINER}" \ -e CARGO_REGISTRIES_CRATES_IO_PROTOCOL=sparse \ -w /build \ "${BUILDER_IMAGE}" \ cargo build --release -p goose-server --bin goosed } build_native() { mkdir -p "${TARGET_DIR}" echo "==> 本机编译 goosed (linux/amd64) ..." ( cd "${ROOT}" CARGO_TARGET_DIR="${TARGET_DIR}" \ cargo build --release -p goose-server --bin goosed ) } build_goosed() { if use_docker_build; then if ! command -v docker >/dev/null 2>&1; then echo "错误: 需要 Docker 才能在 $(uname -s)/$(uname -m) 上编译 linux/amd64 goosed" >&2 exit 1 fi build_with_docker else if ! command -v cargo >/dev/null 2>&1; then echo "错误: 未找到 cargo" >&2 exit 1 fi build_native fi } sync_source() { echo "==> rsync Rust 源码(不含 target/node_modules)..." rsync -az \ --exclude target \ --exclude node_modules \ --exclude ui/h5/MindSpace \ --exclude ui/h5/node_modules \ --exclude ui/h5/dist \ --exclude .git \ --exclude deploy/.cargo-linux-amd64 \ --exclude deploy/.target-linux-amd64 \ "${ROOT}/crates" "${ROOT}/Cargo.toml" "${ROOT}/Cargo.lock" \ "${H5_DEPLOY_HOST}:${GOOSED_REMOTE_DIR}/" } upload_binary() { if [[ ! -x "${LOCAL_BIN}" ]]; then echo "错误: 未找到可执行文件 ${LOCAL_BIN},请先编译或去掉 --skip-build" >&2 exit 1 fi echo "==> 上传 goosed → ${H5_DEPLOY_HOST}:${GOOSED_REMOTE_BIN}" ssh_cmd "mkdir -p '$(dirname "${GOOSED_REMOTE_BIN}")'" rsync -az "${LOCAL_BIN}" "${H5_DEPLOY_HOST}:${GOOSED_REMOTE_BIN}.new" ssh_cmd "install -m 755 '${GOOSED_REMOTE_BIN}.new' '${GOOSED_REMOTE_BIN}' && rm -f '${GOOSED_REMOTE_BIN}.new'" } echo "======================================" echo "goosed → 105 部署(本地编译上传)" echo "时间: $(date '+%Y-%m-%d %H:%M:%S')" echo "本地二进制: ${LOCAL_BIN}" echo "远端: ${H5_DEPLOY_HOST}:${GOOSED_REMOTE_BIN}" echo "编译方式: $(use_docker_build && echo 'docker linux/amd64' || echo 'native cargo')" echo "======================================" if [[ "${SKIP_BUILD}" -eq 0 ]]; then build_goosed else echo "==> 跳过编译 (--skip-build)" fi if [[ "${SKIP_SOURCE}" -eq 0 ]]; then sync_source else echo "==> 跳过源码同步 (--skip-source)" fi upload_binary if [[ "${NO_RESTART}" -eq 0 ]]; then echo "==> 重启 ${GOOSED_SYSTEMD_SERVICE} ..." ssh_cmd "systemctl restart '${GOOSED_SYSTEMD_SERVICE}'" sleep 2 fi echo "" echo "=== 健康检查 ===" ssh_cmd "systemctl is-active '${GOOSED_SYSTEMD_SERVICE}' && echo '${GOOSED_SYSTEMD_SERVICE}: active' || echo '${GOOSED_SYSTEMD_SERVICE}: inactive'" ssh_cmd "curl -sk 'https://127.0.0.1:3000/status' && echo ' ← goosed'" || true ssh_cmd "'${GOOSED_REMOTE_BIN}' --version 2>/dev/null || file '${GOOSED_REMOTE_BIN}'" || true file "${LOCAL_BIN}" 2>/dev/null || true echo "" echo "✅ goosed 已发布"