@@ -342,22 +342,72 @@ struct StderrThread {
342342impl StderrThread {
343343 fn new ( cmd : & str , file : & str , line : u32 , stderr : Option < PipeReader > , capture : bool ) -> Self {
344344 if let Some ( stderr) = stderr {
345+ let file_ = file. to_owned ( ) ;
345346 let thread = std:: thread:: spawn ( move || {
346- let mut output = String :: new ( ) ;
347- BufReader :: new ( stderr)
348- . lines ( )
349- . map_while ( Result :: ok)
350- . for_each ( |line| {
351- if !capture {
352- info ! ( "{line}" ) ;
353- } else {
354- if !output. is_empty ( ) {
355- output. push ( '\n' ) ;
347+ if capture {
348+ let mut output = String :: new ( ) ;
349+ BufReader :: new ( stderr)
350+ . lines ( )
351+ . map_while ( Result :: ok)
352+ . for_each ( |line| {
353+ if !capture {
354+ info ! ( "{line}" ) ;
355+ } else {
356+ if !output. is_empty ( ) {
357+ output. push ( '\n' ) ;
358+ }
359+ output. push_str ( & line) ;
356360 }
357- output. push_str ( & line) ;
361+ } ) ;
362+ return output;
363+ }
364+
365+ // Log output one line at a time, including progress output separated by CR
366+ let mut reader = BufReader :: new ( stderr) ;
367+ let mut buffer = vec ! [ ] ;
368+ loop {
369+ // Unconditionally try to read more data, since the BufReader buffer is empty
370+ let result = match reader. fill_buf ( ) {
371+ Ok ( buffer) => buffer,
372+ Err ( error) => {
373+ warn ! ( "Error reading from child process: {error:?} at {file_}:{line}" ) ;
374+ break ;
375+ }
376+ } ;
377+ // Add the result onto our own buffer
378+ buffer. extend ( result) ;
379+ // Empty the BufReader
380+ let read_len = result. len ( ) ;
381+ reader. consume ( read_len) ;
382+
383+ // Log output. Take whole “lines” at every LF or CR (for progress bars etc),
384+ // but leave any incomplete lines in our buffer so we can try to complete them.
385+ while let Some ( offset) = buffer. iter ( ) . position ( |& b| b == b'\n' || b == b'\r' ) {
386+ let line = & buffer[ ..offset] ;
387+ let line = str:: from_utf8 ( line) . map_err ( |_| line) ;
388+ match line {
389+ Ok ( string) => info ! ( "{string}" ) ,
390+ Err ( bytes) => info ! ( "{bytes:?}" ) ,
358391 }
359- } ) ;
360- output
392+ buffer = buffer. split_off ( offset + 1 ) ;
393+ }
394+
395+ if read_len == 0 {
396+ break ;
397+ }
398+ }
399+
400+ // Log any remaining incomplete line
401+ if !buffer. is_empty ( ) {
402+ let line = & buffer;
403+ let line = str:: from_utf8 ( line) . map_err ( |_| line) ;
404+ match line {
405+ Ok ( string) => info ! ( "{string}" ) ,
406+ Err ( bytes) => info ! ( "{bytes:?}" ) ,
407+ }
408+ }
409+
410+ "" . to_owned ( )
361411 } ) ;
362412 Self {
363413 cmd : cmd. into ( ) ,
0 commit comments