cot-cli 0.6.0

Command-line interface for the Cot web framework
Documentation
use std::env;
use std::path::Path;
use std::process::Command;

fn raw_cargo() -> Command {
    match env::var_os("CARGO") {
        Some(cargo) => Command::new(cargo),
        None => Command::new("cargo"),
    }
}

#[must_use]
pub fn cargo() -> Command {
    let mut cmd = raw_cargo();
    cmd.env_remove("RUSTFLAGS");
    cmd.env("CARGO_INCREMENTAL", "0");

    cmd
}

#[must_use]
pub fn project_cargo(project_path: &Path) -> Command {
    let mut cmd = cargo();
    cmd.current_dir(project_path);
    cmd.env("CARGO_TARGET_DIR", project_path.join("target"));

    cmd
}

pub const WORKSPACE_STUB: &str = "[workspace]\nresolver = \"3\"";

#[derive(Debug, Copy, Clone)]
enum CargoCommand {
    Init,
    New,
}

#[must_use]
pub fn get_nth_crate_name(i: u8) -> String {
    format!("cargo-test-crate-{i}")
}

pub fn make_workspace_package(path: &Path, packages: u8) -> anyhow::Result<()> {
    let workspace_cargo_toml = path.join("Cargo.toml");
    std::fs::write(workspace_cargo_toml, WORKSPACE_STUB)?;

    for i in 0..packages {
        let package_path = path.join(get_nth_crate_name(i + 1));
        make_package(&package_path)?;
    }

    Ok(())
}

pub fn make_package(path: &Path) -> anyhow::Result<()> {
    if path.exists() {
        create_cargo_project(path, path, CargoCommand::Init)
    } else {
        create_cargo_project(
            path,
            path.parent()
                .expect("parent directory must exist when creating a crate"),
            CargoCommand::New,
        )
    }
}

fn create_cargo_project(path: &Path, current_dir: &Path, cmd: CargoCommand) -> anyhow::Result<()> {
    let mut base = cargo();

    let cmd = match cmd {
        CargoCommand::Init => base.arg("init"),
        CargoCommand::New => base.arg("new"),
    };

    cmd.current_dir(current_dir);
    cmd.arg(path).output()?;

    Ok(())
}