1use std::fmt;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10pub enum InventoryFileKind {
11 Hosts,
13 Groups,
15 Defaults,
17}
18
19impl fmt::Display for InventoryFileKind {
20 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
21 match self {
22 InventoryFileKind::Hosts => write!(f, "hosts"),
23 InventoryFileKind::Groups => write!(f, "groups"),
24 InventoryFileKind::Defaults => write!(f, "defaults"),
25 }
26 }
27}
28
29#[derive(Debug, Clone)]
31pub enum InventoryLoadError {
32 Read {
34 kind: InventoryFileKind,
36 path: String,
38 message: String,
40 },
41 ParseJson {
43 kind: InventoryFileKind,
45 path: String,
47 message: String,
49 },
50 ParseYaml {
52 kind: InventoryFileKind,
54 path: String,
56 message: String,
58 },
59 UnsupportedFormat {
61 kind: InventoryFileKind,
63 path: String,
65 },
66 TransformPluginNotFound {
68 name: String,
70 },
71 NotTransformPlugin {
73 name: String,
75 },
76 Message(String),
78}
79
80impl fmt::Display for InventoryLoadError {
81 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
82 match self {
83 InventoryLoadError::Read {
84 kind,
85 path,
86 message,
87 } => write!(f, "failed to read {kind} inventory file {path}: {message}"),
88 InventoryLoadError::ParseJson {
89 kind,
90 path,
91 message,
92 } => write!(
93 f,
94 "failed to parse {kind} inventory JSON file {path}: {message}"
95 ),
96 InventoryLoadError::ParseYaml {
97 kind,
98 path,
99 message,
100 } => write!(
101 f,
102 "failed to parse {kind} inventory YAML file {path}: {message}"
103 ),
104 InventoryLoadError::UnsupportedFormat { kind, path } => write!(
105 f,
106 "unsupported {kind} inventory file format for {path}. Use .json, .yaml, or .yml"
107 ),
108 InventoryLoadError::TransformPluginNotFound { name } => {
109 write!(f, "transform plugin '{name}' not found")
110 }
111 InventoryLoadError::NotTransformPlugin { name } => {
112 write!(f, "plugin '{name}' is not a transform function plugin")
113 }
114 InventoryLoadError::Message(msg) => write!(f, "{msg}"),
115 }
116 }
117}
118
119impl std::error::Error for InventoryLoadError {}
120
121impl From<String> for InventoryLoadError {
122 fn from(value: String) -> Self {
123 InventoryLoadError::Message(value)
124 }
125}
126
127impl From<&str> for InventoryLoadError {
128 fn from(value: &str) -> Self {
129 InventoryLoadError::Message(value.to_string())
130 }
131}
132
133#[derive(Debug, Clone)]
135pub enum SshConfigError {
136 NotFound { path: String },
138 PermissionDenied { path: String, message: String },
140 CheckFailed { path: String, message: String },
142 OpenFailed { path: String, message: String },
144 ParseFailed { path: String, message: String },
146}
147
148impl fmt::Display for SshConfigError {
149 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
150 match self {
151 SshConfigError::NotFound { path } => write!(f, "SSH config file not found: {path}"),
152 SshConfigError::PermissionDenied { path, message } => {
153 write!(
154 f,
155 "SSH config file exists but permission denied: {path}: {message}"
156 )
157 }
158 SshConfigError::CheckFailed { path, message } => {
159 write!(f, "Failed to check SSH config file {path}: {message}")
160 }
161 SshConfigError::OpenFailed { path, message } => {
162 write!(f, "Failed to open SSH config file {path}: {message}")
163 }
164 SshConfigError::ParseFailed { path, message } => {
165 write!(f, "Failed to parse SSH config file {path}: {message}")
166 }
167 }
168 }
169}
170
171impl std::error::Error for SshConfigError {}
172
173#[derive(Debug, Clone)]
175pub enum ConfigLoadError {
176 UnsupportedFormat { path: String },
178 Read { path: String, message: String },
180 Deserialize { path: String, message: String },
182 SshConfig(SshConfigError),
184}
185
186impl fmt::Display for ConfigLoadError {
187 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
188 match self {
189 ConfigLoadError::UnsupportedFormat { path } => {
190 write!(
191 f,
192 "unsupported settings file format for {path}. Use .json, .yaml, or .yml"
193 )
194 }
195 ConfigLoadError::Read { path, message } => {
196 write!(f, "failed to read settings from {path}: {message}")
197 }
198 ConfigLoadError::Deserialize { path, message } => {
199 write!(f, "failed to deserialize settings from {path}: {message}")
200 }
201 ConfigLoadError::SshConfig(err) => write!(f, "{err}"),
202 }
203 }
204}
205
206impl std::error::Error for ConfigLoadError {}
207
208#[derive(Debug, Clone)]
210pub enum GenjaError {
211 PluginsNotLoaded,
213 InventoryNotLoaded,
215 PluginNotFound(String),
217 NotInventoryPlugin(String),
219 AsyncInventoryPluginRequiresAsyncConstruction(String),
221 NotRunnerPlugin(String),
223 PluginLoad(String),
225 ConfigLoad(ConfigLoadError),
227 InventoryLoad(InventoryLoadError),
229 Message(String),
231 NotImplemented(&'static str),
233}
234
235impl fmt::Display for GenjaError {
236 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
237 match self {
238 GenjaError::PluginsNotLoaded => write!(f, "plugins have not been loaded"),
239 GenjaError::InventoryNotLoaded => write!(f, "inventory has not been loaded"),
240 GenjaError::PluginNotFound(name) => write!(f, "plugin '{name}' not found"),
241 GenjaError::NotInventoryPlugin(name) => {
242 write!(f, "plugin '{name}' is not an inventory plugin")
243 }
244 GenjaError::AsyncInventoryPluginRequiresAsyncConstruction(name) => {
245 write!(
246 f,
247 "async inventory plugin '{name}' requires async runtime construction"
248 )
249 }
250 GenjaError::NotRunnerPlugin(name) => {
251 write!(f, "plugin '{name}' is not a runner plugin")
252 }
253 GenjaError::PluginLoad(err) => write!(f, "failed to load plugins: {err}"),
254 GenjaError::ConfigLoad(err) => write!(f, "failed to load settings: {err}"),
255 GenjaError::InventoryLoad(err) => write!(f, "failed to load inventory: {err}"),
256 GenjaError::Message(msg) => write!(f, "{msg}"),
257 GenjaError::NotImplemented(msg) => write!(f, "{msg}"),
258 }
259 }
260}
261
262impl std::error::Error for GenjaError {}
263
264impl From<String> for GenjaError {
265 fn from(value: String) -> Self {
266 GenjaError::Message(value)
267 }
268}
269
270impl From<&str> for GenjaError {
271 fn from(value: &str) -> Self {
272 GenjaError::Message(value.to_string())
273 }
274}
275
276impl From<InventoryLoadError> for GenjaError {
277 fn from(value: InventoryLoadError) -> Self {
278 GenjaError::InventoryLoad(value)
279 }
280}
281
282impl From<ConfigLoadError> for GenjaError {
283 fn from(value: ConfigLoadError) -> Self {
284 GenjaError::ConfigLoad(value)
285 }
286}