1use std::path::PathBuf;
2
3use alpm_parsers::error::{Input, ParseStack};
4use fluent_i18n::t;
5use winnow::error::ParseError;
6
7use crate::Architecture;
8
9#[derive(Debug, thiserror::Error)]
19pub enum Error {
20 #[error("{msg}", msg = t!("error-database", { "error" => .0.to_string() }))]
22 Database(#[from] crate::database::Error),
23
24 #[error("{msg}", msg = t!("error-invalid-architectures", {
26 "architectures" => format!("{architectures:?}"),
27 "context" => context
28 }))]
29 InvalidArchitectures {
30 architectures: Vec<Architecture>,
32 context: &'static str,
34 },
35
36 #[error("{msg}", msg = t!("error-invalid-integer", { "kind" => format!("{kind:?}") }))]
38 InvalidInteger {
39 kind: std::num::IntErrorKind,
41 },
42
43 #[error("{msg}", msg = t!("error-invalid-variant", { "error" => .0.to_string() }))]
45 InvalidVariant(#[from] strum::ParseError),
46
47 #[error("{msg}", msg = t!("error-invalid-email", { "error" => .0.to_string() }))]
49 InvalidEmail(#[from] email_address::Error),
50
51 #[error("{msg}", msg = t!("error-invalid-url", { "error" => .0.to_string() }))]
53 InvalidUrl(#[from] url::ParseError),
54
55 #[error("{msg}", msg = t!("error-invalid-license", { "error" => .0.to_string() }))]
57 InvalidLicense(#[from] spdx::ParseError),
58
59 #[error("{msg}", msg = t!("error-invalid-semver", { "kind" => kind }))]
67 InvalidSemver {
68 kind: String,
70 },
71
72 #[error("{msg}", msg = t!("error-io-path", {
74 "path" => path.display().to_string(),
75 "context" => context,
76 "source" => source.to_string(),
77 }))]
78 IoPath {
79 path: PathBuf,
81 context: String,
85 source: std::io::Error,
87 },
88
89 #[error("{msg}", msg = t!("error-invalid-chars", { "invalid_char" => invalid_char.to_string() }))]
91 ValueContainsInvalidChars {
92 invalid_char: char,
94 },
95
96 #[error("{msg}", msg = t!("error-incorrect-length", { "length" => length, "expected" => expected }))]
98 IncorrectLength {
99 length: usize,
101 expected: usize,
103 },
104
105 #[error("{msg}", msg = t!("error-delimiter-not-found", { "delimiter" => delimiter.to_string() }))]
107 DelimiterNotFound {
108 delimiter: char,
110 },
111
112 #[error("{msg}", msg = t!("error-restrictions-not-met", {
114 "restrictions" => format!("{restrictions:?}")
115 }))]
116 ValueDoesNotMatchRestrictions {
117 restrictions: Vec<String>,
119 },
120
121 #[error("{msg}", msg = t!("error-regex-mismatch", {
123 "value" => value,
124 "regex_type" => regex_type,
125 "regex" => regex
126 }))]
127 RegexDoesNotMatch {
128 value: String,
130 regex_type: String,
132 regex: String,
134 },
135
136 #[error("{msg}", msg = t!("error-parse", { "error" => .0 }))]
138 ParseError(String),
139
140 #[error("{msg}", msg = t!("error-missing-component", { "component" => component }))]
142 MissingComponent {
143 component: &'static str,
145 },
146
147 #[error("{msg}", msg = t!("error-path-not-absolute", { "path" => .0 }))]
149 PathNotAbsolute(PathBuf),
150
151 #[error("{msg}", msg = t!("error-path-not-relative", { "path" => .0 }))]
153 PathNotRelative(PathBuf),
154
155 #[error("{msg}", msg = t!("error-path-not-sibling", { "path" => .0 }))]
157 PathNotSibling(PathBuf),
158
159 #[error("{msg}", msg = t!("error-path-not-file", { "path" => .0 }))]
161 PathIsNotAFile(PathBuf),
162
163 #[error("{msg}", msg = t!("error-filename-invalid-chars", {
165 "path" => .0,
166 "invalid_char" => .1.to_string()
167 }))]
168 FileNameContainsInvalidChars(PathBuf, char),
169
170 #[error("{msg}", msg = t!("error-filename-empty"))]
172 FileNameIsEmpty,
173
174 #[error("{msg}", msg = t!("error-deprecated-license", { "license" => .0 }))]
176 DeprecatedLicense(String),
177
178 #[error("{msg}", msg = t!("error-invalid-component", {
180 "component" => component,
181 "context" => context
182 }))]
183 InvalidComponent {
184 component: &'static str,
186 context: String,
191 },
192
193 #[error("{msg}", msg = t!("error-invalid-pgp-fingerprint"))]
195 InvalidOpenPGPv4Fingerprint,
196
197 #[error("{msg}", msg = t!("error-invalid-pgp-keyid", { "keyid" => .0 }))]
199 InvalidOpenPGPKeyId(String),
200
201 #[error("{msg}", msg = t!("error-invalid-base64-encoding", { "expected_item" => expected_item }))]
203 InvalidBase64Encoding {
204 expected_item: String,
206 },
207
208 #[error("{msg}", msg = t!("error-invalid-soname-v1", { "name" => .0 }))]
210 InvalidSonameV1(&'static str),
211
212 #[error("{msg}", msg = t!("error-package", { "error" => .0.to_string() }))]
214 Package(#[from] crate::PackageError),
215
216 #[error("{msg}", msg = t!("error-unknown-compression", { "value" => value }))]
218 UnknownCompressionAlgorithmFileExtension {
219 value: String,
221 },
222
223 #[error("{msg}", msg = t!("error-unknown-filetype", { "value" => value }))]
225 UnknownFileTypeIdentifier {
226 value: String,
228 },
229}
230
231impl From<std::num::ParseIntError> for crate::error::Error {
232 fn from(e: std::num::ParseIntError) -> Self {
234 Self::InvalidInteger { kind: *e.kind() }
235 }
236}
237
238impl<'a> From<ParseError<Input<'a>, ParseStack<'a>>> for crate::error::Error {
239 fn from(value: ParseError<Input<'a>, ParseStack<'a>>) -> Self {
241 Self::ParseError(value.into_inner().to_string())
244 }
245}
246
247#[cfg(test)]
248mod tests {
249 use std::num::IntErrorKind;
250
251 use rstest::rstest;
252
253 use super::*;
254
255 #[rstest]
256 #[case(
257 "Invalid integer (caused by InvalidDigit)",
258 Error::InvalidInteger {
259 kind: IntErrorKind::InvalidDigit
260 }
261 )]
262 #[case(
263 "Invalid integer (caused by InvalidDigit)",
264 Error::InvalidInteger {
265 kind: IntErrorKind::InvalidDigit
266 }
267 )]
268 #[case(
269 "Invalid integer (caused by PosOverflow)",
270 Error::InvalidInteger {
271 kind: IntErrorKind::PosOverflow
272 }
273 )]
274 #[allow(deprecated)]
275 #[case(
276 "Invalid integer (caused by InvalidDigit)",
277 Error::InvalidInteger {
278 kind: IntErrorKind::InvalidDigit
279 }
280 )]
281 #[case(
282 "Invalid e-mail (Missing separator character '@'.)",
283 email_address::Error::MissingSeparator.into()
284 )]
285 #[case(
286 "Invalid integer (caused by InvalidDigit)",
287 Error::InvalidInteger {
288 kind: IntErrorKind::InvalidDigit
289 }
290 )]
291 fn error_format_string(#[case] error_str: &str, #[case] error: Error) {
292 assert_eq!(error_str, format!("{error}"));
293 }
294}