Skip to main content

olai_stack_runtime/
error.rs

1//! The crate's [`Error`].
2
3use std::process::ExitStatus;
4
5/// What can go wrong driving a [`ComposeEngine`](crate::ComposeEngine).
6#[derive(Debug, thiserror::Error)]
7pub enum Error {
8    /// The engine can't be reached: the `docker` binary is missing, or its daemon isn't
9    /// running. Distinct from "nothing is running", which is an empty listing.
10    #[error("Docker is not available: {reason}")]
11    Unavailable {
12        /// Why, as the CLI or the OS put it.
13        reason: String,
14    },
15    /// A command ran and failed.
16    #[error("`{command}` failed ({status}){}", stderr_suffix(.stderr))]
17    Failed {
18        /// The command line, without the program (e.g. `compose up -d --wait`).
19        command: String,
20        /// Its exit status.
21        status: ExitStatus,
22        /// What it printed on stderr, when it was captured.
23        stderr: String,
24    },
25    /// A command's output didn't parse as expected.
26    #[error("parsing the output of `{command}`: {source}")]
27    Parse {
28        /// The command line, without the program.
29        command: String,
30        /// The JSON error.
31        #[source]
32        source: serde_json::Error,
33    },
34    /// Spawning or talking to a command failed for another reason.
35    #[error("running `{command}`: {source}")]
36    Io {
37        /// The command line, without the program.
38        command: String,
39        /// The I/O error.
40        #[source]
41        source: std::io::Error,
42    },
43}
44
45fn stderr_suffix(stderr: &str) -> String {
46    let stderr = stderr.trim();
47    if stderr.is_empty() {
48        String::new()
49    } else {
50        format!(": {stderr}")
51    }
52}
53
54impl Error {
55    /// Whether this is [`Error::Unavailable`].
56    pub fn is_unavailable(&self) -> bool {
57        matches!(self, Error::Unavailable { .. })
58    }
59}
60
61/// The crate's result type.
62pub type Result<T, E = Error> = std::result::Result<T, E>;