1use std::fmt;
2
3#[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 TaskFailure {
30 source: Box<EngineError>,
31 message: String,
32 },
33 Interpolation(String),
34 ShellNotFound(String),
35 UnsupportedShell(String),
36 Runtime(String),
37 Io {
38 message: &'static str,
39 path: String,
40 source: std::io::Error,
41 },
42}
43
44impl fmt::Display for EngineError {
45 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
46 match self {
47 Self::CommandFailed {
48 task,
49 step,
50 total,
51 command: _,
52 reason,
53 } => write!(
54 f,
55 "task '{task}' failed at step [{step}/{total}] due to {}",
56 reason
57 ),
58 Self::CommandBlockFailed {
59 task,
60 step,
61 total,
62 reason,
63 } => write!(
64 f,
65 "task '{task}' failed at step [{step}/{total}] due to {}",
66 reason
67 ),
68 Self::CommandBlockStartFailed { shell, source } => {
69 write!(
70 f,
71 "could not start command block with shell '{shell}'\n{source}"
72 )
73 }
74 Self::TaskFailure { source, message } => write!(f, "{source}\n{message}"),
75 Self::Interpolation(message) => f.write_str(message),
76 Self::ShellNotFound(message) => f.write_str(message),
77 Self::UnsupportedShell(shell) => write!(f, "shell '{shell}' is not supported"),
78 Self::Runtime(message) => f.write_str(message),
79 Self::Io {
80 message,
81 path,
82 source,
83 } => write!(f, "{message}: {path}: {source}"),
84 }
85 }
86}
87
88pub(crate) fn command_block_failed(
89 task: &str,
90 step_index: usize,
91 step_total: usize,
92 reason: &str,
93) -> EngineError {
94 EngineError::CommandBlockFailed {
95 task: task.to_string(),
96 step: step_index,
97 total: step_total,
98 reason: reason.to_string(),
99 }
100}
101
102impl std::error::Error for EngineError {
103 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
104 match self {
105 Self::Io { source, .. } => Some(source),
106 Self::CommandBlockStartFailed { source, .. } | Self::TaskFailure { source, .. } => {
107 Some(source.as_ref())
108 }
109 _ => None,
110 }
111 }
112}
113
114pub(crate) fn command_block_start_failed(shell: &str, source: EngineError) -> EngineError {
115 match source {
116 EngineError::ShellNotFound(_)
117 | EngineError::UnsupportedShell(_)
118 | EngineError::Io { .. } => EngineError::CommandBlockStartFailed {
119 shell: shell.to_string(),
120 source: Box::new(source),
121 },
122 other => other,
123 }
124}
125
126pub(crate) fn task_failure(source: EngineError, message: String) -> EngineError {
127 EngineError::TaskFailure {
128 source: Box::new(source),
129 message,
130 }
131}
132
133pub(crate) fn command_failed(
134 task: &str,
135 step_index: usize,
136 step_total: usize,
137 command: &str,
138 reason: &str,
139) -> EngineError {
140 EngineError::CommandFailed {
141 task: task.to_string(),
142 step: step_index,
143 total: step_total,
144 command: command.to_string(),
145 reason: reason.to_string(),
146 }
147}