Skip to content

Commit

Permalink
Auto merge of #12727 - ehuss:buffered-shell, r=epage
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
bors committed Sep 23, 2023
2 parents 5369c99 + 902b073 commit 12860b6
Showing 1 changed file with 56 additions and 25 deletions.
81 changes: 56 additions & 25 deletions src/cargo/core/shell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::io::IsTerminal;

use anstyle::Style;
use anstyle_termcolor::to_termcolor_spec;
use termcolor::{self, StandardStream, WriteColor};
use termcolor::{self, BufferWriter, StandardStream, WriteColor};

use crate::util::errors::CargoResult;
use crate::util::style::*;
Expand Down Expand Up @@ -81,9 +81,15 @@ enum ShellOut {
/// A plain write object without color support
Write(Box<dyn Write>),
/// Color-enabled stdio, with information on whether color should be used
///
/// The separate buffered fields are used for buffered writing to the
/// corresponding stream. The non-buffered fields should be used when you
/// do not want content to be buffered.
Stream {
stdout: StandardStream,
buffered_stdout: BufferWriter,
stderr: StandardStream,
buffered_stderr: BufferWriter,
stderr_tty: bool,
color_choice: ColorChoice,
},
Expand All @@ -105,10 +111,14 @@ impl Shell {
/// output.
pub fn new() -> Shell {
let auto_clr = ColorChoice::CargoAuto;
let stdout_choice = auto_clr.to_termcolor_color_choice(Stream::Stdout);
let stderr_choice = auto_clr.to_termcolor_color_choice(Stream::Stderr);
Shell {
output: ShellOut::Stream {
stdout: StandardStream::stdout(auto_clr.to_termcolor_color_choice(Stream::Stdout)),
stderr: StandardStream::stderr(auto_clr.to_termcolor_color_choice(Stream::Stderr)),
stdout: StandardStream::stdout(stdout_choice),
buffered_stdout: BufferWriter::stdout(stdout_choice),
stderr: StandardStream::stderr(stderr_choice),
buffered_stderr: BufferWriter::stderr(stderr_choice),
color_choice: ColorChoice::CargoAuto,
stderr_tty: std::io::stderr().is_terminal(),
},
Expand Down Expand Up @@ -287,7 +297,9 @@ impl Shell {
pub fn set_color_choice(&mut self, color: Option<&str>) -> CargoResult<()> {
if let ShellOut::Stream {
ref mut stdout,
ref mut buffered_stdout,
ref mut stderr,
ref mut buffered_stderr,
ref mut color_choice,
..
} = self.output
Expand All @@ -305,8 +317,12 @@ impl Shell {
),
};
*color_choice = cfg;
*stdout = StandardStream::stdout(cfg.to_termcolor_color_choice(Stream::Stdout));
*stderr = StandardStream::stderr(cfg.to_termcolor_color_choice(Stream::Stderr));
let stdout_choice = cfg.to_termcolor_color_choice(Stream::Stdout);
let stderr_choice = cfg.to_termcolor_color_choice(Stream::Stderr);
*stdout = StandardStream::stdout(stdout_choice);
*buffered_stdout = BufferWriter::stdout(stdout_choice);
*stderr = StandardStream::stderr(stderr_choice);
*buffered_stderr = BufferWriter::stderr(stderr_choice);
}
Ok(())
}
Expand Down Expand Up @@ -410,21 +426,26 @@ impl ShellOut {
justified: bool,
) -> CargoResult<()> {
match *self {
ShellOut::Stream { ref mut stderr, .. } => {
stderr.reset()?;
stderr.set_color(&to_termcolor_spec(*style))?;
ShellOut::Stream {
ref mut buffered_stderr,
..
} => {
let mut buffer = buffered_stderr.buffer();
buffer.reset()?;
buffer.set_color(&to_termcolor_spec(*style))?;
if justified {
write!(stderr, "{:>12}", status)?;
write!(buffer, "{:>12}", status)?;
} else {
write!(stderr, "{}", status)?;
stderr.set_color(termcolor::ColorSpec::new().set_bold(true))?;
write!(stderr, ":")?;
write!(buffer, "{}", status)?;
buffer.set_color(termcolor::ColorSpec::new().set_bold(true))?;
write!(buffer, ":")?;
}
stderr.reset()?;
buffer.reset()?;
match message {
Some(message) => writeln!(stderr, " {}", message)?,
None => write!(stderr, " ")?,
Some(message) => writeln!(buffer, " {}", message)?,
None => write!(buffer, " ")?,
}
buffered_stderr.print(&buffer)?;
}
ShellOut::Write(ref mut w) => {
if justified {
Expand All @@ -444,11 +465,16 @@ impl ShellOut {
/// Write a styled fragment
fn write_stdout(&mut self, fragment: impl fmt::Display, color: &Style) -> CargoResult<()> {
match *self {
ShellOut::Stream { ref mut stdout, .. } => {
stdout.reset()?;
stdout.set_color(&to_termcolor_spec(*color))?;
write!(stdout, "{}", fragment)?;
stdout.reset()?;
ShellOut::Stream {
ref mut buffered_stdout,
..
} => {
let mut buffer = buffered_stdout.buffer();
buffer.reset()?;
buffer.set_color(&to_termcolor_spec(*color))?;
write!(buffer, "{}", fragment)?;
buffer.reset()?;
buffered_stdout.print(&buffer)?;
}
ShellOut::Write(ref mut w) => {
write!(w, "{}", fragment)?;
Expand All @@ -460,11 +486,16 @@ impl ShellOut {
/// Write a styled fragment
fn write_stderr(&mut self, fragment: impl fmt::Display, color: &Style) -> CargoResult<()> {
match *self {
ShellOut::Stream { ref mut stderr, .. } => {
stderr.reset()?;
stderr.set_color(&to_termcolor_spec(*color))?;
write!(stderr, "{}", fragment)?;
stderr.reset()?;
ShellOut::Stream {
ref mut buffered_stderr,
..
} => {
let mut buffer = buffered_stderr.buffer();
buffer.reset()?;
buffer.set_color(&to_termcolor_spec(*color))?;
write!(buffer, "{}", fragment)?;
buffer.reset()?;
buffered_stderr.print(&buffer)?;
}
ShellOut::Write(ref mut w) => {
write!(w, "{}", fragment)?;
Expand Down

0 comments on commit 12860b6

Please sign in to comment.