工程(ci远端化·阶段二): 闸脚本跨平台化——新增tools/gate_platform.sh单点封装(平台探测/路径形式/纯bash带超时执行/孤儿清杀/进程计数,双平台双栖); run_all_gates cygpath×2换封装+PY解析加存在性守卫(修非Windows误选幽灵venv路径); probe_gate/render_gate/golden_baseline_refresh的cygpath/taskkill/PowerShell/tasklist/裸timeout全部收编封装,Windows侧原逻辑保留走平台分支; run_smoke/run_system_test DEFAULT_GODOT改GODOT_BIN环境变量优先; gdstyle_gate DEFAULT_BIN平台化(macOS=/usr/local/bin/gdstyle,自举件装v0.4.0 darwin包); 依据=第七轮容器实测断点清单+runner迁移Mac host模式裁决

This commit is contained in:
DKChan committed 2026-11-03 03:07:10 +08:00
1 parent 0e7fdfb84c
commit b3928f8167
8 files changed
+134 -28

No files matched your search

+86
View File
@@ -0,0 +1,86 @@
#!/usr/bin/env bash
# 闸件跨平台件——平台探测/路径形式/带超时执行/Godot 孤儿清杀,Git Bash 与 macOS/Linux 双栖。
# 单点定义:run_all_gates.sh / probe_gate.sh / render_gate.sh / golden_baseline_refresh.sh 共用(source 引入)。
# 纪律:闸脚本禁裸调 coreutils timeout 与 Windows 专用件(taskkill/PowerShell/ps -W/tasklist/cygpath)——
# 一律走本件封装;macOS 为 BSD 工具链(无 coreutils timeout,sed/stat 语义不同),裸调必断
# (2026-11-03 远端 CI 迁移裁决:runner=Mac 本机 host 模式,禁再增 Windows 专用直调)。
# 平台判定以 uname 为准(Git Bash=MINGW*,macOS=Darwin,Linux=Linux)。
gate_is_win() {
case "$(uname -s 2>/dev/null)" in
MINGW*|MSYS*|CYGWIN*|Windows_NT) return 0 ;;
*) return 1 ;;
esac
}
# Godot --path 接受的项目路径形式:Windows 需 cygpath -m 混合斜杠,其他平台原样。
gate_game_path() {
if gate_is_win; then cygpath -m "$1"; else printf '%s' "$1"; fi
}
# 杀整棵进程树(<pid>)——递归杀子进程后杀本进程。macOS/Linux 走 pgrep -P;
# Windows 侧 MSYS kill 对其可见进程有效,带 wrapper 树的场景仍由调用方原 taskkill /T 逻辑负责。
gate_kill_tree() {
local p c
kill -9 "$1" 2>/dev/null
for c in $(pgrep -P "$1" 2>/dev/null); do gate_kill_tree "$c"; done
}
# 带超时执行(coreutils timeout 的纯 bash 替代,双平台同语义):
# gate_run_timeout <秒> <日志路径> <命令...>
# 命令输出重定向到日志;退出码=命令退出码,超时=124(与 coreutils 语义一致,判据与既有闸一致)。
# 实现=后台启动+守卫落标志文件(probe_gate run_suite 同款手法:taskkill 强杀后 wait 报 0 的
# 假绿以标志文件纠偏);超时先杀整树再回 124。
gate_run_timeout() {
local t="$1" log="$2"; shift 2
local kf
kf="$(mktemp "${TMPDIR:-/tmp}/gatetime_XXXXXX")"
"$@" >"$log" 2>&1 &
local pid=$!
( sleep "$t" 2>/dev/null
touch "$kf"
gate_kill_tree "$pid"
true ) &
local guard=$!
wait "$pid"; local st=$?
kill "$guard" 2>/dev/null; wait "$guard" 2>/dev/null
if [ -f "$kf" ]; then
gate_kill_tree "$pid"
st=124
fi
rm -f "$kf"
return "$st"
}
# 列命令行含 <game路径> 的 Godot 进程 PID(孤儿清杀与批末残留清点共用)。
# Windows:PowerShell WMI 按进程名+命令行匹配(console wrapper+真引擎都算);
# macOS/Linux:ps 全表按「可执行含 godot+命令行含本 game 路径」过滤(ps 两平台同形)。
gate_orphans() {
local gp="$1"
if gate_is_win; then
local tmpf
tmpf="$(mktemp "${TMPDIR:-/tmp}/gateorph_XXXXXX.ps1")"
local gp_win
gp_win="$(cygpath -m "$gp")"
printf "Get-CimInstance Win32_Process -Filter \"Name like 'Godot%%'\" | Where-Object { \$_.CommandLine -like '*%s*' } | ForEach-Object { \$_.ProcessId }\n" "$gp_win" > "$tmpf"
powershell -NoProfile -ExecutionPolicy Bypass -File "$(cygpath -w "$tmpf")" 2>/dev/null | tr -d '\r'
rm -f "$tmpf"
else
ps -axo pid=,command= 2>/dev/null | awk -v g="$gp" 'tolower($0) ~ /godot/ && index($0, g) {print $1}'
fi
}
gate_kill_orphans() { # gate_kill_orphans <game路径>
local p
for p in $(gate_orphans "$1"); do
if gate_is_win; then taskkill //F //PID "$p" >/dev/null 2>&1
else kill -9 "$p" 2>/dev/null; fi
done
}
# 全局 Godot 进程计数(其他会话的仅报数不算账——批末残留清点的对照面)。
gate_godot_count_all() {
if gate_is_win; then tasklist 2>/dev/null | grep -ci '^Godot' || true
else ps -axo comm= 2>/dev/null | grep -ci 'godot' || true
fi
}