| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215 |
- /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
- file Copyright.txt or https://cmake.org/licensing for details. */
- #include "cmCTestHandlerCommand.h"
- #include <algorithm>
- #include <cstdlib>
- #include <sstream>
- #include <cm/string_view>
- #include "cmCTest.h"
- #include "cmCTestGenericHandler.h"
- #include "cmExecutionStatus.h"
- #include "cmMakefile.h"
- #include "cmStringAlgorithms.h"
- #include "cmSystemTools.h"
- #include "cmValue.h"
- #include "cmWorkingDirectory.h"
- 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::GetErrorOccurredFlag();
- cmSystemTools::ResetErrorOccurredFlag(); // 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::SetErrorOccurred();
- }
- return;
- }
- // if we have saved the error in a return variable
- // then put things back exactly like they were
- bool currentState = cmSystemTools::GetErrorOccurredFlag();
- // 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::SetErrorOccurred();
- } else {
- cmSystemTools::ResetErrorOccurredFlag();
- }
- }
- }
- SaveRestoreErrorState(const SaveRestoreErrorState&) = delete;
- SaveRestoreErrorState& operator=(const SaveRestoreErrorState&) = delete;
- private:
- bool InitialErrorState;
- bool CaptureCMakeErrorValue;
- };
- }
- bool cmCTestHandlerCommand::InvokeImpl(
- BasicArguments& args, std::vector<std::string> const& unparsed,
- cmExecutionStatus& status, std::function<bool()> handler)
- {
- // save error state and restore it if needed
- SaveRestoreErrorState errorState;
- if (!args.CaptureCMakeError.empty()) {
- errorState.CaptureCMakeError();
- }
- bool success = [&]() -> bool {
- if (args.MaybeReportError(status.GetMakefile())) {
- return true;
- }
- std::sort(args.ParsedKeywords.begin(), args.ParsedKeywords.end());
- auto const it = std::adjacent_find(args.ParsedKeywords.begin(),
- args.ParsedKeywords.end());
- if (it != args.ParsedKeywords.end()) {
- status.SetError(cmStrCat("called with more than one value for ", *it));
- return false;
- }
- if (!unparsed.empty()) {
- status.SetError(
- cmStrCat("called with unknown argument \"", unparsed.front(), "\"."));
- return false;
- }
- return handler();
- }();
- if (args.CaptureCMakeError.empty()) {
- return success;
- }
- if (!success) {
- cmCTestLog(this->CTest, ERROR_MESSAGE,
- this->GetName() << ' ' << status.GetError() << '\n');
- }
- cmMakefile& mf = status.GetMakefile();
- success = success && !cmSystemTools::GetErrorOccurredFlag();
- mf.AddDefinition(args.CaptureCMakeError, success ? "0" : "-1");
- return true;
- }
- bool cmCTestHandlerCommand::ExecuteHandlerCommand(
- HandlerArguments& args, cmExecutionStatus& /*status*/)
- {
- // Process input arguments.
- this->CheckArguments(args);
- // Set the config type of this ctest to the current value of the
- // CTEST_CONFIGURATION_TYPE script variable if it is defined.
- // The current script value trumps the -C argument on the command
- // line.
- cmValue ctestConfigType =
- this->Makefile->GetDefinition("CTEST_CONFIGURATION_TYPE");
- if (ctestConfigType) {
- this->CTest->SetConfigType(*ctestConfigType);
- }
- if (!args.Build.empty()) {
- this->CTest->SetCTestConfiguration(
- "BuildDirectory", cmSystemTools::CollapseFullPath(args.Build),
- args.Quiet);
- } else {
- std::string const& bdir =
- this->Makefile->GetSafeDefinition("CTEST_BINARY_DIRECTORY");
- if (!bdir.empty()) {
- this->CTest->SetCTestConfiguration(
- "BuildDirectory", cmSystemTools::CollapseFullPath(bdir), args.Quiet);
- } else {
- cmCTestLog(this->CTest, ERROR_MESSAGE,
- "CTEST_BINARY_DIRECTORY not set" << std::endl);
- }
- }
- if (!args.Source.empty()) {
- cmCTestLog(this->CTest, DEBUG,
- "Set source directory to: " << args.Source << std::endl);
- this->CTest->SetCTestConfiguration(
- "SourceDirectory", cmSystemTools::CollapseFullPath(args.Source),
- args.Quiet);
- } else {
- this->CTest->SetCTestConfiguration(
- "SourceDirectory",
- cmSystemTools::CollapseFullPath(
- this->Makefile->GetSafeDefinition("CTEST_SOURCE_DIRECTORY")),
- args.Quiet);
- }
- if (cmValue changeId = this->Makefile->GetDefinition("CTEST_CHANGE_ID")) {
- this->CTest->SetCTestConfiguration("ChangeId", *changeId, args.Quiet);
- }
- cmCTestLog(this->CTest, DEBUG, "Initialize handler" << std::endl);
- auto handler = this->InitializeHandler(args);
- if (!handler) {
- cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Cannot instantiate test handler " << this->GetName()
- << std::endl);
- return false;
- }
- handler->SetAppendXML(args.Append);
- handler->PopulateCustomVectors(this->Makefile);
- if (!args.SubmitIndex.empty()) {
- handler->SetSubmitIndex(atoi(args.SubmitIndex.c_str()));
- }
- cmWorkingDirectory workdir(
- this->CTest->GetCTestConfiguration("BuildDirectory"));
- if (workdir.Failed()) {
- this->SetError(workdir.GetError());
- return false;
- }
- // reread time limit, as the variable may have been modified.
- this->CTest->SetTimeLimit(this->Makefile->GetDefinition("CTEST_TIME_LIMIT"));
- handler->SetCMakeInstance(this->Makefile->GetCMakeInstance());
- int res = handler->ProcessHandler();
- if (!args.ReturnValue.empty()) {
- this->Makefile->AddDefinition(args.ReturnValue, std::to_string(res));
- }
- this->ProcessAdditionalValues(handler.get(), args);
- return true;
- }
- void cmCTestHandlerCommand::CheckArguments(HandlerArguments&)
- {
- }
- std::unique_ptr<cmCTestGenericHandler>
- cmCTestHandlerCommand::InitializeHandler(HandlerArguments&)
- {
- return nullptr;
- };
- void cmCTestHandlerCommand::ProcessAdditionalValues(cmCTestGenericHandler*,
- HandlerArguments const&)
- {
- }
|