11use std:: { env, path:: PathBuf } ;
22
3- use anyhow:: { Context , Error } ;
3+ use anyhow:: { bail , Context , Error } ;
44use structopt:: StructOpt ;
55
66mod util;
@@ -27,20 +27,21 @@ fn main() -> Result<(), Error> {
2727 None => find_repo_root ( ) ?,
2828 } ;
2929
30- #[ cfg( unix) ]
31- setup_output_formatting ( ) ;
30+ let feature = opt. feature ;
3231
3332 let libs = vec ! [
3433 repo_root. clone( ) . join( "library/core" ) ,
3534 repo_root. clone( ) . join( "library/alloc" ) ,
3635 repo_root. clone( ) . join( "library/std" ) ,
3736 ] ;
3837
39- for crate_root in libs {
40- visit:: pub_unstable ( crate_root, & opt. feature ) ?;
41- }
38+ with_output_formatting_maybe ( move || {
39+ for crate_root in libs {
40+ visit:: pub_unstable ( crate_root, & feature) ?;
41+ }
4242
43- Ok ( ( ) )
43+ Ok ( ( ) )
44+ } )
4445}
4546
4647fn find_repo_root ( ) -> Result < PathBuf , Error > {
@@ -56,11 +57,28 @@ fn find_repo_root() -> Result<PathBuf, Error> {
5657 Ok ( path)
5758}
5859
60+ #[ cfg( not( unix) ) ]
61+ fn with_output_formatting_maybe < F > ( f : F ) -> Result < ( ) , Error >
62+ where
63+ F : FnOnce ( ) -> Result < ( ) , Error > ,
64+ {
65+ f ( )
66+ }
67+
5968#[ cfg( unix) ]
60- fn setup_output_formatting ( ) {
61- use nix:: unistd:: { isatty, dup2} ;
69+ fn with_output_formatting_maybe < F > ( f : F ) -> Result < ( ) , Error >
70+ where
71+ F : FnOnce ( ) -> Result < ( ) , Error > ,
72+ {
73+ use nix:: unistd:: { isatty, close, dup, dup2} ;
6274 use std:: os:: unix:: io:: AsRawFd ;
6375 use std:: process:: { Command , Stdio } ;
76+ use std:: io:: { stdout, Write } ;
77+
78+ let mut original_stdout = None ;
79+ let mut inner_child = None ;
80+
81+ stdout ( ) . flush ( ) . unwrap ( ) ; // just in case
6482
6583 if isatty ( 1 ) == Ok ( true ) {
6684 // Pipe the output through `bat` for nice formatting and paging, if available.
@@ -71,8 +89,12 @@ fn setup_output_formatting() {
7189 . stdout ( Stdio :: inherit ( ) )
7290 . spawn ( )
7391 {
92+ // Hold on to our stdout for later.
93+ original_stdout = Some ( dup ( 1 ) . unwrap ( ) ) ;
7494 // Replace our stdout by the pipe into `bat`.
7595 dup2 ( bat. stdin . take ( ) . unwrap ( ) . as_raw_fd ( ) , 1 ) . unwrap ( ) ;
96+
97+ inner_child = Some ( bat) ;
7698 }
7799 }
78100
@@ -82,7 +104,32 @@ fn setup_output_formatting() {
82104 . stdout ( Stdio :: inherit ( ) ) // This pipes into `bat` if it was executed above.
83105 . spawn ( )
84106 {
107+ // Hold on to our stdout for later, if we didn't already.
108+ original_stdout. get_or_insert_with ( || dup ( 1 ) . unwrap ( ) ) ;
85109 // Replace our stdout by the pipe into `rustfmt`.
86110 dup2 ( rustfmt. stdin . take ( ) . unwrap ( ) . as_raw_fd ( ) , 1 ) . unwrap ( ) ;
111+
112+ inner_child. get_or_insert ( rustfmt) ;
87113 }
114+
115+ let result = f ( ) ;
116+
117+ if let Some ( fd) = original_stdout {
118+ // Overwriting the current stdout with the original stdout
119+ // closes the pipe to the child's stdin, allowing the child to
120+ // exit.
121+ stdout ( ) . flush ( ) . unwrap ( ) ; // just in case
122+ dup2 ( fd, 1 ) . unwrap ( ) ;
123+ close ( fd) . unwrap ( ) ;
124+ }
125+
126+ if let Some ( mut child) = inner_child {
127+ // Wait for inner child to exit to ensure it won't write to
128+ // original stdout after we return.
129+ if !child. wait ( ) ?. success ( ) {
130+ bail ! ( "output formatting failed" ) ;
131+ }
132+ }
133+
134+ result
88135}
0 commit comments