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