Skip to main content

cargo_image_runner/core/
error.rs

1use std::path::PathBuf;
2
3/// Result type alias for cargo-image-runner operations.
4pub type Result<T> = std::result::Result<T, Error>;
5
6/// Main error type for cargo-image-runner.
7#[derive(Debug, thiserror::Error)]
8pub enum Error {
9    /// Configuration-related errors.
10    #[error("Configuration error: {0}")]
11    Config(String),
12
13    /// Bootloader-related errors.
14    #[error("Bootloader error: {0}")]
15    Bootloader(String),
16
17    /// Image building errors.
18    #[error("Image build error: {0}")]
19    ImageBuild(String),
20
21    /// Runner execution errors.
22    #[error("Runner error: {0}")]
23    Runner(String),
24
25    /// Firmware-related errors.
26    #[error("Firmware error: {0}")]
27    Firmware(String),
28
29    /// Template processing errors.
30    #[error("Template error: {0}")]
31    Template(String),
32
33    /// File not found.
34    #[error("File not found: {}", .0.display())]
35    FileNotFound(PathBuf),
36
37    /// Missing required configuration field.
38    #[error("Missing required configuration field: {0}")]
39    MissingConfig(String),
40
41    /// Invalid configuration value.
42    #[error("Invalid configuration value for {field}: {value}")]
43    InvalidConfig { field: String, value: String },
44
45    /// Feature not enabled.
46    #[error("Feature '{0}' is not enabled. Enable it in Cargo.toml features.")]
47    FeatureNotEnabled(String),
48
49    /// Unsupported combination of options.
50    #[error("Unsupported combination: {0}")]
51    UnsupportedCombination(String),
52
53    /// IO error.
54    #[error("IO error: {0}")]
55    Io(#[from] std::io::Error),
56
57    /// TOML deserialization error.
58    #[error("TOML parsing error: {0}")]
59    TomlDe(#[from] toml::de::Error),
60
61    /// JSON error.
62    #[error("JSON error: {0}")]
63    Json(#[from] serde_json::Error),
64
65    /// Cargo metadata error.
66    #[cfg(feature = "cargo-metadata")]
67    #[error("Cargo metadata error: {0}")]
68    CargoMetadata(#[from] cargo_metadata::Error),
69
70    /// Git error (when limine feature is enabled).
71    #[cfg(feature = "limine")]
72    #[error("Git error: {0}")]
73    Git(#[from] git2::Error),
74}
75
76impl Error {
77    /// Create a configuration error.
78    pub fn config(msg: impl Into<String>) -> Self {
79        Error::Config(msg.into())
80    }
81
82    /// Create a bootloader error.
83    pub fn bootloader(msg: impl Into<String>) -> Self {
84        Error::Bootloader(msg.into())
85    }
86
87    /// Create an image build error.
88    pub fn image_build(msg: impl Into<String>) -> Self {
89        Error::ImageBuild(msg.into())
90    }
91
92    /// Create a runner error.
93    pub fn runner(msg: impl Into<String>) -> Self {
94        Error::Runner(msg.into())
95    }
96
97    /// Create a firmware error.
98    pub fn firmware(msg: impl Into<String>) -> Self {
99        Error::Firmware(msg.into())
100    }
101
102    /// Create a template error.
103    pub fn template(msg: impl Into<String>) -> Self {
104        Error::Template(msg.into())
105    }
106
107    /// Create a feature not enabled error.
108    pub fn feature_not_enabled(feature: impl Into<String>) -> Self {
109        Error::FeatureNotEnabled(feature.into())
110    }
111
112    /// Create an unsupported combination error.
113    pub fn unsupported(msg: impl Into<String>) -> Self {
114        Error::UnsupportedCombination(msg.into())
115    }
116}
117
118#[cfg(test)]
119mod tests {
120    use super::*;
121
122    #[test]
123    fn test_error_display_messages() {
124        assert_eq!(
125            Error::config("bad value").to_string(),
126            "Configuration error: bad value"
127        );
128        assert_eq!(
129            Error::bootloader("fetch failed").to_string(),
130            "Bootloader error: fetch failed"
131        );
132        assert_eq!(
133            Error::image_build("write error").to_string(),
134            "Image build error: write error"
135        );
136        assert_eq!(
137            Error::runner("not found").to_string(),
138            "Runner error: not found"
139        );
140        assert_eq!(
141            Error::firmware("missing file").to_string(),
142            "Firmware error: missing file"
143        );
144        assert_eq!(
145            Error::template("bad syntax").to_string(),
146            "Template error: bad syntax"
147        );
148        assert_eq!(
149            Error::feature_not_enabled("grub").to_string(),
150            "Feature 'grub' is not enabled. Enable it in Cargo.toml features."
151        );
152        assert_eq!(
153            Error::unsupported("bios + fat").to_string(),
154            "Unsupported combination: bios + fat"
155        );
156    }
157
158    #[test]
159    fn test_error_file_not_found() {
160        let err = Error::FileNotFound(PathBuf::from("/missing/file.txt"));
161        assert_eq!(err.to_string(), "File not found: /missing/file.txt");
162    }
163
164    #[test]
165    fn test_error_missing_config() {
166        let err = Error::MissingConfig("boot.type".to_string());
167        assert_eq!(
168            err.to_string(),
169            "Missing required configuration field: boot.type"
170        );
171    }
172
173    #[test]
174    fn test_error_invalid_config() {
175        let err = Error::InvalidConfig {
176            field: "boot.type".to_string(),
177            value: "unknown".to_string(),
178        };
179        assert_eq!(
180            err.to_string(),
181            "Invalid configuration value for boot.type: unknown"
182        );
183    }
184}