From 03d53b1fc496ce7359334a01a738f264fbbf16b1 Mon Sep 17 00:00:00 2001 From: DKChan <524912269@qq.com> Date: Tue, 3 Nov 2026 08:22:55 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D(CI=E8=BF=BD=E7=BB=BF=C2=B7fi?= =?UTF-8?q?x-ci-obs=E7=BB=AD):=20run=5Fall=E5=A5=97=E4=BB=B6=E6=89=A7?= =?UTF-8?q?=E8=A1=8C=E5=99=A8=E5=B9=B3=E5=8F=B0=E5=88=86=E6=B4=BE=E2=80=94?= =?UTF-8?q?=E2=80=94Windows=20cmd.exe=E5=BD=A2=E6=80=81=E9=80=90=E4=BD=8D?= =?UTF-8?q?=E4=BF=9D=E7=95=99(/V:ON=E5=BB=B6=E8=BF=9F=E5=B1=95=E5=BC=80+ER?= =?UTF-8?q?RORLEVEL=E8=90=BD=E7=9B=98+taskkill=E6=A0=91=E6=9D=80),POSIX?= =?UTF-8?q?=E6=96=B0=E6=94=AF(/bin/sh=20-c=E5=90=8C=E6=AD=A5=E4=B8=B2?= =?UTF-8?q?=E8=A1=8C:=E5=BC=95=E6=93=8E=E9=80=80=E5=87=BA=E5=86=8D?= =?UTF-8?q?=E8=90=BD$=3F,create=5Fprocess=E6=8B=BFsh=20pid=E4=BE=9B?= =?UTF-8?q?=E5=AD=98=E6=B4=BB=E8=BD=AE=E8=AF=A2;=E6=88=AA=E6=AD=A2?= =?UTF-8?q?=E6=9D=80pkill=20-P=E5=AD=90=E8=BF=9B=E7=A8=8B=E5=85=88?= =?UTF-8?q?=E4=BA=8Ekill=E7=88=B6=E9=98=B2=E5=AD=A4=E5=84=BF);=20=E6=A0=B9?= =?UTF-8?q?=E5=9B=A0=3Drun15=E8=BF=9C=E7=AB=AF77=E5=A5=97=E4=BB=B6?= =?UTF-8?q?=E5=85=A8=E6=95=B0=E7=A7=92=E6=AD=BB(24/18/18/17=E5=9B=9B?= =?UTF-8?q?=E5=88=86=E7=89=87)=3Dcmd.exe=E5=9C=A8mac=E4=B8=8D=E5=AD=98?= =?UTF-8?q?=E5=9C=A8create=5Fprocess=E5=A4=B1=E8=B4=A5pid<0=E9=80=90?= =?UTF-8?q?=E5=A5=97=E4=BB=B6=E5=88=A4=E7=BA=A2;=20Windows=E5=9B=9E?= =?UTF-8?q?=E5=BD=92=E5=8D=95=E5=A5=97=E9=AA=8C=E8=AF=81=E7=BB=BF+S9/gdsty?= =?UTF-8?q?le=E7=BB=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- game/tests/run_all.gd | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/game/tests/run_all.gd b/game/tests/run_all.gd index 308c0e0b..4e803b0a 100644 --- a/game/tests/run_all.gd +++ b/game/tests/run_all.gd @@ -279,9 +279,18 @@ func _run_suite(suite: Dictionary, idx: int, filtered: bool = false) -> Dictiona DirAccess.make_dir_recursive_absolute(proj + "/tests/.gates") # /V:ON=延迟展开:!ERRORLEVEL! 到 echo 执行时(套件已退出)才取值; # 延迟展开会吞字面 !,命令串各段(引擎路径/工程路径/套件路径/日志路径)不得含 !。 - var cmd := '"%s" --headless --path "%s" --script "%s" > "%s" 2>&1 & echo !ERRORLEVEL! > "%s"' % [bin, proj, path, log, codefile] + var pid: int = -1 var out := PackedStringArray() - var pid: int = OS.create_process("cmd.exe", PackedStringArray(["/V:ON", "/C", cmd])) + if OS.get_name() == "Windows": + # Windows 形态(原实现逐位保留):/V:ON 延迟展开,!ERRORLEVEL! 到 echo 时(套件已退出)才取值; + # 延迟展开会吞字面 !,命令串各段(引擎路径/工程路径/套件路径/日志路径)不得含 !。 + var cmd := '"%s" --headless --path "%s" --script "%s" > "%s" 2>&1 & echo !ERRORLEVEL! > "%s"' % [bin, proj, path, log, codefile] + pid = OS.create_process("cmd.exe", PackedStringArray(["/V:ON", "/C", cmd])) + else: + # POSIX 形态(mac/Linux runner):/bin/sh -c 同步串行——sh 前台等引擎退出再落 $?, + # 无延迟展开问题;create_process 拿 sh 的 pid(存活轮询=sh 前台等待期),截止杀走 kill 树。 + var sh_cmd := '"%s" --headless --path "%s" --script "%s" > "%s" 2>&1; echo $? > "%s"' % [bin, proj, path, log, codefile] + pid = OS.create_process("/bin/sh", PackedStringArray(["-c", sh_cmd])) if pid < 0: push_error("[run_all] FAIL %s — cmd 子进程启动失败(pid=%d)" % [path, pid]) return {"fail": 1, "timed_out": false} @@ -299,7 +308,12 @@ func _run_suite(suite: Dictionary, idx: int, filtered: bool = false) -> Dictiona var negative := bool(suite.get("negative", false)) if timed_out: var kill_out := PackedStringArray() - OS.execute("taskkill", PackedStringArray(["/F", "/T", "/PID", str(pid)]), kill_out, true) + if OS.get_name() == "Windows": + OS.execute("taskkill", PackedStringArray(["/F", "/T", "/PID", str(pid)]), kill_out, true) + else: + # POSIX:先杀 sh 的直接子进程(引擎),再杀 sh 自身(顺序要紧——先杀父会让子成孤儿续跑) + OS.execute("pkill", PackedStringArray(["-9", "-P", str(pid)]), kill_out, true) + OS.execute("kill", PackedStringArray(["-9", str(pid)]), kill_out, true) # taskkill 落刀到进程对象消失有间隔:等死确认再放行下一套件(10s 宽限), # 确认不了也如实报红留 PID 供手工清杀,不静默放行。 var reap_deadline := Time.get_ticks_msec() + 10000