pub fn run_cmd_in_with_timeout(
dir: &Path,
program: &str,
args: &[&str],
timeout: Duration,
) -> Result<RunOutput, RunError>Expand description
Run a command in a directory, killing it if it exceeds timeout.
Uses background threads to drain stdout and stderr so a chatty process can’t block on pipe buffer overflow. On timeout, the child is killed and any output collected before the kill is included in the error.
Returns RunError::Timeout if the process was killed.
Returns RunError::NonZeroExit if it completed with a non-zero status.
Returns RunError::Spawn if the process couldn’t start.
§Caveat: grandchildren
Only the direct child process receives the kill signal. Grandchildren
(spawned by the child) become orphans and continue running, and they
may hold the stdout/stderr pipes open, delaying this function’s return
until they exit naturally. This is rare for direct invocations of
git/jj but can matter for shell wrappers — use exec in the shell
command (e.g., sh -c "exec git fetch") to replace the shell with the
target process and avoid the grandchild case.
let repo = Path::new("/repo");
match run_cmd_in_with_timeout(repo, "git", &["fetch"], Duration::from_secs(30)) {
Ok(_) => println!("fetched"),
Err(RunError::Timeout { elapsed, .. }) => {
eprintln!("fetch hung, killed after {elapsed:?}");
}
Err(e) => return Err(e.into()),
}