use thiserror::Error;
#[derive(Error, Debug)]
pub enum DockerError {
#[error("Docker connection failed: {0}")]
Connection(String),
#[error("Docker daemon not running. Start Docker Desktop or the Docker service.")]
NotRunning,
#[error("Docker socket not found. Is Docker installed and running?")]
SocketNotFound,
#[error(
"Permission denied accessing Docker socket. You may need to add your user to the 'docker' group."
)]
PermissionDenied,
#[error("Docker build failed: {0}")]
Build(String),
#[error("Docker pull failed: {0}")]
Pull(String),
#[error("Docker image operation failed: {0}")]
Image(String),
#[error("Container operation failed: {0}")]
Container(String),
#[error("Volume operation failed: {0}")]
Volume(String),
#[error("Docker operation timed out")]
Timeout,
}
impl From<bollard::errors::Error> for DockerError {
fn from(err: bollard::errors::Error) -> Self {
let msg = err.to_string();
if msg.contains("No such file or directory") {
DockerError::SocketNotFound
} else if msg.contains("Cannot connect to the Docker daemon")
|| msg.contains("connection refused")
{
DockerError::NotRunning
} else if msg.contains("permission denied") || msg.contains("Permission denied") {
DockerError::PermissionDenied
} else {
DockerError::Connection(msg)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn docker_error_displays_correctly() {
let err = DockerError::NotRunning;
assert!(err.to_string().contains("Docker daemon not running"));
let err = DockerError::SocketNotFound;
assert!(err.to_string().contains("Docker socket not found"));
let err = DockerError::PermissionDenied;
assert!(err.to_string().contains("Permission denied"));
let err = DockerError::Build("layer failed".to_string());
assert!(err.to_string().contains("layer failed"));
}
}