diff --git a/Cargo.lock b/Cargo.lock index d87483e..9b704c2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2121,9 +2121,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.103.10" +version = "0.103.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df33b2b81ac578cabaf06b89b0631153a3f416b0a886e8a7a1707fb51abbd1ef" +checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e" dependencies = [ "ring", "rustls-pki-types", diff --git a/src/executor/runner.rs b/src/executor/runner.rs index 1a9d1f1..d6f0ad6 100644 --- a/src/executor/runner.rs +++ b/src/executor/runner.rs @@ -4,8 +4,9 @@ use super::SafetyAnalyzer; use crate::config::Config; use anyhow::Result; use colored::Colorize; +use std::io::Write; use std::process::Stdio; -use tokio::io::{AsyncBufReadExt, BufReader}; +use tokio::io::AsyncReadExt; use tokio::process::Command; /// Command executor with safety checks @@ -50,30 +51,43 @@ impl CommandExecutor { let exit_code = if follow { // Stream output in real-time - let stdout = child.stdout.take().unwrap(); - let stderr = child.stderr.take().unwrap(); + let mut stdout = child.stdout.take().unwrap(); + let mut stderr = child.stderr.take().unwrap(); - let stdout_reader = BufReader::new(stdout); - let stderr_reader = BufReader::new(stderr); - - let mut stdout_lines = stdout_reader.lines(); - let mut stderr_lines = stderr_reader.lines(); + let mut stdout_buf = [0u8; 1024]; + let mut stderr_buf = [0u8; 1024]; + let mut stdout_done = false; + let mut stderr_done = false; // Process output - loop { + while !stdout_done || !stderr_done { tokio::select! { - line = stdout_lines.next_line() => { - match line { - Ok(Some(line)) => println!("{}", line), - Ok(None) => break, - Err(e) => eprintln!("{}: {}", "Error".red(), e), + res = stdout.read(&mut stdout_buf), if !stdout_done => { + match res { + Ok(0) => stdout_done = true, + Ok(n) => { + print!("{}", String::from_utf8_lossy(&stdout_buf[..n])); + std::io::stdout().flush().unwrap_or(()); + } + Err(e) => { + eprintln!("{}: {}", "Error".red(), e); + stdout_done = true; + } } } - line = stderr_lines.next_line() => { - match line { - Ok(Some(line)) => eprintln!("{}", line.red()), - Ok(None) => {} - Err(e) => eprintln!("{}: {}", "Error".red(), e), + res = stderr.read(&mut stderr_buf), if !stderr_done => { + match res { + Ok(0) => stderr_done = true, + Ok(n) => { + // We print stderr in red but without trailing newline if not present + let text = String::from_utf8_lossy(&stderr_buf[..n]); + eprint!("{}", text.red()); + std::io::stderr().flush().unwrap_or(()); + } + Err(e) => { + eprintln!("{}: {}", "Error".red(), e); + stderr_done = true; + } } } }