use std::os::unix::process::CommandExt;
use std::process::Output;
use anyhow::{Context, Result, ensure};
use tokio::process::{Child, Command};
pub fn spawn(command: &mut Command) -> Result<Child> {
debug!("{:?}", command.as_std());
command.spawn().with_context(|| context(command))
}
pub async fn status(command: &mut Command) -> Result<i32> {
let status = spawn(command)?.wait().await.with_context(|| context(command))?;
status.code().context("no error code")
}
pub async fn exit_status(command: &mut Command) -> Result<()> {
let code = status(command).await?;
if code != 0 {
std::process::exit(code);
}
Ok(())
}
pub async fn execute(command: &mut Command) -> Result<()> {
let code = status(command).await?;
ensure!(code == 0, "failed with code {code}");
Ok(())
}
pub fn replace(mut command: Command) -> ! {
debug!("{:?}", command.as_std());
panic!("{}", command.as_std_mut().exec());
}
pub async fn output(command: &mut Command) -> Result<Output> {
debug!("{:?}", command.as_std());
let output = command.output().await.with_context(|| context(command))?;
ensure!(output.status.success(), "failed with status {}", output.status);
Ok(output)
}
pub async fn output_line(command: &mut Command) -> Result<String> {
let mut output = output(command).await?;
assert!(output.stderr.is_empty());
assert_eq!(output.stdout.pop(), Some(b'\n'));
Ok(String::from_utf8(output.stdout)?)
}
fn context(command: &Command) -> String {
format!("executing {:?}", command.as_std())
}