git-override 0.1.0

Enable overriding git subcommands
Documentation
use crate::{find_upstream_git, scan_path, Options};
use std::path::{Path, PathBuf};
use std::process::Command;

/// This is the main entry point for the [crate] binary called `git`.
pub fn run() -> anyhow::Result<()> {
    let options = Options::parse();
    let upgit = find_upstream_git()?;

    let exepath = if options.upstream {
        upgit.clone()
    } else {
        find_override_path(options.args.iter())?.unwrap_or_else(|| upgit.clone())
    };

    let status = Command::new(exepath)
        .env("GIT_OVERRIDE_UPSTREAM", &upgit)
        .args(&options.args)
        .status()?;

    handle_exit_status(&upgit, status)
}

fn find_override_path<'a, I>(mut args: I) -> anyhow::Result<Option<PathBuf>>
where
    I: Iterator<Item = &'a String>,
{
    if let Some(subcmd) = args.find(|a| !a.starts_with('-')) {
        let candidate = format!("git-{}", subcmd);
        Ok(scan_path(candidate)?.into_iter().next())
    } else {
        Ok(None)
    }
}

fn handle_exit_status(upgit: &Path, status: std::process::ExitStatus) -> anyhow::Result<()> {
    if status.success() {
        Ok(())
    } else {
        let code = status.code().ok_or_else(|| {
            errormsg!(
                "No exit status code from executing upstream git {:?}",
                upgit,
            )
        })?;
        std::process::exit(code);
    }
}