#!/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 } # 杀整棵进程树()——递归杀子进程后杀本进程。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" } # 列命令行含 的 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 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 }