复审 r1(p1-1/fix-then-merge)五项全改:
1. **p1-1 CI 会红的 4 条 integration test**(`crates/core/tests/setting/`,我上一轮只跑了 `--lib`,
scope 漏掉了覆盖 schema 版本号的目录式 target):
- `java_install_keys` / `isolation_keys` / `appearance_keys`:版本断言 1.6.0 → 1.7.0(M168 的
`ui.font_cdn`),并写明「每加一批键推一次 minor 是纪律」。
- `update_keys::a_read_only_launcher_config_never_retires_the_legacy_file`:夹具从**写死
1.7.0** 改成 `launcher_version().minor + 1` 经 `SchemaRef::url()` 生成。写死数字的版本一推
这条守卫就变成「同版本」⇒ 文件可写 ⇒ 迁移真的执行 ⇒ 旧文件被退役,而断言还绿着(用户数据
守卫静默失效)。相对推导不会过期。
2. **p2-1 备用镜像不备用**:`cdn` 与 `fastly` 同属 Fastly(都 CNAME 到 jsdelivr.map.fastly.net),
换掉。现在首选 `gcore.jsdelivr.net`(Cloudflare,独立失败域),二选 `cdn.jsdelivr.net`
(Fastly)。注释里放了实测表(本机 + 复审机两份数据、字节数、sha256、IPv6 慢路径),
并写清排序依据(Fastly 侧 IPv6 实测 67 KB/s ⇒ 丢掉 4 分钟;Cloudflare 侧两次都完整下完)。
3. **p2-2 整体时限**:`core::download::font` 新增 `ATTEMPT_DEADLINE = 90 s` /
`TOTAL_DEADLINE = 180 s`,落在本模块自己的候选循环里(不动引擎全体语义):每次尝试
`min(单次上限, 剩余总预算)`,超时归 `Network` 档。新增守卫
`a_trickling_connection_is_cut_by_the_deadline`(回环服务端每 100 ms 挤 1 字节、预算 300 ms)。
顺带修掉一个真 bug:`tokio::time::timeout` 在运行时外构造会 panic(5 条既有用例当场抓到),
现在整段包进 `block_on(async { … })`。UI 文案改成「网络不通或太慢(超时)」,不校验失败混。
4. **p2-3 说 `Source::PendingPin` 的两处**:`fonts/cjk.rs` 的模块文档已改;`ui/lang.rs::log_cjk`
那句「D28 的下载通道还是 PendingPin」(在下载已发起之后打印,等于当面否定本功能)改成
「已按 D28 发起下载,见 [font] cjk-download … 与设置页那一行」。全仓再扫,只剩注释里的历史说明。
5. **p2-4 假守卫**:判据抽成纯函数 `install::plan(strategy, current) -> Step`(`Skip` / `Apply` /
`Start`),`after_probe` 只执行。旧的空转用例换成打真判据的打表用例;变异证明:删掉
`Skip` 那一臂 ⇒ `a_started_or_finished_install_is_not_restarted` 红(已实跑)。
次要项也一并处理:`from_cache` 改成**本次是否真的命中缓存**(`CdnFetcher::was_cached()`,
`has_cached()` 降级为诊断字段 `cache_present=`);`FontSpec` 的 URL 口径收紧为「非回环必须
https」(`is_acceptable_url` + 守卫);`ui.font_cdn` 写进状态行 hint;文档里的 17.0 MB → 16.9 MB。
`download/font.rs` 拆出 `font/spec.rs` 守 400 行。
验证(这台机器上单个 800 MB 测试 exe 链接要 10 分钟,链接期间文件被 Defender 扫描,故耗时很长):
- `cargo test -p unlucky-core --all-targets` → **1188 passed / 0 failed**(16 个 target,含
`setting` 那个 115 条、上一轮红 4 条的 integration target)
- `cargo test -p unlucky-i18n` → 31 passed / 0 failed
- `cargo test -p unlucky-app-iced --lib` → 685 passed / 0 failed
- `cargo clippy -p unlucky-i18n -p unlucky-core -p unlucky-app-iced --all-targets -- -D warnings` → 干净
- `cargo fmt --all -- --check` → 干净;全仓受检文件行数最大 388(<400)
73 lines
4.0 KiB
Rust
73 lines
4.0 KiB
Rust
//! 中文字体**下载状态行**的文案(M168):设置页 General 组那一行的四态文字 + 三类失败原因。
|
||
//!
|
||
//! ## 为什么单开一个域文件(而不是塞进 `font.rs`)
|
||
//!
|
||
//! `catalog/font.rs` 那四条(`FontCjkNeedsDownload` / `FontCjkDownloading` / `FontCjkDownloadFailed`
|
||
//! / `FontCjkReady`)是 M92「只发信号」时代的文案,位置在装配链**中间**。往那个域后面追加会把
|
||
//! 其后所有 key 在 `Key::ALL` 里整体平移一位 ⇒ 金表(逐 index 逐字节)整片红。
|
||
//!
|
||
//! 本域挂在**链尾**(`update_entries` 之后),于是 `Key::ALL` 的既有顺序一个不动,金表只需在
|
||
//! 末尾追加(M104 / M106 / M107 / M109 / M114 / M159 都是这条做法)。
|
||
//!
|
||
//! ## 四条状态各一句话(tower 定死的口径)
|
||
//!
|
||
//! | 状态 | 文案说什么 |
|
||
//! |---|---|
|
||
//! | 下载中 | 「正在获取中文字体…(≈17 MB)」——**没有**假进度条,有真实量(字节数)才写 |
|
||
//! | 完成 | 「中文字体已就绪:⟨族名⟩」(复用 `FontCjkReady`) |
|
||
//! | 失败 | 「获取失败(⟨三类原因之一⟩)。界面照常可用,用的是系统字体;再切一次语言可以重试」 |
|
||
//! | 无需下载 | 系统已有字体 / 当前语言不需要,两条分开说(对用户是两件事) |
|
||
//!
|
||
//! 「探测不出」也要有话说:那是「不知道」,既不是「没有」也不是「不需要」——写清楚「未下载」,
|
||
//! 免得用户以为我们偷偷下过一份。
|
||
//!
|
||
//! 域文件的形状见 [`crate::catalog`] 的「域装配」一节。
|
||
|
||
macro_rules! font_install_entries {
|
||
($next:ident, $($rest:ident,)* { $($acc:tt)* }) => {
|
||
$next! { $($rest,)* {
|
||
$($acc)*
|
||
// ── 中文字体下载状态行(M168:设置页 General 组)
|
||
FontCjkStatusLabel => ("Chinese font", "中文字体"),
|
||
FontCjkStatusNotNeeded => (
|
||
"Not needed for this interface language",
|
||
"当前界面语言不需要中文字体"
|
||
),
|
||
FontCjkStatusSystem => ("Ready (system font: {family})", "已就绪(系统字体:{family})"),
|
||
FontCjkStatusDownloading => (
|
||
"Fetching a Chinese font… ({size})",
|
||
"正在获取中文字体…({size})"
|
||
),
|
||
FontCjkStatusFailed => (
|
||
"Download failed ({reason}). The interface keeps working with system fonts; switch the language again to retry.",
|
||
"获取失败({reason})。界面照常可用,用的是系统字体;再切一次语言可以重试。"
|
||
),
|
||
// 超时也归这一档(M168 复审 P2-2):用户要分清「太慢/没网」与「内容不对」,
|
||
// 但不需要知道我们内部把它叫 Timeout 还是 Network。
|
||
FontCjkReasonNetwork => (
|
||
"network unreachable or too slow (timed out)",
|
||
"网络不通或太慢(超时)"
|
||
),
|
||
FontCjkReasonIntegrity => (
|
||
"the mirror sent content that failed verification",
|
||
"镜像内容校验不通过"
|
||
),
|
||
FontCjkReasonDisk => ("cannot write to the data directory", "写不进数据目录"),
|
||
FontCjkStatusUnknown => (
|
||
"Not determined yet; nothing was downloaded",
|
||
"尚未判定;没有下载任何字体"
|
||
),
|
||
FontCjkStatusUnprobeable => (
|
||
"System fonts cannot be probed, so nothing was downloaded",
|
||
"无法探测系统字体,因此没有下载"
|
||
),
|
||
FontCjkStatusHint => (
|
||
"Downloaded once into the data directory and cached; the next start does not download it again. A mirror can be set with `ui.font_cdn`.",
|
||
"只下这一次,缓存在数据目录里,下次启动不重下。镜像可用配置键 ui.font_cdn 指定。"
|
||
),
|
||
} }
|
||
};
|
||
}
|
||
|
||
pub(crate) use font_install_entries;
|