diff --git a/crates/app-iced/src/fonts/tests.rs b/crates/app-iced/src/fonts/tests.rs index 8d565ec..26ca8e0 100644 --- a/crates/app-iced/src/fonts/tests.rs +++ b/crates/app-iced/src/fonts/tests.rs @@ -270,10 +270,14 @@ fn evaluation_starts_no_download() { } /// 用 `current_exe()` 把本 test binary 再起一次,只跑 [`resolving_fonts_never_starts_a_download`]。 +/// +/// 子进程经 `unlucky_core::platform::child::quiet` 起(M272):仓规是全树硬约束,测试代码不是 +/// 例外——这条 test binary 本身是控制台程序,父进程将来若换到 GUI 侧(或 CI 用别的方式直接跑 +/// 二进制)也照样不该新建窗口。`quiet` 只动创建 flag,`.output()` 的管道语义一个字不变。 fn rerun_in_own_process() { let exe = std::env::current_exe().expect("取本 test binary 的路径"); let name = "fonts::tests::resolving_fonts_never_starts_a_download"; - let output = std::process::Command::new(&exe) + let output = unlucky_core::platform::child::quiet(&exe) .args(["--exact", "--nocapture", "--test-threads=1", name]) .env(CHILD_ENV, "1") // 截图通道的钉子会直接替换 `status()` 的返回值(`install.rs:157` 先看它), diff --git a/crates/app-iced/src/platform/motion.rs b/crates/app-iced/src/platform/motion.rs index b5ea1d1..99bc4f1 100644 --- a/crates/app-iced/src/platform/motion.rs +++ b/crates/app-iced/src/platform/motion.rs @@ -23,6 +23,15 @@ //! 它在 `on_boot` 跑一次;配置重载时读的是同一个缓存,不会重复 spawn)。 //! - 子进程有 [`COMMAND_TIMEOUT`] 上限:`gsettings` / `defaults` 在坏环境里会挂住, //! 超时按 `Unknown` 处理并 `kill` 掉。 +//! - 子进程经 `unlucky_core::platform::child::quiet` 起(M272):仓规「spawn 控制台程序必须走 +//! `quiet`」是全树硬约束(`crates/core/tests/child_quiet_guard.rs` 钉着),探针不是例外—— +//! 唯一调用点在这里。 +//! +//! ## `quiet` 不影响「可杀」 +//! +//! `child::quiet` 返回的就是普通 [`std::process::Command`](Windows 上多一个 +//! `CREATE_NO_WINDOW`,其它平台原样返回),`.spawn()` 拿到的 [`std::process::Child`] 仍归 +//! `run` 自己,所以 **300 ms 超时 + 超时 `kill` + `wait` 一个字没丢**。 //! //! | 平台 | 来源 | `unsafe` | //! |---|---|---| @@ -33,6 +42,9 @@ use std::sync::OnceLock; +#[cfg(any(target_os = "linux", target_os = "macos"))] +use unlucky_core::platform::child::quiet; + /// 系统偏好:「减少动效」是否要生效。 #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum ReduceMotion { @@ -169,13 +181,17 @@ fn detect() -> ReduceMotion { /// /// 为什么自己写而不是 `Command::output()`:`output()` 会一直等到子进程退出,坏环境里(没有 /// session bus 的 `gsettings`)就是无限期挂住——那会让**启动**卡死,是比"没有动效"严重得多的事故。 +/// +/// 子进程经 [`quiet`] 起(M272,仓规硬约束)。`quiet` 只改创建 flag、返回的仍是普通 +/// `std::process::Command`,所以下面这套自己写的等待循环拿得到 `Child` 句柄,**超时 `kill` +/// 照旧**——「安静」与「可杀」在这里不冲突。 #[cfg(any(target_os = "linux", target_os = "macos"))] fn run(program: &str, args: &[&str]) -> Option { use std::io::Read; - use std::process::{Command, Stdio}; + use std::process::Stdio; use std::time::{Duration, Instant}; - let mut child = Command::new(program) + let mut child = quiet(program) .args(args) .stdin(Stdio::null()) .stdout(Stdio::piped())