1
1
use std:: { env, path:: PathBuf } ;
2
2
3
- use anyhow:: { Context , Error } ;
3
+ use anyhow:: { bail , Context , Error } ;
4
4
use structopt:: StructOpt ;
5
5
6
6
mod util;
@@ -27,20 +27,21 @@ fn main() -> Result<(), Error> {
27
27
None => find_repo_root ( ) ?,
28
28
} ;
29
29
30
- #[ cfg( unix) ]
31
- setup_output_formatting ( ) ;
30
+ let feature = opt. feature ;
32
31
33
32
let libs = vec ! [
34
33
repo_root. clone( ) . join( "library/core" ) ,
35
34
repo_root. clone( ) . join( "library/alloc" ) ,
36
35
repo_root. clone( ) . join( "library/std" ) ,
37
36
] ;
38
37
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
+ }
42
42
43
- Ok ( ( ) )
43
+ Ok ( ( ) )
44
+ } )
44
45
}
45
46
46
47
fn find_repo_root ( ) -> Result < PathBuf , Error > {
@@ -56,11 +57,28 @@ fn find_repo_root() -> Result<PathBuf, Error> {
56
57
Ok ( path)
57
58
}
58
59
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
+
59
68
#[ 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} ;
62
74
use std:: os:: unix:: io:: AsRawFd ;
63
75
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
64
82
65
83
if isatty ( 1 ) == Ok ( true ) {
66
84
// Pipe the output through `bat` for nice formatting and paging, if available.
@@ -71,8 +89,12 @@ fn setup_output_formatting() {
71
89
. stdout ( Stdio :: inherit ( ) )
72
90
. spawn ( )
73
91
{
92
+ // Hold on to our stdout for later.
93
+ original_stdout = Some ( dup ( 1 ) . unwrap ( ) ) ;
74
94
// Replace our stdout by the pipe into `bat`.
75
95
dup2 ( bat. stdin . take ( ) . unwrap ( ) . as_raw_fd ( ) , 1 ) . unwrap ( ) ;
96
+
97
+ inner_child = Some ( bat) ;
76
98
}
77
99
}
78
100
@@ -82,7 +104,32 @@ fn setup_output_formatting() {
82
104
. stdout ( Stdio :: inherit ( ) ) // This pipes into `bat` if it was executed above.
83
105
. spawn ( )
84
106
{
107
+ // Hold on to our stdout for later, if we didn't already.
108
+ original_stdout. get_or_insert_with ( || dup ( 1 ) . unwrap ( ) ) ;
85
109
// Replace our stdout by the pipe into `rustfmt`.
86
110
dup2 ( rustfmt. stdin . take ( ) . unwrap ( ) . as_raw_fd ( ) , 1 ) . unwrap ( ) ;
111
+
112
+ inner_child. get_or_insert ( rustfmt) ;
87
113
}
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
88
135
}
0 commit comments