From deee3ef28498a230500c9a902466cda22081565b Mon Sep 17 00:00:00 2001 From: Nikos Gorogiannis Date: Wed, 6 May 2020 04:42:48 -0700 Subject: [PATCH] [process] redirect desired output stream to file, while logging the other one Summary: Build tool wrappers sometimes have issues when their output streams are redirected to those of infer's while one of those streams is read and used in infer. This diff side-steps this problem by always redirecting the stream of interest to a file (which also helps in debugging), while logging the other stream through `Logging.progress`. Reviewed By: jvillard Differential Revision: D21404736 fbshipit-source-id: 04c92799c --- infer/src/base/Process.ml | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/infer/src/base/Process.ml b/infer/src/base/Process.ml index c60f63481..e999e1566 100644 --- a/infer/src/base/Process.ml +++ b/infer/src/base/Process.ml @@ -38,28 +38,28 @@ let create_process_and_wait ~prog ~args = type action = ReadStdout | ReadStderr let create_process_and_wait_with_output ~prog ~args action = - let {Unix.Process_info.stdin; stdout; stderr; pid} = Unix.create_process ~prog ~args in - Unix.close stdin ; - (* NOTE: this simple implementation works well because we only read on *one* of stdout or - stderr. Reading on both is a lot more difficult: we would have to be careful not to block the - callee process on writing on either stdout or stderr, so issue non-blocking reads on both - stdout and stderr until the end of the program, probably using select(2). *) - let in_chan = - let redirect_read ~redirect:(dst, src) ~read = - (* redirect *) - Unix.dup2 ~src ~dst ; Unix.in_channel_of_descr read - in - match action with - | ReadStdout -> - redirect_read ~redirect:(stderr, Unix.stderr) ~read:stdout - | ReadStderr -> - redirect_read ~redirect:(stdout, Unix.stdout) ~read:stderr + let redirected_fd_name, redirect_spec = + match action with ReadStderr -> ("stderr", "2>") | ReadStdout -> ("stdout", ">") + in + let output_file = + Filename.temp_file ~in_dir:(ResultsDir.get_path Temporary) prog redirected_fd_name + in + let escaped_cmd = List.map ~f:Escape.escape_shell (prog :: args) |> String.concat ~sep:" " in + let redirected_cmd = Printf.sprintf "exec %s %s'%s'" escaped_cmd redirect_spec output_file in + let {Unix.Process_info.stdin; stdout; stderr; pid} = + Unix.create_process ~prog:"sh" ~args:["-c"; redirected_cmd] in - let res = In_channel.input_all in_chan in + let fd_to_log, redirected_fd = + match action with ReadStderr -> (stdout, stderr) | ReadStdout -> (stderr, stdout) + in + let channel_to_log = Unix.in_channel_of_descr fd_to_log in + Utils.with_channel_in channel_to_log ~f:(L.progress "%s-%s: %s@." prog redirected_fd_name) ; + In_channel.close channel_to_log ; + Unix.close redirected_fd ; + Unix.close stdin ; match Unix.waitpid pid with | Ok () -> - Unix.close (Unix.descr_of_in_channel in_chan) ; - res + Utils.with_file_in output_file ~f:In_channel.input_all | Error _ as status -> L.die ExternalError "Error executing: %a@\n%s@\n" Pp.cli_args (prog :: args) (Unix.Exit_or_signal.to_string_hum status)