Skip to content

Commit 12860b6

Browse files
committed
Auto merge of #12727 - ehuss:buffered-shell, r=epage
Buffer console status messages. This adds buffering to some of the console output. This can help with interleaved output, particularly with things like the log output interleaving with status messages. This fixes that interleaving by atomically writing the entire status message, which in turn, helps fix some spurious errors such as #12639. I'm uncertain what the performance impact of this change might have. It might improve performance, since there should be a lot fewer syscalls, and I suspect terminals will be able to handle it more efficiently (and particularly across a network connection). However, I don't know if that will have a noticeable impact. Only the "status" messages are buffered. Everything else is still unbuffered as before.
2 parents 5369c99 + 902b073 commit 12860b6

File tree

1 file changed

+56
-25
lines changed

1 file changed

+56
-25
lines changed

Diff for: src/cargo/core/shell.rs

+56-25
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use std::io::IsTerminal;
44

55
use anstyle::Style;
66
use anstyle_termcolor::to_termcolor_spec;
7-
use termcolor::{self, StandardStream, WriteColor};
7+
use termcolor::{self, BufferWriter, StandardStream, WriteColor};
88

99
use crate::util::errors::CargoResult;
1010
use crate::util::style::*;
@@ -81,9 +81,15 @@ enum ShellOut {
8181
/// A plain write object without color support
8282
Write(Box<dyn Write>),
8383
/// Color-enabled stdio, with information on whether color should be used
84+
///
85+
/// The separate buffered fields are used for buffered writing to the
86+
/// corresponding stream. The non-buffered fields should be used when you
87+
/// do not want content to be buffered.
8488
Stream {
8589
stdout: StandardStream,
90+
buffered_stdout: BufferWriter,
8691
stderr: StandardStream,
92+
buffered_stderr: BufferWriter,
8793
stderr_tty: bool,
8894
color_choice: ColorChoice,
8995
},
@@ -105,10 +111,14 @@ impl Shell {
105111
/// output.
106112
pub fn new() -> Shell {
107113
let auto_clr = ColorChoice::CargoAuto;
114+
let stdout_choice = auto_clr.to_termcolor_color_choice(Stream::Stdout);
115+
let stderr_choice = auto_clr.to_termcolor_color_choice(Stream::Stderr);
108116
Shell {
109117
output: ShellOut::Stream {
110-
stdout: StandardStream::stdout(auto_clr.to_termcolor_color_choice(Stream::Stdout)),
111-
stderr: StandardStream::stderr(auto_clr.to_termcolor_color_choice(Stream::Stderr)),
118+
stdout: StandardStream::stdout(stdout_choice),
119+
buffered_stdout: BufferWriter::stdout(stdout_choice),
120+
stderr: StandardStream::stderr(stderr_choice),
121+
buffered_stderr: BufferWriter::stderr(stderr_choice),
112122
color_choice: ColorChoice::CargoAuto,
113123
stderr_tty: std::io::stderr().is_terminal(),
114124
},
@@ -287,7 +297,9 @@ impl Shell {
287297
pub fn set_color_choice(&mut self, color: Option<&str>) -> CargoResult<()> {
288298
if let ShellOut::Stream {
289299
ref mut stdout,
300+
ref mut buffered_stdout,
290301
ref mut stderr,
302+
ref mut buffered_stderr,
291303
ref mut color_choice,
292304
..
293305
} = self.output
@@ -305,8 +317,12 @@ impl Shell {
305317
),
306318
};
307319
*color_choice = cfg;
308-
*stdout = StandardStream::stdout(cfg.to_termcolor_color_choice(Stream::Stdout));
309-
*stderr = StandardStream::stderr(cfg.to_termcolor_color_choice(Stream::Stderr));
320+
let stdout_choice = cfg.to_termcolor_color_choice(Stream::Stdout);
321+
let stderr_choice = cfg.to_termcolor_color_choice(Stream::Stderr);
322+
*stdout = StandardStream::stdout(stdout_choice);
323+
*buffered_stdout = BufferWriter::stdout(stdout_choice);
324+
*stderr = StandardStream::stderr(stderr_choice);
325+
*buffered_stderr = BufferWriter::stderr(stderr_choice);
310326
}
311327
Ok(())
312328
}
@@ -410,21 +426,26 @@ impl ShellOut {
410426
justified: bool,
411427
) -> CargoResult<()> {
412428
match *self {
413-
ShellOut::Stream { ref mut stderr, .. } => {
414-
stderr.reset()?;
415-
stderr.set_color(&to_termcolor_spec(*style))?;
429+
ShellOut::Stream {
430+
ref mut buffered_stderr,
431+
..
432+
} => {
433+
let mut buffer = buffered_stderr.buffer();
434+
buffer.reset()?;
435+
buffer.set_color(&to_termcolor_spec(*style))?;
416436
if justified {
417-
write!(stderr, "{:>12}", status)?;
437+
write!(buffer, "{:>12}", status)?;
418438
} else {
419-
write!(stderr, "{}", status)?;
420-
stderr.set_color(termcolor::ColorSpec::new().set_bold(true))?;
421-
write!(stderr, ":")?;
439+
write!(buffer, "{}", status)?;
440+
buffer.set_color(termcolor::ColorSpec::new().set_bold(true))?;
441+
write!(buffer, ":")?;
422442
}
423-
stderr.reset()?;
443+
buffer.reset()?;
424444
match message {
425-
Some(message) => writeln!(stderr, " {}", message)?,
426-
None => write!(stderr, " ")?,
445+
Some(message) => writeln!(buffer, " {}", message)?,
446+
None => write!(buffer, " ")?,
427447
}
448+
buffered_stderr.print(&buffer)?;
428449
}
429450
ShellOut::Write(ref mut w) => {
430451
if justified {
@@ -444,11 +465,16 @@ impl ShellOut {
444465
/// Write a styled fragment
445466
fn write_stdout(&mut self, fragment: impl fmt::Display, color: &Style) -> CargoResult<()> {
446467
match *self {
447-
ShellOut::Stream { ref mut stdout, .. } => {
448-
stdout.reset()?;
449-
stdout.set_color(&to_termcolor_spec(*color))?;
450-
write!(stdout, "{}", fragment)?;
451-
stdout.reset()?;
468+
ShellOut::Stream {
469+
ref mut buffered_stdout,
470+
..
471+
} => {
472+
let mut buffer = buffered_stdout.buffer();
473+
buffer.reset()?;
474+
buffer.set_color(&to_termcolor_spec(*color))?;
475+
write!(buffer, "{}", fragment)?;
476+
buffer.reset()?;
477+
buffered_stdout.print(&buffer)?;
452478
}
453479
ShellOut::Write(ref mut w) => {
454480
write!(w, "{}", fragment)?;
@@ -460,11 +486,16 @@ impl ShellOut {
460486
/// Write a styled fragment
461487
fn write_stderr(&mut self, fragment: impl fmt::Display, color: &Style) -> CargoResult<()> {
462488
match *self {
463-
ShellOut::Stream { ref mut stderr, .. } => {
464-
stderr.reset()?;
465-
stderr.set_color(&to_termcolor_spec(*color))?;
466-
write!(stderr, "{}", fragment)?;
467-
stderr.reset()?;
489+
ShellOut::Stream {
490+
ref mut buffered_stderr,
491+
..
492+
} => {
493+
let mut buffer = buffered_stderr.buffer();
494+
buffer.reset()?;
495+
buffer.set_color(&to_termcolor_spec(*color))?;
496+
write!(buffer, "{}", fragment)?;
497+
buffer.reset()?;
498+
buffered_stderr.print(&buffer)?;
468499
}
469500
ShellOut::Write(ref mut w) => {
470501
write!(w, "{}", fragment)?;

0 commit comments

Comments
 (0)