vx_installer/
error.rs

1//! Error types for vx-installer
2
3use std::path::PathBuf;
4
5/// Result type alias for vx-installer operations
6pub type Result<T> = std::result::Result<T, Error>;
7
8/// Error types that can occur during installation operations
9#[derive(Debug, thiserror::Error)]
10pub enum Error {
11    /// IO error occurred
12    #[error("IO error: {0}")]
13    Io(#[from] std::io::Error),
14
15    /// HTTP request failed
16    #[error("HTTP request failed: {0}")]
17    Http(#[from] reqwest::Error),
18
19    /// Download failed
20    #[error("Download failed from {url}: {reason}")]
21    DownloadFailed { url: String, reason: String },
22
23    /// Installation failed
24    #[error("Installation failed for {tool_name} v{version}: {message}")]
25    InstallationFailed {
26        tool_name: String,
27        version: String,
28        message: String,
29    },
30
31    /// Archive extraction failed
32    #[error("Failed to extract archive {archive_path}: {reason}")]
33    ExtractionFailed {
34        archive_path: PathBuf,
35        reason: String,
36    },
37
38    /// Unsupported archive format
39    #[error("Unsupported archive format: {format}")]
40    UnsupportedFormat { format: String },
41
42    /// Executable not found after installation
43    #[error("Executable not found for {tool_name} in {search_path}")]
44    ExecutableNotFound {
45        tool_name: String,
46        search_path: PathBuf,
47    },
48
49    /// Checksum verification failed
50    #[error("Checksum verification failed for {file_path}: expected {expected}, got {actual}")]
51    ChecksumMismatch {
52        file_path: PathBuf,
53        expected: String,
54        actual: String,
55    },
56
57    /// Invalid configuration
58    #[error("Invalid configuration: {message}")]
59    InvalidConfig { message: String },
60
61    /// Permission denied
62    #[error("Permission denied: {path}")]
63    PermissionDenied { path: PathBuf },
64
65    /// Tool already installed
66    #[error("Tool {tool_name} v{version} is already installed")]
67    AlreadyInstalled { tool_name: String, version: String },
68
69    /// Disk space insufficient
70    #[error("Insufficient disk space: required {required} bytes, available {available} bytes")]
71    InsufficientSpace { required: u64, available: u64 },
72
73    /// Network timeout
74    #[error("Network timeout while downloading from {url}")]
75    NetworkTimeout { url: String },
76
77    /// JSON parsing error
78    #[error("JSON parsing error: {0}")]
79    Json(#[from] serde_json::Error),
80
81    /// Walkdir error
82    #[error("Directory traversal error: {0}")]
83    Walkdir(#[from] walkdir::Error),
84
85    /// Custom error for tool-specific issues
86    #[error("Tool-specific error: {message}")]
87    ToolSpecific { message: String },
88}
89
90impl Error {
91    /// Create a download failed error
92    pub fn download_failed(url: impl Into<String>, reason: impl Into<String>) -> Self {
93        Self::DownloadFailed {
94            url: url.into(),
95            reason: reason.into(),
96        }
97    }
98
99    /// Create an installation failed error
100    pub fn installation_failed(
101        tool_name: impl Into<String>,
102        version: impl Into<String>,
103        message: impl Into<String>,
104    ) -> Self {
105        Self::InstallationFailed {
106            tool_name: tool_name.into(),
107            version: version.into(),
108            message: message.into(),
109        }
110    }
111
112    /// Create an extraction failed error
113    pub fn extraction_failed(archive_path: impl Into<PathBuf>, reason: impl Into<String>) -> Self {
114        Self::ExtractionFailed {
115            archive_path: archive_path.into(),
116            reason: reason.into(),
117        }
118    }
119
120    /// Create an unsupported format error
121    pub fn unsupported_format(format: impl Into<String>) -> Self {
122        Self::UnsupportedFormat {
123            format: format.into(),
124        }
125    }
126
127    /// Create an executable not found error
128    pub fn executable_not_found(
129        tool_name: impl Into<String>,
130        search_path: impl Into<PathBuf>,
131    ) -> Self {
132        Self::ExecutableNotFound {
133            tool_name: tool_name.into(),
134            search_path: search_path.into(),
135        }
136    }
137
138    /// Check if this error is recoverable
139    pub fn is_recoverable(&self) -> bool {
140        matches!(
141            self,
142            Error::NetworkTimeout { .. }
143                | Error::Http(_)
144                | Error::DownloadFailed { .. }
145                | Error::InsufficientSpace { .. }
146        )
147    }
148
149    /// Check if this error is related to network issues
150    pub fn is_network_error(&self) -> bool {
151        matches!(
152            self,
153            Error::Http(_) | Error::DownloadFailed { .. } | Error::NetworkTimeout { .. }
154        )
155    }
156}