Skip to main content

pitchfork_cli/
daemon_status.rs

1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Serialize, Deserialize, strum::Display, strum::EnumIs)]
4#[strum(serialize_all = "snake_case")]
5#[serde(rename_all = "snake_case")]
6pub enum DaemonStatus {
7    Failed(String),
8    Waiting,
9    Running,
10    Stopping,
11    /// Exit code of the process, or -1 if unknown.
12    Errored(i32),
13    Stopped,
14}
15
16impl DaemonStatus {
17    pub fn style(&self) -> String {
18        let s = self.to_string();
19        match self {
20            DaemonStatus::Failed(_) => console::style(s).red().to_string(),
21            DaemonStatus::Waiting => console::style(s).yellow().to_string(),
22            DaemonStatus::Running => console::style(s).green().to_string(),
23            DaemonStatus::Stopping => console::style(s).yellow().to_string(),
24            DaemonStatus::Stopped => console::style(s).dim().to_string(),
25            DaemonStatus::Errored(_) => console::style(s).red().to_string(),
26        }
27    }
28
29    pub fn error_message(&self) -> Option<String> {
30        match self {
31            DaemonStatus::Failed(msg) => Some(msg.clone()),
32            DaemonStatus::Errored(code) if *code != -1 => Some(format!("exit code {code}")),
33            DaemonStatus::Errored(_) => Some("unknown exit code".to_string()),
34            _ => None,
35        }
36    }
37}
38
39#[cfg(test)]
40mod tests {
41    use super::*;
42
43    fn all_variants() -> Vec<(&'static str, DaemonStatus)> {
44        vec![
45            ("running", DaemonStatus::Running),
46            ("stopped", DaemonStatus::Stopped),
47            ("waiting", DaemonStatus::Waiting),
48            ("stopping", DaemonStatus::Stopping),
49            ("failed", DaemonStatus::Failed("some error".to_string())),
50            ("errored", DaemonStatus::Errored(1)),
51            ("errored_unknown", DaemonStatus::Errored(-1)),
52        ]
53    }
54
55    #[test]
56    fn test_daemon_status_json_roundtrip() {
57        for (name, status) in all_variants() {
58            let json_str = serde_json::to_string(&status)
59                .unwrap_or_else(|_| panic!("Failed to serialize {name}"));
60            let result: Result<DaemonStatus, _> = serde_json::from_str(&json_str);
61            assert!(
62                result.is_ok(),
63                "Failed to deserialize {name}: {:?}",
64                result.err()
65            );
66        }
67    }
68
69    #[test]
70    fn test_daemon_status_toml_roundtrip() {
71        #[derive(Serialize, Deserialize, Debug)]
72        struct Wrapper {
73            status: DaemonStatus,
74        }
75
76        for (name, status) in all_variants() {
77            let w = Wrapper { status };
78            let toml_str =
79                toml::to_string(&w).unwrap_or_else(|e| panic!("Failed to serialize {name}: {e}"));
80            let result: Result<Wrapper, _> = toml::from_str(&toml_str);
81            assert!(
82                result.is_ok(),
83                "Failed to deserialize {name}: {:?}\nTOML was: {toml_str:?}",
84                result.err()
85            );
86        }
87    }
88}