summaryrefslogtreecommitdiffstats
path: root/Source/CTest
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2021-07-13 12:24:28 (GMT)
committerKitware Robot <kwrobot@kitware.com>2021-07-13 12:24:36 (GMT)
commit3265fa51cd4feec492a157506fff505dbd4c7d37 (patch)
tree1a734924e446176ca42aaa69e6000c3c584af5c0 /Source/CTest
parent95c97a12e8c8498f3ed7142e3644a8b6a7eeb9e1 (diff)
parentde4f1f26b0a3217f7caf842c50857b1ac90d9b7d (diff)
downloadCMake-3265fa51cd4feec492a157506fff505dbd4c7d37.zip
CMake-3265fa51cd4feec492a157506fff505dbd4c7d37.tar.gz
CMake-3265fa51cd4feec492a157506fff505dbd4c7d37.tar.bz2
Merge topic 'ctest-environment-modifications'
de4f1f26b0 CTest: add an ENVIRONMENT_MODIFICATION property 4c757fa3c8 Help/prop_test/ENVIRONMENT: clarify the scope of the changes Acked-by: Kitware Robot <kwrobot@kitware.com> Merge-request: !6299
Diffstat (limited to 'Source/CTest')
-rw-r--r--Source/CTest/cmCTestMultiProcessHandler.cxx5
-rw-r--r--Source/CTest/cmCTestRunTest.cxx145
-rw-r--r--Source/CTest/cmCTestRunTest.h1
-rw-r--r--Source/CTest/cmCTestTestHandler.cxx2
-rw-r--r--Source/CTest/cmCTestTestHandler.h1
5 files changed, 151 insertions, 3 deletions
diff --git a/Source/CTest/cmCTestMultiProcessHandler.cxx b/Source/CTest/cmCTestMultiProcessHandler.cxx
index 86a8e00..d90c4a6 100644
--- a/Source/CTest/cmCTestMultiProcessHandler.cxx
+++ b/Source/CTest/cmCTestMultiProcessHandler.cxx
@@ -1026,6 +1026,11 @@ static Json::Value DumpCTestProperties(
properties.append(DumpCTestProperty(
"ENVIRONMENT", DumpToJsonArray(testProperties.Environment)));
}
+ if (!testProperties.EnvironmentModification.empty()) {
+ properties.append(DumpCTestProperty(
+ "ENVIRONMENT_MODIFICATION",
+ DumpToJsonArray(testProperties.EnvironmentModification)));
+ }
if (!testProperties.ErrorRegularExpressions.empty()) {
properties.append(DumpCTestProperty(
"FAIL_REGULAR_EXPRESSION",
diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx
index 4e9b0f0..20f0ed3 100644
--- a/Source/CTest/cmCTestRunTest.cxx
+++ b/Source/CTest/cmCTestRunTest.cxx
@@ -8,12 +8,16 @@
#include <cstdint>
#include <cstdio>
#include <cstring>
+#include <functional>
#include <iomanip>
#include <ratio>
#include <sstream>
#include <utility>
#include <cm/memory>
+#include <cm/optional>
+#include <cm/string_view>
+#include <cmext/string_view>
#include "cmsys/RegularExpression.hxx"
@@ -640,6 +644,7 @@ bool cmCTestRunTest::StartTest(size_t completed, size_t total)
return this->ForkProcess(timeout, this->TestProperties->ExplicitTimeout,
&this->TestProperties->Environment,
+ &this->TestProperties->EnvironmentModification,
&this->TestProperties->Affinity);
}
@@ -696,6 +701,17 @@ void cmCTestRunTest::ComputeArguments()
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
this->Index << ": " << env << std::endl);
}
+ if (!this->TestProperties->EnvironmentModification.empty()) {
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ this->Index << ": "
+ << "Environment variable modifications: "
+ << std::endl);
+ }
+ for (std::string const& envmod :
+ this->TestProperties->EnvironmentModification) {
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ this->Index << ": " << envmod << std::endl);
+ }
}
void cmCTestRunTest::ParseOutputForMeasurements()
@@ -719,9 +735,11 @@ void cmCTestRunTest::ParseOutputForMeasurements()
}
}
-bool cmCTestRunTest::ForkProcess(cmDuration testTimeOut, bool explicitTimeout,
- std::vector<std::string>* environment,
- std::vector<size_t>* affinity)
+bool cmCTestRunTest::ForkProcess(
+ cmDuration testTimeOut, bool explicitTimeout,
+ std::vector<std::string>* environment,
+ std::vector<std::string>* environment_modification,
+ std::vector<size_t>* affinity)
{
this->TestProcess->SetId(this->Index);
this->TestProcess->SetWorkingDirectory(this->TestProperties->Directory);
@@ -770,6 +788,127 @@ bool cmCTestRunTest::ForkProcess(cmDuration testTimeOut, bool explicitTimeout,
}
}
+ if (environment_modification && !environment_modification->empty()) {
+ std::map<std::string, cm::optional<std::string>> env_application;
+
+#ifdef _WIN32
+ char path_sep = ';';
+#else
+ char path_sep = ':';
+#endif
+
+ auto apply_diff =
+ [&env_application](const std::string& name,
+ std::function<void(std::string&)> const& apply) {
+ auto entry = env_application.find(name);
+ std::string output;
+ if (entry != env_application.end() && entry->second) {
+ output = *entry->second;
+ }
+ apply(output);
+ entry->second = output;
+ };
+
+ bool err_occurred = false;
+
+ for (auto const& envmod : *environment_modification) {
+ // Split on `=`
+ auto const eq_loc = envmod.find_first_of('=');
+ if (eq_loc == std::string::npos) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Error: Missing `=` after the variable name in: "
+ << envmod << std::endl);
+ err_occurred = true;
+ continue;
+ }
+ auto const name = envmod.substr(0, eq_loc);
+
+ // Split value on `:`
+ auto const op_value_start = eq_loc + 1;
+ auto const colon_loc = envmod.find_first_of(':', op_value_start);
+ if (colon_loc == std::string::npos) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Error: Missing `:` after the operation in: " << envmod
+ << std::endl);
+ err_occurred = true;
+ continue;
+ }
+ auto const op =
+ envmod.substr(op_value_start, colon_loc - op_value_start);
+
+ auto const value_start = colon_loc + 1;
+ auto const value = envmod.substr(value_start);
+
+ // Determine what to do with the operation.
+ if (op == "reset"_s) {
+ auto entry = env_application.find(name);
+ if (entry != env_application.end()) {
+ env_application.erase(entry);
+ }
+ } else if (op == "set"_s) {
+ env_application[name] = value;
+ } else if (op == "unset"_s) {
+ env_application[name] = {};
+ } else if (op == "string_append"_s) {
+ apply_diff(name, [&value](std::string& output) { output += value; });
+ } else if (op == "string_prepend"_s) {
+ apply_diff(name,
+ [&value](std::string& output) { output.insert(0, value); });
+ } else if (op == "path_list_append"_s) {
+ apply_diff(name, [&value, path_sep](std::string& output) {
+ if (!output.empty()) {
+ output += path_sep;
+ }
+ output += value;
+ });
+ } else if (op == "path_list_prepend"_s) {
+ apply_diff(name, [&value, path_sep](std::string& output) {
+ if (!output.empty()) {
+ output.insert(output.begin(), path_sep);
+ }
+ output.insert(0, value);
+ });
+ } else if (op == "cmake_list_append"_s) {
+ apply_diff(name, [&value](std::string& output) {
+ if (!output.empty()) {
+ output += ';';
+ }
+ output += value;
+ });
+ } else if (op == "cmake_list_prepend"_s) {
+ apply_diff(name, [&value](std::string& output) {
+ if (!output.empty()) {
+ output.insert(output.begin(), ';');
+ }
+ output.insert(0, value);
+ });
+ } else {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Error: Unrecognized environment manipulation argument: "
+ << op << std::endl);
+ err_occurred = true;
+ continue;
+ }
+ }
+
+ if (err_occurred) {
+ return false;
+ }
+
+ for (auto const& env_apply : env_application) {
+ if (env_apply.second) {
+ auto const env_update =
+ cmStrCat(env_apply.first, '=', *env_apply.second);
+ cmSystemTools::PutEnv(env_update);
+ envMeasurement << env_update << std::endl;
+ } else {
+ cmSystemTools::UnsetEnv(env_apply.first.c_str());
+ // Signify that this variable is being actively unset
+ envMeasurement << "#" << env_apply.first << "=" << std::endl;
+ }
+ }
+ }
+
if (this->UseAllocatedResources) {
std::vector<std::string> envLog;
this->SetupResourcesEnvironment(&envLog);
diff --git a/Source/CTest/cmCTestRunTest.h b/Source/CTest/cmCTestRunTest.h
index a4981c3..2082156 100644
--- a/Source/CTest/cmCTestRunTest.h
+++ b/Source/CTest/cmCTestRunTest.h
@@ -113,6 +113,7 @@ private:
void ExeNotFound(std::string exe);
bool ForkProcess(cmDuration testTimeOut, bool explicitTimeout,
std::vector<std::string>* environment,
+ std::vector<std::string>* environment_modification,
std::vector<size_t>* affinity);
void WriteLogOutputTop(size_t completed, size_t total);
// Run post processing of the process output for MemCheck
diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx
index b60a664..1157d10 100644
--- a/Source/CTest/cmCTestTestHandler.cxx
+++ b/Source/CTest/cmCTestTestHandler.cxx
@@ -2245,6 +2245,8 @@ bool cmCTestTestHandler::SetTestsProperties(
cmExpandList(val, rt.Depends);
} else if (key == "ENVIRONMENT"_s) {
cmExpandList(val, rt.Environment);
+ } else if (key == "ENVIRONMENT_MODIFICATION"_s) {
+ cmExpandList(val, rt.EnvironmentModification);
} else if (key == "LABELS"_s) {
std::vector<std::string> Labels = cmExpandedList(val);
rt.Labels.insert(rt.Labels.end(), Labels.begin(), Labels.end());
diff --git a/Source/CTest/cmCTestTestHandler.h b/Source/CTest/cmCTestTestHandler.h
index 1b42647..f2da320 100644
--- a/Source/CTest/cmCTestTestHandler.h
+++ b/Source/CTest/cmCTestTestHandler.h
@@ -151,6 +151,7 @@ public:
// return code of test which will mark test as "not run"
int SkipReturnCode;
std::vector<std::string> Environment;
+ std::vector<std::string> EnvironmentModification;
std::vector<std::string> Labels;
std::set<std::string> LockedResources;
std::set<std::string> FixturesSetup;