@@ -11,14 +11,16 @@ use termcolor::{ColorChoice, ColorSpec, StandardStream, StandardStreamLock, Writ
1111
1212#[ cfg( feature = "test" ) ]
1313use super :: filesource:: { TestWriter , TestWriterLock } ;
14- use super :: process;
14+ use super :: { process, varsource :: VarSource } ;
1515
1616/// Select what stream to make a terminal on
1717pub ( super ) enum StreamSelector {
1818 Stdout ,
1919 Stderr ,
2020 #[ cfg( feature = "test" ) ]
2121 TestWriter ( TestWriter ) ,
22+ #[ cfg( feature = "test" ) ]
23+ TestTtyWriter ( TestWriter ) ,
2224}
2325
2426impl StreamSelector {
@@ -36,6 +38,8 @@ impl StreamSelector {
3638 } ,
3739 #[ cfg( feature = "test" ) ]
3840 StreamSelector :: TestWriter ( _) => false ,
41+ #[ cfg( feature = "test" ) ]
42+ StreamSelector :: TestTtyWriter ( _) => true ,
3943 }
4044 }
4145}
@@ -55,7 +59,7 @@ pub struct ColorableTerminal {
5559enum TerminalInner {
5660 StandardStream ( StandardStream , ColorSpec ) ,
5761 #[ cfg( feature = "test" ) ]
58- TestWriter ( TestWriter ) ,
62+ TestWriter ( TestWriter , ColorChoice ) ,
5963}
6064
6165pub struct ColorableTerminalLocked {
@@ -73,14 +77,20 @@ enum TerminalInnerLocked {
7377}
7478
7579impl ColorableTerminal {
76- /// Construct a terminal for the selected stream. Colors written to the
77- /// terminal will be discarded if the stream is not a tty.
80+ /// A terminal that supports colorisation of a stream.
81+ /// If `RUSTUP_TERM_COLOR` is set to `always`, or if the stream is a tty and
82+ /// `RUSTUP_TERM_COLOR` either unset or set to `auto`,
83+ /// then color commands will be sent to the stream.
84+ /// Otherwise color commands are discarded.
7885 pub ( super ) fn new ( stream : StreamSelector ) -> Self {
79- let is_a_tty = stream. is_a_tty ( ) ;
80- let choice = if is_a_tty {
81- ColorChoice :: Auto
82- } else {
83- ColorChoice :: Never
86+ let env_override = process ( )
87+ . var ( "RUSTUP_TERM_COLOR" )
88+ . map ( |it| it. to_lowercase ( ) ) ;
89+ let choice = match env_override. as_deref ( ) {
90+ Ok ( "always" ) => ColorChoice :: Always ,
91+ Ok ( "never" ) => ColorChoice :: Never ,
92+ _ if stream. is_a_tty ( ) => ColorChoice :: Auto ,
93+ _ => ColorChoice :: Never ,
8494 } ;
8595 let inner = match stream {
8696 StreamSelector :: Stdout => {
@@ -90,7 +100,9 @@ impl ColorableTerminal {
90100 TerminalInner :: StandardStream ( StandardStream :: stderr ( choice) , ColorSpec :: new ( ) )
91101 }
92102 #[ cfg( feature = "test" ) ]
93- StreamSelector :: TestWriter ( w) => TerminalInner :: TestWriter ( w) ,
103+ StreamSelector :: TestWriter ( w) | StreamSelector :: TestTtyWriter ( w) => {
104+ TerminalInner :: TestWriter ( w, choice)
105+ }
94106 } ;
95107 ColorableTerminal {
96108 inner : Arc :: new ( Mutex :: new ( inner) ) ,
@@ -118,7 +130,7 @@ impl ColorableTerminal {
118130 TerminalInnerLocked :: StandardStream ( locked)
119131 }
120132 #[ cfg( feature = "test" ) ]
121- TerminalInner :: TestWriter ( w) => TerminalInnerLocked :: TestWriter ( w. lock ( ) ) ,
133+ TerminalInner :: TestWriter ( w, _ ) => TerminalInnerLocked :: TestWriter ( w. lock ( ) ) ,
122134 } ) ;
123135 // ColorableTerminalLocked { inner, guard, locked }
124136 uninit. assume_init ( )
@@ -132,7 +144,7 @@ impl ColorableTerminal {
132144 s. set_color ( spec)
133145 }
134146 #[ cfg( feature = "test" ) ]
135- TerminalInner :: TestWriter ( _) => Ok ( ( ) ) ,
147+ TerminalInner :: TestWriter ( _, _ ) => Ok ( ( ) ) ,
136148 }
137149 }
138150
@@ -143,7 +155,7 @@ impl ColorableTerminal {
143155 s. set_color ( spec)
144156 }
145157 #[ cfg( feature = "test" ) ]
146- TerminalInner :: TestWriter ( _) => Ok ( ( ) ) ,
158+ TerminalInner :: TestWriter ( _, _ ) => Ok ( ( ) ) ,
147159 }
148160 }
149161
@@ -157,23 +169,23 @@ impl ColorableTerminal {
157169 s. set_color ( spec)
158170 }
159171 #[ cfg( feature = "test" ) ]
160- TerminalInner :: TestWriter ( _) => Ok ( ( ) ) ,
172+ TerminalInner :: TestWriter ( _, _ ) => Ok ( ( ) ) ,
161173 }
162174 }
163175
164176 pub fn reset ( & mut self ) -> io:: Result < ( ) > {
165177 match self . inner . lock ( ) . unwrap ( ) . deref_mut ( ) {
166178 TerminalInner :: StandardStream ( s, _color) => s. reset ( ) ,
167179 #[ cfg( feature = "test" ) ]
168- TerminalInner :: TestWriter ( _) => Ok ( ( ) ) ,
180+ TerminalInner :: TestWriter ( _, _ ) => Ok ( ( ) ) ,
169181 }
170182 }
171183
172184 pub fn carriage_return ( & mut self ) -> io:: Result < ( ) > {
173185 match self . inner . lock ( ) . unwrap ( ) . deref_mut ( ) {
174186 TerminalInner :: StandardStream ( s, _color) => s. write ( b"\r " ) ?,
175187 #[ cfg( feature = "test" ) ]
176- TerminalInner :: TestWriter ( w) => w. write ( b"\r " ) ?,
188+ TerminalInner :: TestWriter ( w, _ ) => w. write ( b"\r " ) ?,
177189 } ;
178190 Ok ( ( ) )
179191 }
@@ -190,15 +202,15 @@ impl io::Write for ColorableTerminal {
190202 match self . inner . lock ( ) . unwrap ( ) . deref_mut ( ) {
191203 TerminalInner :: StandardStream ( s, _) => s. write ( buf) ,
192204 #[ cfg( feature = "test" ) ]
193- TerminalInner :: TestWriter ( w) => w. write ( buf) ,
205+ TerminalInner :: TestWriter ( w, _ ) => w. write ( buf) ,
194206 }
195207 }
196208
197209 fn flush ( & mut self ) -> std:: result:: Result < ( ) , io:: Error > {
198210 match self . inner . lock ( ) . unwrap ( ) . deref_mut ( ) {
199211 TerminalInner :: StandardStream ( s, _) => s. flush ( ) ,
200212 #[ cfg( feature = "test" ) ]
201- TerminalInner :: TestWriter ( w) => w. flush ( ) ,
213+ TerminalInner :: TestWriter ( w, _ ) => w. flush ( ) ,
202214 }
203215 }
204216}
@@ -220,3 +232,56 @@ impl io::Write for ColorableTerminalLocked {
220232 }
221233 }
222234}
235+
236+ #[ cfg( test) ]
237+ mod tests {
238+ use std:: collections:: HashMap ;
239+
240+ use rustup_macros:: unit_test as test;
241+
242+ use super :: * ;
243+ use crate :: { currentprocess, test:: Env } ;
244+
245+ #[ test]
246+ fn term_color_choice ( ) {
247+ fn assert_color_choice ( env_val : & str , stream : StreamSelector , color_choice : ColorChoice ) {
248+ let mut vars = HashMap :: new ( ) ;
249+ vars. env ( "RUSTUP_TERM_COLOR" , env_val) ;
250+ let tp = currentprocess:: TestProcess {
251+ vars,
252+ ..Default :: default ( )
253+ } ;
254+ currentprocess:: with ( tp. into ( ) , || {
255+ let term = ColorableTerminal :: new ( stream) ;
256+ let inner = term. inner . lock ( ) . unwrap ( ) ;
257+ assert ! ( matches!(
258+ & * inner,
259+ & TerminalInner :: TestWriter ( _, choice) if choice == color_choice
260+ ) ) ;
261+ } ) ;
262+ }
263+
264+ assert_color_choice (
265+ "aLWayS" ,
266+ StreamSelector :: TestWriter ( Default :: default ( ) ) ,
267+ ColorChoice :: Always ,
268+ ) ;
269+ assert_color_choice (
270+ "neVer" ,
271+ StreamSelector :: TestWriter ( Default :: default ( ) ) ,
272+ ColorChoice :: Never ,
273+ ) ;
274+ // tty + `auto` enables the colors.
275+ assert_color_choice (
276+ "AutO" ,
277+ StreamSelector :: TestTtyWriter ( Default :: default ( ) ) ,
278+ ColorChoice :: Auto ,
279+ ) ;
280+ // non-tty + `auto` does not enable the colors.
281+ assert_color_choice (
282+ "aUTo" ,
283+ StreamSelector :: TestWriter ( Default :: default ( ) ) ,
284+ ColorChoice :: Never ,
285+ ) ;
286+ }
287+ }
0 commit comments