@@ -3,6 +3,8 @@ use std::{
3
3
io:: { BufRead , BufReader } ,
4
4
path:: Path ,
5
5
process:: { Command , Stdio } ,
6
+ sync:: mpsc,
7
+ thread,
6
8
} ;
7
9
8
10
use anyhow:: anyhow;
@@ -61,6 +63,7 @@ pub fn run_process_for_workspace<'a>(
61
63
. iter ( )
62
64
. for_each ( |ex| args. extend ( [ "--exclude" , ex] ) ) ;
63
65
group_info ! ( "Command line: cargo {}" , args. join( " " ) ) ;
66
+ // process
64
67
let mut child = Command :: new ( name)
65
68
. args ( & args)
66
69
. stdout ( Stdio :: piped ( ) )
@@ -75,53 +78,76 @@ pub fn run_process_for_workspace<'a>(
75
78
) )
76
79
} ) ?;
77
80
78
- let mut ignore_error = false ;
79
- let mut close_group = false ;
81
+ // handle stdout and stderr in dedicated threads using a MPSC channel for synchronization
82
+ let ( tx, rx) = mpsc:: channel ( ) ;
83
+ // stdout processing thread
80
84
if let Some ( stdout) = child. stdout . take ( ) {
81
- let reader = BufReader :: new ( stdout) ;
82
- reader. lines ( ) . for_each ( |line| {
83
- if let Ok ( line) = line {
84
- println ! ( "{}" , line) ;
85
+ let tx = tx. clone ( ) ;
86
+ thread:: spawn ( move || {
87
+ let reader = BufReader :: new ( stdout) ;
88
+ for line in reader. lines ( ) . flatten ( ) {
89
+ tx. send ( ( line, false ) ) . unwrap ( ) ;
85
90
}
86
91
} ) ;
87
92
}
93
+ // stderr processing thread
88
94
if let Some ( stderr) = child. stderr . take ( ) {
89
- let reader = BufReader :: new ( stderr ) ;
90
- reader . lines ( ) . for_each ( |line | {
91
- let mut skip_line = false ;
92
- if let Ok ( line) = line {
93
- if let Some ( rx ) = & group_rx {
94
- let cleaned_line = standardize_slashes ( & remove_ansi_codes ( & line ) ) ;
95
- if let Some ( caps ) = rx . captures ( & cleaned_line ) {
96
- let crate_name = & caps [ 1 ] ;
97
- if close_group {
98
- endgroup ! ( ) ;
99
- }
100
- close_group = true ;
101
- group ! ( "{}: {}" , group_name . unwrap_or ( "Group" ) , crate_name ) ;
102
- }
103
- }
104
- if let Some ( log ) = ignore_log {
105
- if line . contains ( log ) {
106
- if let Some ( msg ) = ignore_msg {
107
- warn ! ( "{}" , msg ) ;
108
- }
109
- ignore_error = true ;
110
- skip_line = true ;
111
- }
95
+ let tx = tx . clone ( ) ;
96
+ thread :: spawn ( move | | {
97
+ let reader = BufReader :: new ( stderr ) ;
98
+ for line in reader . lines ( ) . flatten ( ) {
99
+ tx . send ( ( line , true ) ) . unwrap ( ) ;
100
+ }
101
+ } ) ;
102
+ }
103
+ // Drop the sender once all the logs have been processed to close the channel
104
+ drop ( tx ) ;
105
+
106
+ // Process the stdout to inject log groups
107
+ let mut ignore_error = false ;
108
+ let mut close_group = false ;
109
+ for ( line , is_stderr ) in rx . iter ( ) {
110
+ let mut skip_line = false ;
111
+
112
+ if let Some ( rx ) = & group_rx {
113
+ let cleaned_line = standardize_slashes ( & remove_ansi_codes ( & line ) ) ;
114
+ if let Some ( caps ) = rx . captures ( & cleaned_line ) {
115
+ let crate_name = & caps [ 1 ] ;
116
+ if close_group {
117
+ endgroup ! ( ) ;
112
118
}
113
- if !skip_line {
114
- eprintln ! ( "{}" , line) ;
119
+ close_group = true ;
120
+ group ! ( "{}: {}" , group_name. unwrap_or( "Group" ) , crate_name) ;
121
+ }
122
+ }
123
+
124
+ if let Some ( log) = ignore_log {
125
+ if line. contains ( log) {
126
+ if let Some ( msg) = ignore_msg {
127
+ warn ! ( "{}" , msg) ;
115
128
}
129
+ ignore_error = true ;
130
+ skip_line = true ;
116
131
}
117
- } ) ;
132
+ }
133
+
134
+ if !skip_line {
135
+ if is_stderr {
136
+ eprintln ! ( "{}" , line) ;
137
+ } else {
138
+ println ! ( "{}" , line) ;
139
+ }
140
+ }
118
141
}
142
+
119
143
if close_group {
120
144
endgroup ! ( ) ;
121
145
}
146
+
122
147
let status = child
123
148
. wait ( )
124
149
. expect ( "Should be able to wait for the process to finish." ) ;
150
+
125
151
if status. success ( ) || ignore_error {
126
152
anyhow:: Ok ( ( ) )
127
153
} else {
0 commit comments