diff options
author | Alex Reinking <alex.reinking@gmail.com> | 2022-08-14 06:28:24 (GMT) |
---|---|---|
committer | Brad King <brad.king@kitware.com> | 2022-08-15 18:11:47 (GMT) |
commit | bfa1c5285b0db8f7dfe8e7c5ac546312723f59db (patch) | |
tree | 86c2c1d1c7d4139910a71db9b163aa06bd20caa8 /Source/cmSystemTools.cxx | |
parent | a0b1c4ee907ee135fdb5727084fc90a07f525470 (diff) | |
download | CMake-bfa1c5285b0db8f7dfe8e7c5ac546312723f59db.zip CMake-bfa1c5285b0db8f7dfe8e7c5ac546312723f59db.tar.gz CMake-bfa1c5285b0db8f7dfe8e7c5ac546312723f59db.tar.bz2 |
cmSystemTools: Add EnvDiff class to hold ENVIRONMENT_MODIFICATION logic
Prepare to re-use this logic when enhancing `cmake -E env`.
Diffstat (limited to 'Source/cmSystemTools.cxx')
-rw-r--r-- | Source/cmSystemTools.cxx | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index 672cdc7..c35c1e7 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -16,6 +16,7 @@ #include <cm/optional> #include <cmext/algorithm> +#include <cmext/string_view> #include <cm3p/uv.h> @@ -1563,6 +1564,126 @@ void cmSystemTools::AppendEnv(std::vector<std::string> const& env) } } +bool cmSystemTools::EnvDiff::ParseOperation(const std::string& envmod) +{ + char path_sep = GetSystemPathlistSeparator(); + + auto apply_diff = [this](const std::string& name, + std::function<void(std::string&)> const& apply) { + cm::optional<std::string> old_value = diff[name]; + std::string output; + if (old_value) { + output = *old_value; + } else { + // This only works because the environment is actually modified when + // processing the ENVIRONMENT property in CTest and cmake -E env + // (`AppendEnv`). If either one ever just creates an environment block + // directly, that block will need to be queried for the subprocess' + // value instead. + const char* curval = cmSystemTools::GetEnv(name); + if (curval) { + output = curval; + } + } + apply(output); + diff[name] = output; + }; + + // 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; + } + + 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) { + cmSystemTools::Error( + cmStrCat("Error: Missing `:` after the operation in: ", envmod, '\n')); + return false; + } + 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 = diff.find(name); + if (entry != diff.end()) { + diff.erase(entry); + } + } else if (op == "set"_s) { + diff[name] = value; + } else if (op == "unset"_s) { + diff[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 { + cmSystemTools::Error(cmStrCat( + "Error: Unrecognized environment manipulation argument: ", op, '\n')); + return false; + } + + return true; +} + +void cmSystemTools::EnvDiff::ApplyToCurrentEnv(std::ostringstream* measurement) +{ + for (auto const& env_apply : diff) { + if (env_apply.second) { + auto const env_update = + cmStrCat(env_apply.first, '=', *env_apply.second); + cmSystemTools::PutEnv(env_update); + if (measurement) { + *measurement << env_update << std::endl; + } + } else { + cmSystemTools::UnsetEnv(env_apply.first.c_str()); + if (measurement) { + // Signify that this variable is being actively unset + *measurement << '#' << env_apply.first << "=\n"; + } + } + } +} + cmSystemTools::SaveRestoreEnvironment::SaveRestoreEnvironment() { this->Env = cmSystemTools::GetEnvironmentVariables(); |