use std::io::Read;
use std::process::{Child, ExitStatus};
use crate::fanout;
use crate::spawner;
pub fn spawn_all_piped(cmds: &[String]) -> std::io::Result<Vec<Child>> {
let mut children = Vec::with_capacity(cmds.len());
for cmd in cmds {
match spawner::spawn_one_piped_stdout(cmd) {
Ok(c) => children.push(c),
Err(e) => {
for mut prior in children.into_iter() {
let _ = prior.kill();
let _ = prior.wait();
}
return Err(e);
}
}
}
Ok(children)
}
pub fn run_with_capture<R: Read, W: std::io::Write>(
reader: R,
children: Vec<Child>,
out: &mut W,
) -> std::io::Result<Vec<ExitStatus>> {
let mut children = children;
let stdouts: Vec<Option<std::process::ChildStdout>> =
children.iter_mut().map(|c| c.stdout.take()).collect();
let drainer_handles: Vec<std::thread::JoinHandle<std::io::Result<Vec<u8>>>> = stdouts
.into_iter()
.map(|maybe_stdout| {
std::thread::spawn(move || {
let mut buf = Vec::new();
if let Some(mut h) = maybe_stdout {
h.read_to_end(&mut buf)?;
}
Ok(buf)
})
})
.collect();
let statuses = fanout::run(reader, children)?;
let mut captured: Vec<Vec<u8>> = Vec::with_capacity(drainer_handles.len());
for handle in drainer_handles {
let bytes = handle
.join()
.map_err(|_| std::io::Error::other("capture drainer thread panicked"))??;
captured.push(bytes);
}
for bytes in &captured {
if bytes.is_empty() {
continue;
}
out.write_all(bytes)?;
if !bytes.ends_with(b"\n") {
out.write_all(b"\n")?;
}
}
out.flush()?;
Ok(statuses)
}