cabin_core/process.rs
1//! Shared classification of a child process's exit status.
2//!
3//! Cabin spawns external tools (formatters, linters, the C/C++
4//! toolchain) and needs to report *how* they exited without leaking
5//! platform-specific `ExitStatus` details into its own error and
6//! report types. [`ExitStatusKind`] is that stable, serializable-free
7//! summary; [`exit_status_kind`] derives it once at the spawn site.
8
9/// Stringified exit-status kind preserved so the orchestration layer
10/// can decide whether to display an exit code or a signal.
11#[derive(Debug, Clone, PartialEq, Eq)]
12pub enum ExitStatusKind {
13 /// The process exited normally with this code.
14 Code(i32),
15 /// The process was terminated by a signal (Unix only).
16 Signal(String),
17 /// The process exited with neither a code nor a signal;
18 /// preserved as a fallback only.
19 Unknown,
20}
21
22impl std::fmt::Display for ExitStatusKind {
23 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
24 match self {
25 ExitStatusKind::Code(c) => write!(f, "{c}"),
26 ExitStatusKind::Signal(s) => write!(f, "signal {s}"),
27 ExitStatusKind::Unknown => write!(f, "<unknown>"),
28 }
29 }
30}
31
32/// Classify a finished [`std::process::ExitStatus`] into an
33/// [`ExitStatusKind`], preferring the exit code and falling back to the
34/// terminating signal on Unix.
35pub fn exit_status_kind(status: std::process::ExitStatus) -> ExitStatusKind {
36 if let Some(code) = status.code() {
37 return ExitStatusKind::Code(code);
38 }
39 #[cfg(unix)]
40 {
41 use std::os::unix::process::ExitStatusExt;
42 if let Some(sig) = status.signal() {
43 return ExitStatusKind::Signal(sig.to_string());
44 }
45 }
46 ExitStatusKind::Unknown
47}