use anyhow::{Context, Result};
use std::path::Path;
use std::process::{Command, ExitStatus, Stdio};
pub fn run_inherit(program: &str, args: &[&str]) -> Result<ExitStatus> {
Command::new(program)
.args(args)
.stdin(Stdio::inherit())
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.status()
.with_context(|| format!("spawning `{program} {}`", args.join(" ")))
}
pub fn run_capture(program: &str, args: &[&str]) -> Result<(ExitStatus, String)> {
let output = Command::new(program)
.args(args)
.stdin(Stdio::null())
.output()
.with_context(|| format!("spawning `{program} {}`", args.join(" ")))?;
let stdout = String::from_utf8_lossy(&output.stdout).to_string();
Ok((output.status, stdout))
}
pub fn run_capture_combined(program: &str, args: &[&str]) -> Result<(ExitStatus, String)> {
let output = Command::new(program)
.args(args)
.stdin(Stdio::null())
.output()
.with_context(|| format!("spawning `{program} {}`", args.join(" ")))?;
let mut combined = String::from_utf8_lossy(&output.stdout).into_owned();
combined.push_str(&String::from_utf8_lossy(&output.stderr));
Ok((output.status, combined))
}
pub fn run_with_stdin_file(program: &str, args: &[&str], stdin_path: &Path) -> Result<ExitStatus> {
let mut child = Command::new(program)
.args(args)
.stdin(Stdio::piped())
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.spawn()
.with_context(|| format!("spawning `{program} {}`", args.join(" ")))?;
let mut file = std::fs::File::open(stdin_path)
.with_context(|| format!("opening {}", stdin_path.display()))?;
let mut stdin = child.stdin.take().expect("child stdin was piped");
std::io::copy(&mut file, &mut stdin).context("streaming file to child stdin")?;
drop(stdin);
child.wait().context("waiting for child process")
}
pub fn require_success(what: &str, status: ExitStatus) -> Result<()> {
if !status.success() {
anyhow::bail!("{what} failed ({status})");
}
Ok(())
}