treeflow 0.2.1

CLI tool for simplified Git worktree management to speed up switching contexts when working collaboratively.
Documentation
use std::error::Error;
use std::fmt::Debug;
use std::path::PathBuf;
use std::str::Utf8Error;

#[derive(thiserror::Error)]
pub enum CustomError {
    #[error("Could not convert")]
    ConversionError(#[source] toml::ser::Error),

    #[error("Could not convert")]
    DeserialisationError(#[source] toml::de::Error),

    #[error("Input/Output error")]
    IoError(#[source] std::io::Error),

    #[error("Project was not found {}", .0.display())]
    ProjectNotFound(PathBuf),

    #[error("Work type '{}' was not found", .0)]
    WorkTypeNotFound(String),

    #[error("Branch does not exist '{}'.", .0)]
    BranchNotFound(String),

    #[error("Project with repository '{}' already exists", .0.display())]
    DuplicateProjectRepository(PathBuf),

    #[error("Project with worktrees directory '{}' already exists", .0.display())]
    DuplicateProjectWorktrees(PathBuf),

    #[error("Work type '{}' already exists", .0)]
    DuplicateWorkTypeName(String),

    #[error("Work type prefix '{}' already exists", .0)]
    DuplicateWorkTypePrefix(String),

    // #[error("Git error: {}", .0.as_display())]
    // GitError(git2::Error),

    #[error("Process error:\n  Exit Code: {:?}\nprocess:  '{}'\n  stdOut:   '{}'\n  stdErr:   '{}'", .0, .1, .2, .3)]
    ProcessFailed(Option<i32>, String, String, String),

    #[error("{}", .0)]
    Custom(String),

    #[error("Invalid argument: {}", .0)]
    InvalidArgument(String),

    #[error("Invalid command: {}", .0)]
    InvalidCommand(String),
}

impl Debug for CustomError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        writeln!(f, "{}", self)?;
        if let Some(source) = self.source() {
            writeln!(f, "Caused by:\n\t{}", source)?;
        }
        Ok(())
    }
}

// impl Termination for CustomError {
//     fn report(self) -> ExitCode {  ExitCode::FAILURE }
// }

// impl From<git2::Error> for CustomError {
//     fn from(error: git2::Error) -> Self {
//         CustomError::GitError(error)
//     }
// }

impl From<toml::de::Error> for CustomError {
    fn from(error: toml::de::Error) -> Self {
        CustomError::DeserialisationError(error)
    }
}

impl From<toml::ser::Error> for CustomError {
    fn from(error: toml::ser::Error) -> Self {
        CustomError::ConversionError(error)
    }
}

impl From<std::io::Error> for CustomError {
    fn from(error: std::io::Error) -> Self {
        CustomError::IoError(error)
    }
}

impl From<std::fmt::Error> for CustomError {
    fn from(error: std::fmt::Error) -> Self {
        CustomError::Custom(error.to_string())
    }
}

impl From<std::string::FromUtf8Error> for CustomError {
    fn from(error: std::string::FromUtf8Error) -> Self {
        CustomError::Custom(error.to_string())
    }
}

impl From<clap::error::Error> for CustomError {
    fn from(error: clap::error::Error) -> Self {
        CustomError::Custom(error.to_string())
    }
}

impl From<std::convert::Infallible> for CustomError {
    fn from(_error: std::convert::Infallible) -> Self {
        // This should never actually be called since Infallible can't be constructed
        CustomError::Custom("Infallible error occurred".to_string())
    }
}

impl From<Utf8Error> for CustomError {
    fn from(error: Utf8Error) -> Self {
        CustomError::Custom(error.to_string())
    }
}