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    #[error("Cargo metadata error: {0}")]
67    CargoMetadata(#[from] cargo_metadata::Error),
68
69    /// Git error (when limine feature is enabled).
70    #[cfg(feature = "limine")]
71    #[error("Git error: {0}")]
72    Git(#[from] git2::Error),
73}
74
75impl Error {
76    /// Create a configuration error.
77    pub fn config(msg: impl Into<String>) -> Self {
78        Error::Config(msg.into())
79    }
80
81    /// Create a bootloader error.
82    pub fn bootloader(msg: impl Into<String>) -> Self {
83        Error::Bootloader(msg.into())
84    }
85
86    /// Create an image build error.
87    pub fn image_build(msg: impl Into<String>) -> Self {
88        Error::ImageBuild(msg.into())
89    }
90
91    /// Create a runner error.
92    pub fn runner(msg: impl Into<String>) -> Self {
93        Error::Runner(msg.into())
94    }
95
96    /// Create a firmware error.
97    pub fn firmware(msg: impl Into<String>) -> Self {
98        Error::Firmware(msg.into())
99    }
100
101    /// Create a template error.
102    pub fn template(msg: impl Into<String>) -> Self {
103        Error::Template(msg.into())
104    }
105
106    /// Create a feature not enabled error.
107    pub fn feature_not_enabled(feature: impl Into<String>) -> Self {
108        Error::FeatureNotEnabled(feature.into())
109    }
110
111    /// Create an unsupported combination error.
112    pub fn unsupported(msg: impl Into<String>) -> Self {
113        Error::UnsupportedCombination(msg.into())
114    }
115}
116
117#[cfg(test)]
118mod tests {
119    use super::*;
120
121    #[test]
122    fn test_error_display_messages() {
123        assert_eq!(
124            Error::config("bad value").to_string(),
125            "Configuration error: bad value"
126        );
127        assert_eq!(
128            Error::bootloader("fetch failed").to_string(),
129            "Bootloader error: fetch failed"
130        );
131        assert_eq!(
132            Error::image_build("write error").to_string(),
133            "Image build error: write error"
134        );
135        assert_eq!(
136            Error::runner("not found").to_string(),
137            "Runner error: not found"
138        );
139        assert_eq!(
140            Error::firmware("missing file").to_string(),
141            "Firmware error: missing file"
142        );
143        assert_eq!(
144            Error::template("bad syntax").to_string(),
145            "Template error: bad syntax"
146        );
147        assert_eq!(
148            Error::feature_not_enabled("grub").to_string(),
149            "Feature 'grub' is not enabled. Enable it in Cargo.toml features."
150        );
151        assert_eq!(
152            Error::unsupported("bios + fat").to_string(),
153            "Unsupported combination: bios + fat"
154        );
155    }
156
157    #[test]
158    fn test_error_file_not_found() {
159        let err = Error::FileNotFound(PathBuf::from("/missing/file.txt"));
160        assert_eq!(err.to_string(), "File not found: /missing/file.txt");
161    }
162
163    #[test]
164    fn test_error_missing_config() {
165        let err = Error::MissingConfig("boot.type".to_string());
166        assert_eq!(
167            err.to_string(),
168            "Missing required configuration field: boot.type"
169        );
170    }
171
172    #[test]
173    fn test_error_invalid_config() {
174        let err = Error::InvalidConfig {
175            field: "boot.type".to_string(),
176            value: "unknown".to_string(),
177        };
178        assert_eq!(
179            err.to_string(),
180            "Invalid configuration value for boot.type: unknown"
181        );
182    }
183}