mirror of
https://gitee.com/xmz7891/ykxmz.git
synced 2026-10-18 18:20:43 +00:00
用户定的规矩:
只修 bug -> 最后一位 +1 1.8.2 -> 1.8.3
加新内容/重构 -> 第二位 +1,最后一位清 0 1.8.2 -> 1.9.0
这一轮既有新东西(设置窗口的中转服务器字段、允许新设备接入开关、
双击开设置窗口)又有重构(手表面板切换收成 showOnly()),
所以是 **1.9.0**,不是我之前说的 1.8.3。
== 顺手加了个「版本号一致性」检查(回归阶段 3a8)==
版本号散落在 8 个地方,靠脚本+人工替换很容易漏。实测漏了两个,
而且**漏了不报错**,只是用户看到一个对不上的版本号:
* windows/version_info.txt 写着 1.7.1
-> 用户在「文件属性 -> 详细信息」里看到的版本,错了三个版本
* docs/LICENSE.txt 写着 1.7.1
-> 安装时许可页上显示 1.7.1
第二个的根因值得记:installer/build_installer.py 会从 docs/ 里三份
文档**重新生成** license-combined.txt,所以光改生成物没用 ——
下次构建又变回去(我第一次就是这么被骗的)。改成在 build_license()
里**统一注入当前版本**,源文档写什么都不影响。
新增:
_tests/check_version_consistency.py 检查 8 处版本号一致
_build/add_verify_stage.py 给套件加阶段(不经 shell,
不会被 PowerShell 吃掉 \$ 变量)
_build/fix_license_version.py 按行精确修 license
== 另外修了两个我自己的坑 ==
1. verify_all.ps1 被 PowerShell heredoc 吃掉了 \ / \,
整个脚本语法错。**同一个坑踩了两次**(3a7 和 3a8)。
以后给 .ps1 加含 \$ 的内容一律写 Python 脚本文件再跑。
2. build_exe.ps1 被 edit 工具吃掉了 UTF-8 BOM
(PowerShell 5.1 会按 GBK 读,中文注释乱码)。
全量回归 43 个阶段全部通过。
147 lines
5.0 KiB
Python
147 lines
5.0 KiB
Python
# -*- coding: utf-8 -*-
|
||
r"""编译 Inno Setup 安装包。
|
||
|
||
做三件事:
|
||
1. 把三份文档合并成 license-combined.txt(Inno 的 LicenseFile 只认一个文件)
|
||
2. 把 .iss 里的版本号同步成当前版本
|
||
3. 调 ISCC.exe 编译
|
||
"""
|
||
from __future__ import annotations
|
||
|
||
import re
|
||
import subprocess
|
||
import sys
|
||
from pathlib import Path
|
||
|
||
ROOT = Path(r"C:\Users\shu\Desktop\deepseekagent\LanRemote")
|
||
INSTALLER = ROOT / "installer"
|
||
ISS = INSTALLER / "ykxmz.iss"
|
||
COMBINED = INSTALLER / "license-combined.txt"
|
||
ISCC = Path(r"C:\Program Files (x86)\Inno Setup 6\ISCC.exe")
|
||
|
||
DOCS = ("LICENSE.txt", "BEFORE-INSTALL.txt", "AFTER-INSTALL.txt")
|
||
|
||
|
||
def current_version() -> str:
|
||
text = (ROOT / "_build" / "package_remote.py").read_text(encoding="utf-8")
|
||
match = re.search(r'VERSION\s*=\s*"([^"]+)"', text)
|
||
return match.group(1) if match else "0.0.0"
|
||
|
||
|
||
def build_license() -> None:
|
||
"""三份文档拼成一份,给 Inno 的许可页用。
|
||
|
||
每份之间加分隔线,免得读起来像一份文档。
|
||
|
||
⚠ 这里**顺手把版本号注入进去**,不让它依赖源文档里写的是什么。
|
||
|
||
为什么:源文档里的版本号是硬编码的,实测 docs/LICENSE.txt 一直
|
||
停在 1.7.1(升级脚本只替换当时那个版本号,比如 1.8.2 ->
|
||
1.9.0,而 LICENSE.txt 里写的是 1.7.1,就永远匹配不上)。
|
||
结果安装时许可页上显示的是 1.7.1。
|
||
|
||
改成在这里统一注入之后,源文档写什么都不影响:
|
||
版本:X.Y.Z -> 版本:<当前版本>
|
||
软件:ykxmz X.Y.Z -> 软件:ykxmz <当前版本>
|
||
|
||
⚠ 只改**头部和落款**这两个格式,不改"八、版本记录"里的历史条目
|
||
—— 那是变更日志,本来就是一堆旧版本号。
|
||
"""
|
||
version = current_version()
|
||
parts = []
|
||
for index, name in enumerate(DOCS):
|
||
path = ROOT / "docs" / name
|
||
if not path.is_file():
|
||
print(f" [警告] 缺少 {name}")
|
||
continue
|
||
text = path.read_text(encoding="utf-8-sig").strip()
|
||
|
||
# 把"版本:x.y.z"和"软件:ykxmz x.y.z"换成当前版本,
|
||
# 但跳过"版本记录"那一段(历史日志)。
|
||
out_lines = []
|
||
in_history = False
|
||
for line in text.splitlines():
|
||
stripped = line.strip()
|
||
if "版本记录" in stripped:
|
||
in_history = True
|
||
if not in_history:
|
||
if re.match(r"^版本:\d+\.\d+\.\d+$", stripped):
|
||
line = line.replace(stripped, f"版本:{version}")
|
||
elif re.match(r"^软件:ykxmz \d+\.\d+\.\d+$", stripped):
|
||
line = line.replace(stripped, f"软件:ykxmz {version}")
|
||
out_lines.append(line)
|
||
text = "\n".join(out_lines)
|
||
|
||
if index:
|
||
parts.append("")
|
||
parts.append("=" * 70)
|
||
parts.append("")
|
||
parts.append(text)
|
||
body = "\n".join(parts) + "\n"
|
||
|
||
# 装许可页的正文要 UTF-8 **带 BOM**,否则 Inno 在中文系统上会显示乱码
|
||
COMBINED.write_bytes(b"\xef\xbb\xbf" + body.encode("utf-8"))
|
||
print(f" 合并三份文档 -> {COMBINED.name}"
|
||
f"({len(body)} 字符,版本注入为 {version})")
|
||
|
||
|
||
def sync_version(version: str) -> None:
|
||
text = ISS.read_text(encoding="utf-8")
|
||
new = re.sub(r'#define MyAppVersion "[^"]*"',
|
||
f'#define MyAppVersion "{version}"', text)
|
||
if new != text:
|
||
ISS.write_text(new, encoding="utf-8", newline="\r\n")
|
||
print(f" .iss 版本号 -> {version}")
|
||
else:
|
||
print(f" .iss 版本号已经是 {version}")
|
||
|
||
|
||
def main() -> int:
|
||
if not ISCC.is_file():
|
||
print(f" [失败] 找不到 Inno Setup: {ISCC}")
|
||
return 1
|
||
|
||
version = current_version()
|
||
print(f" 编译 ykxmz 安装包 v{version}")
|
||
print()
|
||
|
||
build_license()
|
||
sync_version(version)
|
||
|
||
agent = ROOT / "dist_exe" / "ykxmz" / "ykxmz.exe"
|
||
if not agent.is_file():
|
||
print(f" [失败] 被控端还没构建:{agent}")
|
||
print(" 先跑 windows\\build_exe.ps1")
|
||
return 1
|
||
|
||
print()
|
||
print(" 调 ISCC 编译…")
|
||
proc = subprocess.run([str(ISCC), str(ISS)],
|
||
capture_output=True, text=True,
|
||
encoding="utf-8", errors="replace", timeout=1800)
|
||
out = (proc.stdout or "") + (proc.stderr or "")
|
||
for line in out.splitlines():
|
||
line = line.strip()
|
||
if line and ("Error" in line or "error" in line
|
||
or "Successful" in line or "compil" in line.lower()
|
||
or "warning" in line.lower()):
|
||
print(f" {line}")
|
||
|
||
if proc.returncode != 0:
|
||
print(f" [失败] ISCC 退出码 {proc.returncode}")
|
||
print(out[-1500:])
|
||
return 1
|
||
|
||
exe = ROOT / "dist" / f"ykxmz-setup-{version}.exe"
|
||
if not exe.is_file():
|
||
print(f" [失败] 没生成 {exe}")
|
||
return 1
|
||
size = exe.stat().st_size / 1024 / 1024
|
||
print()
|
||
print(f" ✓ 安装包: {exe.name} {size:.2f} MB")
|
||
return 0
|
||
|
||
|
||
if __name__ == "__main__":
|
||
sys.exit(main())
|