2026-03-01 16:26:03 +00:00
|
|
|
|
#!/usr/bin/env bash
|
|
|
|
|
|
set -euo pipefail
|
|
|
|
|
|
|
|
|
|
|
|
ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
|
|
|
|
|
|
ENV_FILE="${1:-$ROOT_DIR/.env.prod}"
|
2026-04-13 08:36:58 +00:00
|
|
|
|
DATA_DIR="$ROOT_DIR/data"
|
2026-04-13 10:10:25 +00:00
|
|
|
|
COMPOSE_FILE="$ROOT_DIR/docker-compose.prod.yml"
|
|
|
|
|
|
AGENT_TEMPLATES_FILE="$DATA_DIR/templates/agent_md_templates.json"
|
|
|
|
|
|
TOPIC_PRESETS_FILE="$DATA_DIR/templates/topic_presets.json"
|
|
|
|
|
|
SKILLS_DIR="$DATA_DIR/skills"
|
|
|
|
|
|
|
|
|
|
|
|
require_file() {
|
|
|
|
|
|
local path="$1"
|
|
|
|
|
|
local hint="$2"
|
|
|
|
|
|
if [[ -f "$path" ]]; then
|
|
|
|
|
|
return 0
|
|
|
|
|
|
fi
|
|
|
|
|
|
echo "Missing file: $path"
|
|
|
|
|
|
if [[ -n "$hint" ]]; then
|
|
|
|
|
|
echo "$hint"
|
|
|
|
|
|
fi
|
|
|
|
|
|
exit 1
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
require_dir() {
|
|
|
|
|
|
local path="$1"
|
|
|
|
|
|
local hint="$2"
|
|
|
|
|
|
if [[ -d "$path" ]]; then
|
|
|
|
|
|
return 0
|
|
|
|
|
|
fi
|
|
|
|
|
|
echo "Missing directory: $path"
|
|
|
|
|
|
if [[ -n "$hint" ]]; then
|
|
|
|
|
|
echo "$hint"
|
|
|
|
|
|
fi
|
|
|
|
|
|
exit 1
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
require_env() {
|
|
|
|
|
|
local name="$1"
|
|
|
|
|
|
if [[ -n "${!name:-}" ]]; then
|
|
|
|
|
|
return 0
|
|
|
|
|
|
fi
|
|
|
|
|
|
echo "Missing required env: $name"
|
|
|
|
|
|
exit 1
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
read_env_value() {
|
|
|
|
|
|
local key="$1"
|
|
|
|
|
|
local line=""
|
|
|
|
|
|
local value=""
|
|
|
|
|
|
|
|
|
|
|
|
while IFS= read -r line || [[ -n "$line" ]]; do
|
|
|
|
|
|
line="${line%$'\r'}"
|
|
|
|
|
|
[[ -z "${line//[[:space:]]/}" ]] && continue
|
|
|
|
|
|
[[ "${line#\#}" != "$line" ]] && continue
|
|
|
|
|
|
[[ "${line#export }" != "$line" ]] && line="${line#export }"
|
|
|
|
|
|
[[ "$line" == "$key="* ]] || continue
|
|
|
|
|
|
value="${line#*=}"
|
|
|
|
|
|
if [[ "$value" =~ ^\"(.*)\"$ ]]; then
|
|
|
|
|
|
value="${BASH_REMATCH[1]}"
|
|
|
|
|
|
elif [[ "$value" =~ ^\'(.*)\'$ ]]; then
|
|
|
|
|
|
value="${BASH_REMATCH[1]}"
|
|
|
|
|
|
fi
|
|
|
|
|
|
printf '%s' "$value"
|
|
|
|
|
|
return 0
|
|
|
|
|
|
done < "$ENV_FILE"
|
|
|
|
|
|
|
|
|
|
|
|
return 1
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
load_env_var() {
|
|
|
|
|
|
local name="$1"
|
|
|
|
|
|
local default_value="${2:-}"
|
|
|
|
|
|
local value=""
|
|
|
|
|
|
|
|
|
|
|
|
value="$(read_env_value "$name" || true)"
|
|
|
|
|
|
if [[ -z "$value" ]]; then
|
|
|
|
|
|
value="$default_value"
|
|
|
|
|
|
fi
|
|
|
|
|
|
printf -v "$name" '%s' "$value"
|
|
|
|
|
|
}
|
2026-03-01 16:26:03 +00:00
|
|
|
|
|
|
|
|
|
|
if [[ ! -f "$ENV_FILE" ]]; then
|
2026-04-13 11:35:41 +00:00
|
|
|
|
echo "[WARNING] Missing env file: $ENV_FILE"
|
|
|
|
|
|
echo "[WARNING] Creating it from: $ROOT_DIR/.env.prod.example ..."
|
|
|
|
|
|
cp "$ROOT_DIR/.env.prod.example" "$ENV_FILE"
|
|
|
|
|
|
echo "[WARNING] 请编辑 $ENV_FILE 文件,配置正确的数据库、Redis、端口等参数"
|
|
|
|
|
|
echo "[WARNING] 按任意键继续,或 Ctrl+C 退出..."
|
|
|
|
|
|
read -n 1 -s
|
2026-03-01 16:26:03 +00:00
|
|
|
|
fi
|
|
|
|
|
|
|
2026-04-13 10:10:25 +00:00
|
|
|
|
require_file "$COMPOSE_FILE" ""
|
|
|
|
|
|
require_file "$AGENT_TEMPLATES_FILE" "Expected tracked template file under project-root data/templates/"
|
|
|
|
|
|
require_file "$TOPIC_PRESETS_FILE" "Expected tracked template file under project-root data/templates/"
|
|
|
|
|
|
require_dir "$SKILLS_DIR" "Expected tracked skills directory under project-root data/skills/"
|
|
|
|
|
|
|
|
|
|
|
|
load_env_var HOST_BOTS_WORKSPACE_ROOT
|
|
|
|
|
|
load_env_var DATABASE_URL
|
|
|
|
|
|
load_env_var NGINX_PORT 8080
|
|
|
|
|
|
load_env_var REDIS_ENABLED false
|
|
|
|
|
|
load_env_var REDIS_URL
|
|
|
|
|
|
|
|
|
|
|
|
require_env HOST_BOTS_WORKSPACE_ROOT
|
|
|
|
|
|
require_env DATABASE_URL
|
|
|
|
|
|
require_env NGINX_PORT
|
|
|
|
|
|
|
|
|
|
|
|
if [[ "$DATABASE_URL" != postgresql* ]]; then
|
|
|
|
|
|
echo "Unsupported DATABASE_URL for deploy-prod.sh: $DATABASE_URL"
|
|
|
|
|
|
echo "deploy-prod.sh now supports external PostgreSQL only."
|
|
|
|
|
|
echo "If you need one-click PostgreSQL + Redis deployment, use scripts/deploy-full.sh."
|
|
|
|
|
|
exit 1
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
if [[ "${REDIS_ENABLED,,}" =~ ^(1|true|yes|on)$ ]] && [[ -z "$REDIS_URL" ]]; then
|
|
|
|
|
|
echo "Missing required env: REDIS_URL"
|
|
|
|
|
|
exit 1
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
2026-03-01 16:26:03 +00:00
|
|
|
|
echo "[deploy] using env: $ENV_FILE"
|
2026-04-13 10:10:25 +00:00
|
|
|
|
mkdir -p "$DATA_DIR" "$DATA_DIR/model" "$HOST_BOTS_WORKSPACE_ROOT"
|
|
|
|
|
|
|
|
|
|
|
|
echo "[deploy] expecting external PostgreSQL to be pre-initialized with scripts/sql/create-tables.sql and scripts/sql/init-data.sql"
|
|
|
|
|
|
docker compose --env-file "$ENV_FILE" -f "$COMPOSE_FILE" config -q
|
|
|
|
|
|
docker compose --env-file "$ENV_FILE" -f "$COMPOSE_FILE" up -d --build
|
2026-03-01 16:26:03 +00:00
|
|
|
|
|
|
|
|
|
|
echo "[deploy] service status"
|
2026-04-13 10:10:25 +00:00
|
|
|
|
docker compose --env-file "$ENV_FILE" -f "$COMPOSE_FILE" ps
|
2026-03-01 16:26:03 +00:00
|
|
|
|
|
|
|
|
|
|
echo "[deploy] done"
|