use super::support::{TIMED_OUT_SIGNAL, without_hint_fields};
use std::io::{BufRead, Read};
use std::os::unix::process::ExitStatusExt;
use std::process::{Command, Stdio};
pub(super) const PATIENCE: std::time::Duration = std::time::Duration::from_secs(60);
pub(super) struct Ended {
pub(super) code: Option<i32>,
pub(super) stderr: String,
}
pub(super) fn run_acting_on_line(command: &mut Command, needle: &str, act: &mut dyn FnMut()) -> Ended {
let mut child = command.stdin(Stdio::null()).stdout(Stdio::piped()).stderr(Stdio::piped()).spawn().expect("process starts");
let mut standard_output = child.stdout.take().expect("piped stdout");
let output_reader = std::thread::spawn(move || {
let mut bytes: Vec<u8> = Vec::new();
let _read = standard_output.read_to_end(&mut bytes);
return bytes;
});
let mut errors = std::io::BufReader::new(child.stderr.take().expect("piped stderr"));
let mut stderr: Vec<u8> = Vec::new();
let mut acted: bool = false;
loop {
let line_start: usize = stderr.len();
if errors.read_until(b'\n', &mut stderr).expect("read standard error") == 0 {
break;
}
if !acted && String::from_utf8_lossy(&stderr[line_start..]).contains(needle) {
acted = true;
act();
}
}
let status = child.wait().expect("process finishes");
assert_ne!(status.signal(), Some(TIMED_OUT_SIGNAL), "the command hit its bound before it ended");
let _output = output_reader.join().expect("standard output reader");
return Ended { code: status.code(), stderr: String::from_utf8_lossy(without_hint_fields(stderr.as_slice()).as_slice()).into_owned() };
}