#![allow(dead_code)]
use std::process::{Command, ExitStatus, Stdio};
use std::time::{Duration, Instant};
use anyhow::{Context, Result};
#[derive(Debug)]
pub struct CommandResult {
pub success: bool,
pub exit_code: i32,
pub stdout: String,
pub stderr: String,
pub duration: Duration,
}
impl CommandResult {
pub fn from_status(status: ExitStatus, stdout: String, stderr: String, duration: Duration) -> Self {
let exit_code = status.code().unwrap_or(-1);
Self {
success: status.success(),
exit_code,
stdout,
stderr,
duration,
}
}
}
pub fn run_command(
program: &str,
args: &[String],
inherit_io: bool,
_timeout: Option<Duration>,
) -> Result<CommandResult> {
let start = Instant::now();
let mut cmd = Command::new(program);
cmd.args(args);
if inherit_io {
cmd.stdin(Stdio::inherit());
cmd.stdout(Stdio::inherit());
cmd.stderr(Stdio::inherit());
let status = cmd
.status()
.with_context(|| format!("Failed to execute {}", program))?;
let duration = start.elapsed();
Ok(CommandResult::from_status(
status,
String::new(),
String::new(),
duration,
))
} else {
let output = cmd
.output()
.with_context(|| format!("Failed to execute {}", program))?;
let duration = start.elapsed();
let stdout = String::from_utf8_lossy(&output.stdout).to_string();
let stderr = String::from_utf8_lossy(&output.stderr).to_string();
Ok(CommandResult::from_status(
output.status,
stdout,
stderr,
duration,
))
}
}
pub fn command_exists(program: &str) -> bool {
which::which(program).is_ok()
}