Skip to content

Commit a0edd32

Browse files
committed
refactor: simplify process stop flow and harden workspace root checks
1 parent 27925b4 commit a0edd32

2 files changed

Lines changed: 70 additions & 56 deletions

File tree

scripts/ci/cleanup-dmg.sh

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,47 @@ rw_dmg_image_prefix="${ASTRBOT_DESKTOP_MACOS_RW_DMG_IMAGE_PREFIX:-/src-tauri/tar
2727
rw_dmg_image_suffix_regex="${ASTRBOT_DESKTOP_MACOS_RW_DMG_IMAGE_SUFFIX_REGEX:-/bundle/macos/rw\\..*\\.dmg$}"
2828
rw_dmg_mountpoint_regex="${ASTRBOT_DESKTOP_MACOS_RW_DMG_MOUNT_REGEX:-^/Volumes/(dmg\\.|rw\\.|dmg-|rw-).*}"
2929
allow_global_helper_cleanup="${ASTRBOT_DESKTOP_MACOS_ALLOW_GLOBAL_HELPER_KILL:-0}"
30+
strict_workspace_root="${ASTRBOT_DESKTOP_MACOS_STRICT_WORKSPACE_ROOT:-}"
31+
32+
if [ -z "${strict_workspace_root}" ]; then
33+
if [ -n "${GITHUB_ACTIONS:-}" ]; then
34+
strict_workspace_root="0"
35+
else
36+
strict_workspace_root="1"
37+
fi
38+
else
39+
case "${strict_workspace_root}" in
40+
1|true|TRUE|yes|YES) strict_workspace_root="1" ;;
41+
0|false|FALSE|no|NO) strict_workspace_root="0" ;;
42+
*)
43+
echo "WARN: invalid ASTRBOT_DESKTOP_MACOS_STRICT_WORKSPACE_ROOT=${strict_workspace_root}; fallback to strict mode." >&2
44+
strict_workspace_root="1"
45+
;;
46+
esac
47+
fi
48+
49+
fail_or_skip_workspace_root() {
50+
local message="$1"
51+
if [ "${strict_workspace_root}" = "1" ]; then
52+
echo "ERROR: ${message}" >&2
53+
return 1
54+
fi
55+
echo "WARN: ${message}; skip DMG cleanup." >&2
56+
return 0
57+
}
58+
3059
if [ -n "${ASTRBOT_DESKTOP_MACOS_WORKSPACE_ROOT:-}" ]; then
3160
workspace_root="${ASTRBOT_DESKTOP_MACOS_WORKSPACE_ROOT}"
3261
elif [ -n "${GITHUB_WORKSPACE:-}" ]; then
3362
workspace_root="${GITHUB_WORKSPACE}"
3463
else
35-
echo "WARN: ASTRBOT_DESKTOP_MACOS_WORKSPACE_ROOT is required outside GitHub Actions; skip DMG cleanup." >&2
64+
fail_or_skip_workspace_root \
65+
"ASTRBOT_DESKTOP_MACOS_WORKSPACE_ROOT is required outside GitHub Actions" || exit 1
3666
exit 0
3767
fi
3868
workspace_root="${workspace_root%/}"
3969
if [ -z "${workspace_root}" ] || [ ! -d "${workspace_root}" ]; then
40-
echo "WARN: workspace root is invalid (${workspace_root}); skip DMG cleanup." >&2
70+
fail_or_skip_workspace_root "workspace root is invalid (${workspace_root})" || exit 1
4171
exit 0
4272
fi
4373

src-tauri/src/main.rs

Lines changed: 38 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -2417,78 +2417,62 @@ fn log_status(label: &str, pid: u32, status: &io::Result<ExitStatus>) {
24172417
}
24182418
}
24192419

2420-
struct StopCommandConfig<'a> {
2421-
max_followup: Duration,
2422-
label_graceful: &'a str,
2423-
label_force: &'a str,
2424-
subject: &'a str,
2425-
}
2426-
2427-
fn stop_child_process_impl(
2428-
child: &mut Child,
2429-
timeout: Duration,
2430-
graceful_cmd: impl FnOnce(&str) -> Command,
2431-
force_cmd: impl FnOnce(&str) -> Command,
2432-
config: StopCommandConfig<'_>,
2433-
) -> bool {
2420+
/// Attempt to stop a child process gracefully within `timeout`.
2421+
///
2422+
/// On the force-kill path, a follow-up wait is derived from `timeout` (`timeout / 4`)
2423+
/// and capped per-platform:
2424+
/// - Windows: up to 2200ms.
2425+
/// - Non-Windows: up to 1500ms.
2426+
#[cfg(target_os = "windows")]
2427+
fn stop_child_process_gracefully(child: &mut Child, timeout: Duration) -> bool {
24342428
let pid = child.id();
24352429
let pid_arg = pid.to_string();
24362430

2437-
let graceful_status = graceful_cmd(pid_arg.as_str()).status();
2438-
log_status(config.label_graceful, pid, &graceful_status);
2431+
let graceful_status = build_stop_command("taskkill", &["/pid", &pid_arg, "/t"]).status();
2432+
log_status("taskkill graceful stop", pid, &graceful_status);
24392433

24402434
if wait_for_child_exit(child, timeout) {
24412435
return true;
24422436
}
24432437

2444-
let force_status = force_cmd(pid_arg.as_str()).status();
2445-
log_status(config.label_force, pid, &force_status);
2438+
let force_status = build_stop_command("taskkill", &["/pid", &pid_arg, "/t", "/f"]).status();
2439+
log_status("taskkill force stop", pid, &force_status);
24462440

2447-
let followup_wait = derive_force_stop_wait(timeout, config.max_followup);
2441+
let followup_wait = derive_force_stop_wait(
2442+
timeout,
2443+
Duration::from_millis(FORCE_STOP_WAIT_MAX_WINDOWS_MS),
2444+
);
24482445
append_desktop_log(&format!(
2449-
"{} graceful stop timed out, force-kill issued: pid={pid}, graceful={graceful_status:?}, force={force_status:?}, followup_wait_ms={}",
2450-
config.subject,
2446+
"child graceful stop timed out, force-kill issued: pid={pid}, graceful={graceful_status:?}, force={force_status:?}, followup_wait_ms={}",
24512447
followup_wait.as_millis(),
24522448
));
24532449
wait_for_child_exit(child, followup_wait)
24542450
}
24552451

2456-
/// Attempt to stop a child process gracefully within `timeout`.
2457-
///
2458-
/// On the force-kill path, a follow-up wait is derived from `timeout` (`timeout / 4`)
2459-
/// and capped per-platform:
2460-
/// - Windows: up to 2200ms.
2461-
/// - Non-Windows: up to 1500ms.
2462-
#[cfg(target_os = "windows")]
2463-
fn stop_child_process_gracefully(child: &mut Child, timeout: Duration) -> bool {
2464-
stop_child_process_impl(
2465-
child,
2466-
timeout,
2467-
|pid_arg| build_stop_command("taskkill", &["/pid", pid_arg, "/t"]),
2468-
|pid_arg| build_stop_command("taskkill", &["/pid", pid_arg, "/t", "/f"]),
2469-
StopCommandConfig {
2470-
max_followup: Duration::from_millis(FORCE_STOP_WAIT_MAX_WINDOWS_MS),
2471-
label_graceful: "taskkill graceful stop",
2472-
label_force: "taskkill force stop",
2473-
subject: "child",
2474-
},
2475-
)
2476-
}
2477-
24782452
#[cfg(not(target_os = "windows"))]
24792453
fn stop_child_process_gracefully(child: &mut Child, timeout: Duration) -> bool {
2480-
stop_child_process_impl(
2481-
child,
2454+
let pid = child.id();
2455+
let pid_arg = pid.to_string();
2456+
2457+
let graceful_status = build_stop_command("kill", &["-TERM", &pid_arg]).status();
2458+
log_status("kill -TERM", pid, &graceful_status);
2459+
2460+
if wait_for_child_exit(child, timeout) {
2461+
return true;
2462+
}
2463+
2464+
let force_status = build_stop_command("kill", &["-KILL", &pid_arg]).status();
2465+
log_status("kill -KILL", pid, &force_status);
2466+
2467+
let followup_wait = derive_force_stop_wait(
24822468
timeout,
2483-
|pid_arg| build_stop_command("kill", &["-TERM", pid_arg]),
2484-
|pid_arg| build_stop_command("kill", &["-KILL", pid_arg]),
2485-
StopCommandConfig {
2486-
max_followup: Duration::from_millis(FORCE_STOP_WAIT_MAX_NON_WINDOWS_MS),
2487-
label_graceful: "kill -TERM",
2488-
label_force: "kill -KILL",
2489-
subject: "child",
2490-
},
2491-
)
2469+
Duration::from_millis(FORCE_STOP_WAIT_MAX_NON_WINDOWS_MS),
2470+
);
2471+
append_desktop_log(&format!(
2472+
"child graceful stop timed out, force-kill issued: pid={pid}, graceful={graceful_status:?}, force={force_status:?}, followup_wait_ms={}",
2473+
followup_wait.as_millis(),
2474+
));
2475+
wait_for_child_exit(child, followup_wait)
24922476
}
24932477

24942478
fn build_debug_command(plan: &LaunchPlan) -> Vec<String> {

0 commit comments

Comments
 (0)