summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Help/command/ctest_build.rst5
-rw-r--r--Help/command/ctest_configure.rst7
-rw-r--r--Help/command/ctest_coverage.rst5
-rw-r--r--Help/command/ctest_test.rst5
-rw-r--r--Help/command/ctest_upload.rst6
-rw-r--r--Help/release/dev/ctest-capture-error.rst8
-rw-r--r--Source/CTest/cmCTestCoverageHandler.cxx3
-rw-r--r--Source/CTest/cmCTestHandlerCommand.cxx112
-rw-r--r--Source/CTest/cmCTestHandlerCommand.h1
-rw-r--r--Source/CTest/cmCTestUploadCommand.cxx8
-rw-r--r--Source/CTest/cmCTestUploadCommand.h1
-rw-r--r--Tests/RunCMake/CMakeLists.txt1
-rw-r--r--Tests/RunCMake/ctest_cmake_error/CMakeLists.txt.in4
-rw-r--r--Tests/RunCMake/ctest_cmake_error/CTestCaptureErrorNonZero-stderr.txt4
-rw-r--r--Tests/RunCMake/ctest_cmake_error/CTestCaptureErrorZero-stderr.txt4
-rw-r--r--Tests/RunCMake/ctest_cmake_error/CTestCaptureErrorZero-stdout.txt1
-rw-r--r--Tests/RunCMake/ctest_cmake_error/CTestConfig.cmake.in1
-rw-r--r--Tests/RunCMake/ctest_cmake_error/CoverageQuiet-stdout.txt1
-rw-r--r--Tests/RunCMake/ctest_cmake_error/RunCMakeTest.cmake10
-rw-r--r--Tests/RunCMake/ctest_cmake_error/test.cmake.in22
20 files changed, 201 insertions, 8 deletions
diff --git a/Help/command/ctest_build.rst b/Help/command/ctest_build.rst
index e1b7793..d3ceb2d 100644
--- a/Help/command/ctest_build.rst
+++ b/Help/command/ctest_build.rst
@@ -13,6 +13,7 @@ Perform the :ref:`CTest Build Step` as a :ref:`Dashboard Client`.
[NUMBER_ERRORS <num-err-var>]
[NUMBER_WARNINGS <num-warn-var>]
[RETURN_VALUE <result-var>]
+ [CAPTURE_CMAKE_ERROR <result-var>]
)
Build the project and store results in ``Build.xml``
@@ -66,6 +67,10 @@ The options are:
``RETURN_VALUE <result-var>``
Store the return value of the native build tool in the given variable.
+``CAPTURE_CMAKE_ERROR <result-var>``
+ Store in the ``<result-var>`` variable -1 if there are any errors running
+ the command and prevent ctest from returning non-zero if an error occurs.
+
``QUIET``
Suppress any CTest-specific non-error output that would have been
printed to the console otherwise. The summary of warnings / errors,
diff --git a/Help/command/ctest_configure.rst b/Help/command/ctest_configure.rst
index 851c292..b11e77c 100644
--- a/Help/command/ctest_configure.rst
+++ b/Help/command/ctest_configure.rst
@@ -6,7 +6,8 @@ Perform the :ref:`CTest Configure Step` as a :ref:`Dashboard Client`.
::
ctest_configure([BUILD <build-dir>] [SOURCE <source-dir>] [APPEND]
- [OPTIONS <options>] [RETURN_VALUE <result-var>] [QUIET])
+ [OPTIONS <options>] [RETURN_VALUE <result-var>] [QUIET]
+ [CAPTURE_CMAKE_ERROR <result-var>])
Configure the project build tree and record results in ``Configure.xml``
for submission with the :command:`ctest_submit` command.
@@ -33,6 +34,10 @@ The options are:
Store in the ``<result-var>`` variable the return value of the native
configuration tool.
+``CAPTURE_CMAKE_ERROR <result-var>``
+ Store in the ``<result-var>`` variable -1 if there are any errors running
+ the command and prevent ctest from returning non-zero if an error occurs.
+
``QUIET``
Suppress any CTest-specific non-error messages that would have
otherwise been printed to the console. Output from the underlying
diff --git a/Help/command/ctest_coverage.rst b/Help/command/ctest_coverage.rst
index 12429b9..ec1ee25 100644
--- a/Help/command/ctest_coverage.rst
+++ b/Help/command/ctest_coverage.rst
@@ -8,6 +8,7 @@ Perform the :ref:`CTest Coverage Step` as a :ref:`Dashboard Client`.
ctest_coverage([BUILD <build-dir>] [APPEND]
[LABELS <label>...]
[RETURN_VALUE <result-var>]
+ [CAPTURE_CMAKE_ERROR <result-var]
[QUIET]
)
@@ -33,6 +34,10 @@ The options are:
Store in the ``<result-var>`` variable ``0`` if coverage tools
ran without error and non-zero otherwise.
+``CAPTURE_CMAKE_ERROR <result-var>``
+ Store in the ``<result-var>`` variable -1 if there are any errors running
+ the command and prevent ctest from returning non-zero if an error occurs.
+
``QUIET``
Suppress any CTest-specific non-error output that would have been
printed to the console otherwise. The summary indicating how many
diff --git a/Help/command/ctest_test.rst b/Help/command/ctest_test.rst
index 412e323..551bc58 100644
--- a/Help/command/ctest_test.rst
+++ b/Help/command/ctest_test.rst
@@ -18,6 +18,7 @@ Perform the :ref:`CTest Test Step` as a :ref:`Dashboard Client`.
[SCHEDULE_RANDOM <ON|OFF>]
[STOP_TIME <time-of-day>]
[RETURN_VALUE <result-var>]
+ [CAPTURE_CMAKE_ERROR <result-var>]
[QUIET]
)
@@ -80,6 +81,10 @@ The options are:
Store in the ``<result-var>`` variable ``0`` if all tests passed.
Store non-zero if anything went wrong.
+``CAPTURE_CMAKE_ERROR <result-var>``
+ Store in the ``<result-var>`` variable -1 if there are any errors running
+ the command and prevent ctest from returning non-zero if an error occurs.
+
``QUIET``
Suppress any CTest-specific non-error messages that would have otherwise
been printed to the console. Output from the underlying test command is not
diff --git a/Help/command/ctest_upload.rst b/Help/command/ctest_upload.rst
index d9630d2..39d9de1 100644
--- a/Help/command/ctest_upload.rst
+++ b/Help/command/ctest_upload.rst
@@ -5,7 +5,7 @@ Upload files to a dashboard server as a :ref:`Dashboard Client`.
::
- ctest_upload(FILES <file>... [QUIET])
+ ctest_upload(FILES <file>... [QUIET] [CAPTURE_CMAKE_ERROR <result-var>])
The options are:
@@ -16,3 +16,7 @@ The options are:
``QUIET``
Suppress any CTest-specific non-error output that would have been
printed to the console otherwise.
+
+``CAPTURE_CMAKE_ERROR <result-var>``
+ Store in the ``<result-var>`` variable -1 if there are any errors running
+ the command and prevent ctest from returning non-zero if an error occurs.
diff --git a/Help/release/dev/ctest-capture-error.rst b/Help/release/dev/ctest-capture-error.rst
new file mode 100644
index 0000000..5a286c7
--- /dev/null
+++ b/Help/release/dev/ctest-capture-error.rst
@@ -0,0 +1,8 @@
+ctest-capture-error
+-------------------
+
+* The :command:`ctest_configure`, :command:`ctest_build`,
+ :command:`ctest_test`, :command:`ctest_coverage`, and :command:`ctest_upload`
+ commands gained a new ``CAPTURE_CMAKE_ERROR`` option to capture any errors
+ that occur as the commands run into a variable and avoid affecting the return
+ code of the :manual:`ctest(1)` process.
diff --git a/Source/CTest/cmCTestCoverageHandler.cxx b/Source/CTest/cmCTestCoverageHandler.cxx
index 2eb64bf..f2cd67e 100644
--- a/Source/CTest/cmCTestCoverageHandler.cxx
+++ b/Source/CTest/cmCTestCoverageHandler.cxx
@@ -929,8 +929,7 @@ int cmCTestCoverageHandler::HandleGCovCoverage(
std::string gcovCommand =
this->CTest->GetCTestConfiguration("CoverageCommand");
if (gcovCommand.empty()) {
- cmCTestLog(this->CTest, ERROR_MESSAGE, "Could not find gcov."
- << std::endl);
+ cmCTestLog(this->CTest, WARNING, "Could not find gcov." << std::endl);
return 0;
}
std::string gcovExtraFlags =
diff --git a/Source/CTest/cmCTestHandlerCommand.cxx b/Source/CTest/cmCTestHandlerCommand.cxx
index e8e2956..19d8595 100644
--- a/Source/CTest/cmCTestHandlerCommand.cxx
+++ b/Source/CTest/cmCTestHandlerCommand.cxx
@@ -31,6 +31,7 @@ cmCTestHandlerCommand::cmCTestHandlerCommand()
this->Arguments.push_back(CM_NULLPTR);
}
this->Arguments[ct_RETURN_VALUE] = "RETURN_VALUE";
+ this->Arguments[ct_CAPTURE_CMAKE_ERROR] = "CAPTURE_CMAKE_ERROR";
this->Arguments[ct_SOURCE] = "SOURCE";
this->Arguments[ct_BUILD] = "BUILD";
this->Arguments[ct_SUBMIT_INDEX] = "SUBMIT_INDEX";
@@ -39,15 +40,71 @@ cmCTestHandlerCommand::cmCTestHandlerCommand()
this->Quiet = false;
}
+namespace {
+// class to save and restore the error state for ctest_* commands
+// if a ctest_* command has a CAPTURE_CMAKE_ERROR then put the error
+// state into there and restore the system wide error to what
+// it was before the command ran
+class SaveRestoreErrorState
+{
+public:
+ SaveRestoreErrorState()
+ {
+ this->InitialErrorState = cmSystemTools::GetErrorOccuredFlag();
+ cmSystemTools::ResetErrorOccuredFlag(); // rest the error state
+ this->CaptureCMakeErrorValue = false;
+ }
+ // if the function has a CAPTURE_CMAKE_ERROR then we should restore
+ // the error state to what it was before the function was run
+ // if not then let the error state be what it is
+ void CaptureCMakeError() { this->CaptureCMakeErrorValue = true; }
+ ~SaveRestoreErrorState()
+ {
+ // if we are not saving the return value then make sure
+ // if it was in error it goes back to being in error
+ // otherwise leave it be what it is
+ if (!this->CaptureCMakeErrorValue) {
+ if (this->InitialErrorState) {
+ cmSystemTools::SetErrorOccured();
+ }
+ return;
+ }
+ // if we have saved the error in a return variable
+ // then put things back exactly like they were
+ bool currentState = cmSystemTools::GetErrorOccuredFlag();
+ // if the state changed during this command we need
+ // to handle it, if not then nothing needs to be done
+ if (currentState != this->InitialErrorState) {
+ // restore the initial error state
+ if (this->InitialErrorState) {
+ cmSystemTools::SetErrorOccured();
+ } else {
+ cmSystemTools::ResetErrorOccuredFlag();
+ }
+ }
+ }
+
+private:
+ bool InitialErrorState;
+ bool CaptureCMakeErrorValue;
+};
+}
+
bool cmCTestHandlerCommand::InitialPass(std::vector<std::string> const& args,
cmExecutionStatus& /*unused*/)
{
+ // save error state and restore it if needed
+ SaveRestoreErrorState errorState;
// Allocate space for argument values.
this->Values.clear();
this->Values.resize(this->Last, CM_NULLPTR);
// Process input arguments.
this->ArgumentDoing = ArgumentDoingNone;
+ // look at all arguments and do not short circuit on the first
+ // bad one so that CAPTURE_CMAKE_ERROR can override setting the
+ // global error state
+ bool foundBadArgument = false;
for (unsigned int i = 0; i < args.size(); ++i) {
// Check this argument.
if (!this->CheckArgumentKeyword(args[i]) &&
@@ -55,14 +112,36 @@ bool cmCTestHandlerCommand::InitialPass(std::vector<std::string> const& args,
std::ostringstream e;
e << "called with unknown argument \"" << args[i] << "\".";
this->SetError(e.str());
- return false;
+ foundBadArgument = true;
}
-
- // Quit if an argument is invalid.
+ // note bad argument
if (this->ArgumentDoing == ArgumentDoingError) {
- return false;
+ foundBadArgument = true;
}
}
+ bool capureCMakeError = (this->Values[ct_CAPTURE_CMAKE_ERROR] &&
+ *this->Values[ct_CAPTURE_CMAKE_ERROR]);
+ // now that arguments are parsed check to see if there is a
+ // CAPTURE_CMAKE_ERROR specified let the errorState object know.
+ if (capureCMakeError) {
+ errorState.CaptureCMakeError();
+ }
+ // if we found a bad argument then exit before running command
+ if (foundBadArgument) {
+ // store the cmake error
+ if (capureCMakeError) {
+ this->Makefile->AddDefinition(this->Values[ct_CAPTURE_CMAKE_ERROR],
+ "-1");
+ const char* err = this->GetError();
+ if (err && !cmSystemTools::FindLastString(err, "unknown error.")) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, err << " error from command\n");
+ }
+ // return success because failure is recorded in CAPTURE_CMAKE_ERROR
+ return true;
+ }
+ // return failure because of bad argument
+ return false;
+ }
// Set the config type of this ctest to the current value of the
// CTEST_CONFIGURATION_TYPE script variable if it is defined.
@@ -117,6 +196,15 @@ bool cmCTestHandlerCommand::InitialPass(std::vector<std::string> const& args,
if (!handler) {
cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot instantiate test handler "
<< this->GetName() << std::endl);
+ if (capureCMakeError) {
+ this->Makefile->AddDefinition(this->Values[ct_CAPTURE_CMAKE_ERROR],
+ "-1");
+ const char* err = this->GetError();
+ if (err && !cmSystemTools::FindLastString(err, "unknown error.")) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, err << " error from command\n");
+ }
+ return true;
+ }
return false;
}
@@ -147,6 +235,22 @@ bool cmCTestHandlerCommand::InitialPass(std::vector<std::string> const& args,
this->Makefile->AddDefinition(this->Values[ct_RETURN_VALUE],
str.str().c_str());
}
+ // log the error message if there was an error
+ if (capureCMakeError) {
+ const char* returnString = "0";
+ if (cmSystemTools::GetErrorOccuredFlag()) {
+ returnString = "-1";
+ const char* err = this->GetError();
+ // print out the error if it is not "unknown error" which means
+ // there was no message
+ if (err && !cmSystemTools::FindLastString(err, "unknown error.")) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, err);
+ }
+ }
+ // store the captured cmake error state 0 or -1
+ this->Makefile->AddDefinition(this->Values[ct_CAPTURE_CMAKE_ERROR],
+ returnString);
+ }
cmSystemTools::ChangeDirectory(current_dir);
return true;
}
diff --git a/Source/CTest/cmCTestHandlerCommand.h b/Source/CTest/cmCTestHandlerCommand.h
index 7c9fd50..95a1581 100644
--- a/Source/CTest/cmCTestHandlerCommand.h
+++ b/Source/CTest/cmCTestHandlerCommand.h
@@ -47,6 +47,7 @@ public:
{
ct_NONE,
ct_RETURN_VALUE,
+ ct_CAPTURE_CMAKE_ERROR,
ct_BUILD,
ct_SOURCE,
ct_SUBMIT_INDEX,
diff --git a/Source/CTest/cmCTestUploadCommand.cxx b/Source/CTest/cmCTestUploadCommand.cxx
index 5ea637e..c4458dd 100644
--- a/Source/CTest/cmCTestUploadCommand.cxx
+++ b/Source/CTest/cmCTestUploadCommand.cxx
@@ -45,11 +45,19 @@ bool cmCTestUploadCommand::CheckArgumentKeyword(std::string const& arg)
this->Quiet = true;
return true;
}
+ if (arg == "CAPTURE_CMAKE_ERROR") {
+ this->ArgumentDoing = ArgumentDoingCaptureCMakeError;
+ return true;
+ }
return false;
}
bool cmCTestUploadCommand::CheckArgumentValue(std::string const& arg)
{
+ if (this->ArgumentDoing == ArgumentDoingCaptureCMakeError) {
+ this->Values[ct_CAPTURE_CMAKE_ERROR] = arg.c_str();
+ return true;
+ }
if (this->ArgumentDoing == ArgumentDoingFiles) {
if (cmSystemTools::FileExists(arg.c_str())) {
this->Files.insert(arg);
diff --git a/Source/CTest/cmCTestUploadCommand.h b/Source/CTest/cmCTestUploadCommand.h
index da291f3..3a5bdef 100644
--- a/Source/CTest/cmCTestUploadCommand.h
+++ b/Source/CTest/cmCTestUploadCommand.h
@@ -61,6 +61,7 @@ protected:
enum
{
ArgumentDoingFiles = Superclass::ArgumentDoingLast1,
+ ArgumentDoingCaptureCMakeError,
ArgumentDoingLast2
};
diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index e36b2a6..a1f35d7 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -184,6 +184,7 @@ add_RunCMake_test(cmake_minimum_required)
add_RunCMake_test(cmake_parse_arguments)
add_RunCMake_test(continue)
add_RunCMake_test(ctest_build)
+add_RunCMake_test(ctest_cmake_error)
add_RunCMake_test(ctest_configure)
if(COVERAGE_COMMAND)
add_RunCMake_test(ctest_coverage -DCOVERAGE_COMMAND=${COVERAGE_COMMAND})
diff --git a/Tests/RunCMake/ctest_cmake_error/CMakeLists.txt.in b/Tests/RunCMake/ctest_cmake_error/CMakeLists.txt.in
new file mode 100644
index 0000000..1babd72
--- /dev/null
+++ b/Tests/RunCMake/ctest_cmake_error/CMakeLists.txt.in
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 3.1)
+project(CTestCoverage@CASE_NAME@ NONE)
+include(CTest)
+add_test(NAME RunCMakeVersion COMMAND "${CMAKE_COMMAND}" --version)
diff --git a/Tests/RunCMake/ctest_cmake_error/CTestCaptureErrorNonZero-stderr.txt b/Tests/RunCMake/ctest_cmake_error/CTestCaptureErrorNonZero-stderr.txt
new file mode 100644
index 0000000..4afb57a
--- /dev/null
+++ b/Tests/RunCMake/ctest_cmake_error/CTestCaptureErrorNonZero-stderr.txt
@@ -0,0 +1,4 @@
+.*ctest_configure called with unknown argument "junk".*
+.*ctest_build called with unknown argument "junk".*
+.*ctest_test called with unknown argument "junk".*
+.*ctest_coverage called with unknown argument "junk".*
diff --git a/Tests/RunCMake/ctest_cmake_error/CTestCaptureErrorZero-stderr.txt b/Tests/RunCMake/ctest_cmake_error/CTestCaptureErrorZero-stderr.txt
new file mode 100644
index 0000000..4afb57a
--- /dev/null
+++ b/Tests/RunCMake/ctest_cmake_error/CTestCaptureErrorZero-stderr.txt
@@ -0,0 +1,4 @@
+.*ctest_configure called with unknown argument "junk".*
+.*ctest_build called with unknown argument "junk".*
+.*ctest_test called with unknown argument "junk".*
+.*ctest_coverage called with unknown argument "junk".*
diff --git a/Tests/RunCMake/ctest_cmake_error/CTestCaptureErrorZero-stdout.txt b/Tests/RunCMake/ctest_cmake_error/CTestCaptureErrorZero-stdout.txt
new file mode 100644
index 0000000..d00b0c8
--- /dev/null
+++ b/Tests/RunCMake/ctest_cmake_error/CTestCaptureErrorZero-stdout.txt
@@ -0,0 +1 @@
+.*Run dashboard with model Experimental.*
diff --git a/Tests/RunCMake/ctest_cmake_error/CTestConfig.cmake.in b/Tests/RunCMake/ctest_cmake_error/CTestConfig.cmake.in
new file mode 100644
index 0000000..1f679d5
--- /dev/null
+++ b/Tests/RunCMake/ctest_cmake_error/CTestConfig.cmake.in
@@ -0,0 +1 @@
+set(CTEST_PROJECT_NAME "CTestCoverage@CASE_NAME@")
diff --git a/Tests/RunCMake/ctest_cmake_error/CoverageQuiet-stdout.txt b/Tests/RunCMake/ctest_cmake_error/CoverageQuiet-stdout.txt
new file mode 100644
index 0000000..3b09eac
--- /dev/null
+++ b/Tests/RunCMake/ctest_cmake_error/CoverageQuiet-stdout.txt
@@ -0,0 +1 @@
+sec$
diff --git a/Tests/RunCMake/ctest_cmake_error/RunCMakeTest.cmake b/Tests/RunCMake/ctest_cmake_error/RunCMakeTest.cmake
new file mode 100644
index 0000000..0ec04c2
--- /dev/null
+++ b/Tests/RunCMake/ctest_cmake_error/RunCMakeTest.cmake
@@ -0,0 +1,10 @@
+include(RunCTest)
+
+set(CASE_CTEST_COVERAGE_ARGS "")
+
+function(run_ctest_coverage CASE_NAME)
+ set(CASE_CTEST_COVERAGE_ARGS "${ARGN}")
+ run_ctest(${CASE_NAME})
+endfunction()
+
+run_ctest_coverage(CTestCaptureErrorNonZero junk CAPTURE_CMAKE_ERROR val)
diff --git a/Tests/RunCMake/ctest_cmake_error/test.cmake.in b/Tests/RunCMake/ctest_cmake_error/test.cmake.in
new file mode 100644
index 0000000..0648e7c
--- /dev/null
+++ b/Tests/RunCMake/ctest_cmake_error/test.cmake.in
@@ -0,0 +1,22 @@
+cmake_minimum_required(VERSION 3.1)
+
+set(CTEST_SITE "test-site")
+set(CTEST_BUILD_NAME "test-build-name")
+set(CTEST_SOURCE_DIRECTORY "@RunCMake_BINARY_DIR@/@CASE_NAME@")
+set(CTEST_BINARY_DIRECTORY "@RunCMake_BINARY_DIR@/@CASE_NAME@-build")
+set(CTEST_CMAKE_GENERATOR "@RunCMake_GENERATOR@")
+set(CTEST_CMAKE_GENERATOR_PLATFORM "@RunCMake_GENERATOR_PLATFORM@")
+set(CTEST_CMAKE_GENERATOR_TOOLSET "@RunCMake_GENERATOR_TOOLSET@")
+set(CTEST_BUILD_CONFIGURATION "$ENV{CMAKE_CONFIG_TYPE}")
+set(CTEST_COVERAGE_COMMAND "@COVERAGE_COMMAND@")
+
+set(ctest_coverage_args "@CASE_CTEST_COVERAGE_ARGS@")
+ctest_start(Experimental)
+ctest_configure( ${ctest_coverage_args} )
+ctest_build( ${ctest_coverage_args} )
+ctest_test( ${ctest_coverage_args} )
+ctest_coverage( ${ctest_coverage_args} )
+ctest_upload(junk CAPTURE_CMAKE_ERROR val)
+if(NOT val EQUAL -1)
+ message(FATAL_ERROR "CAPTURE_CMAKE_ERROR should be -1 is [${val}]")
+endif()