contain-rs 0.1.3

Run containers with podman (or docker)
Documentation
use std::{collections::HashMap, fmt::Display};

use tracing_error::SpanTrace;

pub type Result<T> = std::result::Result<T, ContainersError>;

#[derive(Debug)]
pub enum ErrorType {
    Unrecoverable,
    CommandError,
    JsonError,
    LogError,
    WaitError,
    PsError,
    InspectError,
}

#[derive(Debug)]
pub struct Context {
    source: Option<Box<dyn std::error::Error>>,
    span_trace: SpanTrace,
    info: HashMap<String, String>,
}

impl Context {
    pub fn new() -> Self {
        Self {
            source: None,
            span_trace: SpanTrace::capture(),
            info: HashMap::new(),
        }
    }

    pub fn source<T: std::error::Error + 'static>(mut self, error: T) -> Self {
        self.source = Some(Box::new(error));
        self
    }

    pub fn span_trace(mut self, span_trace: SpanTrace) -> Self {
        self.span_trace = span_trace;
        self
    }

    pub fn info<T: Into<String>, T2: std::fmt::Debug + ?Sized>(
        mut self,
        key: T,
        value: &T2,
    ) -> Self {
        self.info.insert(key.into(), format!("{:?}", value));
        self
    }

    pub fn into_error(self, typ: ErrorType) -> ContainersError {
        ContainersError::from_type_and_context(typ, self)
    }
}

#[derive(Debug)]
pub struct ContainersError {
    pub typ: ErrorType,
    pub context: Context,
}

#[allow(dead_code)]
impl ContainersError {
    fn from_type(typ: ErrorType) -> Self {
        Self::from_type_and_context(typ, Context::new())
    }

    fn from_type_and_context(typ: ErrorType, context: Context) -> Self {
        Self { typ, context }
    }
}

impl<T: std::error::Error + 'static> From<T> for Context {
    fn from(e: T) -> Self {
        Self::new().source(e).span_trace(SpanTrace::capture())
    }
}

impl Display for ContainersError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}: {}", self.typ, self.context,)
    }
}

impl Display for ErrorType {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            ErrorType::Unrecoverable => write!(f, "Unrecoverable Error"),
            ErrorType::CommandError => write!(f, "Command Error"),
            ErrorType::LogError => write!(f, "Log Error"),
            ErrorType::WaitError => write!(f, "Wait Error"),
            ErrorType::PsError => write!(f, "Ps Error"),
            ErrorType::InspectError => write!(f, "Inspect Error"),
            ErrorType::JsonError => write!(f, "Inspect Error"),
        }
    }
}

impl Display for Context {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match &self.source {
            Some(source) => write!(
                f,
                "Span trace: \n{}\nSource error: \n{}\n",
                self.span_trace, source
            ),
            None => write!(f, "Span trace: \n{}\n", self.span_trace),
        }
    }
}

impl std::error::Error for ContainersError {}