cargo-worktree 1.0.0

Deterministic build namespace layer for Cargo
mod cli;
mod commands;
mod core;
mod runtime;

use anyhow::Result;
use clap::Parser;
use cli::{Cli, Command};
use commands::inspect;
use core::{namespace, target};
use runtime::{env as rt_env, exec};
use std::ffi::OsStr;

fn main() -> Result<()> {
    let cli = Cli::parse_from(normalized_args());

    let components = namespace::collect_components()?;
    let target_dir = target::resolve_target_dir(&components)?;

    let injected_env = rt_env::build_env(target_dir.as_deref())?;
    match cli.command {
        Command::Build { args } => exec::exec_cargo("build", &args, &injected_env)?,
        Command::Test { args } => exec::exec_cargo("test", &args, &injected_env)?,
        Command::Run { args } => exec::exec_cargo("run", &args, &injected_env)?,
        Command::Check { args } => exec::exec_cargo("check", &args, &injected_env)?,
        Command::Clippy { args } => exec::exec_cargo("clippy", &args, &injected_env)?,
        Command::Bench { args } => exec::exec_cargo("bench", &args, &injected_env)?,
        Command::Fmt { args } => exec::exec_cargo("fmt", &args, &injected_env)?,
        Command::Clean { args } => exec::exec_cargo("clean", &args, &injected_env)?,
        Command::Install { args } => exec::exec_cargo("install", &args, &injected_env)?,
        Command::Uninstall { args } => exec::exec_cargo("uninstall", &args, &injected_env)?,
        Command::Tree { args } => exec::exec_cargo("tree", &args, &injected_env)?,
        Command::Update { args } => exec::exec_cargo("update", &args, &injected_env)?,
        Command::Inspect => {
            inspect::run(&components, target_dir.as_deref())?;
        }
        Command::Other(v) => {
            let sub = &v[0];
            let args = &v[1..];
            exec::exec_cargo(sub, args, &injected_env)?;
        }
    }

    Ok(())
}

fn normalized_args() -> Vec<std::ffi::OsString> {
    let mut args: Vec<std::ffi::OsString> = std::env::args_os().collect();

    if args
        .get(1)
        .map(|arg| arg == OsStr::new("worktree"))
        .unwrap_or(false)
    {
        args.remove(1);
    }

    args
}