use std::ffi::OsString;
use std::path::PathBuf;
use std::process::ExitCode;
use anyhow::anyhow;
use cabin_core::ColorChoice;
use clap::Parser;
const COMMAND: &str = "stamp";
pub(crate) fn dispatch(argv: &[OsString]) -> Option<ExitCode> {
let operands = match argv.get(1) {
Some(first) if first == COMMAND => &argv[2..],
_ => return None,
};
let program_name = OsString::from("cabin stamp");
let parsed = match StampArgs::try_parse_from(
std::iter::once(program_name).chain(operands.iter().cloned()),
) {
Ok(parsed) => parsed,
Err(err) => err.exit(),
};
Some(match execute(&parsed) {
Ok(code) => code,
Err(err) => {
crate::error_rendering::render_error(&err, ColorChoice::Never);
ExitCode::FAILURE
}
})
}
#[derive(Parser)]
struct StampArgs {
#[arg(value_name = "FILE")]
file: PathBuf,
#[arg(
last = true,
allow_hyphen_values = true,
required = true,
value_name = "ARGV"
)]
command: Vec<String>,
}
fn execute(args: &StampArgs) -> anyhow::Result<ExitCode> {
let Some((program, rest)) = args.command.split_first() else {
anyhow::bail!("cabin stamp: missing command after `--`");
};
match std::process::Command::new(program).args(rest).status() {
Ok(status) if status.success() => {
std::fs::write(&args.file, []).map_err(|err| {
anyhow!(
"cabin stamp: failed to write {}: {err}",
args.file.display()
)
})?;
Ok(ExitCode::SUCCESS)
}
Ok(status) => Ok(ExitCode::from(
u8::try_from(status.code().unwrap_or(1)).unwrap_or(1),
)),
Err(err) => Err(anyhow!("cabin stamp: failed to run {program}: {err}")),
}
}