refactor: use RAII for env vars in hooks

1. Replaces the custom `EnvVarGuard` class with the
`command::EnvironmentVariableGuard` class, which is a RAII wrapper for
setting and unsetting environment variables.
2. Changes the `envVarGuards` vector from holding
instances of `EnvVarGuard` to holding `unique_ptr`s to
`command::EnvironmentVariableGuard`. This ensures that the environment
variables are properly cleaned up when the vector goes out of scope,
even if exceptions are thrown.
3. Marks the `stringEqual` and `splitString` functions as inline to
potentially improve performance by allowing the compiler to inline these
functions.

Influence:
1. Verify hook scripts that rely on environment variables are still
functioning correctly after the change.
2. Confirm that environment variables set by hook scripts are properly
cleaned up after the script execution, even in cases where the script
throws an exception.

重构: 在hooks中使用RAII管理环境变量

1. 将自定义的 `EnvVarGuard` 类替换为 `command::EnvironmentVariableGuard`
类,后者是一个 RAII 包装器,用于设置和取消设置环境变量。
2. 将 `envVarGuards` 向量从保存 `EnvVarGuard` 的实例更改为保存指向
`command::EnvironmentVariableGuard` 的 `unique_ptr`。 这确保了即使抛出异
常,环境变量在向量超出范围时也能正确清理。
3. 将 `stringEqual` 和 `splitString` 函数标记为内联,以通过允许编译器内
联这些函数来潜在地提高性能。

Influence:
1. 验证在更改后,依赖环境变量的 hook 脚本仍然可以正常运行。
2. 确认 hook 脚本设置的环境变量在脚本执行后能够正确清理,即使在脚本抛出
异常的情况下。
This commit is contained in:
dengbo 2025-09-04 19:08:19 +08:00 committed by reddevillg
parent d6e0931419
commit 6992340ffc
2 changed files with 5 additions and 62 deletions

View File

@ -8,14 +8,13 @@
#include "configure.h"
#include "linglong/utils/error/error.h"
#include "linglong/utils/command/env.h"
#include <array>
#include <cstdlib>
#include <cstring>
#include <filesystem>
#include <fstream>
#include <functional>
#include <limits>
#include <sstream>
#include <vector>
@ -29,62 +28,6 @@ static const std::string PRE_INSTALL_ACTION_PREFIX = "ll-pre-install=";
static const std::string POST_INSTALL_ACTION_PREFIX = "ll-post-install=";
static const std::string POST_UNINSTALL_ACTION_PREFIX = "ll-post-uninstall=";
// Ensures variables are cleaned up even on early returns or exceptions.
class EnvVarGuard
{
public:
EnvVarGuard(const std::string &name, const std::string &value)
: name(name)
, setOK(false)
{
if (setenv(name.c_str(), value.c_str(), 1) == 0) {
setOK = true;
} else {
qWarning() << "Failed to set environment variable" << name.c_str() << ":" << errno;
}
}
EnvVarGuard(const EnvVarGuard &) = delete;
EnvVarGuard &operator=(const EnvVarGuard &) = delete;
EnvVarGuard(EnvVarGuard &&other) noexcept
: name(std::move(other.name))
, setOK(other.setOK)
{
other.setOK = false;
}
EnvVarGuard &operator=(EnvVarGuard &&other) noexcept
{
if (this != &other) {
if (setOK && ::getenv(name.c_str()) != nullptr) {
if (unsetenv(name.c_str()) != 0) {
qWarning() << "Failed to unset old environment variable" << name.c_str() << ":"
<< errno;
}
}
name = std::move(other.name);
setOK = other.setOK;
other.setOK = false;
}
return *this;
}
~EnvVarGuard()
{
if (setOK && ::getenv(name.c_str()) != nullptr) {
if (unsetenv(name.c_str()) != 0) {
qWarning() << "Failed to unset environment variable" << name.c_str() << ":"
<< errno;
}
}
}
private:
std::string name; // Name of the environment variable
bool setOK;
};
// This function ensures the command string is safely wrapped for 'sh -c'.
static std::string escapeAndWrapCommandForShell(const std::string &command)
{
@ -106,10 +49,10 @@ utils::error::Result<void> executeHookCommands(
{
LINGLONG_TRACE("Executing command");
std::vector<EnvVarGuard> envVarGuards;
std::vector<std::unique_ptr<command::EnvironmentVariableGuard>> envVarGuards;
envVarGuards.reserve(envVars.size());
for (const auto &pair : envVars) {
envVarGuards.emplace_back(pair.first, pair.second);
envVarGuards.emplace_back(std::make_unique<command::EnvironmentVariableGuard>(pair.first, pair.second));
}
for (const auto &command_raw : commands) {

View File

@ -11,7 +11,7 @@
namespace linglong::utils {
bool stringEqual(std::string_view str1, std::string_view str2, bool caseSensitive = false)
inline bool stringEqual(std::string_view str1, std::string_view str2, bool caseSensitive = false)
{
if (caseSensitive) {
return str1 == str2;
@ -22,7 +22,7 @@ bool stringEqual(std::string_view str1, std::string_view str2, bool caseSensitiv
});
}
std::vector<std::string> splitString(std::string_view str, char delimiter)
inline std::vector<std::string> splitString(std::string_view str, char delimiter)
{
std::vector<std::string> result;
std::string token;