1use std::process::{Output, Stdio};
2use std::time::Duration;
3
4use anyhow::{Context, Result, anyhow};
5use tokio::process::Command;
6use tokio::time;
7
8pub enum RunOutcome {
10 Completed(Output),
12 TimedOut,
14}
15
16pub async fn run_with_timeout(
18 program: &str,
19 args: &[String],
20 timeout: Duration,
21) -> Result<RunOutcome> {
22 let mut cmd = Command::new(program);
23 cmd.args(args)
24 .stdin(Stdio::null())
25 .stdout(Stdio::piped())
26 .stderr(Stdio::piped());
27
28 let child = cmd
29 .spawn()
30 .with_context(|| format!("Failed to spawn command: {} {:?}", program, args))?;
31
32 match time::timeout(timeout, child.wait_with_output()).await {
33 Ok(Ok(output)) => Ok(RunOutcome::Completed(output)),
34 Ok(Err(e)) => Err(anyhow!("Error while running command: {}", e)),
35 Err(_) => Ok(RunOutcome::TimedOut),
36 }
37}