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>;