Skip to content

Commit b79579a

Browse files
authored
Merge branch 'master' into tracing
2 parents 625a46a + a72b039 commit b79579a

File tree

3 files changed

+72
-14
lines changed

3 files changed

+72
-14
lines changed

examples/progress.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
use cmd_lib::{run_cmd, CmdResult};
2+
3+
#[cmd_lib::main]
4+
fn main() -> CmdResult {
5+
run_cmd!(dd if=/dev/urandom of=/dev/null bs=1M status=progress)?;
6+
7+
Ok(())
8+
}

src/child.rs

Lines changed: 63 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -344,24 +344,74 @@ impl StderrThread {
344344
#[cfg(feature = "tracing")]
345345
let span = tracing::Span::current();
346346
if let Some(stderr) = stderr {
347+
let file_ = file.to_owned();
347348
let thread = std::thread::spawn(move || {
348349
#[cfg(feature = "tracing")]
349350
let _entered = span.enter();
350-
let mut output = String::new();
351-
BufReader::new(stderr)
352-
.lines()
353-
.map_while(Result::ok)
354-
.for_each(|line| {
355-
if !capture {
356-
info!("{line}");
357-
} else {
358-
if !output.is_empty() {
359-
output.push('\n');
351+
if capture {
352+
let mut output = String::new();
353+
BufReader::new(stderr)
354+
.lines()
355+
.map_while(Result::ok)
356+
.for_each(|line| {
357+
if !capture {
358+
info!("{line}");
359+
} else {
360+
if !output.is_empty() {
361+
output.push('\n');
362+
}
363+
output.push_str(&line);
360364
}
361-
output.push_str(&line);
365+
});
366+
return output;
367+
}
368+
369+
// Log output one line at a time, including progress output separated by CR
370+
let mut reader = BufReader::new(stderr);
371+
let mut buffer = vec![];
372+
loop {
373+
// Unconditionally try to read more data, since the BufReader buffer is empty
374+
let result = match reader.fill_buf() {
375+
Ok(buffer) => buffer,
376+
Err(error) => {
377+
warn!("Error reading from child process: {error:?} at {file_}:{line}");
378+
break;
379+
}
380+
};
381+
// Add the result onto our own buffer
382+
buffer.extend(result);
383+
// Empty the BufReader
384+
let read_len = result.len();
385+
reader.consume(read_len);
386+
387+
// Log output. Take whole “lines” at every LF or CR (for progress bars etc),
388+
// but leave any incomplete lines in our buffer so we can try to complete them.
389+
while let Some(offset) = buffer.iter().position(|&b| b == b'\n' || b == b'\r') {
390+
let line = &buffer[..offset];
391+
let line = str::from_utf8(line).map_err(|_| line);
392+
match line {
393+
Ok(string) => info!("{string}"),
394+
Err(bytes) => info!("{bytes:?}"),
362395
}
363-
});
364-
output
396+
buffer = buffer.split_off(offset + 1);
397+
}
398+
399+
if read_len == 0 {
400+
break;
401+
}
402+
}
403+
404+
// Log any remaining incomplete line
405+
if !buffer.is_empty() {
406+
let line = &buffer;
407+
let line = str::from_utf8(line).map_err(|_| line);
408+
match line {
409+
Ok(string) => info!("{string}"),
410+
Err(bytes) => info!("{bytes:?}"),
411+
}
412+
}
413+
414+
"".to_owned()
365415
});
366416
Self {
367417
cmd: cmd.into(),

tests/test_macros.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ fn test_export_cmd() {
217217
fn test_escape() {
218218
let xxx = 42;
219219
assert_eq!(
220-
run_fun!(/bin/echo "\"a你好${xxx}世界b\"").unwrap(),
220+
run_fun!(echo "\"a你好${xxx}世界b\"").unwrap(),
221221
"\"a你好42世界b\""
222222
);
223223
}

0 commit comments

Comments
 (0)