1use std::fmt::Formatter;
25
26use getset::Getters;
27use itertools::fold;
28use std::fmt::Display;
29use std::io::Error as IoError;
30use strict_yaml_rust::ScanError;
31use strict_yaml_rust::StrictYaml;
32use subprocess::ExitStatus;
33
34pub fn process_until_first_err<I, F, E>(iterable: I, mut process_function: F) -> Result<(), E>
38where
39 I: IntoIterator,
40 F: FnMut(I::Item) -> Result<(), E>,
41{
42 fold(iterable, Ok(()), |prev_res, item| match prev_res {
43 Ok(()) => process_function(item),
44 Err(err) => Err(err),
45 })
46}
47
48pub fn fold_until_first_err<I, Folded, Processed, F, P, E>(
52 iterable: I,
53 init: Result<Folded, E>,
54 process_function: P,
55 mut fold_function: F,
56) -> Result<Folded, E>
57where
58 I: IntoIterator,
59 F: FnMut(Folded, Processed) -> Result<Folded, E>,
60 P: FnMut(I::Item) -> Result<Processed, E>,
61{
62 let processed_vec_res: Result<Vec<Processed>, E> =
63 iterable.into_iter().map(process_function).collect();
64
65 processed_vec_res.and_then(|processed_vec| {
66 fold(processed_vec, init, |prev_res, item| match prev_res {
67 Ok(prev_folded) => fold_function(prev_folded, item),
68 Err(err) => Err(err),
69 })
70 })
71}
72
73#[derive(Debug)]
75pub enum ErrorType {
76 ExecutionError {
78 io_error: Option<IoError>,
81 exit_status: Option<ExitStatus>,
84 },
85 FileSystemError {
88 fs_error: std::io::Error,
90 },
91 InconsistentConfigurationError,
93 IncompleteConfigurationError {
95 missing_field: String,
97 },
98 YamlParseError {
100 scan_error: ScanError,
102 },
103 UnexpectedYamlTypeError {
105 encountered: Box<StrictYaml>,
107 expected: Box<StrictYaml>,
109 },
110 CoreError,
112 TestingErrorActionSucceedsWhenItShouldFail,
114}
115
116impl Display for ErrorType {
117 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
118 write!(
119 f,
120 "{}",
121 match self {
122 ErrorType::ExecutionError {
123 io_error: _,
124 exit_status: _,
125 } => "ExecutionError",
126 ErrorType::FileSystemError { fs_error: _ } => "FileSystemError",
127 ErrorType::InconsistentConfigurationError => "InconsistentConfigurationError",
128 ErrorType::IncompleteConfigurationError { missing_field: _ } =>
129 "IncompleteConfigurationError",
130 ErrorType::YamlParseError { scan_error: _ } => "YamlParseError",
131 ErrorType::UnexpectedYamlTypeError {
132 encountered: _,
133 expected: _,
134 } => "UnexpectedYamlTypeError",
135 ErrorType::CoreError => "CoreError",
136 ErrorType::TestingErrorActionSucceedsWhenItShouldFail =>
137 "TestingErrorActionSucceedsWhenItShouldFail",
138 }
139 )
140 }
141}
142
143pub fn execution_error(io_error: Option<IoError>, exit_status: Option<ExitStatus>) -> ErrorType {
145 ErrorType::ExecutionError {
146 io_error,
147 exit_status,
148 }
149}
150
151#[derive(Getters, Debug)]
153pub struct DotfilesError {
154 #[getset(get = "pub")]
156 message: String,
157 #[getset(get = "pub")]
159 error_type: ErrorType,
160}
161
162impl Display for DotfilesError {
163 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
164 write!(f, "{}: {}", self.error_type(), self.message())
165 }
166}
167
168impl DotfilesError {
169 pub fn add_message_prefix(&mut self, prefix: String) {
171 self.message = format!("{prefix}: {}", self.message,);
172 }
173 pub fn is_missing_config(&self, config_name: &str) -> bool {
175 match &self.error_type {
176 ErrorType::IncompleteConfigurationError { missing_field } => missing_field == config_name,
177 _ => false,
178 }
179 }
180
181 pub fn is_wrong_yaml(&self) -> bool {
183 matches!(
184 &self.error_type,
185 ErrorType::UnexpectedYamlTypeError {
186 encountered: _,
187 expected: _,
188 }
189 )
190 }
191
192 pub fn is_yaml_parse_error(&self) -> bool {
194 matches!(
195 &self.error_type,
196 ErrorType::YamlParseError { scan_error: _ }
197 )
198 }
199
200 pub fn is_inconsistent_config(&self) -> bool {
202 matches!(&self.error_type, ErrorType::InconsistentConfigurationError)
203 }
204 pub fn is_fs_error(&self) -> bool {
206 matches!(&self.error_type, ErrorType::FileSystemError { fs_error: _ })
207 }
208
209 pub fn from(message: String, error_type: ErrorType) -> Self {
211 DotfilesError {
212 message,
213 error_type,
214 }
215 }
216
217 pub fn from_wrong_yaml(
219 message: String,
220 wrong_yaml: StrictYaml,
221 expected_type: StrictYaml,
222 ) -> Self {
223 DotfilesError {
224 message,
225 error_type: ErrorType::UnexpectedYamlTypeError {
226 encountered: Box::new(wrong_yaml),
227 expected: Box::new(expected_type),
228 },
229 }
230 }
231 pub fn from_io_error(io_error: std::io::Error) -> Self {
233 DotfilesError {
234 message: io_error.to_string(),
235 error_type: ErrorType::FileSystemError { fs_error: io_error },
236 }
237 }
238}