mirror of
https://github.com/Kitware/CMake.git
synced 2026-08-03 06:10:28 +00:00
cmCTestRunTest: Don't modify the current environment
Instead, pass the environment variables to the child process.
This commit is contained in:
@@ -21,6 +21,7 @@
|
||||
#include "cmCTestMemCheckHandler.h"
|
||||
#include "cmCTestMultiProcessHandler.h"
|
||||
#include "cmDuration.h"
|
||||
#include "cmEnvironment.h"
|
||||
#include "cmInstrumentation.h"
|
||||
#include "cmProcess.h"
|
||||
#include "cmStringAlgorithms.h"
|
||||
@@ -853,62 +854,36 @@ bool cmCTestRunTest::ForkProcess()
|
||||
this->TestHandler->GetQuiet());
|
||||
}
|
||||
|
||||
cmSystemTools::SaveRestoreEnvironment sre;
|
||||
std::ostringstream envMeasurement;
|
||||
|
||||
// We split processing ENVIRONMENT and ENVIRONMENT_MODIFICATION into two
|
||||
// phases to ensure that MYVAR=reset: in the latter phase resets to the
|
||||
// former phase's settings, rather than to the original environment.
|
||||
if (!this->TestProperties->Environment.empty()) {
|
||||
cmSystemTools::EnvDiff diff;
|
||||
diff.AppendEnv(this->TestProperties->Environment);
|
||||
diff.ApplyToCurrentEnv(&envMeasurement);
|
||||
}
|
||||
// Record the original environment before modifying it
|
||||
auto const originalEnvironment =
|
||||
cmEnvironment{ cmSystemTools::GetEnvironmentVariables() };
|
||||
|
||||
auto env = originalEnvironment;
|
||||
env.Update(this->TestProperties->Environment);
|
||||
if (!this->TestProperties->EnvironmentModification.empty()) {
|
||||
cmSystemTools::EnvDiff diff;
|
||||
bool env_ok = true;
|
||||
|
||||
for (auto const& envmod : this->TestProperties->EnvironmentModification) {
|
||||
env_ok &= diff.ParseOperation(envmod);
|
||||
}
|
||||
|
||||
if (!env_ok) {
|
||||
auto diff = cmEnvironmentModification{};
|
||||
if (!diff.Add(this->TestProperties->EnvironmentModification)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
diff.ApplyToCurrentEnv(&envMeasurement);
|
||||
diff.ApplyTo(env);
|
||||
}
|
||||
|
||||
if (this->UseAllocatedResources) {
|
||||
std::vector<std::string> envLog;
|
||||
this->SetupResourcesEnvironment(&envLog);
|
||||
for (auto const& var : envLog) {
|
||||
envMeasurement << var << std::endl;
|
||||
}
|
||||
this->SetupResourcesEnvironment(env);
|
||||
} else {
|
||||
cmSystemTools::UnsetEnv("CTEST_RESOURCE_GROUP_COUNT");
|
||||
// Signify that this variable is being actively unset
|
||||
envMeasurement << "#CTEST_RESOURCE_GROUP_COUNT=" << std::endl;
|
||||
env.UnPutEnv("CTEST_RESOURCE_GROUP_COUNT");
|
||||
}
|
||||
|
||||
this->TestResult.Environment = envMeasurement.str();
|
||||
// Remove last newline
|
||||
this->TestResult.Environment.erase(this->TestResult.Environment.length() -
|
||||
1);
|
||||
|
||||
this->TestProcess->SetEnvironment(env.GetVariables());
|
||||
this->TestResult.Environment = env.RecordDifference(originalEnvironment);
|
||||
return this->TestProcess->StartProcess(*this->MultiTestHandler.Loop,
|
||||
&this->TestProperties->Affinity);
|
||||
}
|
||||
|
||||
void cmCTestRunTest::SetupResourcesEnvironment(std::vector<std::string>* log)
|
||||
void cmCTestRunTest::SetupResourcesEnvironment(cmEnvironment& env)
|
||||
{
|
||||
std::string processCount =
|
||||
cmStrCat("CTEST_RESOURCE_GROUP_COUNT=", this->AllocatedResources.size());
|
||||
cmSystemTools::PutEnv(processCount);
|
||||
if (log) {
|
||||
log->emplace_back(std::move(processCount));
|
||||
}
|
||||
env.PutEnv(
|
||||
cmStrCat("CTEST_RESOURCE_GROUP_COUNT=", this->AllocatedResources.size()));
|
||||
|
||||
std::size_t i = 0;
|
||||
for (auto const& process : this->AllocatedResources) {
|
||||
@@ -933,15 +908,9 @@ void cmCTestRunTest::SetupResourcesEnvironment(std::vector<std::string>* log)
|
||||
firstName = false;
|
||||
var += cmStrCat("id:", it2.Id, ",slots:", it2.Slots);
|
||||
}
|
||||
cmSystemTools::PutEnv(var);
|
||||
if (log) {
|
||||
log->push_back(var);
|
||||
}
|
||||
}
|
||||
cmSystemTools::PutEnv(resourceList);
|
||||
if (log) {
|
||||
log->push_back(resourceList);
|
||||
env.PutEnv(var);
|
||||
}
|
||||
env.PutEnv(resourceList);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
#include "cmCTestTestHandler.h"
|
||||
#include "cmProcess.h"
|
||||
|
||||
class cmEnvironment;
|
||||
|
||||
/** \class cmRunTest
|
||||
* \brief represents a single test to be run
|
||||
*
|
||||
@@ -113,7 +115,7 @@ private:
|
||||
// Run post processing of the process output for MemCheck
|
||||
void MemCheckPostProcess();
|
||||
|
||||
void SetupResourcesEnvironment(std::vector<std::string>* log = nullptr);
|
||||
void SetupResourcesEnvironment(cmEnvironment& env);
|
||||
|
||||
// Returns "completed/total Test #Index: "
|
||||
std::string GetTestPrefix(size_t completed, size_t total) const;
|
||||
|
||||
@@ -35,19 +35,24 @@ cmProcess::cmProcess(std::unique_ptr<cmCTestRunTest> runner)
|
||||
|
||||
cmProcess::~cmProcess() = default;
|
||||
|
||||
void cmProcess::SetCommand(std::string const& command)
|
||||
void cmProcess::SetCommand(std::string command)
|
||||
{
|
||||
this->Command = command;
|
||||
this->Command = std::move(command);
|
||||
}
|
||||
|
||||
void cmProcess::SetCommandArguments(std::vector<std::string> const& args)
|
||||
void cmProcess::SetCommandArguments(std::vector<std::string> args)
|
||||
{
|
||||
this->Arguments = args;
|
||||
this->Arguments = std::move(args);
|
||||
}
|
||||
|
||||
void cmProcess::SetWorkingDirectory(std::string const& dir)
|
||||
void cmProcess::SetEnvironment(std::vector<std::string> env)
|
||||
{
|
||||
this->WorkingDirectory = dir;
|
||||
this->Environment = std::move(env);
|
||||
}
|
||||
|
||||
void cmProcess::SetWorkingDirectory(std::string dir)
|
||||
{
|
||||
this->WorkingDirectory = std::move(dir);
|
||||
}
|
||||
|
||||
bool cmProcess::StartProcess(uv_loop_t& loop, std::vector<size_t>* affinity)
|
||||
@@ -128,6 +133,15 @@ bool cmProcess::StartProcess(uv_loop_t& loop, std::vector<size_t>* affinity)
|
||||
#else
|
||||
static_cast<void>(affinity);
|
||||
#endif
|
||||
if (!this->Environment.empty()) {
|
||||
this->Env.clear();
|
||||
this->Env.reserve(this->Environment.size() + 1);
|
||||
for (auto const& var : this->Environment) {
|
||||
this->Env.push_back(var.c_str());
|
||||
}
|
||||
this->Env.push_back(nullptr);
|
||||
options.env = const_cast<char**>(this->Env.data());
|
||||
}
|
||||
|
||||
status =
|
||||
uv_read_start(pipe_reader, &cmProcess::OnAllocateCB, &cmProcess::OnReadCB);
|
||||
|
||||
@@ -34,9 +34,10 @@ class cmProcess
|
||||
public:
|
||||
explicit cmProcess(std::unique_ptr<cmCTestRunTest> runner);
|
||||
~cmProcess();
|
||||
void SetCommand(std::string const& command);
|
||||
void SetCommandArguments(std::vector<std::string> const& arg);
|
||||
void SetWorkingDirectory(std::string const& dir);
|
||||
void SetCommand(std::string command);
|
||||
void SetCommandArguments(std::vector<std::string> arg);
|
||||
void SetEnvironment(std::vector<std::string> env);
|
||||
void SetWorkingDirectory(std::string dir);
|
||||
void SetStopTimeout(cmDuration t) { this->StopTimeout = t; }
|
||||
void SetTimeout(cmDuration t) { this->Timeout = t; }
|
||||
void ChangeTimeout(cmDuration t);
|
||||
@@ -161,6 +162,8 @@ private:
|
||||
std::string WorkingDirectory;
|
||||
std::vector<std::string> Arguments;
|
||||
std::vector<char const*> ProcessArgs;
|
||||
std::vector<std::string> Environment;
|
||||
std::vector<char const*> Env;
|
||||
int Id;
|
||||
int64_t ExitValue;
|
||||
Termination TerminationStyle = Termination::Normal;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "cmEnvironment.h"
|
||||
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <utility>
|
||||
|
||||
#include <cm/string_view>
|
||||
@@ -69,6 +70,29 @@ std::vector<std::string> cmEnvironment::GetVariables() const
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string cmEnvironment::RecordDifference(
|
||||
cmEnvironment const& original) const
|
||||
{
|
||||
cm::string_view nl;
|
||||
std::ostringstream os;
|
||||
for (auto const& elem : this->Map) {
|
||||
if (!elem.second) {
|
||||
// Signify that this variable is being actively unset
|
||||
os << nl << '#' << elem.first << '=';
|
||||
nl = "\n";
|
||||
continue;
|
||||
}
|
||||
auto const it = original.Map.find(elem.first);
|
||||
if (it != original.Map.end() && *elem.second == it->second) {
|
||||
// Skip variables that are unchanged
|
||||
continue;
|
||||
}
|
||||
os << nl << elem.first << '=' << *elem.second;
|
||||
nl = "\n";
|
||||
}
|
||||
return os.str();
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
auto const ValidOperators = std::set<cm::string_view>{
|
||||
|
||||
@@ -46,6 +46,8 @@ public:
|
||||
|
||||
std::vector<std::string> GetVariables() const;
|
||||
|
||||
std::string RecordDifference(cmEnvironment const& original) const;
|
||||
|
||||
protected:
|
||||
struct EnvNameLess
|
||||
{
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
verify_ctest_resources()
|
||||
|
||||
read_testing_file("Test.xml" _test_contents)
|
||||
if(NOT _test_contents MATCHES "\nCTEST_RESOURCE_GROUP_0=widgets")
|
||||
if(NOT _test_contents MATCHES "(>|\n)CTEST_RESOURCE_GROUP_0=widgets")
|
||||
string(APPEND RunCMake_TEST_FAILED "Could not find variable CTEST_RESOURCE_GROUP_0 in test measurements\n")
|
||||
endif()
|
||||
if(NOT _test_contents MATCHES "\nCTEST_RESOURCE_GROUP_0_WIDGETS=id:")
|
||||
if(NOT _test_contents MATCHES "(>|\n)CTEST_RESOURCE_GROUP_0_WIDGETS=id:")
|
||||
string(APPEND RunCMake_TEST_FAILED "Could not find variable CTEST_RESOURCE_GROUP_0_WIDGETS in test measurements\n")
|
||||
endif()
|
||||
|
||||
@@ -2,7 +2,7 @@ file(READ "${RunCMake_TEST_BINARY_DIR}/Testing/TAG" _tag)
|
||||
string(REGEX REPLACE "^([^\n]*)\n.*$" "\\1" _date "${_tag}")
|
||||
file(READ "${RunCMake_TEST_BINARY_DIR}/Testing/${_date}/Test.xml" _test_contents)
|
||||
|
||||
if(NOT _test_contents MATCHES "<Value>ENV1=env1\nENV2=env2\n#CTEST_RESOURCE_GROUP_COUNT=</Value>")
|
||||
if(NOT _test_contents MATCHES "<Value>#CTEST_RESOURCE_GROUP_COUNT=\nENV1=env1\nENV2=env2</Value>")
|
||||
string(APPEND RunCMake_TEST_FAILED "Could not find expected environment variables in Test.xml")
|
||||
endif()
|
||||
if(_test_contents MATCHES "BAD_ENVIRONMENT_VARIABLE")
|
||||
|
||||
Reference in New Issue
Block a user