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
11pub 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}