treeflow 0.1.9

CLI tool for simplified Git worktree management to speed up switching contexts when working collaboratively.
Documentation
use crate::utils::errors::CustomError;
use std::path::PathBuf;
use std::process::{Command, Output};

pub fn branch_exists(branch: String) -> Result<bool, CustomError> {
    match git(&["show-ref", "--quiet", branch.as_str()]) {
        Ok(_) => Ok(true),
        Err(err) =>
            match err {
                CustomError::ProcessFailed(Some(1), _, _, _) => Ok(false),
                _ => Err(err)
            }
    }
}

pub fn checkout_worktree(dir: &PathBuf, branch: &str) -> Result<Output, CustomError> {
    let dir_str = dir.to_str().ok_or(CustomError::Custom(dir.display().to_string() + " was not a UTF-8 string."))?;
    git(&["worktree", "add", dir_str, branch])
}

pub fn new_worktree(dir: &PathBuf, branch: String) -> Result<Output, CustomError> {
    let dir_str = dir.to_str().ok_or(CustomError::Custom(dir.display().to_string() + " was not a UTF-8 string."))?;
    git(&["worktree", "add", dir_str, "-b", branch.as_str()])
}

pub fn list_branches(pattern: &str) -> Result<Vec<String>, CustomError> {
    let output = git(&["branch", "-l", &format!("{}*", pattern)])?;
    let branches: Vec<String> = str::from_utf8(&output.stdout)?.to_string()
        .lines()
        .map(|line| line.trim_start_matches("* ").trim_start_matches("+ ").trim_start_matches(" ").trim_end_matches(" ").to_string())
        .collect();
    Ok(branches)
}

pub fn remove_worktree(name: &str, force: bool) -> Result<Output, CustomError> {
    let mut args = vec!["worktree", "remove", name];
    if force {
        args.push("--force");
    }
    git(&args)
}

pub fn delete_branch(branch: &str, force: bool) -> Result<Output, CustomError> {
    let mut args = vec!["branch", "-D", branch];
    if !force {
        args = vec!["branch", "-d", branch];
    }
    git(&args)
}

fn git(args: &[&str]) -> Result<Output, CustomError> {
    let output = Command::new("git")
        .args(args)
        .output()?;
    match output.status.success() {
        true => Ok(output),
        false => Err(CustomError::ProcessFailed(output.status.code(), "git".to_string(), std::str::from_utf8(&output.stdout).map(|str| str.to_string())?, std::str::from_utf8(&output.stderr).map(|str| str.to_string())?))
    }
}