From 584a373576da9a9c59d1a425c28474517474f905 Mon Sep 17 00:00:00 2001 From: EMRG Evolution Date: Thu, 13 Aug 2026 10:54:02 +0800 Subject: [PATCH 1/6] emrg: add iscc compile gate to Windows test job (v0.2.30 .iss failure class) --- .github/workflows/test.yml | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8cc14dbc..fa6c5c75 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -56,3 +56,30 @@ jobs: - run: uv sync - name: Python tests (Windows) run: uv run pytest tests/ -v + - name: Inno Setup script compiles (Windows) + shell: bash + run: | + set -euo pipefail + # v0.2.30 教训:Test 绿 ≠ .iss 可编译 — iscc(Inno Setup 6.7.1)只在 tag 触发的 + # Build Release 里跑;#727 的 stop-log 块首次过 iscc 即 "Invalid number of parameters" + # (emrg.iss:183:47)。每个 PR 都应在 Windows 上编译一次生成的 emrg.iss。 + mkdir -p stage/payload/bin stage/artifacts + touch stage/payload/placeholder.txt stage/payload/bin/stop-emrg.cmd + ROOT_WIN="$(cygpath -m "$PWD")" + export VERSION="0.0.0-test" DIST_WIN="$ROOT_WIN/stage" \ + ROOT_WIN="$ROOT_WIN" STAGE_WIN="$ROOT_WIN/stage" + # 用与 make-installer.sh 相同的未加引号 heredoc 渲染(行 221-415) + { + echo 'cat > emrg-test.iss < render-iss.sh + bash render-iss.sh + if ! iscc emrg-test.iss > iscc.log 2>&1; then + echo "::error::iscc compile failed — generated emrg-test.iss lines 170-200:" + sed -n '170,200p' emrg-test.iss + echo "::error::iscc output:" + cat iscc.log + exit 1 + fi + echo "iscc compile OK" From 36115796506d56198ce84348b197d638993dc325 Mon Sep 17 00:00:00 2001 From: argszero Date: Thu, 13 Aug 2026 10:56:17 +0800 Subject: [PATCH 2/6] emrg: fix .iss LoadStringFromFile 2-param signature (v0.2.30 Build Release windows gate) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit v0.2.30 Build Release 31661378619 failed at the windows 'Make installer' step: iscc rejected the emrg.iss [Code] section with 'Invalid number of parameters' on LoadStringFromFile(LogFile). Root cause: Inno Setup's Pascal Script API declares function LoadStringFromFile(const FileName: String; var S: AnsiString): Boolean; (2-param out-argument form, identical in 6.7.1 through 7.x — verified against issrc Shared.ScriptFunc.pas). #727's R125 log-surfacing code called the non-existent 1-param string-returning form; the Test workflow never compiles the .iss, so the error only surfaced at tag-push Build Release (v0.2.7 lesson recurring). Fix (folded into #731's iscc gate): - make-installer.sh: call LoadStringFromFile(LogFile, LogText) (out-param), keep FileExists guard + 2000-char truncation - tests/test_installer_stop.py: assert the 2-param form (positive) and forbid the 1-param form (negative) --- .github/workflows/test.yml | 43 ++++++++++++++++-------------------- packaging/make-installer.sh | 8 ++++++- tests/test_installer_stop.py | 8 ++++++- 3 files changed, 33 insertions(+), 26 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index fa6c5c75..c87ee71c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -56,30 +56,25 @@ jobs: - run: uv sync - name: Python tests (Windows) run: uv run pytest tests/ -v - - name: Inno Setup script compiles (Windows) + # v0.2.30 教训(Build Release 31661378619):Test 全绿 ≠ .iss 能编译。 + # make-installer.sh 的 emrg.iss 只在 tag 触发 Build Release 时经 iscc 编译, + # #727 误用 LoadStringFromFile 单参数形式(Inno 真实签名是 2 参数 out-param) + # → iscc "Invalid number of parameters" 发版才暴露。此处用 runner 预装的 + # iscc 编译渲染出的 emrg.iss(stub payload),PR CI 即拦截 .iss 语法/签名错误。 + - name: Inno Setup script compile smoke test shell: bash run: | set -euo pipefail - # v0.2.30 教训:Test 绿 ≠ .iss 可编译 — iscc(Inno Setup 6.7.1)只在 tag 触发的 - # Build Release 里跑;#727 的 stop-log 块首次过 iscc 即 "Invalid number of parameters" - # (emrg.iss:183:47)。每个 PR 都应在 Windows 上编译一次生成的 emrg.iss。 - mkdir -p stage/payload/bin stage/artifacts - touch stage/payload/placeholder.txt stage/payload/bin/stop-emrg.cmd - ROOT_WIN="$(cygpath -m "$PWD")" - export VERSION="0.0.0-test" DIST_WIN="$ROOT_WIN/stage" \ - ROOT_WIN="$ROOT_WIN" STAGE_WIN="$ROOT_WIN/stage" - # 用与 make-installer.sh 相同的未加引号 heredoc 渲染(行 221-415) - { - echo 'cat > emrg-test.iss < render-iss.sh - bash render-iss.sh - if ! iscc emrg-test.iss > iscc.log 2>&1; then - echo "::error::iscc compile failed — generated emrg-test.iss lines 170-200:" - sed -n '170,200p' emrg-test.iss - echo "::error::iscc output:" - cat iscc.log - exit 1 - fi - echo "iscc compile OK" + STAGE="$(mktemp -d)" + mkdir -p "$STAGE/payload/bin" "$STAGE/dist/artifacts" + touch "$STAGE/payload/bin/stop-emrg.cmd" + # 渲染 make-installer.sh 的 emrg.iss heredoc(变量展开与真实构建一致) + sed -n '/cat > "\$STAGE\/emrg.iss" < "$STAGE/gen.sh" + VERSION="0.0.0-smoke" \ + DIST_WIN="$(cygpath -m "$STAGE/dist")" \ + STAGE_WIN="$(cygpath -m "$STAGE")" \ + ROOT_WIN="$(cygpath -m "$PWD")" \ + STAGE="$STAGE" \ + bash "$STAGE/gen.sh" + command -v iscc >/dev/null 2>&1 || { echo "::error::iscc not on PATH (runner image regression)"; exit 1; } + iscc "$STAGE/emrg.iss" diff --git a/packaging/make-installer.sh b/packaging/make-installer.sh index f2e73280..340f6519 100755 --- a/packaging/make-installer.sh +++ b/packaging/make-installer.sh @@ -400,8 +400,14 @@ begin if ResultCode <> 0 then begin LogText := ''; + // LoadStringFromFile 的 Inno Pascal Script 签名是 + // `function LoadStringFromFile(const FileName: String; var S: AnsiString): Boolean;` + // (6.7.1 → 7.x 全版本一致,见 issrc Shared.ScriptFunc.pas)——不存在单参数 + // 字符串返回形式!v0.2.30 Build Release 31661378619 因此编译失败 + // (iscc "Invalid number of parameters",Test CI 不编译 .iss 未拦住)。 + // 正确用法:out-param 写入 LogText,返回 Boolean 表示成功。 if FileExists(LogFile) then - LogText := LoadStringFromFile(LogFile); + LoadStringFromFile(LogFile, LogText); if Length(LogText) > 2000 then LogText := Copy(LogText, 1, 2000); if LogText <> '' then diff --git a/tests/test_installer_stop.py b/tests/test_installer_stop.py index cc431ed3..ca8ba040 100644 --- a/tests/test_installer_stop.py +++ b/tests/test_installer_stop.py @@ -146,7 +146,13 @@ def test_make_installer_iss_has_prepare_to_install(): # R125: rant 2026-08-13T09:24:37 — 输出重定向到 {tmp}\stop-emrg.log(2>&1), # 失败时 LoadStringFromFile 读日志展示杀不掉的进程,不再让宿主手动跑诊断 assert '/c ""\' + StopScript + \'" > "\' + LogFile + \'" 2>&1"' in content - assert "LoadStringFromFile(LogFile)" in content + # ⚡ LoadStringFromFile 的 Inno Pascal Script 签名是 2 参数 out-param 形式 + # `(const FileName: String; var S: AnsiString): Boolean`(6.7.1 → 7.x 一致, + # issrc Shared.ScriptFunc.pas)——单参数字符串返回形式不存在,iscc 编译报 + # "Invalid number of parameters"(v0.2.30 Build Release 31661378619 实际失败, + # Test CI 不编译 .iss 未拦住)。正反两态钉死正确调用形态。 + assert "LoadStringFromFile(LogFile, LogText)" in content # 正:out-param 形式 + assert ":= LoadStringFromFile(LogFile)" not in content # 反:1 参数形式不存在 assert "Length(LogText) > 2000" in content assert "Details from stop-emrg.cmd:" in content assert "SW_HIDE" in content # 批处理执行不弹控制台窗口(#592 纪律) From a47df08722106081b6392ec56c4ea882b3c54612 Mon Sep 17 00:00:00 2001 From: argszero Date: Thu, 13 Aug 2026 11:02:26 +0800 Subject: [PATCH 3/6] emrg: de-backtick heredoc comment + shellcheck-clean iscc gate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - make-installer.sh: the LoadStringFromFile signature comment used backticks inside the unquoted < "\$STAGE\/emrg.iss" < "$STAGE/gen.sh" - VERSION="0.0.0-smoke" \ - DIST_WIN="$(cygpath -m "$STAGE/dist")" \ - STAGE_WIN="$(cygpath -m "$STAGE")" \ - ROOT_WIN="$(cygpath -m "$PWD")" \ - STAGE="$STAGE" \ bash "$STAGE/gen.sh" command -v iscc >/dev/null 2>&1 || { echo "::error::iscc not on PATH (runner image regression)"; exit 1; } iscc "$STAGE/emrg.iss" diff --git a/packaging/make-installer.sh b/packaging/make-installer.sh index 340f6519..153131f2 100755 --- a/packaging/make-installer.sh +++ b/packaging/make-installer.sh @@ -401,11 +401,13 @@ begin begin LogText := ''; // LoadStringFromFile 的 Inno Pascal Script 签名是 - // `function LoadStringFromFile(const FileName: String; var S: AnsiString): Boolean;` + // function LoadStringFromFile(const FileName: String; var S: AnsiString): Boolean; // (6.7.1 → 7.x 全版本一致,见 issrc Shared.ScriptFunc.pas)——不存在单参数 // 字符串返回形式!v0.2.30 Build Release 31661378619 因此编译失败 // (iscc "Invalid number of parameters",Test CI 不编译 .iss 未拦住)。 // 正确用法:out-param 写入 LogText,返回 Boolean 表示成功。 + // 注意:本注释位于未加引号 heredoc(< 2000 then From 27bb21d19bfcd1069a4d73a9b5f9c11567adc71c Mon Sep 17 00:00:00 2001 From: EMRG Evolution Date: Thu, 13 Aug 2026 11:03:17 +0800 Subject: [PATCH 4/6] emrg: stub icon.ico + {app} files in iscc compile gate (gen-assets artifacts) --- .github/workflows/test.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 2c7d87c5..bcc485a8 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -68,6 +68,21 @@ jobs: STAGE="$(mktemp -d)" mkdir -p "$STAGE/payload/bin" "$STAGE/dist/artifacts" touch "$STAGE/payload/bin/stop-emrg.cmd" + # icon.ico 是 gen-assets 产物(未入库)——生成最小合法 .ico 供 iscc 编译期 + # SetupIconFile 检查;{app}(={%USERPROFILE}\.emrg\install)引用的文件 + # (UninstallDisplayIcon/[Icons]/[UninstallRun])也需存在。 + uv run python - <<'PY' + import struct + def write_ico(path): + hdr = struct.pack(' Date: Thu, 13 Aug 2026 11:07:59 +0800 Subject: [PATCH 5/6] emrg: SC2016-clean sed anchor + heredoc comment reword - test.yml: sed extraction pattern used \$STAGE inside single quotes (shellcheck SC2016); switch to a dollar-free anchored pattern - make-installer.sh: reword heredoc comment to avoid literal command substitution syntax --- .github/workflows/test.yml | 3 ++- packaging/make-installer.sh | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index bcc485a8..0943adee 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -90,7 +90,8 @@ jobs: STAGE_WIN="$(cygpath -m "$STAGE")" ROOT_WIN="$(cygpath -m "$PWD")" export VERSION DIST_WIN STAGE_WIN ROOT_WIN STAGE - sed -n '/cat > "\$STAGE\/emrg.iss" < "$STAGE/gen.sh" + # 单引号内避免 \$ 字面量(shellcheck SC2016),用无 $ 的锚定模式 + sed -n '/cat > .*emrg\.iss.*< "$STAGE/gen.sh" bash "$STAGE/gen.sh" command -v iscc >/dev/null 2>&1 || { echo "::error::iscc not on PATH (runner image regression)"; exit 1; } iscc "$STAGE/emrg.iss" diff --git a/packaging/make-installer.sh b/packaging/make-installer.sh index 153131f2..68500181 100755 --- a/packaging/make-installer.sh +++ b/packaging/make-installer.sh @@ -406,8 +406,8 @@ begin // 字符串返回形式!v0.2.30 Build Release 31661378619 因此编译失败 // (iscc "Invalid number of parameters",Test CI 不编译 .iss 未拦住)。 // 正确用法:out-param 写入 LogText,返回 Boolean 表示成功。 - // 注意:本注释位于未加引号 heredoc(< 2000 then From 23de09687d40bfc6f5375959210382e1e1e117a6 Mon Sep 17 00:00:00 2001 From: EMRG Evolution Date: Thu, 13 Aug 2026 11:09:11 +0800 Subject: [PATCH 6/6] emrg: LogText must be AnsiString for LoadStringFromFile var param (iscc Type mismatch) --- packaging/make-installer.sh | 2 +- tests/test_installer_stop.py | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/packaging/make-installer.sh b/packaging/make-installer.sh index 68500181..b73d94a0 100755 --- a/packaging/make-installer.sh +++ b/packaging/make-installer.sh @@ -385,7 +385,7 @@ var ResultCode: Integer; StopScript: string; LogFile: string; - LogText: string; + LogText: AnsiString; begin Result := ''; ExtractTemporaryFile('stop-emrg.cmd'); diff --git a/tests/test_installer_stop.py b/tests/test_installer_stop.py index ca8ba040..fcde1de4 100644 --- a/tests/test_installer_stop.py +++ b/tests/test_installer_stop.py @@ -153,6 +153,10 @@ def test_make_installer_iss_has_prepare_to_install(): # Test CI 不编译 .iss 未拦住)。正反两态钉死正确调用形态。 assert "LoadStringFromFile(LogFile, LogText)" in content # 正:out-param 形式 assert ":= LoadStringFromFile(LogFile)" not in content # 反:1 参数形式不存在 + # ⚡ 2 参形式第 2 参是 var S: AnsiString——LogText 必须声明 AnsiString(Inno 6 + # 的 string=UnicodeString,传 string 变量 → iscc "Type mismatch",门禁实测拦截)。 + assert "LogText: AnsiString;" in content # 正:AnsiString 变量 + assert "LogText: string;" not in content # 反:UnicodeString 不匹配 var AnsiString assert "Length(LogText) > 2000" in content assert "Details from stop-emrg.cmd:" in content assert "SW_HIDE" in content # 批处理执行不弹控制台窗口(#592 纪律)