fix(coexist): r2 返工——帮助写真实例路径 + 加载器安装也说出「原版清单被替换」+ --json 给出绑定成败(M216)

r2 复审两条 P2 必修 + 一条「能一行接上就接」的 P3。

P2-1(`ull help pack` 的落点少一层 `.ULL/data`)
- 「数据根」在这份帮助自己的定义里是「含 `.ULL/` 与 `.minecraft/` 的父目录」(`--data-dir` 那行),
  所以真路径是 `<数据根>/.ULL/data/instances/<实例目录名>`。r1 写成 `<数据根>/instances/<实例名>`,
  照读会去一个不存在的位置找包内容。
- help.rs 与 model.rs 的字段文档改成真路径,并点明目录名是归一化后的结果(`Better-MC`)。
- 用例改成 `help_describes_the_new_default_target_with_the_real_path`:先断言真路径整串在、
  再断言 `<数据根>/instances/` **不在**(这一条就是抓「少写 .ULL/data」那种错法)。

P2-2(装加载器时原版那一步的「替换了清单」没人说)
- `loader.rs`:`plan.vanilla_install_needed` 那条路以前只拿 `vanilla_report` 判 `is_complete()`
  就丢掉;现在把它留在 `vanilla_report` 里传给 `report_loader::build`。
- `report_loader.rs`:`build` / `human_lines` 各多一个 `vanilla: Option<&InstallReport>`;
  新增 `vanilla_lines`(人读:`告警(原版): …` + `原版版本清单已替换(旧的那份备份在 …)`)与
  `vanilla_json`(`--json` 的 `vanilla` 段:warnings / version_json / manifest{kind,backup})。
- 用例 `a_replaced_vanilla_manifest_is_said_out_loud_in_the_loader_output`:用真
  `LoaderInstallPlan`(最小 Fabric,零网络)调 `human_lines`,断言告警与备份路径都在;
  未先装原版时不多说话;`vanilla_json` 的 `kind`/`backup` 结构正确、`None` 时没有该段。

P3(复审「能一行接上就接」):`--json` 给出导入绑定的**结构化成败**
- core `pack_dir::bind_created_instance` 返回 `Option<Result<String, String>>`(None=不需要绑 /
  Ok=已绑 / Err=绑失败),一句话就能分出成败,不必猜文案。
- CLI:`outcome` 多写一个 `"instance_bound": true|false`(人读行照旧给原因);
  GUI:`import.rs` 按 Ok/Err 分别记 `instance_bound` / `instance_binding_failed` 注记。
- 端到端用例里补断言 `data.instance_bound == true`。
This commit is contained in:
AskaEth committed 2026-11-09 20:43:46 +08:00
1 parent 4e1323212b
commit aa61565fe7
8 files changed
+188 -27

No files matched your search

+8 -5
View File
@@ -132,6 +132,9 @@ pub fn bind_instance_dir(
/// 导入收尾:把「我们新建出来的实例」绑到它的内容目录,返回一句给人读的结论。
///
/// 返回 `None` = 不需要绑;`Some(Ok(说明))` = 已绑;`Some(Err(说明))` = 绑失败(档案在、内容在,
/// 只是运行目录没指过来——调用方**别**把它当整次导入失败,但要让人看见)。
///
/// 判据(CLI 与 GUI 共用一份,别自己再写一遍):
/// - `auto_bound == false` ⇒ 不绑(用户显式给了目标目录 / `--no-register`:那目录可能是别人的
/// 运行目录,也可能被用户自己指过);
@@ -146,23 +149,23 @@ pub fn bind_created_instance(
target: &Path,
auto_bound: bool,
report: &crate::addon::import::ImportReport,
) -> Option<String> {
) -> Option<Result<String, String>> {
if !auto_bound {
return None;
}
let registered = report.registered.as_ref().filter(|item| item.created)?;
Some(
match bind_instance_dir(layout, &registered.id, &registered.version_id, target) {
Ok(()) => format!(
Ok(()) => Ok(format!(
"运行目录已指向 {}(实例 {})",
target.display(),
registered.name
),
)),
// 内容与档案都已就位,只是目录没指过来 ⇒ 不把整次导入判失败,但必须说出来。
Err(error) => format!(
Err(error) => Err(format!(
"实例已登记但没能绑到导入目录({error}):启动前请把该实例的运行目录指到 {}",
target.display()
),
)),
},
)
}