11use crate :: error:: { Error , Result } ;
2+ use std:: env:: consts:: OS ;
23use std:: ffi:: { OsStr , OsString } ;
34use std:: fmt:: Debug ;
45use std:: path:: PathBuf ;
6+ use std:: process:: ExitStatus ;
57use std:: time:: Duration ;
68use tracing:: debug;
79
@@ -140,46 +142,37 @@ impl CommandExecutor for std::process::Command {
140142 /// Execute the command and return the stdout and stderr
141143 fn execute ( & mut self ) -> Result < ( String , String ) > {
142144 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 ;
165149
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.
171152 let mut process = self
172153 . stdout ( std:: process:: Stdio :: piped ( ) )
173154 . stderr ( std:: process:: Stdio :: piped ( ) )
174155 . 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 } )
183176 }
184177 }
185178}
@@ -194,19 +187,18 @@ impl AsyncCommandExecutor for tokio::process::Command {
194187 Some ( duration) => tokio:: time:: timeout ( duration, self . output ( ) ) . await ?,
195188 None => self . output ( ) . await ,
196189 } ?;
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+ }
210202
211203 debug ! (
212204 "Result: {}\n stdout: {}\n stderr: {}" ,
@@ -371,10 +363,7 @@ mod test {
371363 command. args ( [ "/C" , "echo foo" ] ) ;
372364
373365 let ( stdout, stderr) = command. execute ( ) ?;
374- #[ cfg( not( target_os = "windows" ) ) ]
375366 assert ! ( stdout. starts_with( "foo" ) ) ;
376- #[ cfg( target_os = "windows" ) ]
377- assert ! ( stdout. is_empty( ) ) ;
378367 assert ! ( stderr. is_empty( ) ) ;
379368 Ok ( ( ) )
380369 }
0 commit comments