diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock index 8195823efaff..69bb98135ca1 100644 --- a/src/bootstrap/Cargo.lock +++ b/src/bootstrap/Cargo.lock @@ -67,11 +67,11 @@ dependencies = [ "sha2", "sysinfo", "tar", + "termcolor", "toml", "walkdir", "winapi", "xz2", - "yansi-term", ] [[package]] @@ -649,6 +649,15 @@ dependencies = [ "xattr", ] +[[package]] +name = "termcolor" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +dependencies = [ + "winapi-util", +] + [[package]] name = "thread_local" version = "1.1.4" @@ -813,12 +822,3 @@ name = "yansi" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" - -[[package]] -name = "yansi-term" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe5c30ade05e61656247b2e334a031dfd0cc466fadef865bdcdea8d537951bf1" -dependencies = [ - "winapi", -] diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index e704799867b3..83e63df50147 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -47,13 +47,13 @@ serde_derive = "1.0.137" serde_json = "1.0.2" sha2 = "0.10" tar = "0.4" +termcolor = "1.2.0" toml = "0.5" ignore = "0.4.10" opener = "0.5" once_cell = "1.7.2" xz2 = "0.1" walkdir = "2" -yansi-term = "0.1.2" # Dependencies needed by the build-metrics feature sysinfo = { version = "0.26.0", optional = true } diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 0eff8769b609..9e1d88a6aefc 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -89,7 +89,7 @@ pub use crate::builder::PathSet; use crate::cache::{Interned, INTERNER}; pub use crate::config::Config; pub use crate::flags::Subcommand; -use yansi_term::Color; +use termcolor::{ColorChoice, StandardStream, WriteColor}; const LLVM_TOOLS: &[&str] = &[ "llvm-cov", // used to generate coverage report @@ -1577,21 +1577,29 @@ to download LLVM rather than building it. self.config.ninja_in_file } - pub fn color_for_stdout(&self, color: Color, message: &str) -> String { - self.color_for_inner(color, message, self.config.stdout_is_tty) + pub fn colored_stdout R>(&self, f: F) -> R { + self.colored_stream_inner(StandardStream::stdout, self.config.stdout_is_tty, f) } - pub fn color_for_stderr(&self, color: Color, message: &str) -> String { - self.color_for_inner(color, message, self.config.stderr_is_tty) + pub fn colored_stderr R>(&self, f: F) -> R { + self.colored_stream_inner(StandardStream::stderr, self.config.stderr_is_tty, f) } - fn color_for_inner(&self, color: Color, message: &str, is_tty: bool) -> String { - let use_color = match self.config.color { - flags::Color::Always => true, - flags::Color::Never => false, - flags::Color::Auto => is_tty, + fn colored_stream_inner(&self, constructor: C, is_tty: bool, f: F) -> R + where + C: Fn(ColorChoice) -> StandardStream, + F: FnOnce(&mut dyn WriteColor) -> R, + { + let choice = match self.config.color { + flags::Color::Always => ColorChoice::Always, + flags::Color::Never => ColorChoice::Never, + flags::Color::Auto if !is_tty => ColorChoice::Never, + flags::Color::Auto => ColorChoice::Auto, }; - if use_color { color.paint(message).to_string() } else { message.to_string() } + let mut stream = constructor(choice); + let result = f(&mut stream); + stream.reset().unwrap(); + result } } diff --git a/src/bootstrap/render_tests.rs b/src/bootstrap/render_tests.rs index 4e7b85d97ee5..fd78e449a49b 100644 --- a/src/bootstrap/render_tests.rs +++ b/src/bootstrap/render_tests.rs @@ -10,7 +10,7 @@ use crate::builder::Builder; use std::io::{BufRead, BufReader, Write}; use std::process::{ChildStdout, Command, Stdio}; use std::time::Duration; -use yansi_term::Color; +use termcolor::{Color, ColorSpec, WriteColor}; const TERSE_TESTS_PER_LINE: usize = 88; @@ -139,16 +139,12 @@ impl<'a> Renderer<'a> { } fn render_test_outcome_verbose(&self, outcome: Outcome<'_>, test: &TestOutcome) { + print!("test {} ... ", test.name); + self.builder.colored_stdout(|stdout| outcome.write_long(stdout)).unwrap(); if let Some(exec_time) = test.exec_time { - println!( - "test {} ... {} (in {:.2?})", - test.name, - outcome.long(self.builder), - Duration::from_secs_f64(exec_time) - ); - } else { - println!("test {} ... {}", test.name, outcome.long(self.builder)); + print!(" ({exec_time:.2?})"); } + println!(); } fn render_test_outcome_terse(&mut self, outcome: Outcome<'_>, _: &TestOutcome) { @@ -163,7 +159,7 @@ impl<'a> Renderer<'a> { } self.terse_tests_in_line += 1; - print!("{}", outcome.short(self.builder)); + self.builder.colored_stdout(|stdout| outcome.write_short(stdout)).unwrap(); let _ = std::io::stdout().flush(); } @@ -208,10 +204,11 @@ impl<'a> Renderer<'a> { } } + print!("\ntest result: "); + self.builder.colored_stdout(|stdout| outcome.write_long(stdout)).unwrap(); println!( - "\ntest result: {}. {} passed; {} failed; {} ignored; {} measured; \ - {} filtered out; finished in {:.2?}\n", - outcome.long(self.builder), + ". {} passed; {} failed; {} ignored; {} measured; {} filtered out; \ + finished in {:.2?}\n", suite.passed, suite.failed, suite.ignored, @@ -276,25 +273,51 @@ enum Outcome<'a> { } impl Outcome<'_> { - fn short(&self, builder: &Builder<'_>) -> String { + fn write_short(&self, writer: &mut dyn WriteColor) -> Result<(), std::io::Error> { match self { - Outcome::Ok => builder.color_for_stdout(Color::Green, "."), - Outcome::BenchOk => builder.color_for_stdout(Color::Cyan, "b"), - Outcome::Failed => builder.color_for_stdout(Color::Red, "F"), - Outcome::Ignored { .. } => builder.color_for_stdout(Color::Yellow, "i"), - } - } - - fn long(&self, builder: &Builder<'_>) -> String { - match self { - Outcome::Ok => builder.color_for_stdout(Color::Green, "ok"), - Outcome::BenchOk => builder.color_for_stdout(Color::Cyan, "benchmarked"), - Outcome::Failed => builder.color_for_stdout(Color::Red, "FAILED"), - Outcome::Ignored { reason: None } => builder.color_for_stdout(Color::Yellow, "ignored"), - Outcome::Ignored { reason: Some(reason) } => { - builder.color_for_stdout(Color::Yellow, &format!("ignored, {reason}")) + Outcome::Ok => { + writer.set_color(&ColorSpec::new().set_fg(Some(Color::Green)))?; + write!(writer, ".")?; + } + Outcome::BenchOk => { + writer.set_color(&ColorSpec::new().set_fg(Some(Color::Cyan)))?; + write!(writer, "b")?; + } + Outcome::Failed => { + writer.set_color(&ColorSpec::new().set_fg(Some(Color::Red)))?; + write!(writer, "F")?; + } + Outcome::Ignored { .. } => { + writer.set_color(&ColorSpec::new().set_fg(Some(Color::Yellow)))?; + write!(writer, "i")?; } } + writer.reset() + } + + fn write_long(&self, writer: &mut dyn WriteColor) -> Result<(), std::io::Error> { + match self { + Outcome::Ok => { + writer.set_color(&ColorSpec::new().set_fg(Some(Color::Green)))?; + write!(writer, "ok")?; + } + Outcome::BenchOk => { + writer.set_color(&ColorSpec::new().set_fg(Some(Color::Cyan)))?; + write!(writer, "benchmarked")?; + } + Outcome::Failed => { + writer.set_color(&ColorSpec::new().set_fg(Some(Color::Red)))?; + write!(writer, "FAILED")?; + } + Outcome::Ignored { reason } => { + writer.set_color(&ColorSpec::new().set_fg(Some(Color::Yellow)))?; + write!(writer, "ignored")?; + if let Some(reason) = reason { + write!(writer, ", {reason}")?; + } + } + } + writer.reset() } }