1use isoloom_manifest::Error as ManifestError;
4use isoloom_plan::Refusal;
5use isoloom_render::Error as RenderError;
6use isoloom_spec::model::Target;
7
8#[derive(Debug, thiserror::Error)]
10#[non_exhaustive]
11pub enum Error {
12 #[error("{}: {refusal}", target.id())]
14 Refused {
15 target: Target,
17 refusal: Refusal,
19 },
20 #[error("{}: the Compose file couldn't be written as YAML", target.id())]
22 Unwritable {
23 target: Target,
25 #[source]
27 source: serde_yaml_ng::Error,
28 },
29 #[error("{}: the run manifest refused a value of this backend", Target::Docker.id())]
32 Manifest {
33 #[source]
35 source: ManifestError,
36 },
37 #[error("the Compose file isn't YAML")]
39 Unreadable {
40 #[source]
42 source: serde_yaml_ng::Error,
43 },
44}
45
46pub type Result<T, E = Error> = std::result::Result<T, E>;
48
49impl From<ManifestError> for Error {
50 fn from(source: ManifestError) -> Error {
51 Error::Manifest { source }
52 }
53}
54
55impl From<Error> for RenderError {
56 fn from(e: Error) -> RenderError {
59 match e {
60 Error::Refused { target, refusal } => RenderError::Refused { target, refusal },
61 Error::Unwritable { target, source } => unsupported(target, source.to_string()),
62 Error::Manifest { source } => unsupported(Target::Docker, format!("the run manifest: {source}")),
63 Error::Unreadable { source } => unsupported(Target::Docker, format!("the Compose file isn't YAML: {source}")),
64 }
65 }
66}
67
68fn unsupported(target: Target, what: String) -> RenderError {
69 RenderError::Unsupported { target, what }
70}
71
72#[cfg(test)]
73mod tests {
74 use std::error::Error as _;
75
76 use isoloom_plan::Requirement;
77
78 use super::*;
79
80 #[test]
81 fn a_refusal_reads_the_same_as_the_backend_reports_it() {
82 let refusal = Refusal {
83 requirement: Requirement::EnvironmentProvisioning,
84 };
85 let e = Error::Refused {
86 target: Target::Hosted,
87 refusal: refusal.clone(),
88 };
89 assert_eq!(e.to_string(), format!("hosted: {refusal}"));
90 assert_eq!(RenderError::from(e).to_string(), format!("hosted: {refusal}"));
91 }
92
93 #[test]
94 fn a_manifest_bug_keeps_its_cause_and_names_the_run_manifest() {
95 let source = isoloom_manifest::LabName::parse("Not A Name").expect_err("refused");
96 let e = Error::from(source);
97 assert!(e.source().is_some());
98 let reported = RenderError::from(e).to_string();
99 assert!(reported.starts_with("docker: the run manifest: "), "{reported}");
100 }
101}