| /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying | |
| file LICENSE.rst or https://cmake.org/licensing for details. */ | |
| #include "cmCTestSubmitCommand.h" | |
| #include <set> | |
| #include <utility> | |
| #include <cm/memory> | |
| #include <cm/vector> | |
| #include <cmext/string_view> | |
| #include "cmArgumentParser.h" | |
| #include "cmCTest.h" | |
| #include "cmCTestGenericHandler.h" | |
| #include "cmCTestSubmitHandler.h" | |
| #include "cmExecutionStatus.h" | |
| #include "cmList.h" | |
| #include "cmMakefile.h" | |
| #include "cmMessageType.h" | |
| #include "cmRange.h" | |
| #include "cmStringAlgorithms.h" | |
| #include "cmSystemTools.h" | |
| #include "cmValue.h" | |
| std::unique_ptr<cmCTestGenericHandler> cmCTestSubmitCommand::InitializeHandler( | |
| HandlerArguments& arguments, cmExecutionStatus& status) const | |
| { | |
| cmMakefile& mf = status.GetMakefile(); | |
| auto const& args = static_cast<SubmitArguments&>(arguments); | |
| cmValue submitURL = !args.SubmitURL.empty() | |
| ? cmValue(args.SubmitURL) | |
| : mf.GetDefinition("CTEST_SUBMIT_URL"); | |
| if (submitURL) { | |
| this->CTest->SetCTestConfiguration("SubmitURL", *submitURL, args.Quiet); | |
| } else { | |
| this->CTest->SetCTestConfigurationFromCMakeVariable( | |
| &mf, "DropMethod", "CTEST_DROP_METHOD", args.Quiet); | |
| this->CTest->SetCTestConfigurationFromCMakeVariable( | |
| &mf, "DropSiteUser", "CTEST_DROP_SITE_USER", args.Quiet); | |
| this->CTest->SetCTestConfigurationFromCMakeVariable( | |
| &mf, "DropSitePassword", "CTEST_DROP_SITE_PASSWORD", args.Quiet); | |
| this->CTest->SetCTestConfigurationFromCMakeVariable( | |
| &mf, "DropSite", "CTEST_DROP_SITE", args.Quiet); | |
| this->CTest->SetCTestConfigurationFromCMakeVariable( | |
| &mf, "DropLocation", "CTEST_DROP_LOCATION", args.Quiet); | |
| } | |
| if (!this->CTest->SetCTestConfigurationFromCMakeVariable( | |
| &mf, "TLSVersion", "CTEST_TLS_VERSION", args.Quiet)) { | |
| if (cmValue tlsVersionVar = mf.GetDefinition("CMAKE_TLS_VERSION")) { | |
| cmCTestOptionalLog( | |
| this->CTest, HANDLER_VERBOSE_OUTPUT, args.Quiet, | |
| "SetCTestConfiguration from CMAKE_TLS_VERSION:TLSVersion:", | |
| *tlsVersionVar, '\n'); | |
| this->CTest->SetCTestConfiguration("TLSVersion", *tlsVersionVar, | |
| args.Quiet); | |
| } else if (cm::optional<std::string> tlsVersionEnv = | |
| cmSystemTools::GetEnvVar("CMAKE_TLS_VERSION")) { | |
| cmCTestOptionalLog( | |
| this->CTest, HANDLER_VERBOSE_OUTPUT, args.Quiet, | |
| "SetCTestConfiguration from ENV{CMAKE_TLS_VERSION}:TLSVersion:", | |
| *tlsVersionEnv, '\n'); | |
| this->CTest->SetCTestConfiguration("TLSVersion", *tlsVersionEnv, | |
| args.Quiet); | |
| } | |
| } | |
| if (!this->CTest->SetCTestConfigurationFromCMakeVariable( | |
| &mf, "TLSVerify", "CTEST_TLS_VERIFY", args.Quiet)) { | |
| if (cmValue tlsVerifyVar = mf.GetDefinition("CMAKE_TLS_VERIFY")) { | |
| cmCTestOptionalLog( | |
| this->CTest, HANDLER_VERBOSE_OUTPUT, args.Quiet, | |
| "SetCTestConfiguration from CMAKE_TLS_VERIFY:TLSVerify:", | |
| *tlsVerifyVar, '\n'); | |
| this->CTest->SetCTestConfiguration("TLSVerify", *tlsVerifyVar, | |
| args.Quiet); | |
| } else if (cm::optional<std::string> tlsVerifyEnv = | |
| cmSystemTools::GetEnvVar("CMAKE_TLS_VERIFY")) { | |
| cmCTestOptionalLog( | |
| this->CTest, HANDLER_VERBOSE_OUTPUT, args.Quiet, | |
| "SetCTestConfiguration from ENV{CMAKE_TLS_VERIFY}:TLSVerify:", | |
| *tlsVerifyEnv, '\n'); | |
| this->CTest->SetCTestConfiguration("TLSVerify", *tlsVerifyEnv, | |
| args.Quiet); | |
| } | |
| } | |
| this->CTest->SetCTestConfigurationFromCMakeVariable( | |
| &mf, "CurlOptions", "CTEST_CURL_OPTIONS", args.Quiet); | |
| this->CTest->SetCTestConfigurationFromCMakeVariable( | |
| &mf, "SubmitInactivityTimeout", "CTEST_SUBMIT_INACTIVITY_TIMEOUT", | |
| args.Quiet); | |
| cmValue notesFilesVariable = mf.GetDefinition("CTEST_NOTES_FILES"); | |
| if (notesFilesVariable) { | |
| cmList notesFiles{ *notesFilesVariable }; | |
| this->CTest->GenerateNotesFile(mf.GetCMakeInstance(), notesFiles); | |
| } | |
| cmValue extraFilesVariable = mf.GetDefinition("CTEST_EXTRA_SUBMIT_FILES"); | |
| if (extraFilesVariable) { | |
| cmList extraFiles{ *extraFilesVariable }; | |
| if (!this->CTest->SubmitExtraFiles(extraFiles)) { | |
| status.SetError("problem submitting extra files."); | |
| return nullptr; | |
| } | |
| } | |
| auto handler = cm::make_unique<cmCTestSubmitHandler>(this->CTest); | |
| // If no FILES or PARTS given, *all* PARTS are submitted by default. | |
| // | |
| // If FILES are given, but not PARTS, only the FILES are submitted | |
| // and *no* PARTS are submitted. | |
| // (This is why we select the empty "noParts" set in the | |
| // if(args.Files) block below...) | |
| // | |
| // If PARTS are given, only the selected PARTS are submitted. | |
| // | |
| // If both PARTS and FILES are given, only the selected PARTS *and* | |
| // all the given FILES are submitted. | |
| // If given explicit FILES to submit, pass them to the handler. | |
| // | |
| if (args.Files) { | |
| // Intentionally select *no* PARTS. (Pass an empty set.) If PARTS | |
| // were also explicitly mentioned, they will be selected below... | |
| // But FILES with no PARTS mentioned should just submit the FILES | |
| // without any of the default parts. | |
| // | |
| handler->SelectParts(std::set<cmCTest::Part>()); | |
| handler->SelectFiles( | |
| std::set<std::string>(args.Files->begin(), args.Files->end())); | |
| } | |
| // If a PARTS option was given, select only the named parts for submission. | |
| // | |
| if (args.Parts) { | |
| auto parts = | |
| cmMakeRange(*(args.Parts)).transform([this](std::string const& arg) { | |
| return this->CTest->GetPartFromName(arg); | |
| }); | |
| handler->SelectParts(std::set<cmCTest::Part>(parts.begin(), parts.end())); | |
| } | |
| // Pass along any HTTPHEADER to the handler if this option was given. | |
| if (!args.HttpHeaders.empty()) { | |
| handler->SetHttpHeaders(args.HttpHeaders); | |
| } | |
| handler->RetryDelay = args.RetryDelay; | |
| handler->RetryCount = args.RetryCount; | |
| handler->InternalTest = args.InternalTest; | |
| handler->SetQuiet(args.Quiet); | |
| if (args.CDashUpload) { | |
| handler->CDashUpload = true; | |
| handler->CDashUploadFile = args.CDashUploadFile; | |
| handler->CDashUploadType = args.CDashUploadType; | |
| } | |
| return std::unique_ptr<cmCTestGenericHandler>(std::move(handler)); | |
| } | |
| bool cmCTestSubmitCommand::InitialPass(std::vector<std::string> const& args, | |
| cmExecutionStatus& status) const | |
| { | |
| // Arguments used by both modes. | |
| static auto const parserBase = | |
| cmArgumentParser<SubmitArguments>{ MakeHandlerParser<SubmitArguments>() } | |
| .Bind("BUILD_ID"_s, &SubmitArguments::BuildID) | |
| .Bind("HTTPHEADER"_s, &SubmitArguments::HttpHeaders) | |
| .Bind("RETRY_COUNT"_s, &SubmitArguments::RetryCount) | |
| .Bind("RETRY_DELAY"_s, &SubmitArguments::RetryDelay) | |
| .Bind("SUBMIT_URL"_s, &SubmitArguments::SubmitURL) | |
| .Bind("INTERNAL_TEST_CHECKSUM"_s, &SubmitArguments::InternalTest); | |
| // Arguments specific to the CDASH_UPLOAD signature. | |
| static auto const uploadParser = | |
| cmArgumentParser<SubmitArguments>{ parserBase } | |
| .Bind("CDASH_UPLOAD"_s, &SubmitArguments::CDashUploadFile) | |
| .Bind("CDASH_UPLOAD_TYPE"_s, &SubmitArguments::CDashUploadType); | |
| // Arguments that cannot be used with CDASH_UPLOAD. | |
| static auto const partsParser = | |
| cmArgumentParser<SubmitArguments>{ parserBase } | |
| .Bind("PARTS"_s, &SubmitArguments::Parts) | |
| .Bind("FILES"_s, &SubmitArguments::Files); | |
| bool const cdashUpload = !args.empty() && args[0] == "CDASH_UPLOAD"; | |
| auto const& parser = cdashUpload ? uploadParser : partsParser; | |
| return this->Invoke(parser, args, status, [&](SubmitArguments& a) -> bool { | |
| a.CDashUpload = cdashUpload; | |
| return this->ExecuteHandlerCommand(a, status); | |
| }); | |
| } | |
| void cmCTestSubmitCommand::CheckArguments(HandlerArguments& arguments, | |
| cmExecutionStatus& status) const | |
| { | |
| cmMakefile& mf = status.GetMakefile(); | |
| auto& args = static_cast<SubmitArguments&>(arguments); | |
| // Honor CTEST_SUBMIT_PARTS when PARTS is not given explicitly. | |
| // Skip for FILES-only calls (where PARTS is intentionally absent so that | |
| // only the named files are submitted) and for CDASH_UPLOAD calls (where | |
| // the PARTS concept does not apply at all). | |
| if (!args.Parts && !args.Files && !args.CDashUpload) { | |
| cmValue submitPartsVar = mf.GetDefinition("CTEST_SUBMIT_PARTS"); | |
| if (submitPartsVar && !submitPartsVar->empty()) { | |
| cmList submitPartsList{ *submitPartsVar }; | |
| if (!submitPartsList.empty()) { | |
| args.Parts.emplace(submitPartsList.begin(), submitPartsList.end()); | |
| } | |
| } | |
| } | |
| if (args.Parts) { | |
| cm::erase_if(*(args.Parts), [this, &mf](std::string const& arg) -> bool { | |
| cmCTest::Part p = this->CTest->GetPartFromName(arg); | |
| if (p == cmCTest::PartCount) { | |
| mf.IssueMessage(MessageType::FATAL_ERROR, | |
| cmStrCat("Part name \"", arg, "\" is invalid.")); | |
| return true; | |
| } | |
| return false; | |
| }); | |
| } | |
| if (args.Files) { | |
| cm::erase_if(*(args.Files), [&mf](std::string const& arg) -> bool { | |
| if (!cmSystemTools::FileExists(arg)) { | |
| mf.IssueMessage( | |
| MessageType::FATAL_ERROR, | |
| cmStrCat("File \"", arg, | |
| "\" does not exist. Cannot submit a non-existent file.")); | |
| return true; | |
| } | |
| return false; | |
| }); | |
| } | |
| } | |
| void cmCTestSubmitCommand::ProcessAdditionalValues( | |
| cmCTestGenericHandler*, HandlerArguments const& arguments, | |
| cmExecutionStatus& status) const | |
| { | |
| cmMakefile& mf = status.GetMakefile(); | |
| auto const& args = static_cast<SubmitArguments const&>(arguments); | |
| if (!args.BuildID.empty()) { | |
| mf.AddDefinition(args.BuildID, this->CTest->GetBuildID()); | |
| } | |
| } |