Skip to main content

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}