Files
liuzhuohua 6df3a94b90 适配 arm64 Debian(Armbian 26.8.1 trixie):去掉架构假设
有用户要在 arm64 的 Debian 上跑 drouter。这一轮只对一个发行版做了适配
—— Armbian 26.8.1 trixie(Debian 13.6)/ aarch64 / 内核 6.18.35-ophub
(Amlogic S912 板),别的 arm64 发行版未验证,验证范围与实测数据全部
写在 docs/07-arm64-适配说明.md。

改掉的四处 x86 假设:

1. helper._read_bios():ARM 板既无 /sys/firmware/efi 也无 /sys/class/dmi,
   原代码把它们一律落到 else 分支,系统概览显示「传统 BIOS」(错的,
   这类机器根本没有 BIOS)。新增设备树分支,判据顺序 EFI → 设备树 → BIOS
   (树莓派 4 这类两可的机器要优先认 EFI);读 /proc/device-tree 与
   /sys/firmware/devicetree 两个候选路径,compatible 按 NUL 切开取第一条;
   没有 DMI 厂商时拿设备树板名顶上,厂商格不再空白。返回结构加 fw_type
   / is_dt / compat,旧字段一个没动。

2. update.py:离线包资源名原先写死 -offline-amd64,arm64 机器点一键更新
   会下载 x86 离线包,传几十 MB 才在装包阶段炸依赖。改为按
   dpkg --print-architecture 拼名(_deb_arch / build_assets),并为带架构
   后缀的附件在下载前先拿官方 SHA256SUMS 核对存在性,没有就明确报错。

3. packaging:离线包说明里两处写死的 amd64 换成 $ARCH(包名早就是变量拼的,
   但包里那份 README 还在教用户核对 amd64);build-docker.sh 新增可选的
   第 2 个参数 [arch],交叉构建时加 --platform 并给标签加 -<arch> 后缀,
   不传第二参数时行为与改动前逐字节一致。

4. web/i18n.js:给新增的「设备树 (Device Tree)」展示串登记英文,
   否则英文界面漏中文。

配套:
- _dev/t-arch.py(31 条判据)+ _dev/t-arch-inject.py(20 例反向验证)。
  反向验证抓出一条假绿:i18n 词条的 n/d 判据用了 300 字符松弛窗口,
  会跨到下一条词条,删掉本词条的 d 之后照样绿 —— 已收紧为本词条花括号内。
- _dev/run-static.py 的 EXCL 补上 t-update-inject —— 它名字也是 t- 前缀,
  之前一直被全量回归自动执行,会在回归过程中反复改写 backend/ 与 web/。
- devtools/verify-arm64.py:只读验收脚本,方便他人在自己的板子上复验。
- README 支持矩阵里 arm64 从「理论可用」改为「已实测 1 个发行版」。

本机全量静态回归 71 个检查器 / 0 失败;目标机上只读验证 12 条全通
(构建 753 396 字节的 deb / depcheck 73 项 / 8 个渲染模块 / 架构感知清单)。
目标机未安装 drouter,未启用任何服务,未改动网络。
2026-10-16 06:16:31 +08:00

101 lines
4.0 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""drouter 静态回归驱动器(Windows 开发机用)。
为什么不用 shell 脚本跑:
这个环境里 bash 会话有 SIGTERM 风险,把整轮结果一起带走,
表现为「跑全量回归 → 命令莫名死掉」,看不出跑到第几个。
改成 Python逐个跑 + 每项前后写日志文件,崩了也能定位到具体那一项。
用法:
python _dev/run-static.py 跑全部
python _dev/run-static.py t-107 t-ca 只跑指定的
"""
import glob
import os
import re
import subprocess
import sys
HERE = os.path.dirname(os.path.abspath(__file__))
ROOT = os.path.dirname(HERE)
# 需要真机 / 网络 / 交互 / 长时间压测的,不在静态回归范围内。
# ⚠️ 必须带 `t-` 前缀 —— ls 出来的名字就是 t-xxx。写裸名的话一个都
# 排除不掉,交互脚本照样跑,其中一个会把整个会话干掉。
EXCL = {
't-live', 't-smoke', 't-ulog-perf', 't-ulog-detail', 't-perf',
't-print', 't-cachebust', 't-cleanup', 't-webshell', 't-pty',
't-daemon-restart',
# ⚠️ 反向验证脚本**会真的改源文件**(注入 bug → 跑测试 → 还原)。
# 名字前缀也是 t-,会被 glob 自动收进来;一旦被自动执行,
# 它就会在回归过程中反复改写 backend/ 与 web/ —— 后果是
# 别的检查器读到被注入污染的代码,报出一堆假红,
# 更糟的是中途被打断会留下污染(已经发生过一次)。
# 只能手动跑:python _dev/t-107-inject-wg.py --batch 0
't-107-inject-wg',
# arm64 适配(2026-10-16)的反向验证,同上:覆盖 backend/drouter-update.py、
# backend/drouter-helper.py、web/i18n.js、packaging/*.sh 四处源码。
't-arch-inject', 't-update-inject', 'upd-inject',
}
def main():
args = sys.argv[1:]
if args:
names = [a if a.startswith('t-') else 't-' + a for a in args]
else:
names = sorted(os.path.basename(p)[:-3]
for p in glob.glob(os.path.join(HERE, 't-*.py')))
names = [n for n in names if n not in EXCL]
logpath = os.path.join(HERE, '.run-static.log')
log = open(logpath, 'w', encoding='utf-8')
def say(msg):
sys.stdout.write(msg + '\n')
sys.stdout.flush()
log.write(msg + '\n')
log.flush()
passed, failed = [], []
for n in names:
f = os.path.join(HERE, n + '.py')
if not os.path.isfile(f):
say(' %-20s 跳过(不存在)' % n)
continue
say(' %-20s ... ' % n)
try:
p = subprocess.run([sys.executable, f], capture_output=True,
text=True, encoding='utf-8', errors='replace',
timeout=180)
rc, out = p.returncode, (p.stdout or '')
except subprocess.TimeoutExpired:
rc, out = 124, 'TIMEOUT'
if rc == 0:
m = re.findall(r'通过 (\d+) 项', out)
say('ok%s' % ((' (%s 项)' % m[-1]) if m else ''))
passed.append(n)
else:
say('失败 rc=%s' % rc)
# 把红的那几行打出来 —— 只写 rc 的话,排查时只能一个个单独跑
# (2026-10-06:t-msg-en 在全量里红、单独跑绿,顺序依赖查不出来,
# 就是因为日志里只有「失败 rc=1」,看不到是哪条判据。)
# 各检查器的红标记不统一:有的用 [NG]、有的用 [FAIL]、有的打 ✘。
for line in out.splitlines():
if re.search(r'\[NG\]|\[FAIL\]|Traceback|Error|✘|异常',
line):
say(' ' + line[:150])
failed.append(n)
log.close()
print()
print('通过 %d 个检查器,失败 %d 个' % (len(passed), len(failed)))
if failed:
print('失败:%s' % ' '.join(failed))
return 1
print('(明细见 _dev/.run-static.log)')
return 0
if __name__ == '__main__':
sys.exit(main())