1use std::error::Error;
2use thiserror::Error;
3
4#[derive(Error, Debug)]
5pub enum ConfigError {
6 #[error("Invalid configuration")]
7 InvalidConfig,
8
9 #[error("Configuration file already exists")]
10 ConfigAlreadyExists,
11
12 #[error("Invalid profile: {0}")]
13 InvalidProfile(String),
14
15 #[error("TOML deserialization error: {0}")]
16 TomlDeError(#[from] toml::de::Error),
17
18 #[error("TOML serialization error: {0}")]
19 TomlSerError(#[from] toml::ser::Error),
20
21 #[error("IO error reading config: {0}")]
22 IoError(#[from] std::io::Error),
23
24 #[error("Default profile '{0}' does not exist")]
25 MissingDefaultProfile(String),
26
27 #[error("Reserved repository name 'local' is not allowed")]
28 ReservedRepositoryName,
29
30 #[error("Duplicate repository name '{0}'")]
31 DuplicateRepositoryName(String),
32
33 #[error("Profile '{0}' does not exist")]
34 MissingProfile(String),
35
36 #[error("{0}")]
37 Custom(String),
38}
39
40#[derive(Error, Debug)]
41pub enum SoarError {
42 #[error(transparent)]
43 Config(#[from] ConfigError),
44
45 #[error("System error: {0}")]
46 Errno(#[from] nix::errno::Errno),
47
48 #[error("Environment variable error: {0}")]
49 VarError(#[from] std::env::VarError),
50
51 #[error("IO error while {action}: {source}")]
52 IoError {
53 action: String,
54 source: std::io::Error,
55 },
56
57 #[error("System time error: {0}")]
58 SystemTimeError(#[from] std::time::SystemTimeError),
59
60 #[error("TOML serialization error: {0}")]
61 TomlError(#[from] toml::ser::Error),
62
63 #[error("SQLite database error: {0}")]
64 RusqliteError(#[from] rusqlite::Error),
65
66 #[error("Database operation failed: {0}")]
67 DatabaseError(String),
68
69 #[error("HTTP request error: {0:?}")]
70 ReqwestError(#[from] reqwest::Error),
71
72 #[error("Download failed: {0}")]
73 DownloadError(#[from] soar_dl::error::DownloadError),
74
75 #[error("{0}")]
76 PlatformError(soar_dl::error::PlatformError),
77
78 #[error("Squashy Error: {0}")]
79 SquishyError(#[from] squishy::error::SquishyError),
80
81 #[error("Image Error: {0}")]
82 ImageError(#[from] image::error::ImageError),
83
84 #[error("Package integration failed: {0}")]
85 PackageIntegrationFailed(String),
86
87 #[error("Package {0} not found")]
88 PackageNotFound(String),
89
90 #[error("Failed to fetch from remote source: {0}")]
91 FailedToFetchRemote(String),
92
93 #[error("Invalid path specified")]
94 InvalidPath,
95
96 #[error("Thread lock poison error")]
97 PoisonError,
98
99 #[error("Invalid checksum detected")]
100 InvalidChecksum,
101
102 #[error("Configuration file already exists")]
103 ConfigAlreadyExists,
104
105 #[error("Invalid package query: {0}")]
106 InvalidPackageQuery(String),
107
108 #[error("{0}")]
109 Custom(String),
110
111 #[error("Invalid profile: {0}")]
112 InvalidProfile(String),
113
114 #[error("{0}")]
115 Warning(String),
116}
117
118impl SoarError {
119 pub fn message(&self) -> String {
120 self.to_string()
121 }
122
123 pub fn root_cause(&self) -> String {
124 match self {
125 Self::ReqwestError(e) => format!(
126 "Root cause: {}",
127 e.source()
128 .map_or_else(|| e.to_string(), |source| source.to_string())
129 ),
130 Self::RusqliteError(e) => format!(
131 "Root cause: {}",
132 e.source()
133 .map_or_else(|| e.to_string(), |source| source.to_string())
134 ),
135 Self::Config(err) => err.to_string(),
136 _ => self.to_string(),
137 }
138 }
139}
140
141impl<T> From<std::sync::PoisonError<T>> for SoarError {
142 fn from(_: std::sync::PoisonError<T>) -> Self {
143 Self::PoisonError
144 }
145}
146
147impl From<soar_dl::error::PlatformError> for SoarError {
148 fn from(value: soar_dl::error::PlatformError) -> Self {
149 Self::PlatformError(value)
150 }
151}
152
153pub trait ErrorContext<T> {
154 fn with_context<C>(self, context: C) -> Result<T, SoarError>
155 where
156 C: FnOnce() -> String;
157}
158
159impl<T> ErrorContext<T> for std::io::Result<T> {
160 fn with_context<C>(self, context: C) -> Result<T, SoarError>
161 where
162 C: FnOnce() -> String,
163 {
164 self.map_err(|err| SoarError::IoError {
165 action: context(),
166 source: err,
167 })
168 }
169}