3
3
4
4
use std:: {
5
5
ffi:: OsString ,
6
- fmt, io,
6
+ fmt,
7
+ io:: { self , BufWriter , Write } ,
7
8
marker:: PhantomData ,
8
9
path:: PathBuf ,
9
10
process:: { ChildStderr , ChildStdout , Command , Stdio } ,
10
11
} ;
11
12
12
13
use crossbeam_channel:: Sender ;
14
+ use paths:: Utf8PathBuf ;
13
15
use process_wrap:: std:: { StdChildWrapper , StdCommandWrap } ;
14
16
use stdx:: process:: streaming_output;
15
17
@@ -40,7 +42,7 @@ impl<T: Sized + Send + 'static> CargoActor<T> {
40
42
}
41
43
42
44
impl < T : Sized + Send + ' static > CargoActor < T > {
43
- fn run ( self ) -> io:: Result < ( bool , String ) > {
45
+ fn run ( self , outfile : Option < Utf8PathBuf > ) -> io:: Result < ( bool , String ) > {
44
46
// We manually read a line at a time, instead of using serde's
45
47
// stream deserializers, because the deserializer cannot recover
46
48
// from an error, resulting in it getting stuck, because we try to
@@ -50,6 +52,15 @@ impl<T: Sized + Send + 'static> CargoActor<T> {
50
52
// simply skip a line if it doesn't parse, which just ignores any
51
53
// erroneous output.
52
54
55
+ let mut stdout = outfile. as_ref ( ) . and_then ( |path| {
56
+ _ = std:: fs:: create_dir_all ( path) ;
57
+ Some ( BufWriter :: new ( std:: fs:: File :: create ( path. join ( "stdout" ) ) . ok ( ) ?) )
58
+ } ) ;
59
+ let mut stderr = outfile. as_ref ( ) . and_then ( |path| {
60
+ _ = std:: fs:: create_dir_all ( path) ;
61
+ Some ( BufWriter :: new ( std:: fs:: File :: create ( path. join ( "stderr" ) ) . ok ( ) ?) )
62
+ } ) ;
63
+
53
64
let mut stdout_errors = String :: new ( ) ;
54
65
let mut stderr_errors = String :: new ( ) ;
55
66
let mut read_at_least_one_stdout_message = false ;
@@ -67,11 +78,19 @@ impl<T: Sized + Send + 'static> CargoActor<T> {
67
78
self . stdout ,
68
79
self . stderr ,
69
80
& mut |line| {
81
+ if let Some ( stdout) = & mut stdout {
82
+ _ = stdout. write_all ( line. as_bytes ( ) ) ;
83
+ _ = stdout. write_all ( b"\n " ) ;
84
+ }
70
85
if process_line ( line, & mut stdout_errors) {
71
86
read_at_least_one_stdout_message = true ;
72
87
}
73
88
} ,
74
89
& mut |line| {
90
+ if let Some ( stderr) = & mut stderr {
91
+ _ = stderr. write_all ( line. as_bytes ( ) ) ;
92
+ _ = stderr. write_all ( b"\n " ) ;
93
+ }
75
94
if process_line ( line, & mut stderr_errors) {
76
95
read_at_least_one_stderr_message = true ;
77
96
}
@@ -130,6 +149,7 @@ impl<T: Sized + Send + 'static> CommandHandle<T> {
130
149
mut command : Command ,
131
150
parser : impl CargoParser < T > ,
132
151
sender : Sender < T > ,
152
+ out_file : Option < Utf8PathBuf > ,
133
153
) -> std:: io:: Result < Self > {
134
154
command. stdout ( Stdio :: piped ( ) ) . stderr ( Stdio :: piped ( ) ) . stdin ( Stdio :: null ( ) ) ;
135
155
@@ -150,7 +170,7 @@ impl<T: Sized + Send + 'static> CommandHandle<T> {
150
170
let actor = CargoActor :: < T > :: new ( parser, sender, stdout, stderr) ;
151
171
let thread =
152
172
stdx:: thread:: Builder :: new ( stdx:: thread:: ThreadIntent :: Worker , "CommandHandle" )
153
- . spawn ( move || actor. run ( ) )
173
+ . spawn ( move || actor. run ( out_file ) )
154
174
. expect ( "failed to spawn thread" ) ;
155
175
Ok ( CommandHandle { program, arguments, current_dir, child, thread, _phantom : PhantomData } )
156
176
}
0 commit comments