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, PartialEq)]
19pub enum Error {
20 #[error("{msg}", msg = t!("error-invalid-architectures", {
22 "architectures" => format!("{architectures:?}"),
23 "context" => context
24 }))]
25 InvalidArchitectures {
26 architectures: Vec<Architecture>,
28 context: &'static str,
30 },
31
32 #[error("{msg}", msg = t!("error-invalid-integer", { "kind" => format!("{kind:?}") }))]
34 InvalidInteger {
35 kind: std::num::IntErrorKind,
37 },
38
39 #[error("{msg}", msg = t!("error-invalid-variant", { "error" => .0.to_string() }))]
41 InvalidVariant(#[from] strum::ParseError),
42
43 #[error("{msg}", msg = t!("error-invalid-email", { "error" => .0.to_string() }))]
45 InvalidEmail(#[from] email_address::Error),
46
47 #[error("{msg}", msg = t!("error-invalid-url", { "error" => .0.to_string() }))]
49 InvalidUrl(#[from] url::ParseError),
50
51 #[error("{msg}", msg = t!("error-invalid-license", { "error" => .0.to_string() }))]
53 InvalidLicense(#[from] spdx::ParseError),
54
55 #[error("{msg}", msg = t!("error-invalid-semver", { "kind" => kind }))]
63 InvalidSemver {
64 kind: String,
66 },
67
68 #[error("{msg}", msg = t!("error-invalid-chars", { "invalid_char" => invalid_char.to_string() }))]
70 ValueContainsInvalidChars {
71 invalid_char: char,
73 },
74
75 #[error("{msg}", msg = t!("error-incorrect-length", { "length" => length, "expected" => expected }))]
77 IncorrectLength {
78 length: usize,
80 expected: usize,
82 },
83
84 #[error("{msg}", msg = t!("error-delimiter-not-found", { "delimiter" => delimiter.to_string() }))]
86 DelimiterNotFound {
87 delimiter: char,
89 },
90
91 #[error("{msg}", msg = t!("error-restrictions-not-met", {
93 "restrictions" => format!("{restrictions:?}")
94 }))]
95 ValueDoesNotMatchRestrictions {
96 restrictions: Vec<String>,
98 },
99
100 #[error("{msg}", msg = t!("error-regex-mismatch", {
102 "value" => value,
103 "regex_type" => regex_type,
104 "regex" => regex
105 }))]
106 RegexDoesNotMatch {
107 value: String,
109 regex_type: String,
111 regex: String,
113 },
114
115 #[error("{msg}", msg = t!("error-parse", { "error" => .0 }))]
117 ParseError(String),
118
119 #[error("{msg}", msg = t!("error-missing-component", { "component" => component }))]
121 MissingComponent {
122 component: &'static str,
124 },
125
126 #[error("{msg}", msg = t!("error-path-not-absolute", { "path" => .0 }))]
128 PathNotAbsolute(PathBuf),
129
130 #[error("{msg}", msg = t!("error-path-not-relative", { "path" => .0 }))]
132 PathNotRelative(PathBuf),
133
134 #[error("{msg}", msg = t!("error-path-not-sibling", { "path" => .0 }))]
136 PathNotSibling(PathBuf),
137
138 #[error("{msg}", msg = t!("error-path-not-file", { "path" => .0 }))]
140 PathIsNotAFile(PathBuf),
141
142 #[error("{msg}", msg = t!("error-filename-invalid-chars", {
144 "path" => .0,
145 "invalid_char" => .1.to_string()
146 }))]
147 FileNameContainsInvalidChars(PathBuf, char),
148
149 #[error("{msg}", msg = t!("error-filename-empty"))]
151 FileNameIsEmpty,
152
153 #[error("{msg}", msg = t!("error-deprecated-license", { "license" => .0 }))]
155 DeprecatedLicense(String),
156
157 #[error("{msg}", msg = t!("error-invalid-component", {
159 "component" => component,
160 "context" => context
161 }))]
162 InvalidComponent {
163 component: &'static str,
165 context: String,
170 },
171
172 #[error("{msg}", msg = t!("error-invalid-pgp-fingerprint"))]
174 InvalidOpenPGPv4Fingerprint,
175
176 #[error("{msg}", msg = t!("error-invalid-pgp-keyid", { "keyid" => .0 }))]
178 InvalidOpenPGPKeyId(String),
179
180 #[error("{msg}", msg = t!("error-invalid-base64-encoding", { "expected_item" => expected_item }))]
182 InvalidBase64Encoding {
183 expected_item: String,
185 },
186
187 #[error("{msg}", msg = t!("error-invalid-soname-v1", { "name" => .0 }))]
189 InvalidSonameV1(&'static str),
190
191 #[error("{msg}", msg = t!("error-package", { "error" => .0.to_string() }))]
193 Package(#[from] crate::PackageError),
194
195 #[error("{msg}", msg = t!("error-unknown-compression", { "value" => value }))]
197 UnknownCompressionAlgorithmFileExtension {
198 value: String,
200 },
201
202 #[error("{msg}", msg = t!("error-unknown-filetype", { "value" => value }))]
204 UnknownFileTypeIdentifier {
205 value: String,
207 },
208}
209
210impl From<std::num::ParseIntError> for crate::error::Error {
211 fn from(e: std::num::ParseIntError) -> Self {
213 Self::InvalidInteger { kind: *e.kind() }
214 }
215}
216
217impl<'a> From<ParseError<Input<'a>, ParseStack<'a>>> for crate::error::Error {
218 fn from(value: ParseError<Input<'a>, ParseStack<'a>>) -> Self {
220 Self::ParseError(value.into_inner().to_string())
223 }
224}
225
226#[cfg(test)]
227mod tests {
228 use std::num::IntErrorKind;
229
230 use rstest::rstest;
231
232 use super::*;
233
234 #[rstest]
235 #[case(
236 "Invalid integer (caused by InvalidDigit)",
237 Error::InvalidInteger {
238 kind: IntErrorKind::InvalidDigit
239 }
240 )]
241 #[case(
242 "Invalid integer (caused by InvalidDigit)",
243 Error::InvalidInteger {
244 kind: IntErrorKind::InvalidDigit
245 }
246 )]
247 #[case(
248 "Invalid integer (caused by PosOverflow)",
249 Error::InvalidInteger {
250 kind: IntErrorKind::PosOverflow
251 }
252 )]
253 #[allow(deprecated)]
254 #[case(
255 "Invalid integer (caused by InvalidDigit)",
256 Error::InvalidInteger {
257 kind: IntErrorKind::InvalidDigit
258 }
259 )]
260 #[case(
261 "Invalid e-mail (Missing separator character '@'.)",
262 email_address::Error::MissingSeparator.into()
263 )]
264 #[case(
265 "Invalid integer (caused by InvalidDigit)",
266 Error::InvalidInteger {
267 kind: IntErrorKind::InvalidDigit
268 }
269 )]
270 fn error_format_string(#[case] error_str: &str, #[case] error: Error) {
271 assert_eq!(error_str, format!("{error}"));
272 }
273}