This commit is contained in:
vet
2026-04-13 01:27:34 +07:00
commit c7c3c02bc3
18 changed files with 2730 additions and 0 deletions

225
common.sh Executable file
View File

@@ -0,0 +1,225 @@
#!/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)