fix(core,cli): M231 复审三条 P2 —— 恢复误删用例 / 收窄 --dry-run 文案 / 判定链去重
P2-1:`natives_cases.rs` 里 `missing_native_jar_becomes_missing_component` 是上一轮 批量截断时**误伤**掉的(我把「tree_snapshot 之后的所有内容」整段砍掉,连带这条与 dry-run 无关的用例),不是有意删。现已从 main 原样贴回,`MissingNativeJar` / natives 组件缺失这条用户可见失败路径恢复覆盖。 P2-2:help 的「也不写盘」是过度承诺 —— `commands/launch.rs` 的 `launcher_log::set_dir` /`record_start`/`record` 都在 `if args.dry_run` 之前,dry-run 仍会 append `<数据根>/logs/launcher.log`(连父目录 create_dir_all)。文案收窄成「不碰版本树 (不解压 natives、不建 natives 目录);启动器自身的运行日志照记」。core 的 `DryRun` 文档同步加了「本层承诺 / 调用方日志另算」的边界。 P2-3:`extract` 与 `preview` 的「无 jar / 戳记命中 / 重解」判定链合成 `inspect()` 一份, 返回 `DirStatus`(NoJars / Ready(files) / Stale)+ 源 jar 指纹;两个入口只在这里分叉。 另:`tree_snapshot_notices_a_transient_directory` 在全量并行跑时偶发红(本轮门禁抓到 1 次, 单跑 3 次全绿)——「建了立刻删」对父目录 mtime 的影响会被 NTFS 合并。换成确定性自检 `tree_snapshot_sees_new_nodes_and_mtime_changes`(新节点 + 同内容重写的 mtime 变化), 并把这条能力边界写进 `tree_snapshot` 的「抓不住」。
This commit is contained in:
1 parent
1fa30c4885
commit
c917bfa18f
5 files changed
+134
-50
No files matched your search
@@ -91,11 +91,13 @@ impl LauncherConfig {
|
||||
}
|
||||
}
|
||||
|
||||
/// `--dry-run` 的输出(D18):完整命令行,但**不 spawn、不写会话文件、不落盘**。
|
||||
/// `--dry-run` 的输出(D18):完整命令行,但**不 spawn、不写会话文件、不碰磁盘**。
|
||||
///
|
||||
/// 环境准备(第 6 段)在 dry-run 下走 [`crate::launch::natives::preview`]:只算「会解出
|
||||
/// 几个原生库 / natives 目录是不是已经就绪」,**不建目录、不写文件、不删文件**——
|
||||
/// `--dry-run` 对版本树(尤其是别人铺的 `versions/<id>/`)是纯读的。
|
||||
/// 「不碰磁盘」是本层(core 启动管线)的承诺:环境准备(第 6 段)在 dry-run 下走
|
||||
/// [`crate::launch::natives::preview`],只算「会解出几个原生库 / natives 目录是不是
|
||||
/// 已经就绪」,**不建目录、不写文件、不删文件**——对版本树(尤其是别人铺的
|
||||
/// `versions/<id>/`)是纯读的。调用方自己的运行日志(CLI 的 `<数据根>/logs/launcher.log`)
|
||||
/// 不在此列。
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct DryRun {
|
||||
/// 实际要执行的程序。
|
||||
|
||||
@@ -227,6 +227,34 @@ pub fn collect(
|
||||
natives
|
||||
}
|
||||
|
||||
/// 目录状态的三种结论:两个入口共用一条判定链,别各写一份。
|
||||
enum DirStatus {
|
||||
/// 无需解压:1.19+ 没有 natives 分类器 jar,只要目录在。
|
||||
NoJars,
|
||||
/// 戳记与当前 jar 集一致:目录已就绪,上次解出 `usize` 个原生库。
|
||||
Ready(usize),
|
||||
/// 需要(重新)解压。
|
||||
Stale,
|
||||
}
|
||||
|
||||
/// 判定链 + 本次源 jar 指纹(真解压拿它写戳记,预览丢弃)。
|
||||
///
|
||||
/// `extract` 与 `preview` **只在这里**决定「要不要解压」:改判定只改这一处,
|
||||
/// 两边不会漂。
|
||||
fn inspect(dir: &Path, plan: &NativesPlan) -> (DirStatus, Vec<jar::JarStamp>) {
|
||||
let stamps = jar_stamps(&plan.jars);
|
||||
if plan.jars.is_empty() {
|
||||
return (DirStatus::NoJars, stamps);
|
||||
}
|
||||
let ready = read_stamp(dir)
|
||||
.filter(|stamp| stamp.matches(&stamps))
|
||||
.map(|stamp| stamp.files());
|
||||
match ready {
|
||||
Some(files) => (DirStatus::Ready(files), stamps),
|
||||
None => (DirStatus::Stale, stamps),
|
||||
}
|
||||
}
|
||||
|
||||
/// 解压一个计划(幂等:目录与源 jar 都没变时零写盘)。
|
||||
///
|
||||
/// `--dry-run` 不走这里,走 [`preview`]:那里一个字节都不写。
|
||||
@@ -254,18 +282,18 @@ pub fn extract(dir: &Path, plan: &NativesPlan) -> Result<NativesReport, NativesE
|
||||
std::fs::create_dir_all(dir)
|
||||
.map_err(|source| jar::io_error("create_natives_dir", dir, source))?;
|
||||
report.dir_exists = true;
|
||||
if plan.jars.is_empty() {
|
||||
report.up_to_date = true;
|
||||
return Ok(report);
|
||||
}
|
||||
|
||||
let stamps = jar_stamps(&plan.jars);
|
||||
if let Some(stamp) = read_stamp(dir) {
|
||||
if stamp.matches(&stamps) {
|
||||
let (status, stamps) = inspect(dir, plan);
|
||||
match status {
|
||||
DirStatus::NoJars => {
|
||||
report.up_to_date = true;
|
||||
report.skipped = stamp.files();
|
||||
return Ok(report);
|
||||
}
|
||||
DirStatus::Ready(files) => {
|
||||
report.up_to_date = true;
|
||||
report.skipped = files;
|
||||
return Ok(report);
|
||||
}
|
||||
DirStatus::Stale => {}
|
||||
}
|
||||
|
||||
// 源变了:先清旧原生库(避免两代 dll 混在同一个 java.library.path 里),再全量解。
|
||||
@@ -279,10 +307,10 @@ pub fn extract(dir: &Path, plan: &NativesPlan) -> Result<NativesReport, NativesE
|
||||
|
||||
/// 预览一个计划:算出「真启动会怎么解压」,**不建目录、不写文件、不删文件**。
|
||||
///
|
||||
/// `--dry-run` 的唯一环境准备入口。与 [`extract`] 共用口径:
|
||||
/// 无 jar(1.19+)= 无需解压;戳记与当前 jar 集一致 = 已就绪;否则读 jar 清点
|
||||
/// 「将写下几个原生库」。区别只有「不落盘」:没有 `create_dir_all`、没有 `clear_natives`、
|
||||
/// 没有 `write_stamp`,因此版本树的目录结构与父目录 mtime 都不动。
|
||||
/// `--dry-run` 的唯一环境准备入口。与 [`extract`] 共用判定链([`inspect`])与条目
|
||||
/// 筛选口径:无 jar(1.19+)= 无需解压;戳记与当前 jar 集一致 = 已就绪;否则读 jar
|
||||
/// 清点「将写下几个原生库」。区别只有「不落盘」:没有 `create_dir_all`、没有
|
||||
/// `clear_natives`、没有 `write_stamp`,因此版本树的目录结构与父目录 mtime 都不动。
|
||||
///
|
||||
/// jar 打不开 / 不是合法 zip 照样报错(与真启动同一条失败路径),预览不会藏坏包。
|
||||
///
|
||||
@@ -305,18 +333,18 @@ pub fn preview(dir: &Path, plan: &NativesPlan) -> Result<NativesReport, NativesE
|
||||
planned: true,
|
||||
dir_exists: dir.is_dir(),
|
||||
};
|
||||
if plan.jars.is_empty() {
|
||||
report.up_to_date = true;
|
||||
return Ok(report);
|
||||
}
|
||||
|
||||
let stamps = jar_stamps(&plan.jars);
|
||||
if let Some(stamp) = read_stamp(dir) {
|
||||
if stamp.matches(&stamps) {
|
||||
let (status, _stamps) = inspect(dir, plan);
|
||||
match status {
|
||||
DirStatus::NoJars => {
|
||||
report.up_to_date = true;
|
||||
report.skipped = stamp.files();
|
||||
return Ok(report);
|
||||
}
|
||||
DirStatus::Ready(files) => {
|
||||
report.up_to_date = true;
|
||||
report.skipped = files;
|
||||
return Ok(report);
|
||||
}
|
||||
DirStatus::Stale => {}
|
||||
}
|
||||
|
||||
for native in &plan.jars {
|
||||
|
||||
Reference in new issue
Block a user