1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
//! Why the command line stopped: one enum for the binary. Its message is the line printed after
//! `error: `; the runner's errors already say their cause.
use isothrum_runner::ErrorCode;
use crate::cancel::Signal;
/// The binary's result.
pub(crate) type Result<T, E = Error> = std::result::Result<T, E>;
/// Why a command failed.
#[derive(Debug, thiserror::Error)]
pub(crate) enum Error {
/// The command line doesn't make sense (a run with no manifest, a value missing).
#[error("{0}")]
Usage(String),
/// The runner refused or failed.
#[error(transparent)]
Runner(#[from] isothrum_runner::Error),
/// A folder the command reads couldn't be read.
#[error("{} couldn't be read: {source}", path.display())]
Read {
/// The folder.
path: std::path::PathBuf,
/// The OS's reason.
#[source]
source: std::io::Error,
},
/// Writing the output failed (not because its reader left: that ends nothing).
#[error("writing the output failed: {0}")]
Output(#[source] std::io::Error),
/// A run's status or event couldn't be written as JSON.
#[error("writing JSON failed: {0}")]
Json(#[from] serde_json::Error),
/// A signal asked the command to stop; the operation in flight was dropped, and the tools it
/// started stopped with it.
#[error("cancelled by {}: the tools the command started were stopped", .0.name())]
Cancelled(Signal),
}
impl Error {
/// The code an `error` event gives it: the runner's own, else the closest one.
pub(crate) fn code(&self) -> ErrorCode {
match self {
Error::Usage(_) => ErrorCode::Usage,
Error::Runner(e) => e.code(),
Error::Read { .. } | Error::Output(_) | Error::Json(_) => ErrorCode::Io,
Error::Cancelled(_) => ErrorCode::Cancelled,
}
}
}