Skip to main content

only_engine/
error.rs

1use std::fmt;
2
3/// Engine-level runtime and host execution errors.
4///
5/// Args:
6/// None.
7///
8/// Returns:
9/// Stable typed error values for planner/runtime consumers.
10#[derive(Debug)]
11pub enum EngineError {
12    CommandFailed {
13        task: String,
14        step: usize,
15        total: usize,
16        command: String,
17        reason: String,
18    },
19    CommandBlockFailed {
20        task: String,
21        step: usize,
22        total: usize,
23        reason: String,
24    },
25    CommandBlockStartFailed {
26        shell: String,
27        source: Box<EngineError>,
28    },
29    Interpolation(String),
30    ShellNotFound(String),
31    UnsupportedShell(String),
32    Runtime(String),
33    Io {
34        message: &'static str,
35        path: String,
36        source: std::io::Error,
37    },
38}
39
40impl fmt::Display for EngineError {
41    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42        match self {
43            Self::CommandFailed {
44                task,
45                step,
46                total,
47                command: _,
48                reason,
49            } => write!(
50                f,
51                "task '{task}' failed at step [{step}/{total}] with {}",
52                reason
53            ),
54            Self::CommandBlockFailed {
55                task,
56                step,
57                total,
58                reason,
59            } => write!(
60                f,
61                "task '{task}' failed at step [{step}/{total}] with {}",
62                reason
63            ),
64            Self::CommandBlockStartFailed { shell, source } => {
65                write!(
66                    f,
67                    "could not start command block with shell '{shell}'\n{source}"
68                )
69            }
70            Self::Interpolation(message) => f.write_str(message),
71            Self::ShellNotFound(message) => f.write_str(message),
72            Self::UnsupportedShell(shell) => write!(f, "shell '{shell}' is not supported"),
73            Self::Runtime(message) => f.write_str(message),
74            Self::Io {
75                message,
76                path,
77                source,
78            } => write!(f, "{message}: {path}: {source}"),
79        }
80    }
81}
82
83pub(crate) fn command_block_failed(
84    task: &str,
85    step_index: usize,
86    step_total: usize,
87    reason: &str,
88) -> EngineError {
89    EngineError::CommandBlockFailed {
90        task: task.to_string(),
91        step: step_index,
92        total: step_total,
93        reason: reason.to_string(),
94    }
95}
96
97impl std::error::Error for EngineError {
98    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
99        match self {
100            Self::Io { source, .. } => Some(source),
101            Self::CommandBlockStartFailed { source, .. } => Some(source.as_ref()),
102            _ => None,
103        }
104    }
105}
106
107pub(crate) fn command_block_start_failed(shell: &str, source: EngineError) -> EngineError {
108    match source {
109        EngineError::ShellNotFound(_)
110        | EngineError::UnsupportedShell(_)
111        | EngineError::Io { .. } => EngineError::CommandBlockStartFailed {
112            shell: shell.to_string(),
113            source: Box::new(source),
114        },
115        other => other,
116    }
117}
118
119pub(crate) fn command_failed(
120    task: &str,
121    step_index: usize,
122    step_total: usize,
123    command: &str,
124    reason: &str,
125) -> EngineError {
126    EngineError::CommandFailed {
127        task: task.to_string(),
128        step: step_index,
129        total: step_total,
130        command: command.to_string(),
131        reason: reason.to_string(),
132    }
133}