feat(m160): 整合包逐文件覆盖/保留决策 + 导入前冲突清单 + 限额口径统一
主任务(逐文件覆盖/保留)
- core: 新增 import/scan.rs —— 只读预检产出「冲突清单」(目标已存在且 SHA-1 不同才进),
逐条给路径/来源/两侧体积与哈希;用户删过的、内容相同的、被叠层遮蔽的一律不打扰。
- core: 新增 import/decision.rs —— ConflictDecisions(整批档 + 逐项表,逐项优先),
缺省档恒为 KeepUser;ImportRequest.conflict_policy 改由它承载,CLI 调用点不变。
- core: phase.rs 的 settle 按 path 取决策;非冲突路径不受决策影响。
- presenter: ImportScanView / ImportConflictView / ConflictDecisionsView(全部保留 /
全部覆盖 / 逐项{default,items})+ PackCommand::Scan / PackEvent::Scan;host 新增只读
spawn_scan,且新实例路径不再提前建目录(target_of 只算路径,prepare_target 才建)。
- app-iced: 导入前冲突清单页(分页 40 条/页、三入口、计数摘要、确认/取消、两行式行布局);
预检干净时直接往下导,不打扰用户。出图见 C:/Temp/m160-shots/{pick-light,pick-dark}.png。
- i18n: 新增 18 条 en/zh 文案 + 更新「两者都留」那条口径说明。
限额口径统一
- pack/archive/limits.rs 成为唯一来源:PACK_MAX_ENTRIES/UNCOMPRESSED_BYTES/ENTRY_BYTES
(20k / 512 MiB / 64 MiB);读侧 PackLimits::default 与写侧 WriteLimits::production 同源。
- 写侧不再直接用 zip::ZIP64_BYTES_THR;新增单条目闸,于是「能导出的包一定能导入」。
不等式在 pack/tests/limits.rs 里用 const 断言钉死。
测试临时物泄漏(塔台追加项)
- addon/temp.rs:TempRoot —— Drop 即删(panic 展开同样删),Deref/AsRef 到落点路径,
under()/at() 支持"子树落点、删父根"。形状照 core::update::tests::support::TempDir。
- addon::pack 与 addon::tests 两族全部改用 TempRoot(含 fixtures::Fixture 持守卫、
multimc/fabric_instance 等返回守卫);4 GiB 稀疏文件的语义一字未改,只改"谁负责删"。
- 自证:pack/tests/mod.rs 三条用例(drop 删 / panic 也删 / 子树删父根)。
测试
- import_decisions.rs(11 例):预检清单、不打扰、逐项决策后的最终文件集、基线记包内哈希。
- roundtrip_three.rs(2 例):叠层 + 冲突夹具 import→export→import 三轮文件集逐字节一致,
以及「选保留就按设计分叉」的反向证据。
- pack/tests/limits.rs(5 例):单条/总量边界、读侧用同一批常量、写出即可读回。
证据:cargo fmt --check 干净;cargo clippy --workspace --all-targets -D warnings 干净;
cargo test --workspace --all-targets -j 4 → 2507 passed / 0 failed(51 个 test binary)。
This commit is contained in:
1 parent
a4f096eea3
commit
4defc41e8d
64 files changed
+3819
-442
No files matched your search
@@ -149,8 +149,8 @@ macro_rules! content_entries {
|
||||
),
|
||||
PackOverwriteAction => ("Re-import, the pack wins", "以包为准重新导入"),
|
||||
PackOverwriteNote => (
|
||||
"Keeping both (renamed) is not supported yet: the import pipeline has one global conflict policy and no per-file decision channel.",
|
||||
"「两者都留(改名)」暂不支持:导入管线只有一套全局冲突策略,没有逐文件决策通道。"
|
||||
"Keeping both (renamed) is not supported yet: for each existing file you pick either “keep” or “overwrite”.",
|
||||
"「两者都留(改名)」暂不支持:每个已存在的文件只能选「保留」或「覆盖」。"
|
||||
),
|
||||
PackMissingOffline => ("offline import", "离线导入"),
|
||||
PackMissingNoSource => (
|
||||
@@ -173,6 +173,36 @@ macro_rules! content_entries {
|
||||
"包内 {pack} · 基线 {base} · 磁盘 {disk}"
|
||||
),
|
||||
PackConflictDetail => ("Hashes", "三方哈希"),
|
||||
PackPickTitle => (
|
||||
"Before importing: {count} files already exist with different content",
|
||||
"导入前:有 {count} 个文件已存在且内容不同"
|
||||
),
|
||||
PackPickSummary => (
|
||||
"Keep {keep} · overwrite {overwrite} · overwriting discards {bytes}",
|
||||
"保留 {keep} · 覆盖 {overwrite} · 覆盖将丢弃 {bytes}"
|
||||
),
|
||||
PackPickKeepAll => ("Keep all mine", "全部保留我的"),
|
||||
PackPickOverwriteAll => ("Overwrite all", "全部覆盖"),
|
||||
PackPickRowKeep => ("Keep", "保留"),
|
||||
PackPickRowOverwrite => ("Overwrite", "覆盖"),
|
||||
PackPickPage => ("Items {from}-{to} of {total}", "第 {from}-{to} 项,共 {total} 项"),
|
||||
PackPickPrev => ("Previous", "上一页"),
|
||||
PackPickNext => ("Next", "下一页"),
|
||||
PackPickConfirm => ("Import with these choices", "按这些选择导入"),
|
||||
PackPickCancel => ("Cancel import", "取消导入"),
|
||||
PackPickDefaultNote => (
|
||||
"Anything you do not change stays as you have it: file content is only replaced where you pick “Overwrite”.",
|
||||
"没有改动的一律按「保留」:只有你点了「覆盖」的文件才会被包内内容替换。"
|
||||
),
|
||||
PackPickUnknownRemote => (
|
||||
"{count} remote entries only learn their path after download; they follow “keep”.",
|
||||
"还有 {count} 条远端条目要下载后才知道路径,一律按「保留」处置。"
|
||||
),
|
||||
PackPickSourceOverrides => ("in the pack (overrides/)", "包内 overrides/"),
|
||||
PackPickSourceClientOverrides => ("in the pack (client-overrides/)", "包内 client-overrides/"),
|
||||
PackPickSourceManifest => ("manifest files[]", "清单 files[]"),
|
||||
PackPickDisk => ("yours: {size}", "你的:{size}"),
|
||||
PackPickIncoming => ("pack: {size}", "包内:{size}"),
|
||||
PackFormatModrinth => ("Modrinth .mrpack", "Modrinth 的 .mrpack"),
|
||||
PackFormatCurseforge => ("CurseForge manifest", "CurseForge 清单"),
|
||||
PackFormatMultimc => ("MultiMC / Prism instance", "MultiMC·Prism 实例"),
|
||||
|
||||
Reference in new issue
Block a user