D50 的「检查 → 提示 → 可拒绝 → 下载校验 → 下一次启动生效」整环接线,GUI 与
CLI 共用 core 的一条内核(`update::Job`),并顺带修掉 M157 最后一轮复审的三处 P3。
内核(core::update)
- 新增 job.rs:`Job { source, target, staging, dest }` + `check` / `apply`(复查 →
取包 → 长度/SHA256 双检 → 原子替换),`default_source`(GitHub,`ULL_UPDATE_DIR`
可切本地目录夹具)、`process_dest`、`staging_dir`。
- `mod.rs` 导出 job 一族;`source.rs` 为 `Box<dyn UpdateSource>` 补 trait 转发
(壳层要运行期选源,`UpdateChecker` 是泛型的)。
presenter(宿主通道)
- `dto/update.rs`:`UpdateView` / `UpdateOutcome`(Idle/Checking/UpToDate/Available/
MissingArtifact/Failed 六态,**失败与最新不折叠**)/ `UpdateBanner` 优先级判据。
- `host/update.rs`:Factory(生产 GitHub / 单测本地目录)+ core 结论 → DTO 的唯一映射
+ 更新域偏好(`cache/update/prefs.json`)。
- `host/update_state.rs`:Runtime(会话状态机:begin_check/adopt/begin_apply/dismiss/
set_auto_check)+ `CoreHost` 派发与后台线程。
- `AppCommand::{CheckUpdate, ApplyUpdate, DismissUpdate, SetUpdateAutoCheck}`、
`CoreEvent::Update`、`AppState.update`;`refresh_all` 按开关派发静默检查。
app-iced
- 设置页新增第 5 组「更新」(当前版本 / 渠道 / 自动检查开关 / 立即检查 / 上次检查与
结果 / 下载并安装 / 就位后立即重启),走 `settings::view` 的 `update` 形参 + 按下标
分发(与 M106 语言行同一取舍)。
- 顶部提示条(每页可见):有新版本(版本号 + 体积 + 说明摘要,可安装/可忽略)、下载中、
已就位(立即重启);静默检查失败**不**弹条(原因进设置页)。
- `pages::Message::Update(UpdateAction)` → `app/update/update_action.rs`;「立即重启」
拉同参数的新进程后退出(截图通道不重启)。
CLI
- `ull update check` / `ull update apply [--dest <path>]`:复用同一 `Job`;四种结论分开
报(`--json` 的 `status`),失败退出码 1(`update_check_failed` / `update_apply_failed`)。
i18n
- 新增 `catalog/update.rs`(30 条,链尾追加)+ 金表对应 30 行。
M157 复审 P3 三件
- `app/update/instances.rs` 模块文档改成「清脏的唯一时机是回程快照等于表单」。
- `pages/instances/demo.rs` 的 `demo_form` 注释改成现状(两个参数框早已是单行输入)。
- `pages/instances/launch_args.rs`:门限不满足时只灰 `opengl`/`vulkan`,`default` 仍可点
(它是「不下发」的安全档);判据抽成 `backend_chip_enabled` 并补 3 条用例。浅色 + 灰化
两张图:`C:/Temp/m159-shots/instances-launch-args-{light,gated}.png`。
顺带:harness 支持 `ULL_SETTINGS_GROUP=<下标>`(拍第 5 组的验收图需要它)。
验证:cargo fmt --check 绿;cargo clippy --workspace --all-targets -D warnings 绿;
cargo test --workspace --all-targets 51 个测试二进制全绿(唯一例外:core::addon::pack
一族要造 4 GiB 稀疏文件,本机磁盘 99% 满 ⇒ StorageFull,与本次改动无关);CLI 用本地
目录夹具跑通「发现 9.9.9 → 下载 → 校验 → 替换运行中的 exe → 备份留旧文件」,并验证
摘要不符时拒绝应用、目标文件零改动、暂存目录零残留。
56 lines
2.2 KiB
Rust
56 lines
2.2 KiB
Rust
//! 「启动参数」区(M157)的**门限**判据:三态 chips 在版本不够时谁可点。
|
|
//!
|
|
//! 为什么只测一个纯函数:iced 0.14 的 `Element` 没有内省接口,画出来的「禁用态」在测试里
|
|
//! 拿不到(`Chip::disabled` 只是把 `on_press` 清成 `None`)。所以把判据抽成
|
|
//! [`backend_chip_enabled`] 并在这里钉住——页面那一行必须调它(否则这条绿着也没意义,
|
|
//! 守门形状与 `instances/tests.rs` 的源码断言同一取舍)。
|
|
|
|
use super::super::launch_args::backend_chip_enabled;
|
|
use crate::pages::LaunchFacts;
|
|
|
|
/// 门限满足:三档全可点。
|
|
#[test]
|
|
fn every_backend_chip_is_clickable_when_the_gate_is_open() {
|
|
for id in ["default", "opengl", "vulkan"] {
|
|
assert!(backend_chip_enabled(true, id), "门限满足时 {id} 必须可点");
|
|
}
|
|
}
|
|
|
|
/// 门限不满足:只有 `default` 可点(它是「不下发」的安全档)。
|
|
///
|
|
/// 抓得住:把 `default` 一起灰掉(M157 复审 P3 的原状)——那时旧版本实例上写了
|
|
/// `graphicsBackend: vulkan` 的用户在 UI 里回不到 `default`,只能「恢复跟随全局」
|
|
/// (连带清空 JVM / 游戏参数 / 内存 / Java 四项)。
|
|
#[test]
|
|
fn the_default_chip_stays_clickable_when_the_gate_is_closed() {
|
|
assert!(
|
|
backend_chip_enabled(false, "default"),
|
|
"门限不满足时 default 也必须可点:它是唯一永远合法的档"
|
|
);
|
|
for id in ["opengl", "vulkan"] {
|
|
assert!(
|
|
!backend_chip_enabled(false, id),
|
|
"门限不满足时 {id} 必须灰掉(下发会被 core 拒绝)"
|
|
);
|
|
}
|
|
}
|
|
|
|
/// 词表与判据不许脱节:`default` 必须真在这份快照的 options 里,否则「安全档」无从点起。
|
|
#[test]
|
|
fn the_gate_rule_covers_the_demo_option_table() {
|
|
let facts = LaunchFacts {
|
|
options: ["default", "opengl", "vulkan"]
|
|
.iter()
|
|
.map(|id| (*id).to_string())
|
|
.collect(),
|
|
..LaunchFacts::default()
|
|
};
|
|
assert!(
|
|
facts
|
|
.options
|
|
.iter()
|
|
.any(|id| backend_chip_enabled(false, id)),
|
|
"门限关闭时至少有一档可点(否则三态整体锁死)"
|
|
);
|
|
}
|