diff options
13 files changed, 101 insertions, 2 deletions
diff --git a/Help/command/execute_process.rst b/Help/command/execute_process.rst index b32025f..a6f141a 100644 --- a/Help/command/execute_process.rst +++ b/Help/command/execute_process.rst @@ -23,7 +23,8 @@ Execute one or more child processes. [ERROR_STRIP_TRAILING_WHITESPACE] [ENCODING <name>] [ECHO_OUTPUT_VARIABLE] - [ECHO_ERROR_VARIABLE]) + [ECHO_ERROR_VARIABLE] + [COMMAND_ERROR_IS_FATAL <ANY|LAST>]) Runs the given sequence of one or more commands. @@ -116,6 +117,11 @@ Options: This is analogous to the ``tee`` Unix command. +``COMMAND_ERROR_IS_FATAL <ANY|LAST>`` + ``COMMAND_ERROR_IS_FATAL ANY`` option stops processing if any command fails. + ``COMMAND_ERROR_IS_FATAL LAST`` option stops processing if the last command + in the command list fails. + If more than one ``OUTPUT_*`` or ``ERROR_*`` option is given for the same pipe the precedence is not specified. If no ``OUTPUT_*`` or ``ERROR_*`` options are given the output will diff --git a/Help/release/dev/execute-process-command-error-is-fatal.rst b/Help/release/dev/execute-process-command-error-is-fatal.rst new file mode 100644 index 0000000..fbc54bf --- /dev/null +++ b/Help/release/dev/execute-process-command-error-is-fatal.rst @@ -0,0 +1,5 @@ +execute-process-command-error-is-fatal +-------------------------------------- + +* The :command:`execute_process` command gained a ``COMMAND_ERROR_IS_FATAL`` + option to specify a fatal error. diff --git a/Source/cmExecuteProcessCommand.cxx b/Source/cmExecuteProcessCommand.cxx index 9c53bdf..14147e0 100644 --- a/Source/cmExecuteProcessCommand.cxx +++ b/Source/cmExecuteProcessCommand.cxx @@ -7,8 +7,10 @@ #include <cstdio> #include <iostream> #include <memory> +#include <sstream> #include <vector> +#include <cm/string_view> #include <cmext/algorithm> #include <cmext/string_view> @@ -63,6 +65,7 @@ bool cmExecuteProcessCommand(std::vector<std::string> const& args, bool EchoOutputVariable = false; bool EchoErrorVariable = false; std::string Encoding; + std::string CommandErrorIsFatal; }; static auto const parser = @@ -86,7 +89,8 @@ bool cmExecuteProcessCommand(std::vector<std::string> const& args, &Arguments::ErrorStripTrailingWhitespace) .Bind("ENCODING"_s, &Arguments::Encoding) .Bind("ECHO_OUTPUT_VARIABLE"_s, &Arguments::EchoOutputVariable) - .Bind("ECHO_ERROR_VARIABLE"_s, &Arguments::EchoErrorVariable); + .Bind("ECHO_ERROR_VARIABLE"_s, &Arguments::EchoErrorVariable) + .Bind("COMMAND_ERROR_IS_FATAL"_s, &Arguments::CommandErrorIsFatal); std::vector<std::string> unparsedArguments; std::vector<std::string> keywordsMissingValue; @@ -131,6 +135,14 @@ bool cmExecuteProcessCommand(std::vector<std::string> const& args, return false; } } + + if (!arguments.CommandErrorIsFatal.empty()) { + if (arguments.CommandErrorIsFatal != "ANY"_s && + arguments.CommandErrorIsFatal != "LAST"_s) { + status.SetError("COMMAND_ERROR_IS_FATAL option can be ANY or LAST"); + return false; + } + } // Create a process instance. std::unique_ptr<cmsysProcess, void (*)(cmsysProcess*)> cp_ptr( cmsysProcess_New(), cmsysProcess_Delete); @@ -363,6 +375,50 @@ bool cmExecuteProcessCommand(std::vector<std::string> const& args, } } + if (arguments.CommandErrorIsFatal == "ANY"_s) { + if (cmsysProcess_GetState(cp) == cmsysProcess_State_Exited) { + std::vector<int> failedIndexes; + for (int i = 0; i < static_cast<int>(arguments.Commands.size()); ++i) { + if (cmsysProcess_GetStateByIndex(cp, i) == + kwsysProcess_StateByIndex_Exited) { + int exitCode = cmsysProcess_GetExitValueByIndex(cp, i); + if (exitCode) { + failedIndexes.push_back(i); + } + } + } + if (!failedIndexes.empty()) { + std::ostringstream oss; + oss << "failed command indexes: "; + for (auto i = 0u; i < failedIndexes.size(); i++) { + if (i == failedIndexes.size() - 1) { + oss << failedIndexes[i] + 1; + } else { + oss << failedIndexes[i] + 1 << ", "; + } + } + status.SetError(oss.str()); + cmSystemTools::SetFatalErrorOccured(); + return false; + } + } + } + + if (arguments.CommandErrorIsFatal == "LAST"_s) { + if (cmsysProcess_GetState(cp) == cmsysProcess_State_Exited) { + int lastIndex = static_cast<int>(arguments.Commands.size() - 1); + if (cmsysProcess_GetStateByIndex(cp, lastIndex) == + kwsysProcess_StateByIndex_Exited) { + int exitCode = cmsysProcess_GetExitValueByIndex(cp, lastIndex); + if (exitCode) { + status.SetError("last command failed"); + cmSystemTools::SetFatalErrorOccured(); + return false; + } + } + } + } + return true; } diff --git a/Tests/RunCMake/execute_process/AnyCommandError-result.txt b/Tests/RunCMake/execute_process/AnyCommandError-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/execute_process/AnyCommandError-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/execute_process/AnyCommandError-stderr.txt b/Tests/RunCMake/execute_process/AnyCommandError-stderr.txt new file mode 100644 index 0000000..0380562 --- /dev/null +++ b/Tests/RunCMake/execute_process/AnyCommandError-stderr.txt @@ -0,0 +1,2 @@ +CMake Error at .*AnyCommandError.cmake:1 \(execute_process\): + execute_process failed command indexes: 2, 3, 4 diff --git a/Tests/RunCMake/execute_process/AnyCommandError.cmake b/Tests/RunCMake/execute_process/AnyCommandError.cmake new file mode 100644 index 0000000..f8ec385 --- /dev/null +++ b/Tests/RunCMake/execute_process/AnyCommandError.cmake @@ -0,0 +1,8 @@ +execute_process(COMMAND ${CMAKE_COMMAND} -E true + COMMAND ${CMAKE_COMMAND} -E false + COMMAND ${CMAKE_COMMAND} -E false + COMMAND ${CMAKE_COMMAND} -E false + COMMAND ${CMAKE_COMMAND} -E true + COMMAND ${CMAKE_COMMAND} -E true + COMMAND_ERROR_IS_FATAL ANY +) diff --git a/Tests/RunCMake/execute_process/CommandError-result.txt b/Tests/RunCMake/execute_process/CommandError-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/execute_process/CommandError-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/execute_process/CommandError-stderr.txt b/Tests/RunCMake/execute_process/CommandError-stderr.txt new file mode 100644 index 0000000..c28f3a3 --- /dev/null +++ b/Tests/RunCMake/execute_process/CommandError-stderr.txt @@ -0,0 +1,2 @@ +CMake Error at .*CommandError.cmake:1 \(execute_process\): + execute_process COMMAND_ERROR_IS_FATAL option can be ANY or LAST diff --git a/Tests/RunCMake/execute_process/CommandError.cmake b/Tests/RunCMake/execute_process/CommandError.cmake new file mode 100644 index 0000000..da58928 --- /dev/null +++ b/Tests/RunCMake/execute_process/CommandError.cmake @@ -0,0 +1,3 @@ +execute_process(COMMAND ${CMAKE_COMMAND} -E true + COMMAND_ERROR_IS_FATAL ALL +) diff --git a/Tests/RunCMake/execute_process/LastCommandError-result.txt b/Tests/RunCMake/execute_process/LastCommandError-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/execute_process/LastCommandError-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/execute_process/LastCommandError-stderr.txt b/Tests/RunCMake/execute_process/LastCommandError-stderr.txt new file mode 100644 index 0000000..ff191b3 --- /dev/null +++ b/Tests/RunCMake/execute_process/LastCommandError-stderr.txt @@ -0,0 +1,2 @@ +CMake Error at .*LastCommandError.cmake:1 \(execute_process\): + execute_process last command failed diff --git a/Tests/RunCMake/execute_process/LastCommandError.cmake b/Tests/RunCMake/execute_process/LastCommandError.cmake new file mode 100644 index 0000000..6116a5c --- /dev/null +++ b/Tests/RunCMake/execute_process/LastCommandError.cmake @@ -0,0 +1,8 @@ +execute_process(COMMAND ${CMAKE_COMMAND} -E true + COMMAND ${CMAKE_COMMAND} -E false + COMMAND ${CMAKE_COMMAND} -E false + COMMAND ${CMAKE_COMMAND} -E false + COMMAND ${CMAKE_COMMAND} -E true + COMMAND ${CMAKE_COMMAND} -E false + COMMAND_ERROR_IS_FATAL LAST +) diff --git a/Tests/RunCMake/execute_process/RunCMakeTest.cmake b/Tests/RunCMake/execute_process/RunCMakeTest.cmake index 89ad6b2..f4c3d19 100644 --- a/Tests/RunCMake/execute_process/RunCMakeTest.cmake +++ b/Tests/RunCMake/execute_process/RunCMakeTest.cmake @@ -26,3 +26,7 @@ run_cmake_command(EchoCommand3 ${CMAKE_COMMAND} ${RunCMake_SOURCE_DIR}/EchoCommand.cmake) run_cmake_command(EchoVariable ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/EchoVariable.cmake) + +run_cmake_command(AnyCommandError ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/AnyCommandError.cmake) +run_cmake_command(LastCommandError ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/LastCommandError.cmake) +run_cmake_command(CommandError ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/CommandError.cmake) |