Merge branch 'feat/m291-quietspawn-route-presenter-junction'
Guards / 依赖许可与来源(cargo-deny) (push) Canceled after 0s
Guards / 文件行数 ≤400 守门 (push) Canceled after 0s
Guards / unsafe 落点守门(集合必须恰好等于期望) (push) Canceled after 0s
Guards / design 零第三方依赖守门 (push) Canceled after 0s
Guards / presenter 零 UI 守门 (push) Canceled after 0s
Guards / core 零 UI 守门 (push) Canceled after 0s
Dev Guards / 架构与合规守门(同 main 口径) (push) Canceled after 0s
GPU evidence / GPU 证据 — 真实产物判据 (push) Canceled after 0s
GPU evidence / GPU 证据 — 探测可用产物与硬件适配器 (push) Canceled after 0s
GPU evidence / GPU 判据自测(不需 GPU;跳过 ≠ 已验证) (push) Canceled after 0s
Dev Guards / GPU 证据门禁(同 main 口径;无 GPU 只跑自测) (push) Canceled after 0s
Dev Guards / fmt (rustfmt --check) (push) Canceled after 0s
Dev Guards / clippy (ubuntu) (push) Canceled after 0s
Guards / 依赖许可与来源(cargo-deny) (push) Canceled after 0s
Guards / 文件行数 ≤400 守门 (push) Canceled after 0s
Guards / unsafe 落点守门(集合必须恰好等于期望) (push) Canceled after 0s
Guards / design 零第三方依赖守门 (push) Canceled after 0s
Guards / presenter 零 UI 守门 (push) Canceled after 0s
Guards / core 零 UI 守门 (push) Canceled after 0s
Dev Guards / 架构与合规守门(同 main 口径) (push) Canceled after 0s
GPU evidence / GPU 证据 — 真实产物判据 (push) Canceled after 0s
GPU evidence / GPU 证据 — 探测可用产物与硬件适配器 (push) Canceled after 0s
GPU evidence / GPU 判据自测(不需 GPU;跳过 ≠ 已验证) (push) Canceled after 0s
Dev Guards / GPU 证据门禁(同 main 口径;无 GPU 只跑自测) (push) Canceled after 0s
Dev Guards / fmt (rustfmt --check) (push) Canceled after 0s
Dev Guards / clippy (ubuntu) (push) Canceled after 0s
This commit is contained in:
commit
bba98d5898
3 files changed
+37
-40
No files matched your search
@@ -30,10 +30,10 @@
|
|||||||
//! `creation_flags(CREATE_NO_WINDOW)` ⇒ [`the_constructor_actually_passes_create_no_window`] 红;
|
//! `creation_flags(CREATE_NO_WINDOW)` ⇒ [`the_constructor_actually_passes_create_no_window`] 红;
|
||||||
//! ④`game/java/discover.rs` 的 `quiet("reg")` 改回裸构造 ⇒ 必须红(见 P1-1)。
|
//! ④`game/java/discover.rs` 的 `quiet("reg")` 改回裸构造 ⇒ 必须红(见 P1-1)。
|
||||||
//!
|
//!
|
||||||
//! M217(落在**此前不在射程内**的 crate 上):⑤`presenter/src/host/env.rs` 塞裸
|
//! M217(此前不在射程内的 crate):⑤`presenter/src/host/env.rs` 塞裸 `Command::new("tzutil")`
|
||||||
//! `Command::new("tzutil")` ⇒ 红并点名 `crates/presenter/src/host/env.rs:<行>`;⑥
|
//! ⇒ 红并点名 `crates/presenter/src/host/env.rs:<行>`;⑥`app-iced/src/platform/locale.rs` 的
|
||||||
//! `app-iced/src/platform/locale.rs` 的 `quiet(program)` 改回裸构造 ⇒ 红(用户报的那处
|
//! `quiet(program)` 改回裸构造 ⇒ 红(用户报的 `reg.exe`);⑦`export.rs` 三个 opener 留裸 +
|
||||||
//! `reg.exe`);⑦`export.rs` 三个 opener 留裸 + 清单写明理由 ⇒ **不**红。
|
//! 理由 ⇒ **不**红;⑧M291:`roots.rs::make_dir_link` 改回裸构造 ⇒ 红并点名(收并后仅 1 处)。
|
||||||
//!
|
//!
|
||||||
//! ## P1-1:守卫自己被变异验了两遍才对的
|
//! ## P1-1:守卫自己被变异验了两遍才对的
|
||||||
//!
|
//!
|
||||||
|
|||||||
@@ -38,7 +38,8 @@
|
|||||||
//! # 只读
|
//! # 只读
|
||||||
//!
|
//!
|
||||||
//! 本模块只 `is_dir()` / `canonicalize()`:不建目录、不写一个字节。官方启动器那个根上尤其要紧
|
//! 本模块只 `is_dir()` / `canonicalize()`:不建目录、不写一个字节。官方启动器那个根上尤其要紧
|
||||||
//! ——那是**别人的**目录。
|
//! ——那是**别人的**目录。(唯一的例外是 `#[cfg(test)]` 的 [`make_dir_link`]:它只在用例自己的
|
||||||
|
//! 临时目录里造链接,不属于任何产品路径。)
|
||||||
|
|
||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeSet;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
@@ -131,6 +132,31 @@ pub(in crate::host) fn key_of(path: &Path) -> String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 造一个目录链接:Windows 用 junction(无管理员权限也能建),Unix 用符号链接。造不出来返回 `false`。
|
||||||
|
///
|
||||||
|
/// 模块级而不是 `mod tests` 里,因为 [`super::tests_multiroot`] 的判据②也要造链接(M291):两处
|
||||||
|
/// 各写一份一字不差的 `cmd /c mklink /J` 只是把同一个坑埋两遍,`child_quiet_guard` 也是一次抓两处。
|
||||||
|
/// 可见性只开到 `super`(`host::game`)——两个调用方都是它的直接子模块。
|
||||||
|
///
|
||||||
|
/// 走 [`unlucky_core::platform::child::quiet`]:本仓库的 exe 是 GUI 程序(PE Subsystem = 2),
|
||||||
|
/// spawn `cmd.exe` 这种控制台程序时 Windows 会新开一块控制台(桌面上「黑框闪一下」)。
|
||||||
|
/// 语义不变:只看退出码(`.status()`),不读输出,失败一律 `false`。
|
||||||
|
#[cfg(all(test, windows))]
|
||||||
|
pub(super) fn make_dir_link(link: &Path, target: &Path) -> bool {
|
||||||
|
unlucky_core::platform::child::quiet("cmd")
|
||||||
|
.args(["/c", "mklink", "/J"])
|
||||||
|
.arg(link)
|
||||||
|
.arg(target)
|
||||||
|
.status()
|
||||||
|
.map(|status| status.success())
|
||||||
|
.unwrap_or(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(test, not(windows)))]
|
||||||
|
pub(super) fn make_dir_link(link: &Path, target: &Path) -> bool {
|
||||||
|
std::os::unix::fs::symlink(target, link).is_ok()
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
@@ -168,7 +194,9 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn junction_to_the_same_folder_is_one_root() {
|
fn junction_to_the_same_folder_is_one_root() {
|
||||||
let root = temp_root("ull-roots-junction");
|
let root = temp_root("ull-roots-junction");
|
||||||
let target = root.join("official/.minecraft");
|
// 逐段 `join`:`join("official/.minecraft")` 会留下正斜杠,而 `cmd` 把 `/` 当开关前缀,
|
||||||
|
// `mklink` 于是报「无效语法」⇒ 这条用例一直走的是下面的「跳过」分支(M291 实测)。
|
||||||
|
let target = root.join("official").join(".minecraft");
|
||||||
std::fs::create_dir_all(target.join("versions")).expect("建目录");
|
std::fs::create_dir_all(target.join("versions")).expect("建目录");
|
||||||
let link = root.join("linked");
|
let link = root.join("linked");
|
||||||
if !make_dir_link(&link, &target) {
|
if !make_dir_link(&link, &target) {
|
||||||
@@ -186,21 +214,4 @@ mod tests {
|
|||||||
);
|
);
|
||||||
std::fs::remove_dir_all(&root).ok();
|
std::fs::remove_dir_all(&root).ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 造一个目录链接:Windows 用 junction(无管理员权限也能建),Unix 用符号链接。
|
|
||||||
#[cfg(windows)]
|
|
||||||
fn make_dir_link(link: &Path, target: &Path) -> bool {
|
|
||||||
std::process::Command::new("cmd")
|
|
||||||
.args(["/c", "mklink", "/J"])
|
|
||||||
.arg(link)
|
|
||||||
.arg(target)
|
|
||||||
.status()
|
|
||||||
.map(|status| status.success())
|
|
||||||
.unwrap_or(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(windows))]
|
|
||||||
fn make_dir_link(link: &Path, target: &Path) -> bool {
|
|
||||||
std::os::unix::fs::symlink(target, link).is_ok()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -77,22 +77,8 @@ fn write_world(root: &Path, name: &str) {
|
|||||||
std::fs::write(dir.join("level.dat"), b"fixture").expect("level.dat");
|
std::fs::write(dir.join("level.dat"), b"fixture").expect("level.dat");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 目录链接(Windows 用 junction:不需要管理员;其它平台符号链接)。造不出来返回 `false`。
|
// 目录链接夹具走 `host::game::roots::make_dir_link`——一份代码两处共用(M291)。别在这里再写一份
|
||||||
#[cfg(windows)]
|
// `cmd /c mklink /J`:多一个 spawn 点就多一个绕过 `platform::child::quiet` 的机会。
|
||||||
fn link_dir(link: &Path, target: &Path) -> bool {
|
|
||||||
std::process::Command::new("cmd")
|
|
||||||
.args(["/c", "mklink", "/J"])
|
|
||||||
.arg(link)
|
|
||||||
.arg(target)
|
|
||||||
.status()
|
|
||||||
.map(|status| status.success())
|
|
||||||
.unwrap_or(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(windows))]
|
|
||||||
fn link_dir(link: &Path, target: &Path) -> bool {
|
|
||||||
std::os::unix::fs::symlink(target, link).is_ok()
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------ 判据①:两个根各一条
|
// ------------------------------------------------------------------ 判据①:两个根各一条
|
||||||
|
|
||||||
@@ -194,7 +180,7 @@ fn a_junction_to_the_configured_root_is_not_a_second_root() {
|
|||||||
let mut env = HostEnv::at_root(&root.0);
|
let mut env = HostEnv::at_root(&root.0);
|
||||||
write_version(&env.game, "A");
|
write_version(&env.game, "A");
|
||||||
let link = root.0.join("linked");
|
let link = root.0.join("linked");
|
||||||
if !link_dir(&link, env.game.root()) {
|
if !super::roots::make_dir_link(&link, env.game.root()) {
|
||||||
// 造不出链接就**不假绿**:这一条判据在造不出链接的盘上等于没验。
|
// 造不出链接就**不假绿**:这一条判据在造不出链接的盘上等于没验。
|
||||||
eprintln!("跳过:这个环境造不出目录链接({})", link.display());
|
eprintln!("跳过:这个环境造不出目录链接({})", link.display());
|
||||||
return;
|
return;
|
||||||
|
|||||||
Reference in new issue
Block a user