1use std::fmt;
2use std::process::ExitCode;
3
4#[derive(Debug)]
12pub enum EngineError {
13 CommandFailed {
14 task: String,
15 step: usize,
16 total: usize,
17 command: String,
18 code: ExitCode,
19 },
20 Interpolation(String),
21 ShellNotFound(String),
22 UnsupportedShell(String),
23 Runtime(String),
24 Io {
25 message: &'static str,
26 path: String,
27 source: std::io::Error,
28 },
29}
30
31impl fmt::Display for EngineError {
32 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
33 match self {
34 Self::CommandFailed {
35 task,
36 step,
37 total,
38 command,
39 code,
40 } => write!(
41 f,
42 "task '{task}' failed at step [{step}/{total}] while running `{command}` with exit code {code:?}"
43 ),
44 Self::Interpolation(message) => f.write_str(message),
45 Self::ShellNotFound(message) => f.write_str(message),
46 Self::UnsupportedShell(shell) => write!(f, "unsupported shell '{shell}'"),
47 Self::Runtime(message) => f.write_str(message),
48 Self::Io {
49 message,
50 path,
51 source,
52 } => write!(f, "{message}: {path}: {source}"),
53 }
54 }
55}
56
57impl std::error::Error for EngineError {
58 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
59 match self {
60 Self::Io { source, .. } => Some(source),
61 _ => None,
62 }
63 }
64}
65
66pub(crate) fn command_failed(
67 task: &str,
68 step_index: usize,
69 step_total: usize,
70 command: &str,
71 code: ExitCode,
72) -> EngineError {
73 EngineError::CommandFailed {
74 task: task.to_string(),
75 step: step_index,
76 total: step_total,
77 command: command.to_string(),
78 code,
79 }
80}