Files
liuzhuohua b7ca9c89e8 feat(i18n/layout): 全站中英双语 + 四轮排版修复收官 + 修 boot_id 重启检测
v1.0.10 两件大事:

1. 界面中英双语(英文界面无中文残留)
   - 新增 web/i18n.js(约 4200 条词条),零依赖零构建
   - 后端下发中文数据走 bt4() 查表翻译;独立模块(upstream/netdetail/
     realtime/update)纳入翻译并注册切语言重绘钩子
   - 后端「状态/聚合」接口只回稳定枚举+原始数值,不下发中文文案
   - 顺带修一个真实 XSS:顶层 const 不挂 window,独立脚本 esc 静默退化成零转义

2. 修掉「文字竖着排/错位」(多分辨率反复暴露)
   - 单元格 min-content 只有 1 字宽 → word-break:keep-all + 表头 nowrap
   - 依赖卡片正文被标签/按钮挤成 27px → .dep-body{flex:1 1 200px} + flex-wrap
   - 裸 flex:1(下限为0)给正文 → 一律改 flex:1 1 <px>
   - .dep-item 横向容器直接塞块级子项 → 退回块级
   - 关键陷阱:auto-fill 布局屏越宽列数越多单卡越窄,窄屏反而测不出来,
     真机审计推进到「逐视图点按钮 + 1920/2560 宽视口 + 中英双语」
   - 守卫 t-layout.py 扩到 35 条,12 处反向验证全红

3. 修真缺陷:_link_since() 重启检测被误改成 if False:(注释还写着「已修」),
   uptime 归零后相减得负数 → 恢复比对 boot_id

附带:新增 25 个检查器(t-*.py)、排版审计工具链(shot-*/ocr-*/live-*)、
版本号兜底值同步到 1.0.10、.gitignore 收纳 i18n/排版排查的一次性脚本。
2026-10-10 04:50:32 +08:00

133 lines
7.5 KiB
Bash
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.
#!/bin/bash
# =============================================================================
# 构建 drouter 的 .deb 安装包(需在 Debian/Ubuntu 上执行,用到 dpkg-deb)
#
# bash packaging/build-deb.sh [版本号]
#
# 产物:dist/drouter_<版本>_all.deb
#
# 说明:.deb 本身不内嵌依赖的二进制(那是 apt 的职责),control 里用 Depends
# 声明完整依赖清单,安装时由 apt 自动补齐。若目标机无外网,可先用
# scripts/make-offline-deps.sh 把依赖预下载成离线包,再离线安装。
# =============================================================================
set -euo pipefail
HERE="$(cd "$(dirname "$0")/.." && pwd)"
# ⚠️ 版本号的**唯一真源**是 packaging/VERSION,不要在脚本里另写一份。
# 早先 4 个构建脚本各写死一个默认值,改版本时漏改一处就产出一个
# 「文件名是 1.0.9、control 里是 1.0.8」的包 —— apt 会按 control 认版本,
# 表现为 `dpkg -l` 永远显示旧版,升级也升不上去。
VERSION_FILE="$HERE/packaging/VERSION"
[ -f "$VERSION_FILE" ] || { echo "缺少 $VERSION_FILE(版本号唯一真源)"; exit 1; }
VERSION="${1:-$(tr -d ' \t\r\n' < "$VERSION_FILE")}"
[ -n "$VERSION" ] || { echo "$VERSION_FILE 为空"; exit 1; }
DIST="$HERE/dist"
PKG="drouter"
STAGE="$DIST/${PKG}_${VERSION}_all"
command -v dpkg-deb >/dev/null 2>&1 || { echo "需要 dpkg-deb(请在 Debian/Ubuntu 上执行)"; exit 1; }
echo "== 1/6 清理并准备目录 =="
rm -rf "$STAGE"
mkdir -p "$STAGE/DEBIAN" \
"$STAGE/opt/drouter/backend" \
"$STAGE/opt/drouter/web" \
"$STAGE/opt/drouter/docs" \
"$STAGE/opt/drouter/scripts" \
"$STAGE/usr/local/bin" \
"$STAGE/lib/systemd/system"
mkdir -p "$DIST"
echo "== 2/6 复制程序文件 =="
install -m 0644 "$HERE"/backend/*.py "$STAGE/opt/drouter/backend/"
install -m 0644 "$HERE"/web/* "$STAGE/opt/drouter/web/"
# 文档只装顶层文件,**不能写 `docs/*`**:`docs/screenshots/` 是个目录,
# GNU install 遇到目录会报 "略过目录" 并**返回非 0**,在 set -e 下直接中断整个打包。
# (截图是给 GitHub README 用的,也没必要塞进 deb 里白白撑大体积。)
# 逐项 `[ -f ]` 过滤的写法与 scripts/deploy.sh 保持一致。
for d in "$HERE"/docs/*; do
[ -f "$d" ] || continue
install -m 0644 "$d" "$STAGE/opt/drouter/docs/"
done
install -m 0755 "$HERE"/scripts/*.sh "$STAGE/opt/drouter/scripts/"
# 版本号随包落到 /opt/drouter/VERSION —— 页面底部的版本号和 openapi 的
# version 字段都从它读。不装的话后端只能退回硬编码的兜底值,
# 表现是「deb 装的是 1.0.9,页面却显示 1.0.8」。
install -m 0644 "$VERSION_FILE" "$STAGE/opt/drouter/VERSION"
# 一键运维命令:直接随包提供,postinst 里再做一次兜底安装
install -m 0755 "$HERE/scripts/drouter-ctl.sh" "$STAGE/usr/local/bin/drouter-ctl"
# systemd 单元必须随包发。踩过的坑:原先 .deb 里**一个单元都没有** ——
# 单元只在 scripts/deploy.sh 里用 heredoc 写,所以「用 deploy.sh 部署」能用,
# 但「用 .deb 装」的用户装完是一堆文件、没有任何服务,必须再手工跑一遍
# deploy.sh 才行。对 Release 用户来说这是致命的。
# 注意:drouter-logd.service / drouter-qos.service **不在这里** ——
# 它们的内容随用户的日志/限速配置变化,由 helper 在保存配置时动态生成,
# 静态打进包里反而会写错默认值。
install -m 0644 "$HERE"/packaging/deb/units/*.service "$STAGE/lib/systemd/system/"
install -m 0644 "$HERE"/packaging/deb/units/*.timer "$STAGE/lib/systemd/system/"
echo "== 3/6 写入 DEBIAN 元数据 =="
# 注:DEBIAN/control 是 deb822 格式,不保证支持 "#" 注释行 —— 需要说明的地方
# 一律写在本脚本里,不要写进 control,否则某些 dpkg 工具会解析失败。
#
# 依赖策略:apt 默认会装 Recommends,所以 Recommends 里只放「不自带守护进程」
# 的工具。以下三类一律降级到 Suggests,由用户在界面上按需逐项安装:
# * smartmontools —— 装完自动拉起 smartd 常驻;
# * samba / nfs-kernel-server —— 装完会启用 smbd / nfs-server 文件共享服务;
# * docker.io / docker-compose —— 装完会启用 docker 守护,4GB 机器上很重。
# 注意包名:Debian 13 是 docker-compose(提供 compose v2 插件),
# docker-compose-v2 是 Ubuntu 的叫法,在 Debian 上装不到。
# 格式化工具(exfatprogs / ntfs-3g / dosfstools / xfsprogs / btrfs-progs /
# f2fs-tools)和 etherwake、zip 等纯工具没有守护进程,放在 Recommends 即可。
sed "s/__VERSION__/$VERSION/" "$HERE/packaging/deb/control" > "$STAGE/DEBIAN/control"
install -m 0755 "$HERE/packaging/deb/postinst" "$STAGE/DEBIAN/postinst"
install -m 0755 "$HERE/packaging/deb/prerm" "$STAGE/DEBIAN/prerm"
install -m 0755 "$HERE/packaging/deb/postrm" "$STAGE/DEBIAN/postrm"
# md5sums 让 dpkg 能检测文件被改动
( cd "$STAGE" && find . -path ./DEBIAN -prune -o -type f -print \
| sed 's|^\./||' | xargs -r md5sum > DEBIAN/md5sums )
echo "== 4/6 校验 =="
# 后端 13 个模块必须齐全,缺一个上线后就是某个功能打不开。
# ⚠️ drouter-ddnsd.py 是 DDNS 定时更新守护(1.0.8 新增):
# deb 里**只有这个脚本**,drouter-ddns.service/.timer 是运行时由
# helper 的 _write_ddns_timer() 生成的(周期取自用户填的检测间隔),
# 所以下面的 systemd 清单里不能出现它们,否则构建会误判「缺少单元」。
for f in render.py drouter-helper.py drouter-web.py drouter-logd.py \
drouter-snapshotd.py drouter-rescue.py drouter-shelld.py \
drouter-helpd.py drouter-backupd.py drouter-alertd.py \
drouter-quotad.py drouter-ddnsd.py drouter-update.py \
theme.py; do
[ -f "$STAGE/opt/drouter/backend/$f" ] || { echo "✘ 缺少 $f"; exit 1; }
# ⚠️ 必须用 compile() 不是 ast.parse():后者只做语法分析,抓不到
# 「重复关键字参数」这类语义错误(1.0.10 实测:ast.parse 通过,
# import 时 SyntaxError)。构建期就崩在这里,别等到真机才发现。
python3 -c 'import sys; compile(open(sys.argv[1],encoding="utf-8").read(),sys.argv[1],"exec")' \
"$STAGE/opt/drouter/backend/$f"
done
for wf in app.js app.css index.html update.js update.css upstream.js netdetail.js realtime.js i18n.js; do
[ -f "$STAGE/opt/drouter/web/$wf" ] || { echo "✘ 缺少 $wf"; exit 1; }
done
# 这里的数字必须等于上面for 里的条目数。写错了不会让构建失败,
# 但会让人以为清单是全的(历史上「7 个」和实际 12 个长期不符)。
echo " 后端模块 14 个、语法全部通过"
# systemd 单元齐全性:少一个就是「某项功能装完不工作」
for u in drouter-web.service drouter-helpd.service drouter-shelld.service \
drouter-snapshot.service drouter-snapshot.timer drouter-rescue.service; do
[ -f "$STAGE/lib/systemd/system/$u" ] || { echo "✘ 缺少 systemd 单元 $u"; exit 1; }
done
echo " systemd 单元 6 个齐全"
echo "== 5/6 构建 =="
dpkg-deb --build --root-owner-group "$STAGE" "$DIST/${PKG}_${VERSION}_all.deb"
echo "== 6/6 产物 =="
ls -lh "$DIST/${PKG}_${VERSION}_all.deb"
dpkg-deb -I "$DIST/${PKG}_${VERSION}_all.deb" | sed -n '1,14p'
echo ""
echo "安装:sudo apt install ./dist/${PKG}_${VERSION}_all.deb"
echo "卸载:sudo apt remove drouter (保留配置)"
echo " sudo apt purge drouter (连配置一起删)"