1
1
use crate :: error:: { Error , Result } ;
2
+ use std:: env:: consts:: OS ;
2
3
use std:: ffi:: { OsStr , OsString } ;
3
4
use std:: fmt:: Debug ;
4
5
use std:: path:: PathBuf ;
6
+ use std:: process:: ExitStatus ;
5
7
use std:: time:: Duration ;
6
8
use tracing:: debug;
7
9
@@ -140,46 +142,37 @@ impl CommandExecutor for std::process::Command {
140
142
/// Execute the command and return the stdout and stderr
141
143
fn execute ( & mut self ) -> Result < ( String , String ) > {
142
144
debug ! ( "Executing command: {}" , self . to_command_string( ) ) ;
143
- #[ cfg( not( target_os = "windows" ) ) ]
144
- {
145
- let output = self . output ( ) ?;
146
- let stdout = String :: from_utf8_lossy ( & output. stdout ) . into_owned ( ) ;
147
- let stderr = String :: from_utf8_lossy ( & output. stderr ) . into_owned ( ) ;
148
-
149
- debug ! (
150
- "Result: {}\n stdout: {}\n stderr: {}" ,
151
- output
152
- . status
153
- . code( )
154
- . map_or( "None" . to_string( ) , |c| c. to_string( ) ) ,
155
- stdout,
156
- stderr
157
- ) ;
158
-
159
- if output. status . success ( ) {
160
- Ok ( ( stdout, stderr) )
161
- } else {
162
- Err ( Error :: CommandError { stdout, stderr } )
163
- }
164
- }
145
+ let program = self . get_program ( ) . to_string_lossy ( ) . to_string ( ) ;
146
+ let stdout: String ;
147
+ let stderr: String ;
148
+ let status: ExitStatus ;
165
149
166
- // TODO: Processes can hang on Windows when attempting to get stdout/stderr using code
167
- // that works for Linux/MacOS; this implementation should be updated to retrieve the
168
- // values of stdout/stderr without hanging
169
- #[ cfg( target_os = "windows" ) ]
170
- {
150
+ if OS == "windows" && program. as_str ( ) . ends_with ( "pg_ctl" ) {
151
+ // The pg_ctl process can hang on Windows when attempting to get stdout/stderr.
171
152
let mut process = self
172
153
. stdout ( std:: process:: Stdio :: piped ( ) )
173
154
. stderr ( std:: process:: Stdio :: piped ( ) )
174
155
. spawn ( ) ?;
175
- let status = process. wait ( ) ?;
176
- let stdout = String :: new ( ) ;
177
- let stderr = String :: new ( ) ;
178
- if status. success ( ) {
179
- Ok ( ( stdout, stderr) )
180
- } else {
181
- Err ( Error :: CommandError { stdout, stderr } )
182
- }
156
+ stdout = String :: new ( ) ;
157
+ stderr = String :: new ( ) ;
158
+ status = process. wait ( ) ?;
159
+ } else {
160
+ let output = self . output ( ) ?;
161
+ stdout = String :: from_utf8_lossy ( & output. stdout ) . into_owned ( ) ;
162
+ stderr = String :: from_utf8_lossy ( & output. stderr ) . into_owned ( ) ;
163
+ status = output. status ;
164
+ }
165
+ debug ! (
166
+ "Result: {}\n stdout: {}\n stderr: {}" ,
167
+ status. code( ) . map_or( "None" . to_string( ) , |c| c. to_string( ) ) ,
168
+ stdout,
169
+ stderr
170
+ ) ;
171
+
172
+ if status. success ( ) {
173
+ Ok ( ( stdout, stderr) )
174
+ } else {
175
+ Err ( Error :: CommandError { stdout, stderr } )
183
176
}
184
177
}
185
178
}
@@ -194,19 +187,18 @@ impl AsyncCommandExecutor for tokio::process::Command {
194
187
Some ( duration) => tokio:: time:: timeout ( duration, self . output ( ) ) . await ?,
195
188
None => self . output ( ) . await ,
196
189
} ?;
197
-
198
- #[ cfg( not( target_os = "windows" ) ) ]
199
- let stdout = String :: from_utf8_lossy ( & output. stdout ) . into_owned ( ) ;
200
- #[ cfg( not( target_os = "windows" ) ) ]
201
- let stderr = String :: from_utf8_lossy ( & output. stderr ) . into_owned ( ) ;
202
-
203
- // TODO: Processes can hang on Windows when attempting to get stdout/stderr using code
204
- // that works for Linux/MacOS; this implementation should be updated to retrieve the
205
- // values of stdout/stderr without hanging
206
- #[ cfg( target_os = "windows" ) ]
207
- let stdout = String :: new ( ) ;
208
- #[ cfg( target_os = "windows" ) ]
209
- let stderr = String :: new ( ) ;
190
+ let program = self . as_std ( ) . get_program ( ) . to_string_lossy ( ) . to_string ( ) ;
191
+ let stdout: String ;
192
+ let stderr: String ;
193
+
194
+ if OS == "windows" && program. as_str ( ) . ends_with ( "pg_ctl" ) {
195
+ // The pg_ctl process can hang on Windows when attempting to get stdout/stderr.
196
+ stdout = String :: new ( ) ;
197
+ stderr = String :: new ( ) ;
198
+ } else {
199
+ stdout = String :: from_utf8_lossy ( & output. stdout ) . into_owned ( ) ;
200
+ stderr = String :: from_utf8_lossy ( & output. stderr ) . into_owned ( ) ;
201
+ }
210
202
211
203
debug ! (
212
204
"Result: {}\n stdout: {}\n stderr: {}" ,
@@ -371,10 +363,7 @@ mod test {
371
363
command. args ( [ "/C" , "echo foo" ] ) ;
372
364
373
365
let ( stdout, stderr) = command. execute ( ) ?;
374
- #[ cfg( not( target_os = "windows" ) ) ]
375
366
assert ! ( stdout. starts_with( "foo" ) ) ;
376
- #[ cfg( target_os = "windows" ) ]
377
- assert ! ( stdout. is_empty( ) ) ;
378
367
assert ! ( stderr. is_empty( ) ) ;
379
368
Ok ( ( ) )
380
369
}
0 commit comments