rg (ripgrep 15.2), grep (ours, on ripgrep's regex crates), find and xargs (ours), sed (uutils 0.3 wrapper), diff and cmp (uutils diffutils 0.6 with -r), fd 10.5, jaq 2.3, env and timeout. userland/spawn is a small Command-like client of the process interface. search-test.nu: 42 cases match native tools.
26 lines
1.3 KiB
Rust
26 lines
1.3 KiB
Rust
//! Stop a world child after a deadline. Expiration returns status 124.
|
|
use sausage_spawn::Command;
|
|
use std::time::{Duration, Instant};
|
|
fn run() -> Result<i32, Box<dyn std::error::Error>> {
|
|
let mut args = std::env::args().skip(1);
|
|
let duration = args.next().ok_or("a duration is required")?;
|
|
let (number, multiplier) = match duration.as_bytes().last() {
|
|
Some(b's') => (&duration[..duration.len()-1], 1.0),
|
|
Some(b'm') => (&duration[..duration.len()-1], 60.0),
|
|
Some(b'h') => (&duration[..duration.len()-1], 3600.0),
|
|
Some(b'd') => (&duration[..duration.len()-1], 86400.0),
|
|
_ => (&duration[..], 1.0),
|
|
};
|
|
let duration = Duration::try_from_secs_f64(number.parse::<f64>()? * multiplier)?;
|
|
let program = args.next().ok_or("a command is required")?;
|
|
let child = Command::new(program).args(args).new_group().spawn()?;
|
|
if duration.is_zero() { return Ok(child.wait()); }
|
|
let deadline = Instant::now() + duration;
|
|
loop {
|
|
if let Some(code) = child.try_wait() { return Ok(code); }
|
|
if Instant::now() >= deadline { child.kill(); child.wait(); return Ok(124); }
|
|
std::thread::sleep(Duration::from_millis(10).min(deadline.saturating_duration_since(Instant::now())));
|
|
}
|
|
}
|
|
fn main() { std::process::exit(match run() { Ok(code) => code, Err(e) => { eprintln!("timeout: {e}"); 125 } }); }
|