From 3b41a870ff849fdac2dac5399a10b53400a73b30 Mon Sep 17 00:00:00 2001 From: Cooper <90701697+CooperWang0912@users.noreply.github.com> Date: Thu, 2 Jul 2026 10:33:47 +0800 Subject: [PATCH] fix: updated reboot logic (#9073) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update updator.py * test: cover Windows reboot process spawning --------- Co-authored-by: 邹永赫 <1259085392@qq.com> --- astrbot/core/updator.py | 6 ++++ tests/test_updator_socks.py | 55 +++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/astrbot/core/updator.py b/astrbot/core/updator.py index 58d14bd0e..9317b0387 100644 --- a/astrbot/core/updator.py +++ b/astrbot/core/updator.py @@ -1,4 +1,5 @@ import os +import subprocess import sys import time import zipfile @@ -139,6 +140,11 @@ class AstrBotUpdator(RepoZipUpdator): quoted_args = [f'"{arg}"' if " " in arg else arg for arg in argv[1:]] os.execl(executable, quoted_executable, *quoted_args) return + elif os.name == "nt": + subprocess.Popen( + [executable] + argv[1:], creationflags=subprocess.CREATE_NEW_CONSOLE + ) + os._exit(0) os.execv(executable, argv) def _reboot(self, delay: int = 3) -> None: diff --git a/tests/test_updator_socks.py b/tests/test_updator_socks.py index 4cb30430a..03880096f 100644 --- a/tests/test_updator_socks.py +++ b/tests/test_updator_socks.py @@ -10,6 +10,7 @@ import certifi import httpx import pytest +from astrbot.core import updator as core_updator from astrbot.core.star.updator import PluginUpdator from astrbot.core.updator import AstrBotUpdator from astrbot.core.utils import io as io_utils @@ -80,6 +81,60 @@ class _FakeStatusErrorResponse: ) +def test_astrbot_updator_exec_reboot_spawns_new_console_on_windows( + monkeypatch: pytest.MonkeyPatch, +): + popen_calls = [] + exit_codes = [] + execv_calls = [] + + def fake_popen(args, creationflags=0): + popen_calls.append((args, creationflags)) + return SimpleNamespace(pid=1234) + + def fake_exit(code): + exit_codes.append(code) + raise SystemExit(code) + + def fake_execv(*args): + execv_calls.append(args) + + monkeypatch.setattr(core_updator.os, "name", "nt") + monkeypatch.setattr(core_updator.sys, "frozen", False, raising=False) + monkeypatch.setattr( + core_updator.subprocess, "CREATE_NEW_CONSOLE", 0x00000010, raising=False + ) + monkeypatch.setattr(core_updator.subprocess, "Popen", fake_popen) + monkeypatch.setattr(core_updator.os, "_exit", fake_exit) + monkeypatch.setattr(core_updator.os, "execv", fake_execv) + + with pytest.raises(SystemExit) as exc_info: + AstrBotUpdator._exec_reboot( + r"C:\Python312\python.exe", + [ + r"C:\Python312\python.exe", + "main.py", + "--webui-dir", + r"C:\AstrBot WebUI\dist", + ], + ) + + assert exc_info.value.code == 0 + assert popen_calls == [ + ( + [ + r"C:\Python312\python.exe", + "main.py", + "--webui-dir", + r"C:\AstrBot WebUI\dist", + ], + core_updator.subprocess.CREATE_NEW_CONSOLE, + ) + ] + assert exit_codes == [0] + assert execv_calls == [] + + @dataclass class _FakeAsyncClientState: json_payload: object = field(default_factory=list)