mirror of
https://gitee.com/xmz7891/ykxmz.git
synced 2026-10-18 19:30:42 +00:00
1. 卸载里 input() 在无 stdin 时永久阻塞
从控制面板卸载**永远卡住不结束**。安装包的 [UninstallRun]
用 runhidden 调用,没有 stdin,input() 就一直等。
改成只在 sys.stdin.isatty() 时才等回车。
2. Popen 没重定向子进程 stdio,导致 capture_output 等管道 EOF
_schedule_self_delete 起的 cmd 继承了父进程的 stdout/stderr 句柄,
任何用 capture_output 调 --uninstall 的地方都会一直等,
表现为"程序卡死"(实测 90 秒不返回,改后 0.2 秒)。
Popen 加 stdin/stdout/stderr=DEVNULL。
顺带把延迟从 timeout 换成 ping —— timeout 在 DETACHED_PROCESS
下没有控制台会立刻失败,等于没延迟直接删。
3. _kill_running 用 taskkill /IM ykxmz.exe 把**自己**杀了
--uninstall 本身就跑在 ykxmz.exe 里,这条命令一发,
后面的"删开机自启""删数据目录"全都没执行。
现象:卸载看着完成了,HKCU 的自启注册表项还留着。
改成 /FI "PID ne <self>" 排除自己。
4. 安装器关不掉以管理员身份运行的旧实例 -> 整个安装回滚
Inno 自带机制只会"请求"对方退出,遇上常驻的服务进程关不掉,
弹"无法自动关闭所有应用程序",静默模式下被压成"终止",
安装直接回滚 —— 用户看到的是"装了没反应/还是旧版本"。
改成 PrepareToInstall 里自己 taskkill /F,关掉 Inno 那套。
另外修了两个卸载残留:
* 安装目录留个空壳 -> [UninstallDelete] 加 dirifempty
* ProgramData\ykxmz 没删 -> 加进 [UninstallDelete]
还有一处 Inno 写法陷阱(踩了三次):
注释里写 [区段名] 或 {常量} 会让编译直接失败,
因为 [Code] 解析器连注释内容也处理。
加了 _build/check_iss.py 专门扫这个,并进全量套件。
实测结果:
静默安装 5 秒内退出,退出码 0,配对码正确写入,程序自动跑起来
静默卸载 0.7 秒退出(原来无限卡住)
全量回归 29 项全通过
卸载逻辑 11 项全通过
141 lines
4.3 KiB
Python
141 lines
4.3 KiB
Python
# -*- coding: utf-8 -*-
|
|
r'''检查 Inno Setup 的 .iss 里有没有会害编译失败的写法。
|
|
|
|
踩过的三个坑,都是 Inno 的 [Code] 解析器**连注释内容也处理**:
|
|
|
|
1. 注释里写方括号区段名
|
|
{ 规范化,后面 [Run] 阶段用得到 }
|
|
报 "无效的区段标记",编译直接失败。踩了两次。
|
|
|
|
2. 注释里写花括号常量
|
|
{ 不带 --keep-dir 的话会 rmdir 删 {app} }
|
|
Inno 会把 {app} 展开,展开后花括号配不上 ->
|
|
报 "Syntax error",编译失败。踩了一次。
|
|
|
|
3. 注释里写 {param:XXX|}
|
|
Inno 会展开它,参数没传就展开成空,同样破坏括号配对。
|
|
|
|
所以规则:**[Code] 段落里,注释内容不能出现 [Section] 或 {常量}。**
|
|
|
|
⚠ 判断"是不是注释"必须跳过字符串字面量:
|
|
ExpandConstant('{app}\x') <- 这里的 { 在字符串里,不是注释
|
|
{ 这是注释 } <- 这里的 { 才是注释
|
|
'''
|
|
from __future__ import annotations
|
|
|
|
import re
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
ISS = (Path(r"C:\Users\shu\Desktop\deepseekagent\LanRemote")
|
|
/ "installer" / "ykxmz.iss")
|
|
|
|
SECTIONS = {
|
|
"Setup", "Types", "Components", "Tasks", "Dirs", "Files", "Icons",
|
|
"Ini", "InstallDelete", "Languages", "Messages", "CustomMessages",
|
|
"Registry", "Run", "UninstallRun", "UninstallDelete", "Code",
|
|
}
|
|
|
|
|
|
def scan_comment_text(line: str, in_comment: bool):
|
|
"""返回 (这一行注释里的文字, 扫完后的 in_comment)。
|
|
|
|
关键:字符串字面量里的 { } 不算注释。
|
|
"""
|
|
out = []
|
|
cursor = 0
|
|
in_string = False
|
|
length = len(line)
|
|
|
|
while cursor < length:
|
|
ch = line[cursor]
|
|
|
|
if in_string:
|
|
if ch == "'":
|
|
# Pascal 用 '' 表示一个单引号
|
|
if cursor + 1 < length and line[cursor + 1] == "'":
|
|
cursor += 2
|
|
continue
|
|
in_string = False
|
|
cursor += 1
|
|
continue
|
|
|
|
if not in_comment:
|
|
if ch == "'":
|
|
in_string = True
|
|
elif ch == "{":
|
|
in_comment = True
|
|
cursor += 1
|
|
continue
|
|
|
|
# 在注释里
|
|
if ch == "}":
|
|
in_comment = False
|
|
cursor += 1
|
|
continue
|
|
out.append(ch)
|
|
cursor += 1
|
|
|
|
return "".join(out), in_comment
|
|
|
|
|
|
def main() -> int:
|
|
if not ISS.is_file():
|
|
print(" 找不到 %s" % ISS)
|
|
return 1
|
|
|
|
lines = ISS.read_text(encoding="utf-8").splitlines()
|
|
|
|
code_start = None
|
|
for index, line in enumerate(lines):
|
|
if line.strip() == "[Code]":
|
|
code_start = index
|
|
break
|
|
|
|
if code_start is None:
|
|
print(" 没有 [Code] 段落,跳过")
|
|
return 0
|
|
|
|
problems = []
|
|
in_comment = False
|
|
|
|
for index in range(code_start, len(lines)):
|
|
line = lines[index]
|
|
comment_text, in_comment = scan_comment_text(line, in_comment)
|
|
if not comment_text:
|
|
continue
|
|
|
|
# 只有**行首**的 [Section] 才会被 Inno 当成区段标记。
|
|
# 行中间的("交给 Run 段用...")不影响 —— 实测编译能过。
|
|
m = re.match(r"\s*\[([A-Za-z][A-Za-z0-9]*)\]", comment_text)
|
|
if m and m.group(1) in SECTIONS:
|
|
problems.append((index + 1,
|
|
"注释**行首**有区段名 [%s]" % m.group(1),
|
|
line.strip()))
|
|
|
|
# 花括号常量:注释里出现就会被展开
|
|
for match in re.finditer(
|
|
r"\{[A-Za-z][A-Za-z0-9]*(?:[:|][^}]*)?\}", comment_text):
|
|
problems.append((index + 1,
|
|
"注释里有会展开的常量 %s" % match.group(0),
|
|
line.strip()))
|
|
|
|
# 真区段必须顶格
|
|
for index, line in enumerate(lines):
|
|
if re.match(r"^\s+\[[A-Za-z]+\]\s*$", line):
|
|
problems.append((index + 1, "区段名前面有空格", line.strip()))
|
|
|
|
if problems:
|
|
print(" 发现 %d 个会让编译失败的问题:" % len(problems))
|
|
for lineno, why, text in problems:
|
|
print(" 行 %d: %s" % (lineno, why))
|
|
print(" %s" % text[:74])
|
|
return 1
|
|
|
|
print(" [Code] 段落里没有违规写法 ✓")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|