docker_image_pusher/
error.rs

1//! Error handling for the docker image pusher
2//!
3//! This module defines the [`PusherError`] enum for all major error types encountered in the application,
4//! and provides standardized error handlers to eliminate duplication and improve reporting.
5
6pub mod handlers;
7
8use std::fmt;
9
10#[derive(Debug)]
11pub enum PusherError {
12    Config(String),
13    Authentication(String),
14    Network(String),
15    Upload(String),
16    Io(String),
17    Parse(String),
18    Registry(String),
19    ImageParsing(String),
20    Validation(String),
21    Timeout(String),
22}
23
24impl Clone for PusherError {
25    fn clone(&self) -> Self {
26        match self {
27            PusherError::Config(msg) => PusherError::Config(msg.clone()),
28            PusherError::Authentication(msg) => PusherError::Authentication(msg.clone()),
29            PusherError::Network(msg) => PusherError::Network(msg.clone()),
30            PusherError::Upload(msg) => PusherError::Upload(msg.clone()),
31            PusherError::Io(msg) => PusherError::Io(msg.clone()),
32            PusherError::Parse(msg) => PusherError::Parse(msg.clone()),
33            PusherError::Registry(msg) => PusherError::Registry(msg.clone()),
34            PusherError::ImageParsing(msg) => PusherError::ImageParsing(msg.clone()),
35            PusherError::Validation(msg) => PusherError::Validation(msg.clone()),
36            PusherError::Timeout(msg) => PusherError::Timeout(msg.clone()),
37        }
38    }
39}
40
41impl fmt::Display for PusherError {
42    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
43        match self {
44            PusherError::Config(msg) => write!(f, "Configuration error: {}", msg),
45            PusherError::Authentication(msg) => write!(f, "Authentication failed: {}", msg),
46            PusherError::Network(msg) => write!(f, "Network error: {}", msg),
47            PusherError::Upload(msg) => write!(f, "Upload failed: {}", msg),
48            PusherError::Io(msg) => write!(f, "I/O error: {}", msg),
49            PusherError::Parse(msg) => write!(f, "Parse error: {}", msg),
50            PusherError::Registry(msg) => write!(f, "Registry error: {}", msg),
51            PusherError::ImageParsing(msg) => write!(f, "Image parsing failed: {}", msg),
52            PusherError::Validation(msg) => write!(f, "Validation error: {}", msg),
53            PusherError::Timeout(msg) => write!(f, "Operation timed out: {}", msg),
54        }
55    }
56}
57
58impl std::error::Error for PusherError {}
59
60// Enhanced From implementations with context
61impl From<std::io::Error> for PusherError {
62    fn from(err: std::io::Error) -> Self {
63        match err.kind() {
64            std::io::ErrorKind::NotFound => PusherError::Io(format!("File not found: {}", err)),
65            std::io::ErrorKind::PermissionDenied => {
66                PusherError::Io(format!("Permission denied: {}", err))
67            }
68            std::io::ErrorKind::TimedOut => {
69                PusherError::Timeout(format!("I/O operation timed out: {}", err))
70            }
71            _ => PusherError::Io(err.to_string()),
72        }
73    }
74}
75
76impl From<reqwest::Error> for PusherError {
77    fn from(err: reqwest::Error) -> Self {
78        if err.is_timeout() {
79            PusherError::Timeout(format!("Network request timed out: {}", err))
80        } else if err.is_connect() {
81            PusherError::Network(format!("Connection failed: {}", err))
82        } else if err.is_decode() {
83            PusherError::Parse(format!("Response decode error: {}", err))
84        } else {
85            PusherError::Network(err.to_string())
86        }
87    }
88}
89
90impl From<serde_json::Error> for PusherError {
91    fn from(err: serde_json::Error) -> Self {
92        PusherError::Parse(format!("JSON parsing failed: {}", err))
93    }
94}
95
96impl From<url::ParseError> for PusherError {
97    fn from(err: url::ParseError) -> Self {
98        PusherError::Config(format!("Invalid URL format: {}", err))
99    }
100}
101
102pub type Result<T> = std::result::Result<T, PusherError>;
103
104// Utility function for creating contextual errors
105pub fn context_error<T>(result: std::result::Result<T, PusherError>, context: &str) -> Result<T> {
106    result.map_err(|e| match e {
107        PusherError::Config(msg) => PusherError::Config(format!("{}: {}", context, msg)),
108        PusherError::Authentication(msg) => {
109            PusherError::Authentication(format!("{}: {}", context, msg))
110        }
111        PusherError::Network(msg) => PusherError::Network(format!("{}: {}", context, msg)),
112        PusherError::Upload(msg) => PusherError::Upload(format!("{}: {}", context, msg)),
113        PusherError::Io(msg) => PusherError::Io(format!("{}: {}", context, msg)),
114        PusherError::Parse(msg) => PusherError::Parse(format!("{}: {}", context, msg)),
115        PusherError::Registry(msg) => PusherError::Registry(format!("{}: {}", context, msg)),
116        PusherError::ImageParsing(msg) => {
117            PusherError::ImageParsing(format!("{}: {}", context, msg))
118        }
119        PusherError::Validation(msg) => PusherError::Validation(format!("{}: {}", context, msg)),
120        PusherError::Timeout(msg) => PusherError::Timeout(format!("{}: {}", context, msg)),
121    })
122}