#!/usr/bin/env bash # shellcheck disable=SC2034 # 共用:路徑、載入 env、log helper。由其他腳本 source。 set -euo pipefail DEPLOY_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" ROOT_DIR="$(cd "$DEPLOY_DIR/.." && pwd)" BACKEND_DIR="$ROOT_DIR/apps/backend" WEB_DIR="$ROOT_DIR/apps/web" RUN_DIR="$DEPLOY_DIR/run" COMPOSE_FILE="$DEPLOY_DIR/docker-compose.infra.yml" PID_GATEWAY="$RUN_DIR/gateway.pid" PID_WEB="$RUN_DIR/web.pid" LOG_GATEWAY="$RUN_DIR/gateway.log" LOG_WEB="$RUN_DIR/web.log" mkdir -p "$RUN_DIR" log() { printf '[deploy] %s\n' "$*"; } err() { printf '[deploy] ERROR: %s\n' "$*" >&2; } die() { err "$*"; exit 1; } # 優先 .env.dev,其次 .env resolve_env_file() { if [[ -n "${ENV_FILE:-}" && -f "$ENV_FILE" ]]; then echo "$ENV_FILE" return fi if [[ -f "$DEPLOY_DIR/.env.dev" ]]; then echo "$DEPLOY_DIR/.env.dev" return fi if [[ -f "$DEPLOY_DIR/.env" ]]; then echo "$DEPLOY_DIR/.env" return fi return 1 } load_env() { local f if ! f="$(resolve_env_file)"; then die "找不到 env。請先:cp deploy/.env.example deploy/.env.dev 並填密鑰" fi log "env: $f" set -a # shellcheck disable=SC1090 source "$f" set +a # 別名正規化(給 gateway ApplyEnv / migrate) export MONGO_URI="${MONGO_URI:-${HAIXUN_MONGO_URI:-}}" if [[ -z "${MONGO_URL:-}" ]]; then if [[ -n "${MONGO_URI:-}" ]]; then export MONGO_URL="$( MONGO_URI="$MONGO_URI" MONGO_DATABASE="${MONGO_DATABASE:-haixun}" python3 -c " import os, re u = os.environ.get('MONGO_URI', '') db = os.environ.get('MONGO_DATABASE', 'haixun') if re.search(r'/\?', u): print(re.sub(r'/\?', f'/{db}?', u, count=1)) elif re.search(r'/' + re.escape(db) + r'(\?|$)', u): print(u) else: print(u.rstrip('/') + f'/{db}') " )" else local user="${MONGO_ROOT_USER:-haixun}" local pass="${MONGO_ROOT_PASSWORD:-}" local db="${MONGO_DATABASE:-haixun}" export MONGO_URI="mongodb://${user}:${pass}@127.0.0.1:27017/?authSource=admin" export MONGO_URL="mongodb://${user}:${pass}@127.0.0.1:27017/${db}?authSource=admin" fi fi export REDIS_PASSWORD="${REDIS_PASSWORD:-${HAIXUN_REDIS_PASSWORD:-}}" export HAIXUN_REDIS_PASSWORD="${HAIXUN_REDIS_PASSWORD:-$REDIS_PASSWORD}" export AUTH_ACCESS_SECRET="${AUTH_ACCESS_SECRET:-${HAIXUN_JWT_ACCESS_SECRET:-}}" export AUTH_REFRESH_SECRET="${AUTH_REFRESH_SECRET:-${HAIXUN_JWT_REFRESH_SECRET:-}}" export HAIXUN_STORAGE_S3_ACCESS_KEY="${HAIXUN_STORAGE_S3_ACCESS_KEY:-${MINIO_ROOT_USER:-haixun}}" export HAIXUN_STORAGE_S3_SECRET_KEY="${HAIXUN_STORAGE_S3_SECRET_KEY:-${MINIO_ROOT_PASSWORD:-}}" export MINIO_ROOT_USER="${MINIO_ROOT_USER:-haixun}" export MINIO_ROOT_PASSWORD="${MINIO_ROOT_PASSWORD:-$HAIXUN_STORAGE_S3_SECRET_KEY}" export OBJECT_STORAGE_PUBLIC_BASE_URL="${OBJECT_STORAGE_PUBLIC_BASE_URL:-${HAIXUN_STORAGE_S3_PUBLIC_BASE_URL:-}}" export HAIXUN_STORAGE_S3_PUBLIC_BASE_URL="${HAIXUN_STORAGE_S3_PUBLIC_BASE_URL:-$OBJECT_STORAGE_PUBLIC_BASE_URL}" export PUBLIC_WEB_BASE="${PUBLIC_WEB_BASE:-http://127.0.0.1:5173}" export GATEWAY_PORT="${GATEWAY_PORT:-8888}" export WEB_PORT="${WEB_PORT:-5173}" ENV_FILE_RESOLVED="$f" } compose() { local f f="$(resolve_env_file)" || die "no env" docker compose --env-file "$f" -f "$COMPOSE_FILE" "$@" } pid_alive() { local pid="${1:-}" [[ -n "$pid" ]] && kill -0 "$pid" 2>/dev/null } kill_port() { local port="$1" local p p="$(ss -tlnp 2>/dev/null | sed -n "s/.*:${port} .*pid=\([0-9]*\).*/\1/p" | head -1 || true)" if [[ -n "$p" ]]; then log "kill port :$port pid=$p" kill "$p" 2>/dev/null || true sleep 0.4 kill -9 "$p" 2>/dev/null || true fi } require_cmd() { command -v "$1" >/dev/null 2>&1 || die "需要指令:$1" }