Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions bin/stop-emrg.cmd
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ REM fallback), excludes the daemon (pythonw.exe -m emrg.server)
REM 3. daemon: `emrg server stop` protocol shutdown via the OLD install's CLI
REM (present since #364 -- version-safe), emrgd.pid poll (<=10s), then
REM taskkill /F /PID fallback
REM 4. bundled git (rant 2026-08-11T17:56:25): kill orphaned git/ssh/bash
REM processes whose executable lives under %INSTALL%\git\ (the portable Git
REM the daemon spawns for evolution-cycle git ops). When the daemon is killed
REM mid-operation these become orphans holding install\git\usr\bin\msys-2.0.dll
REM -> Inno "DeleteFile failed; code 5" on upgrade. Filter is by executable
REM PATH so system Git (C:\Program Files\Git) is never touched.
REM
REM Returns 0 when nothing EMRG-related survives; 1 if a process could not be
REM stopped (installer aborts with a clear message instead of hanging).
Expand Down Expand Up @@ -61,6 +67,13 @@ set "DPID="
for /f "usebackq delims=" %%p in ("%EMRG_DIR%\emrgd.pid") do set "DPID=%%p"
if defined DPID taskkill /F /PID %DPID% >nul 2>&1

REM --- 4. bundled git: orphaned git/ssh/bash under %INSTALL%\git (msys-2.0.dll lock) ---
REM (host 2026-08-11T17:56:25: daemon killed mid-git-op leaves orphans holding
REM install\git\usr\bin\msys-2.0.dll -> Inno DeleteFile code 5. Filter by
REM ExecutablePath prefix so system Git is never touched. `\"` = PowerShell
REM quote escape precedent: TUI branch line 44.)
powershell -NoProfile -Command "Get-CimInstance Win32_Process | Where-Object { $_.ExecutablePath -like \"$env:USERPROFILE\.emrg\install\git\*\" } | ForEach-Object { Stop-Process -Id $_.ProcessId -Force }" >nul 2>&1

:verify
set "EXIT_CODE=0"
tasklist /FI "IMAGENAME eq EMRG.exe" 2>nul | findstr /i "EMRG.exe" >nul && set "EXIT_CODE=1"
Expand All @@ -73,4 +86,8 @@ if exist "%EMRG_DIR%\emrgd.pid" (
tasklist /FI "PID eq !DPID!" 2>nul | findstr /i "!DPID!" >nul && set "EXIT_CODE=1"
)
)
REM bundled-git survival check: any process still under install\git\ -> exit 1
REM (installer aborts with a clear message instead of a repeat "Try again" loop)
powershell -NoProfile -Command "if (Get-CimInstance Win32_Process | Where-Object { $_.ExecutablePath -like \"$env:USERPROFILE\.emrg\install\git\*\" }) { exit 1 }" >nul 2>&1
if errorlevel 1 set "EXIT_CODE=1"
endlocal & exit /b %EXIT_CODE%
10 changes: 6 additions & 4 deletions packaging/make-installer.sh
Original file line number Diff line number Diff line change
Expand Up @@ -372,8 +372,10 @@ end;
// -m emrg.server 常驻锁文件),覆盖 ~/.emrg\install 时卡在"停止已有进程"。
// PrepareToInstall 在安装开始前运行 bin\stop-emrg.cmd:taskkill EMRG.exe
// 优雅→/F 兜底、wmic/PowerShell 命令行过滤 TUI、emrg server stop 协议关闭
// daemon + emrgd.pid 轮询兜底(顺序 GUI→TUI→daemon)。干净安装(无旧 install)
// 脚本自行跳过。返回非空字符串 = 中止安装并显示该消息(宁可中止也不卡死)。
// daemon + emrgd.pid 轮询兜底、按可执行文件路径杀 bundled git 孤儿
// (rant 2026-08-11T17:56:25: daemon 演化周期 git 操作中途被杀 → git/ssh/bash
// 孤儿锁 install\git\usr\bin\msys-2.0.dll → Inno DeleteFile code 5)。干净安装
// (无旧 install)脚本自行跳过。返回非空字符串 = 中止安装并显示该消息(宁可中止也不卡死)。
// {cmd} = cmd.exe(Inno 预定义常量,批处理文件须经 cmd 启动)。
function PrepareToInstall(var NeedsRestart: Boolean): String;
var
Expand All @@ -386,10 +388,10 @@ begin
if Exec(ExpandConstant('{cmd}'), '/c "' + StopScript + '"', '', SW_HIDE, ewWaitUntilTerminated, ResultCode) then
begin
if ResultCode <> 0 then
Result := 'EMRG could not stop all running processes (stop-emrg.cmd exit code ' + IntToStr(ResultCode) + '). Please close EMRG (GUI/TUI) and retry the install.';
Result := 'EMRG could not stop all running processes (stop-emrg.cmd exit code ' + IntToStr(ResultCode) + '). Please close EMRG (GUI/TUI) and retry the install, or restart the computer and retry (a helper process such as the bundled Git may still hold a file lock).';
end
else
Result := 'EMRG could not run the process-stop helper (stop-emrg.cmd). Please close EMRG (GUI/TUI) and retry the install.';
Result := 'EMRG could not run the process-stop helper (stop-emrg.cmd). Please close EMRG (GUI/TUI) and retry the install, or restart the computer and retry.';
end;
EOF
# Windows 路径转义(iscc 需要 Windows 路径,但在 bash/msys 下用当前路径)
Expand Down
18 changes: 18 additions & 0 deletions tests/test_installer_stop.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,18 @@ def test_stop_emrg_cmd_covers_gui_tui_daemon_in_order():
# 顺序:GUI 在 daemon 之前(GUI 不能复活 daemon)
daemon_line = content.index('call "%INSTALL%\\bin\\emrg.cmd" server stop')
assert content.index("taskkill /IM EMRG.exe") < daemon_line
# step 4(rant 2026-08-11T17:56:25):按可执行文件路径杀 bundled git 孤儿
# (daemon 演化周期 git 操作中途被杀 → git/ssh/bash 孤儿锁 msys-2.0.dll → Inno
# DeleteFile code 5)。判别:ExecutablePath 前缀过滤只命中 %INSTALL%\git\,
# 不误杀系统 Git;daemon 停止之后、:verify 之前。
assert 'Get-CimInstance Win32_Process' in content
assert r'$env:USERPROFILE\.emrg\install\git\*' in content
# 锚定实际 kill 命令($_.ExecutablePath 只在 step 4 出现——TUI 分支是
# -Filter Name='python.exe',不共享此模式),勿用 index() 撞到 TUI/REM 注释
git_kill = content.index("$_.ExecutablePath -like")
daemon_line2 = content.index('call "%INSTALL%\\bin\\emrg.cmd" server stop')
verify_idx = content.index(':verify\nset "EXIT_CODE=0"') # 标签定义处(goto :verify 在前,勿用裸 index(":verify"))
assert daemon_line2 < git_kill < verify_idx
# 干净安装安全:无旧 install 目录时跳过
assert 'set "INSTALL=%EMRG_DIR%\\install"' in content
# 括号块内 pid 判定必须用延迟展开(!DPID!)——%DPID% 在块解析时展开,
Expand All @@ -50,6 +62,10 @@ def test_stop_emrg_cmd_covers_gui_tui_daemon_in_order():
assert "PID eq !DPID!" in verify_block
# 非延迟展开 %DPID% 不得出现在括号块内(块解析时展开=恒旧值)
assert "%DPID%" not in verify_block
# :verify 的 bundled-git 存活判定:仍有进程在 install\git\ 下 → exit 1
assert "exit 1" in verify_block
assert r'ExecutablePath -like \"$env:USERPROFILE\.emrg\install\git\*\"' in verify_block
assert "if errorlevel 1 set \"EXIT_CODE=1\"" in verify_block


def test_emrgd_cmd_has_stop_branch():
Expand All @@ -66,6 +82,8 @@ def test_make_installer_iss_has_prepare_to_install():
assert "PrepareToInstall" in content
assert "ExtractTemporaryFile('stop-emrg.cmd')" in content
assert "SW_HIDE" in content # 批处理执行不弹控制台窗口(#592 纪律)
# rant 2026-08-11T17:56:25:中止消息含重启兜底引导(杀不掉时宿主可重启后重试)
assert "restart the computer" in content


def test_build_runtime_copies_stop_emrg_cmd():
Expand Down
Loading