diff options
Diffstat (limited to 'Source/CTest/cmCTestHandlerCommand.cxx')
-rw-r--r-- | Source/CTest/cmCTestHandlerCommand.cxx | 112 |
1 files changed, 108 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; } |