soar_core/
error.rs

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}