cmEnvironment: Add class for environment modification

This commit is contained in:
Daniel Pfeifer
2026-03-08 21:58:43 +01:00
parent a5d0e0fb69
commit 31040ff609
2 changed files with 158 additions and 0 deletions

View File

@@ -2,12 +2,16 @@
file LICENSE.rst or https://cmake.org/licensing for details. */
#include "cmEnvironment.h"
#include <set>
#include <utility>
#include <cm/string_view>
#include <cm/vector>
#include <cmext/algorithm>
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
#if defined(_WIN32)
# include "cmsys/String.h"
#endif
@@ -64,3 +68,138 @@ std::vector<std::string> cmEnvironment::GetVariables() const
}
return result;
}
namespace {
auto const ValidOperators = std::set<cm::string_view>{
"set",
"unset",
"string_append",
"string_prepend",
"path_list_append",
"path_list_prepend",
"cmake_list_append",
"cmake_list_prepend",
};
struct ListAppend
{
public:
ListAppend(std::string val, char sep)
: value(std::move(val))
, separator(sep)
{
}
void operator()(std::string& output) const
{
if (!output.empty()) {
output += separator;
}
output += value;
}
private:
std::string value;
char separator;
};
struct ListPrepend
{
public:
ListPrepend(std::string val, char sep)
: value(std::move(val))
, separator(sep)
{
}
void operator()(std::string& output) const
{
if (!output.empty()) {
output.insert(output.begin(), separator);
}
output.insert(0, value);
}
private:
std::string value;
char separator;
};
} // namespace
bool cmEnvironmentModification::Add(std::vector<std::string> const& envmod)
{
bool ok = true;
for (auto const& entry : envmod) {
ok &= this->Add(entry);
}
return ok;
}
bool cmEnvironmentModification::Add(std::string const& envmod)
{
// Split on `=`
auto const eq_loc = envmod.find_first_of('=');
if (eq_loc == std::string::npos) {
cmSystemTools::Error(cmStrCat(
"Error: Missing `=` after the variable name in: ", envmod, '\n'));
return false;
}
// Split operation 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) {
cmSystemTools::Error(
cmStrCat("Error: Missing `:` after the operation in: ", envmod, '\n'));
return false;
}
auto entry = Entry{};
entry.Name = envmod.substr(0, eq_loc);
entry.Op = envmod.substr(op_value_start, colon_loc - op_value_start);
entry.Value = envmod.substr(colon_loc + 1);
if (entry.Op == "reset") {
cm::erase_if(this->Entries,
[&entry](Entry const& e) { return e.Name == entry.Name; });
return true;
}
if (!cm::contains(ValidOperators, entry.Op)) {
cmSystemTools::Error(cmStrCat(
"Error: Unrecognized environment manipulation argument: ", entry.Op,
'\n'));
return false;
}
this->Entries.push_back(std::move(entry));
return true;
}
void cmEnvironmentModification::ApplyTo(cmEnvironment& env)
{
char const path_sep = cmSystemTools::GetSystemPathlistSeparator();
for (auto const& e : this->Entries) {
if (e.Op == "set") {
env.PutEnv(e.Name + "=" + e.Value);
} else if (e.Op == "unset") {
env.UnPutEnv(e.Name);
} else if (e.Op == "string_append") {
env.Modify(e.Name, [&e](std::string& output) { output += e.Value; });
} else if (e.Op == "string_prepend") {
env.Modify(e.Name,
[&e](std::string& output) { output.insert(0, e.Value); });
} else if (e.Op == "path_list_append") {
env.Modify(e.Name, ListAppend(e.Value, path_sep));
} else if (e.Op == "path_list_prepend") {
env.Modify(e.Name, ListPrepend(e.Value, path_sep));
} else if (e.Op == "cmake_list_append") {
env.Modify(e.Name, ListAppend(e.Value, ';'));
} else if (e.Op == "cmake_list_prepend") {
env.Modify(e.Name, ListPrepend(e.Value, ';'));
}
}
}

View File

@@ -53,3 +53,22 @@ protected:
};
std::map<std::string, cm::optional<std::string>, EnvNameLess> Map;
};
class cmEnvironmentModification
{
public:
bool Add(std::string const& envmod);
bool Add(std::vector<std::string> const& envmod);
void ApplyTo(cmEnvironment& env);
private:
struct Entry
{
std::string Name;
std::string Value;
std::string Op;
};
std::vector<Entry> Entries;
};