From d955bdeac897227f495ebadb8fb4b258e49ffccd Mon Sep 17 00:00:00 2001 From: rami3l Date: Tue, 15 Aug 2023 09:50:51 +0800 Subject: [PATCH 1/3] Support `RUSTUP_TERM_COLOR` as an override environment variable --- doc/user-guide/src/environment-variables.md | 4 ++++ src/currentprocess/terminalsource.rs | 20 ++++++++++++-------- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/doc/user-guide/src/environment-variables.md b/doc/user-guide/src/environment-variables.md index 8ef3351945..97b876c508 100644 --- a/doc/user-guide/src/environment-variables.md +++ b/doc/user-guide/src/environment-variables.md @@ -29,6 +29,10 @@ determines the directory that traces will be written too. Traces are of the form PID.trace. Traces can be read by the Catapult project [tracing viewer]. +- `RUSTUP_TERM_COLOR` (default: `auto`) Controls whether colored output is used in the terminal. + Set to `auto` to use colors only in tty streams, to `always` to always enable colors, + or to `never` to disable colors. + - `RUSTUP_UNPACK_RAM` *unstable* (default free memory or 500MiB if unable to tell, min 210MiB) Caps the amount of RAM `rustup` will use for IO tasks while unpacking. diff --git a/src/currentprocess/terminalsource.rs b/src/currentprocess/terminalsource.rs index 2a6e28b97b..3f07557271 100644 --- a/src/currentprocess/terminalsource.rs +++ b/src/currentprocess/terminalsource.rs @@ -11,7 +11,7 @@ use termcolor::{ColorChoice, ColorSpec, StandardStream, StandardStreamLock, Writ #[cfg(feature = "test")] use super::filesource::{TestWriter, TestWriterLock}; -use super::process; +use super::{process, varsource::VarSource}; /// Select what stream to make a terminal on pub(super) enum StreamSelector { @@ -73,14 +73,18 @@ enum TerminalInnerLocked { } impl ColorableTerminal { - /// Construct a terminal for the selected stream. Colors written to the - /// terminal will be discarded if the stream is not a tty. + /// A terminal that supports colorisation of a stream. + /// If `RUSTUP_TERM_COLOR` is set to `always`, or if the stream is a tty and + /// `RUSTUP_TERM_COLOR` either unset or set to `auto`, + /// then color commands will be sent to the stream. + /// Otherwise color commands are discarded. pub(super) fn new(stream: StreamSelector) -> Self { - let is_a_tty = stream.is_a_tty(); - let choice = if is_a_tty { - ColorChoice::Auto - } else { - ColorChoice::Never + let env_override = process().var("RUSTUP_TERM_COLOR"); + let choice = match env_override.as_deref() { + Ok("always") => ColorChoice::Always, + Ok("never") => ColorChoice::Never, + _ if stream.is_a_tty() => ColorChoice::Auto, + _ => ColorChoice::Never, }; let inner = match stream { StreamSelector::Stdout => { From 106b9c344727fe9e1cf91939eeb955b4e96dc818 Mon Sep 17 00:00:00 2001 From: rami3l Date: Tue, 15 Aug 2023 09:50:51 +0800 Subject: [PATCH 2/3] Add unit tests for `RUSTUP_TERM_COLOR` --- src/currentprocess/filesource.rs | 2 +- src/currentprocess/terminalsource.rs | 79 ++++++++++++++++++++++++---- 2 files changed, 70 insertions(+), 11 deletions(-) diff --git a/src/currentprocess/filesource.rs b/src/currentprocess/filesource.rs index 36aa508b63..0f021fb212 100644 --- a/src/currentprocess/filesource.rs +++ b/src/currentprocess/filesource.rs @@ -198,7 +198,7 @@ impl Write for TestWriterLock<'_> { #[cfg(feature = "test")] pub(super) type TestWriterInner = Arc>>; /// A thread-safe test file handle that pretends to be e.g. stdout. -#[derive(Clone)] +#[derive(Clone, Default)] #[cfg(feature = "test")] pub(super) struct TestWriter(TestWriterInner); diff --git a/src/currentprocess/terminalsource.rs b/src/currentprocess/terminalsource.rs index 3f07557271..2c189dc372 100644 --- a/src/currentprocess/terminalsource.rs +++ b/src/currentprocess/terminalsource.rs @@ -19,6 +19,8 @@ pub(super) enum StreamSelector { Stderr, #[cfg(feature = "test")] TestWriter(TestWriter), + #[cfg(feature = "test")] + TestTtyWriter(TestWriter), } impl StreamSelector { @@ -36,6 +38,8 @@ impl StreamSelector { }, #[cfg(feature = "test")] StreamSelector::TestWriter(_) => false, + #[cfg(feature = "test")] + StreamSelector::TestTtyWriter(_) => true, } } } @@ -55,7 +59,7 @@ pub struct ColorableTerminal { enum TerminalInner { StandardStream(StandardStream, ColorSpec), #[cfg(feature = "test")] - TestWriter(TestWriter), + TestWriter(TestWriter, ColorChoice), } pub struct ColorableTerminalLocked { @@ -94,7 +98,9 @@ impl ColorableTerminal { TerminalInner::StandardStream(StandardStream::stderr(choice), ColorSpec::new()) } #[cfg(feature = "test")] - StreamSelector::TestWriter(w) => TerminalInner::TestWriter(w), + StreamSelector::TestWriter(w) | StreamSelector::TestTtyWriter(w) => { + TerminalInner::TestWriter(w, choice) + } }; ColorableTerminal { inner: Arc::new(Mutex::new(inner)), @@ -122,7 +128,7 @@ impl ColorableTerminal { TerminalInnerLocked::StandardStream(locked) } #[cfg(feature = "test")] - TerminalInner::TestWriter(w) => TerminalInnerLocked::TestWriter(w.lock()), + TerminalInner::TestWriter(w, _) => TerminalInnerLocked::TestWriter(w.lock()), }); // ColorableTerminalLocked { inner, guard, locked } uninit.assume_init() @@ -136,7 +142,7 @@ impl ColorableTerminal { s.set_color(spec) } #[cfg(feature = "test")] - TerminalInner::TestWriter(_) => Ok(()), + TerminalInner::TestWriter(_, _) => Ok(()), } } @@ -147,7 +153,7 @@ impl ColorableTerminal { s.set_color(spec) } #[cfg(feature = "test")] - TerminalInner::TestWriter(_) => Ok(()), + TerminalInner::TestWriter(_, _) => Ok(()), } } @@ -161,7 +167,7 @@ impl ColorableTerminal { s.set_color(spec) } #[cfg(feature = "test")] - TerminalInner::TestWriter(_) => Ok(()), + TerminalInner::TestWriter(_, _) => Ok(()), } } @@ -169,7 +175,7 @@ impl ColorableTerminal { match self.inner.lock().unwrap().deref_mut() { TerminalInner::StandardStream(s, _color) => s.reset(), #[cfg(feature = "test")] - TerminalInner::TestWriter(_) => Ok(()), + TerminalInner::TestWriter(_, _) => Ok(()), } } @@ -177,7 +183,7 @@ impl ColorableTerminal { match self.inner.lock().unwrap().deref_mut() { TerminalInner::StandardStream(s, _color) => s.write(b"\r")?, #[cfg(feature = "test")] - TerminalInner::TestWriter(w) => w.write(b"\r")?, + TerminalInner::TestWriter(w, _) => w.write(b"\r")?, }; Ok(()) } @@ -194,7 +200,7 @@ impl io::Write for ColorableTerminal { match self.inner.lock().unwrap().deref_mut() { TerminalInner::StandardStream(s, _) => s.write(buf), #[cfg(feature = "test")] - TerminalInner::TestWriter(w) => w.write(buf), + TerminalInner::TestWriter(w, _) => w.write(buf), } } @@ -202,7 +208,7 @@ impl io::Write for ColorableTerminal { match self.inner.lock().unwrap().deref_mut() { TerminalInner::StandardStream(s, _) => s.flush(), #[cfg(feature = "test")] - TerminalInner::TestWriter(w) => w.flush(), + TerminalInner::TestWriter(w, _) => w.flush(), } } } @@ -224,3 +230,56 @@ impl io::Write for ColorableTerminalLocked { } } } + +#[cfg(test)] +mod tests { + use std::collections::HashMap; + + use rustup_macros::unit_test as test; + + use super::*; + use crate::{currentprocess, test::Env}; + + #[test] + fn term_color_choice() { + fn assert_color_choice(env_val: &str, stream: StreamSelector, color_choice: ColorChoice) { + let mut vars = HashMap::new(); + vars.env("RUSTUP_TERM_COLOR", env_val); + let tp = currentprocess::TestProcess { + vars, + ..Default::default() + }; + currentprocess::with(tp.into(), || { + let term = ColorableTerminal::new(stream); + let inner = term.inner.lock().unwrap(); + assert!(matches!( + &*inner, + &TerminalInner::TestWriter(_, choice) if choice == color_choice + )); + }); + } + + assert_color_choice( + "always", + StreamSelector::TestWriter(Default::default()), + ColorChoice::Always, + ); + assert_color_choice( + "never", + StreamSelector::TestWriter(Default::default()), + ColorChoice::Never, + ); + // tty + `auto` enables the colors. + assert_color_choice( + "auto", + StreamSelector::TestTtyWriter(Default::default()), + ColorChoice::Auto, + ); + // non-tty + `auto` does not enable the colors. + assert_color_choice( + "auto", + StreamSelector::TestWriter(Default::default()), + ColorChoice::Never, + ); + } +} From b6cf38019c33f61eca1c5bd38f3a12edab4599d7 Mon Sep 17 00:00:00 2001 From: rami3l Date: Tue, 15 Aug 2023 09:59:11 +0800 Subject: [PATCH 3/3] Make `RUSTUP_TERM_COLOR`'s value case insensitive --- src/currentprocess/terminalsource.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/currentprocess/terminalsource.rs b/src/currentprocess/terminalsource.rs index 2c189dc372..19658ce8c5 100644 --- a/src/currentprocess/terminalsource.rs +++ b/src/currentprocess/terminalsource.rs @@ -83,7 +83,9 @@ impl ColorableTerminal { /// then color commands will be sent to the stream. /// Otherwise color commands are discarded. pub(super) fn new(stream: StreamSelector) -> Self { - let env_override = process().var("RUSTUP_TERM_COLOR"); + let env_override = process() + .var("RUSTUP_TERM_COLOR") + .map(|it| it.to_lowercase()); let choice = match env_override.as_deref() { Ok("always") => ColorChoice::Always, Ok("never") => ColorChoice::Never, @@ -260,24 +262,24 @@ mod tests { } assert_color_choice( - "always", + "aLWayS", StreamSelector::TestWriter(Default::default()), ColorChoice::Always, ); assert_color_choice( - "never", + "neVer", StreamSelector::TestWriter(Default::default()), ColorChoice::Never, ); // tty + `auto` enables the colors. assert_color_choice( - "auto", + "AutO", StreamSelector::TestTtyWriter(Default::default()), ColorChoice::Auto, ); // non-tty + `auto` does not enable the colors. assert_color_choice( - "auto", + "aUTo", StreamSelector::TestWriter(Default::default()), ColorChoice::Never, );