summaryrefslogtreecommitdiffstats
path: root/Source/CTest
diff options
context:
space:
mode:
authorBill Hoffman <bill.hoffman@kitware.com>2016-07-28 19:12:43 (GMT)
committerBrad King <brad.king@kitware.com>2016-09-20 17:14:20 (GMT)
commitd328dc6853e211dc05c4abcf62cc64b9c91235a2 (patch)
tree188238fc8ae3c7a85dc3edf1eae3a70b85b6197f /Source/CTest
parent9ac2e189607433b45b252a1e2261ccfaf11e492b (diff)
downloadCMake-d328dc6853e211dc05c4abcf62cc64b9c91235a2.zip
CMake-d328dc6853e211dc05c4abcf62cc64b9c91235a2.tar.gz
CMake-d328dc6853e211dc05c4abcf62cc64b9c91235a2.tar.bz2
CTest: Add CAPTURE_CMAKE_ERROR val to `ctest_*` commands
If a `ctest_*` command has CAPTURE_CMAKE_ERROR then any errors generated by cmake during that command will cause the value to be assigned `-1`. This will prevent a `ctest -S` script from returning non-zero unless the script explicitly calls `message(FATAL_ERROR)`.
Diffstat (limited to 'Source/CTest')
-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
4 files changed, 118 insertions, 4 deletions
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
};