98 lines
4.1 KiB
Bash
98 lines
4.1 KiB
Bash
#!/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 tmpd tmpf
|
||
tmpd="$(mktemp -d "${TMPDIR:-/tmp}/gateorph_XXXXXX")" # macOS BSD mktemp 禁 X 后带后缀(本分支 Windows 专用,模板统一防复用)
|
||
tmpf="$tmpd/k.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 -rf "$tmpd"
|
||
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
|
||
}
|
||
|
||
# golden 基线平台子目录名——渲染基线按平台各存一份(Windows 显卡字形/抗锯齿与 macOS CoreText
|
||
# 差异使跨平台逐像素比对必失配,2026-11-03 用户裁:按平台各存基线,平台内部照常严格比对)。
|
||
gate_platform_id() {
|
||
case "$(uname -s 2>/dev/null)" in
|
||
MINGW*|MSYS*|CYGWIN*|Windows_NT) echo "windows" ;;
|
||
Darwin) echo "mac" ;;
|
||
*) echo "linux" ;;
|
||
esac
|
||
}
|