Skip to content

Commit 4b713e4

Browse files
committed
Add spawn_pipe_thread to capture pipe output
Introduce a reusable helper that reads from a reader, writes to a sink, and sends the collected bytes via a channel. Use it for both stdout and stderr in Command::try_call, replacing the previous inline threads and duplicated logic.
1 parent fcd0fb5 commit 4b713e4

File tree

1 file changed

+34
-50
lines changed

1 file changed

+34
-50
lines changed

src/util/command.rs

Lines changed: 34 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use std::sync::mpsc::Sender;
12
use std::{
23
fmt::{self},
34
io::{Read, Write},
@@ -156,6 +157,36 @@ impl Command {
156157
// }
157158
// }
158159

160+
fn spawn_pipe_thread<R, W>(
161+
mut reader: R,
162+
sink: W,
163+
tx: Sender<Vec<u8>>,
164+
) -> thread::JoinHandle<()>
165+
where
166+
R: Read + Send + 'static,
167+
W: Write + Send + 'static,
168+
{
169+
thread::spawn(move || {
170+
let mut output = Vec::new();
171+
let mut buf = [0u8; 8192];
172+
let mut sink = sink;
173+
174+
loop {
175+
let n = match reader.read(&mut buf) {
176+
Ok(0) => break,
177+
Ok(n) => n,
178+
Err(_) => break,
179+
};
180+
181+
output.extend_from_slice(&buf[..n]);
182+
let _ = sink.write_all(&buf[..n]);
183+
}
184+
185+
let _ = sink.flush();
186+
let _ = tx.send(output);
187+
})
188+
}
189+
159190
/// Execute the command and capture both stdout and stderr while simultaneously printing them live if live is true
160191
pub fn try_call(&self) -> CommandResults {
161192
println!("{self:#}");
@@ -177,61 +208,14 @@ impl Command {
177208
let stdout = child.stdout.take().expect("Failed to capture stdout");
178209
let stderr = child.stderr.take().expect("Failed to capture stderr");
179210

180-
// Create channels to collect output
181211
let (stdout_tx, stdout_rx) = std::sync::mpsc::channel();
182212
let (stderr_tx, stderr_rx) = std::sync::mpsc::channel();
183213

184-
fn ssd() {}
185-
// Spawn thread to read and print stdout
186-
let stdout_thread = thread::spawn(move || {
187-
let mut reader = stdout;
188-
let mut output = Vec::new();
189-
let mut buf = [0u8; 8192];
190-
191-
let mut out = std::io::stdout().lock();
192-
193-
loop {
194-
let n = match reader.read(&mut buf) {
195-
Ok(0) => break,
196-
Ok(n) => n,
197-
Err(_) => break,
198-
};
199-
200-
output.extend_from_slice(&buf[..n]);
201-
let _ = out.write_all(&buf[..n]); // <-- bytes, not chars
202-
let _ = out.flush();
203-
}
204-
205-
let _ = stdout_tx.send(output);
206-
});
207-
208-
// Spawn thread to read and print stderr
209-
let stderr_thread = thread::spawn(move || {
210-
let mut reader = stderr;
211-
let mut output = Vec::new();
212-
let mut buf = [0u8; 8192];
213-
214-
let mut err = std::io::stderr().lock();
215-
216-
loop {
217-
let n = match reader.read(&mut buf) {
218-
Ok(0) => break,
219-
Ok(n) => n,
220-
Err(_) => break,
221-
};
222-
223-
output.extend_from_slice(&buf[..n]);
224-
let _ = err.write_all(&buf[..n]);
225-
let _ = err.flush();
226-
}
227-
228-
let _ = stderr_tx.send(output);
229-
});
230-
231-
// Wait for the child process to complete
214+
let stdout_thread = Self::spawn_pipe_thread(stdout, std::io::stdout(), stdout_tx);
215+
let stderr_thread = Self::spawn_pipe_thread(stderr, std::io::stderr(), stderr_tx);
216+
232217
let status = child.wait().expect("Failed to wait on child process");
233218

234-
// Wait for threads to finish and collect output
235219
stdout_thread.join().expect("Failed to join stdout thread");
236220
stderr_thread.join().expect("Failed to join stderr thread");
237221

0 commit comments

Comments
 (0)