From f65bb82f3688ba33faccf2ef0690571e1aa6edc2 Mon Sep 17 00:00:00 2001
From: Brad King <brad.king@kitware.com>
Date: Thu, 7 May 2015 14:40:38 -0400
Subject: execute_process: Improve stdout/stderr merging

Use the KWSys Process "MergeOutput" option to give the child process
the same pipe (or file) for both stdout and stderr.  This allows
natural merging of stdout and stderr together instead of merging
on arbitrary buffered read boundaries as before.
---
 Help/command/execute_process.rst                   |  3 ++-
 Help/release/dev/execute_process-merge-output.rst  |  5 +++++
 Source/cmExecuteProcessCommand.cxx                 | 24 +++++++++++++++++-----
 Tests/RunCMake/CMakeLists.txt                      |  1 +
 .../execute_process/MergeOutput-stdout.txt         | 10 +++++++++
 Tests/RunCMake/execute_process/MergeOutput.cmake   |  4 ++++
 .../execute_process/MergeOutputFile-stderr.txt     | 10 +++++++++
 .../RunCMake/execute_process/MergeOutputFile.cmake |  7 +++++++
 .../execute_process/MergeOutputVars-stderr.txt     | 10 +++++++++
 .../RunCMake/execute_process/MergeOutputVars.cmake |  6 ++++++
 Tests/RunCMake/execute_process/RunCMakeTest.cmake  |  8 ++++++++
 11 files changed, 82 insertions(+), 6 deletions(-)
 create mode 100644 Help/release/dev/execute_process-merge-output.rst
 create mode 100644 Tests/RunCMake/execute_process/MergeOutput-stdout.txt
 create mode 100644 Tests/RunCMake/execute_process/MergeOutput.cmake
 create mode 100644 Tests/RunCMake/execute_process/MergeOutputFile-stderr.txt
 create mode 100644 Tests/RunCMake/execute_process/MergeOutputFile.cmake
 create mode 100644 Tests/RunCMake/execute_process/MergeOutputVars-stderr.txt
 create mode 100644 Tests/RunCMake/execute_process/MergeOutputVars.cmake
 create mode 100644 Tests/RunCMake/execute_process/RunCMakeTest.cmake

diff --git a/Help/command/execute_process.rst b/Help/command/execute_process.rst
index 478b30e..c38ec1a 100644
--- a/Help/command/execute_process.rst
+++ b/Help/command/execute_process.rst
@@ -57,7 +57,8 @@ OUTPUT_VARIABLE, ERROR_VARIABLE
 INPUT_FILE, OUTPUT_FILE, ERROR_FILE
  The file named will be attached to the standard input of the first
  process, standard output of the last process, or standard error of
- all processes, respectively.
+ all processes, respectively.  If the same file is named for both
+ output and error then it will be used for both.
 
 OUTPUT_QUIET, ERROR_QUIET
  The standard output or standard error results will be quietly ignored.
diff --git a/Help/release/dev/execute_process-merge-output.rst b/Help/release/dev/execute_process-merge-output.rst
new file mode 100644
index 0000000..4c80cdd
--- /dev/null
+++ b/Help/release/dev/execute_process-merge-output.rst
@@ -0,0 +1,5 @@
+execute_process-merge-output
+----------------------------
+
+* The :command:`execute_process` command learned to support specifying
+  the same file for ``OUTPUT_FILE`` and ``ERROR_FILE``.
diff --git a/Source/cmExecuteProcessCommand.cxx b/Source/cmExecuteProcessCommand.cxx
index 1225992..a371390 100644
--- a/Source/cmExecuteProcessCommand.cxx
+++ b/Source/cmExecuteProcessCommand.cxx
@@ -255,7 +255,7 @@ bool cmExecuteProcessCommand
   cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
 
   // Check the output variables.
-  bool merge_output = (output_variable == error_variable);
+  bool merge_output = false;
   if(!input_file.empty())
     {
     cmsysProcess_SetPipeFile(cp, cmsysProcess_Pipe_STDIN, input_file.c_str());
@@ -267,8 +267,23 @@ bool cmExecuteProcessCommand
     }
   if(!error_file.empty())
     {
-    cmsysProcess_SetPipeFile(cp, cmsysProcess_Pipe_STDERR,
-                             error_file.c_str());
+    if (error_file == output_file)
+      {
+      merge_output = true;
+      }
+    else
+      {
+      cmsysProcess_SetPipeFile(cp, cmsysProcess_Pipe_STDERR,
+                               error_file.c_str());
+      }
+    }
+  if (!output_variable.empty() && output_variable == error_variable)
+    {
+    merge_output = true;
+    }
+  if (merge_output)
+    {
+    cmsysProcess_SetOption(cp, cmsysProcess_Option_MergeOutput, 1);
     }
 
   // Set the timeout if any.
@@ -289,8 +304,7 @@ bool cmExecuteProcessCommand
   while((p = cmsysProcess_WaitForData(cp, &data, &length, 0), p))
     {
     // Put the output in the right place.
-    if((p == cmsysProcess_Pipe_STDOUT && !output_quiet) ||
-       (p == cmsysProcess_Pipe_STDERR && !error_quiet && merge_output))
+    if (p == cmsysProcess_Pipe_STDOUT && !output_quiet)
       {
       if(output_variable.empty())
         {
diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index d5f1d22..16fb056 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -132,6 +132,7 @@ add_RunCMake_test(add_custom_command)
 add_RunCMake_test(add_custom_target)
 add_RunCMake_test(add_dependencies)
 add_RunCMake_test(build_command)
+add_RunCMake_test(execute_process)
 add_RunCMake_test(export)
 add_RunCMake_test(cmake_minimum_required)
 add_RunCMake_test(continue)
diff --git a/Tests/RunCMake/execute_process/MergeOutput-stdout.txt b/Tests/RunCMake/execute_process/MergeOutput-stdout.txt
new file mode 100644
index 0000000..676f0ed
--- /dev/null
+++ b/Tests/RunCMake/execute_process/MergeOutput-stdout.txt
@@ -0,0 +1,10 @@
+^-- Output on stdout
+Output on stderr
+-- Output on stdout
+Output on stderr
+-- Output on stdout
+Output on stderr
+-- Output on stdout
+Output on stderr
+-- Output on stdout
+Output on stderr$
diff --git a/Tests/RunCMake/execute_process/MergeOutput.cmake b/Tests/RunCMake/execute_process/MergeOutput.cmake
new file mode 100644
index 0000000..528ac90
--- /dev/null
+++ b/Tests/RunCMake/execute_process/MergeOutput.cmake
@@ -0,0 +1,4 @@
+foreach(i RANGE 1 5)
+  message(STATUS "Output on stdout")
+  message("Output on stderr")
+endforeach()
diff --git a/Tests/RunCMake/execute_process/MergeOutputFile-stderr.txt b/Tests/RunCMake/execute_process/MergeOutputFile-stderr.txt
new file mode 100644
index 0000000..676f0ed
--- /dev/null
+++ b/Tests/RunCMake/execute_process/MergeOutputFile-stderr.txt
@@ -0,0 +1,10 @@
+^-- Output on stdout
+Output on stderr
+-- Output on stdout
+Output on stderr
+-- Output on stdout
+Output on stderr
+-- Output on stdout
+Output on stderr
+-- Output on stdout
+Output on stderr$
diff --git a/Tests/RunCMake/execute_process/MergeOutputFile.cmake b/Tests/RunCMake/execute_process/MergeOutputFile.cmake
new file mode 100644
index 0000000..1a0d90e
--- /dev/null
+++ b/Tests/RunCMake/execute_process/MergeOutputFile.cmake
@@ -0,0 +1,7 @@
+execute_process(
+  COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_LIST_DIR}/MergeOutput.cmake
+  OUTPUT_FILE out.txt
+  ERROR_FILE out.txt
+  )
+file(READ out.txt out)
+message("${out}")
diff --git a/Tests/RunCMake/execute_process/MergeOutputVars-stderr.txt b/Tests/RunCMake/execute_process/MergeOutputVars-stderr.txt
new file mode 100644
index 0000000..676f0ed
--- /dev/null
+++ b/Tests/RunCMake/execute_process/MergeOutputVars-stderr.txt
@@ -0,0 +1,10 @@
+^-- Output on stdout
+Output on stderr
+-- Output on stdout
+Output on stderr
+-- Output on stdout
+Output on stderr
+-- Output on stdout
+Output on stderr
+-- Output on stdout
+Output on stderr$
diff --git a/Tests/RunCMake/execute_process/MergeOutputVars.cmake b/Tests/RunCMake/execute_process/MergeOutputVars.cmake
new file mode 100644
index 0000000..3e7c69e
--- /dev/null
+++ b/Tests/RunCMake/execute_process/MergeOutputVars.cmake
@@ -0,0 +1,6 @@
+execute_process(
+  COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_LIST_DIR}/MergeOutput.cmake
+  OUTPUT_VARIABLE out
+  ERROR_VARIABLE out
+  )
+message("${out}")
diff --git a/Tests/RunCMake/execute_process/RunCMakeTest.cmake b/Tests/RunCMake/execute_process/RunCMakeTest.cmake
new file mode 100644
index 0000000..2080437
--- /dev/null
+++ b/Tests/RunCMake/execute_process/RunCMakeTest.cmake
@@ -0,0 +1,8 @@
+include(RunCMake)
+
+set(RunCMake_TEST_OUTPUT_MERGE 1)
+run_cmake_command(MergeOutput ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/MergeOutput.cmake)
+unset(RunCMake_TEST_OUTPUT_MERGE)
+
+run_cmake_command(MergeOutputFile ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/MergeOutputFile.cmake)
+run_cmake_command(MergeOutputVars ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/MergeOutputVars.cmake)
-- 
cgit v0.12