wr/
tee_helper.rs

1use std::io::{self, Read, Write};
2use std::process::{Command, Stdio};
3use std::thread;
4
5pub struct Captured {
6    pub stdout: Vec<u8>,
7    pub stderr: Vec<u8>,
8    pub status: std::process::ExitStatus,
9}
10
11/// Run a pre-configured `Command` so that its stdout & stderr are
12/// both forwarded live to the parent’s stdout/stderr and also captured.
13pub fn run_and_capture(mut cmd: Command) -> io::Result<Captured> {
14    let mut child = cmd.stdout(Stdio::piped()).stderr(Stdio::piped()).spawn()?;
15
16    let mut child_stdout = child.stdout.take().unwrap();
17    let mut child_stderr = child.stderr.take().unwrap();
18
19    let stdout_buf = std::sync::Arc::new(std::sync::Mutex::new(Vec::new()));
20    let stderr_buf = std::sync::Arc::new(std::sync::Mutex::new(Vec::new()));
21
22    let out_clone = stdout_buf.clone();
23    let out_handle = thread::spawn(move || {
24        let mut buf = [0u8; 4096];
25        let mut out = io::stdout();
26        while let Ok(n) = child_stdout.read(&mut buf) {
27            if n == 0 {
28                break;
29            }
30            let chunk = &buf[..n];
31            out.write_all(chunk).ok();
32            out.flush().ok();
33            out_clone.lock().unwrap().extend_from_slice(chunk);
34        }
35    });
36
37    let err_clone = stderr_buf.clone();
38    let err_handle = thread::spawn(move || {
39        let mut buf = [0u8; 4096];
40        let mut err = io::stderr();
41        while let Ok(n) = child_stderr.read(&mut buf) {
42            if n == 0 {
43                break;
44            }
45            let chunk = &buf[..n];
46            err.write_all(chunk).ok();
47            err.flush().ok();
48            err_clone.lock().unwrap().extend_from_slice(chunk);
49        }
50    });
51
52    let status = child.wait()?;
53    out_handle.join().unwrap();
54    err_handle.join().unwrap();
55
56    let stdout = stdout_buf.lock().unwrap().clone();
57    let stderr = stderr_buf.lock().unwrap().clone();
58
59    Ok(Captured {
60        stdout,
61        stderr,
62        status,
63    })
64}