Files
deploy-test/common.sh
2026-04-13 01:27:34 +07:00

226 lines
10 KiB
Bash
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env bash
# =============================================================================
# common.sh — 公共函数库,供各子脚本 source 引入
# 不可直接执行
# =============================================================================
# 防止重复加载
[[ -n "${_COMMON_LOADED:-}" ]] && return 0
_COMMON_LOADED=1
# ── 根目录workspace46/)──────────────────────────────────────────────────────
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
# ── 运行时目录(测试服务器环境) ───────────────────────────────────────────────
LOG_DIR="$ROOT_DIR/.deploy-test/logs" # 后端服务日志
PID_DIR="$ROOT_DIR/.deploy-test/pids" # PID 文件(含日志收集进程)
BUILD_DIR="$ROOT_DIR/.deploy-test/bin" # 编译产物
DATA_DIR="$ROOT_DIR/.deploy-test/docker-data" # Docker 数据卷
DOCKER_LOG_DIR="$ROOT_DIR/.deploy-test/docker-logs" # Docker 容器日志
SCRIPT_LOG_DIR="$ROOT_DIR/.deploy-test/script-logs" # 脚本执行日志
ENV_FILE="$ROOT_DIR/.env.deploy-test"
# ── 颜色 ───────────────────────────────────────────────────────────────────────
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'
BLUE='\033[0;34m'; CYAN='\033[0;36m'; BOLD='\033[1m'; NC='\033[0m'
info() { echo -e "${CYAN}[INFO]${NC} $*"; }
success() { echo -e "${GREEN}[OK]${NC} $*"; }
warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
error() { echo -e "${RED}[ERROR]${NC} $*" >&2; }
step() { echo -e "\n${BOLD}${BLUE}$*${NC}"; }
header() {
echo ""
echo -e "${BOLD}${BLUE}══════════════════════════════════════════${NC}"
echo -e "${BOLD}${BLUE} $*${NC}"
echo -e "${BOLD}${BLUE}══════════════════════════════════════════${NC}"
}
# ── 初始化运行时目录 ────────────────────────────────────────────────────────────
init_dirs() {
mkdir -p "$LOG_DIR" "$PID_DIR" "$BUILD_DIR" "$DATA_DIR" \
"$DOCKER_LOG_DIR" "$SCRIPT_LOG_DIR"
}
# ──────────────────────────────────────────────────────────────────────────────
# 脚本执行日志
# 调用位置:每个脚本 init_dirs 之后
# 效果所有输出stdout+stderr同时写入 .local-dev/script-logs/<name>-<ts>.log
# ──────────────────────────────────────────────────────────────────────────────
init_script_log() {
local script_name
script_name="$(basename "${BASH_SOURCE[1]:-$0}" .sh)"
local ts; ts="$(date +%Y%m%d-%H%M%S)"
export _CURRENT_SCRIPT_LOG="$SCRIPT_LOG_DIR/${script_name}-${ts}.log"
mkdir -p "$SCRIPT_LOG_DIR"
# 写入文件头(纯文本,不含颜色码)
{
echo "========================================"
echo "Script : $script_name"
echo "Started: $(date '+%Y-%m-%d %H:%M:%S')"
echo "========================================"
} > "$_CURRENT_SCRIPT_LOG"
# exec将所有后续输出同时流向终端和日志文件
# 用 sed 去除 ANSI 颜色码,保证日志文件可读
exec > >(tee >(sed $'s/\033\\[[0-9;]*m//g' >> "$_CURRENT_SCRIPT_LOG")) 2>&1
info "脚本日志 → $_CURRENT_SCRIPT_LOG"
}
# ──────────────────────────────────────────────────────────────────────────────
# Docker 容器日志收集
# ──────────────────────────────────────────────────────────────────────────────
# 启动后台日志收集进程docker logs -f → 本地文件(按日期滚动)
start_docker_logger() {
local cname="$1"
local svc="${cname#dev-}" # dev-redis → redis
local log_dir="$DOCKER_LOG_DIR/$svc"
local logfile="$log_dir/${svc}-$(date +%Y%m%d).log"
local pid_file="$PID_DIR/docker-log-${cname}.pid"
mkdir -p "$log_dir"
# 停止已有的收集进程
if [[ -f "$pid_file" ]] && kill -0 "$(cat "$pid_file")" 2>/dev/null; then
kill "$(cat "$pid_file")" 2>/dev/null || true
sleep 0.3
fi
# 写分隔符,区分每次启动会话
{
echo ""
echo "──── 容器启动 $(date '+%Y-%m-%d %H:%M:%S') ────"
} >> "$logfile"
# 后台跟踪容器日志docker logs 本身已含历史,--tail 0 只取新增)
# 首次启动时先 dump 当前快照,再 follow 新增
docker logs "$cname" >> "$logfile" 2>&1 || true
docker logs -f --tail 0 "$cname" >> "$logfile" 2>&1 &
echo $! > "$pid_file"
info " 容器日志 → $logfile"
}
# 停止容器日志收集进程
stop_docker_logger() {
local cname="$1"
local pid_file="$PID_DIR/docker-log-${cname}.pid"
if [[ -f "$pid_file" ]]; then
local pid; pid=$(cat "$pid_file")
kill "$pid" 2>/dev/null || true
rm -f "$pid_file"
fi
}
# ── 加载 .env.local ─────────────────────────────────────────────────────────────
load_env() {
if [[ ! -f "$ENV_FILE" ]]; then
error ".env.local 不存在,请先执行: ./deploy-test/01-init-env.sh"
exit 1
fi
set -a
# shellcheck source=/dev/null
source "$ENV_FILE"
set +a
}
# ── 检查必要工具 ────────────────────────────────────────────────────────────────
require_tools() {
local missing=()
for tool in "$@"; do
command -v "$tool" &>/dev/null || missing+=("$tool")
done
if [[ ${#missing[@]} -gt 0 ]]; then
error "缺少必要工具: ${missing[*]}"
for t in "${missing[@]}"; do
case "$t" in
go) echo " → 安装 Go: https://go.dev/dl/" ;;
docker) echo " → 安装 Docker Desktop: https://www.docker.com/products/docker-desktop/" ;;
esac
done
exit 1
fi
}
# ── Docker daemon 检查 ──────────────────────────────────────────────────────────
require_docker_running() {
require_tools docker
if ! docker info &>/dev/null; then
error "Docker daemon 未运行,请启动 Docker Desktop"
exit 1
fi
}
# ── 启动单个后端服务nohup 后台) ───────────────────────────────────────────────
start_svc() {
local name="$1" bin="$2" args="${3:-}" workdir="${4:-$ROOT_DIR}"
local pidfile="$PID_DIR/$name.pid" logfile="$LOG_DIR/$name.log"
if [[ -f "$pidfile" ]] && kill -0 "$(cat "$pidfile")" 2>/dev/null; then
warn "$name 已在运行 (PID=$(cat "$pidfile")),跳过"
return 0
fi
[[ ! -f "$bin" ]] && { error "$name 二进制不存在 ($bin),请先执行 04-build.sh"; return 1; }
info "启动 $name ..."
(
cd "$workdir"
# shellcheck disable=SC2086
nohup "$bin" $args > "$logfile" 2>&1 &
echo $! > "$pidfile"
)
sleep 1
if kill -0 "$(cat "$pidfile")" 2>/dev/null; then
success " $name 已启动 (PID=$(cat "$pidfile")) → $logfile"
else
error " $name 启动失败,查看日志:"
tail -20 "$logfile" 2>/dev/null || true
return 1
fi
}
# ── 停止单个后端服务 ────────────────────────────────────────────────────────────
stop_svc() {
local name="$1" pidfile="$PID_DIR/$name.pid"
if [[ -f "$pidfile" ]]; then
local pid; pid=$(cat "$pidfile")
if kill -0 "$pid" 2>/dev/null; then
kill "$pid" && success "$name 已停止 (PID=$pid)"
else
warn "$name 进程 $pid 不存在(可能已退出)"
fi
rm -f "$pidfile"
else
warn "$name 没有 PID 记录(未运行)"
fi
}
# ── Docker 容器状态打印 ─────────────────────────────────────────────────────────
print_container_status() {
local label="$1" cname="$2" port="$3"
if docker ps --format '{{.Names}}' 2>/dev/null | grep -q "^${cname}$"; then
printf " ${GREEN}${NC} %-12s container=%-14s :%-5s\n" "$label" "$cname" "$port"
elif docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "^${cname}$"; then
printf " ${YELLOW}${NC} %-12s stopped=%-14s :%-5s\n" "$label" "$cname" "$port"
else
printf " ${RED}${NC} %-12s (未创建) :%-5s\n" "$label" "$port"
fi
}
# ── 后端服务状态打印 ────────────────────────────────────────────────────────────
print_svc_status() {
local name="$1" desc="$2" pidfile="$PID_DIR/$name.pid"
if [[ -f "$pidfile" ]] && kill -0 "$(cat "$pidfile")" 2>/dev/null; then
printf " ${GREEN}${NC} %-18s PID=%-7s %s\n" "$name" "$(cat "$pidfile")" "$desc"
else
printf " ${RED}${NC} %-18s %-11s %s\n" "$name" "未运行" "$desc"
fi
}
# ── 所有后端服务名列表 ──────────────────────────────────────────────────────────
ALL_SVCS=(openim-server chat-rpc admin-rpc chat-api admin-api meetingmsg livecloud livestream build-server)