#include <core/wincompat.hpp>
#include <fmtmacros.hpp>
#include <util/Tokenizer.hpp>
+#include <util/environment.hpp>
#include <util/expected.hpp>
#include <util/file.hpp>
#include <util/path.hpp>
return;
}
- std::string value = Util::expand_environment_variables(unexpanded_value);
+ std::string value = util::expand_environment_variables(unexpanded_value);
switch (it->second.item) {
case ConfigItem::absolute_paths_in_stderr:
}
}
-std::string
-expand_environment_variables(const std::string& str)
-{
- std::string result;
- const char* left = str.c_str();
- const char* right = left;
-
- while (*right) {
- if (*right == '$') {
- result.append(left, right - left);
-
- if (*(right + 1) == '$') {
- result += '$';
- right += 2;
- left = right;
- continue;
- }
-
- left = right + 1;
- bool curly = *left == '{';
- if (curly) {
- ++left;
- }
- right = left;
- while (isalnum(*right) || *right == '_') {
- ++right;
- }
- if (curly && *right != '}') {
- throw core::Error(FMT("syntax error: missing '}}' after \"{}\"", left));
- }
- if (right == left) {
- // Special case: don't consider a single $ the left of a variable.
- result += '$';
- --right;
- } else {
- std::string name(left, right - left);
- const char* value = getenv(name.c_str());
- if (!value) {
- throw core::Error(FMT("environment variable \"{}\" not set", name));
- }
- result += value;
- if (!curly) {
- --right;
- }
- left = right + 1;
- }
- }
- ++right;
- }
-
- result += left;
- return result;
-}
-
int
fallocate(int fd, long new_size)
{
return umask(mask);
}
-void
-setenv(const std::string& name, const std::string& value)
-{
-#ifdef HAVE_SETENV
- ::setenv(name.c_str(), value.c_str(), true);
-#else
- char* string;
- asprintf(&string, "%s=%s", name.c_str(), value.c_str());
- putenv(string); // Leak to environment.
-#endif
-}
-
std::vector<std::string_view>
split_into_views(std::string_view string,
const char* separators,
return success;
}
-void
-unsetenv(const std::string& name)
-{
-#ifdef HAVE_UNSETENV
- ::unsetenv(name.c_str());
-#elif defined(_WIN32)
- SetEnvironmentVariable(name.c_str(), NULL);
-#else
- putenv(strdup(name.c_str())); // Leak to environment.
-#endif
-}
-
void
wipe_path(const std::string& path)
{
// Like create_dir but throws Fatal on error.
void ensure_dir_exists(std::string_view dir);
-// Expand all instances of $VAR or ${VAR}, where VAR is an environment variable,
-// in `str`. Throws `core::Error` if one of the environment variables.
-[[nodiscard]] std::string expand_environment_variables(const std::string& str);
-
// Extends file size to at least new_size by calling posix_fallocate() if
// supported, otherwise by writing zeros last to the file.
//
// Set process umask. Returns the previous mask.
mode_t set_umask(mode_t mask);
-// Set environment variable `name` to `value`.
-void setenv(const std::string& name, const std::string& value);
-
// Return size change in KiB between `old_stat` and `new_stat`.
inline int64_t
size_change_kibibyte(const Stat& old_stat, const Stat& new_stat)
bool unlink_tmp(const std::string& path,
UnlinkLog unlink_log = UnlinkLog::log_failure);
-// Unset environment variable `name`.
-void unsetenv(const std::string& name);
-
// Remove `path` (and its contents if it's a directory). A nonexistent path is
// not considered an error.
//
#include <core/types.hpp>
#include <core/wincompat.hpp>
#include <storage/Storage.hpp>
+#include <util/environment.hpp>
#include <util/expected.hpp>
#include <util/file.hpp>
#include <util/path.hpp>
return nonstd::make_unexpected(Statistic::internal_error);
}
- Util::setenv("UNCACHED_ERR_FD", FMT("{}", uncached_fd));
+ util::setenv("UNCACHED_ERR_FD", FMT("{}", uncached_fd));
return {};
}
// calling ccache second time. For instance, if the real compiler is a wrapper
// script that calls "ccache $compiler ..." we want that inner ccache call to
// be disabled.
- Util::setenv("CCACHE_DISABLE", "1");
+ util::setenv("CCACHE_DISABLE", "1");
MTR_BEGIN("main", "process_args");
ProcessArgsResult processed = process_args(ctx);
// VS_UNICODE_OUTPUT prevents capturing stdout/stderr, as the output is sent
// directly to Visual Studio.
if (ctx.config.compiler_type() == CompilerType::msvc) {
- Util::unsetenv("VS_UNICODE_OUTPUT");
+ util::unsetenv("VS_UNICODE_OUTPUT");
}
for (const auto& name : {"DEPENDENCIES_OUTPUT", "SUNPRO_DEPENDENCIES"}) {
#include <storage/local/LocalStorage.hpp>
#include <util/TextTable.hpp>
#include <util/XXH3_128.hpp>
+#include <util/environment.hpp>
#include <util/expected.hpp>
#include <util/file.hpp>
#include <util/string.hpp>
switch (c) {
case 'd': // --dir
- Util::setenv("CCACHE_DIR", arg);
+ util::setenv("CCACHE_DIR", arg);
break;
case CONFIG_PATH:
- Util::setenv("CCACHE_CONFIGPATH", arg);
+ util::setenv("CCACHE_CONFIGPATH", arg);
break;
case RECOMPRESS_THREADS:
TextTable.cpp
TimePoint.cpp
Tokenizer.cpp
+ environment.cpp
file.cpp
path.cpp
string.cpp
--- /dev/null
+// Copyright (C) 2023 Joel Rosdahl and other contributors
+//
+// See doc/AUTHORS.adoc for a complete list of contributors.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include "environment.hpp"
+
+#include <Win32Util.hpp> // for asprintf
+#include <core/exceptions.hpp>
+#include <core/wincompat.hpp>
+#include <fmtmacros.hpp>
+
+namespace util {
+
+std::string
+expand_environment_variables(const std::string& str)
+{
+ std::string result;
+ const char* left = str.c_str();
+ const char* right = left;
+
+ while (*right) {
+ if (*right == '$') {
+ result.append(left, right - left);
+
+ if (*(right + 1) == '$') {
+ result += '$';
+ right += 2;
+ left = right;
+ continue;
+ }
+
+ left = right + 1;
+ bool curly = *left == '{';
+ if (curly) {
+ ++left;
+ }
+ right = left;
+ while (isalnum(*right) || *right == '_') {
+ ++right;
+ }
+ if (curly && *right != '}') {
+ throw core::Error(FMT("syntax error: missing '}}' after \"{}\"", left));
+ }
+ if (right == left) {
+ // Special case: don't consider a single $ the left of a variable.
+ result += '$';
+ --right;
+ } else {
+ std::string name(left, right - left);
+ const char* value = getenv(name.c_str());
+ if (!value) {
+ throw core::Error(FMT("environment variable \"{}\" not set", name));
+ }
+ result += value;
+ if (!curly) {
+ --right;
+ }
+ left = right + 1;
+ }
+ }
+ ++right;
+ }
+
+ result += left;
+ return result;
+}
+
+void
+setenv(const std::string& name, const std::string& value)
+{
+#ifdef HAVE_SETENV
+ ::setenv(name.c_str(), value.c_str(), true);
+#else
+ char* string;
+ asprintf(&string, "%s=%s", name.c_str(), value.c_str());
+ putenv(string); // Leak to environment.
+#endif
+}
+
+void
+unsetenv(const std::string& name)
+{
+#ifdef HAVE_UNSETENV
+ ::unsetenv(name.c_str());
+#elif defined(_WIN32)
+ SetEnvironmentVariable(name.c_str(), NULL);
+#else
+ putenv(strdup(name.c_str())); // Leak to environment.
+#endif
+}
+
+} // namespace util
--- /dev/null
+// Copyright (C) 2023 Joel Rosdahl and other contributors
+//
+// See doc/AUTHORS.adoc for a complete list of contributors.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#pragma once
+
+#include <string>
+
+namespace util {
+
+// Expand all instances of $VAR or ${VAR}, where VAR is an environment variable,
+// in `str`. Throws `core::Error` if one of the environment variables.
+[[nodiscard]] std::string expand_environment_variables(const std::string& str);
+
+// Set environment variable `name` to `value`.
+void setenv(const std::string& name, const std::string& value);
+
+// Unset environment variable `name`.
+void unsetenv(const std::string& name);
+
+} // namespace util
test_util_XXH3_128.cpp
test_util_XXH3_64.cpp
test_util_conversion.cpp
+ test_util_environment.cpp
test_util_expected.cpp
test_util_file.cpp
test_util_path.cpp
-// Copyright (C) 2010-2020 Joel Rosdahl and other contributors
+// Copyright (C) 2010-2023 Joel Rosdahl and other contributors
//
// See doc/AUTHORS.adoc for a complete list of contributors.
//
#include "../src/fmtmacros.hpp"
#include "TestUtil.hpp"
+#include <util/environment.hpp>
+
#include "third_party/fmt/core.h"
#define DOCTEST_THREAD_LOCAL // Avoid MinGW thread_local bug
main(int argc, char** argv)
{
#ifdef _WIN32
- Util::setenv("CCACHE_DETECT_SHEBANG", "1");
+ util::setenv("CCACHE_DETECT_SHEBANG", "1");
#endif
- Util::unsetenv("GCC_COLORS"); // Don't confuse argument processing tests.
+ util::unsetenv("GCC_COLORS"); // Don't confuse argument processing tests.
std::string dir_before = Util::get_actual_cwd();
std::string testdir = FMT("testdir/{}", getpid());
#include "TestUtil.hpp"
#include <core/exceptions.hpp>
+#include <util/environment.hpp>
#include <util/file.hpp>
#include "third_party/doctest.h"
TestContext test_context;
const char user[] = "rabbit";
- Util::setenv("USER", user);
+ util::setenv("USER", user);
#ifndef _WIN32
std::string base_dir = FMT("/{0}/foo/{0}", user);
{
Config config;
- Util::setenv("CCACHE_COMPRESS", "1");
+ util::setenv("CCACHE_COMPRESS", "1");
config.update_from_environment();
CHECK(config.compression());
- Util::unsetenv("CCACHE_COMPRESS");
+ util::unsetenv("CCACHE_COMPRESS");
- Util::setenv("CCACHE_NOCOMPRESS", "1");
+ util::setenv("CCACHE_NOCOMPRESS", "1");
config.update_from_environment();
CHECK(!config.compression());
}
#include <core/exceptions.hpp>
#include <core/wincompat.hpp>
+#include <util/environment.hpp>
#include <util/file.hpp>
#include "third_party/doctest.h"
// Instead, test a well-known junction that has existed in all Windows versions
// since Vista. (Not present on Wine.)
TEST_CASE("Win32 Directory Junction"
- * doctest::skip(!win32_is_junction(Util::expand_environment_variables(
+ * doctest::skip(!win32_is_junction(util::expand_environment_variables(
"${ALLUSERSPROFILE}\\Application Data"))))
{
TestContext test_context;
SUBCASE("junction stat")
{
- auto stat = Stat::stat(Util::expand_environment_variables(
+ auto stat = Stat::stat(util::expand_environment_variables(
"${ALLUSERSPROFILE}\\Application Data"));
CHECK(stat);
CHECK(stat.error_number() == 0);
SUBCASE("junction lstat")
{
- auto stat = Stat::lstat(Util::expand_environment_variables(
+ auto stat = Stat::lstat(util::expand_environment_variables(
"${ALLUSERSPROFILE}\\Application Data"));
CHECK(stat);
CHECK(stat.error_number() == 0);
#include <core/exceptions.hpp>
#include <core/wincompat.hpp>
+#include <util/environment.hpp>
#include <util/file.hpp>
#include "third_party/doctest.h"
"Failed to create directory create/dir/file: Not a directory");
}
-TEST_CASE("Util::expand_environment_variables")
-{
- Util::setenv("FOO", "bar");
-
- CHECK(Util::expand_environment_variables("") == "");
- CHECK(Util::expand_environment_variables("$FOO") == "bar");
- CHECK(Util::expand_environment_variables("$$FOO") == "$FOO");
- CHECK(Util::expand_environment_variables("$$$FOO") == "$bar");
- CHECK(Util::expand_environment_variables("$ $$ $") == "$ $ $");
- CHECK(Util::expand_environment_variables("$FOO $FOO:$FOO") == "bar bar:bar");
- CHECK(Util::expand_environment_variables("x$FOO") == "xbar");
- CHECK(Util::expand_environment_variables("${FOO}x") == "barx");
-
- DOCTEST_GCC_SUPPRESS_WARNING_PUSH
- DOCTEST_GCC_SUPPRESS_WARNING("-Wunused-result")
- CHECK_THROWS_WITH(
- (void)Util::expand_environment_variables("$surelydoesntexist"),
- "environment variable \"surelydoesntexist\" not set");
- CHECK_THROWS_WITH((void)Util::expand_environment_variables("${FOO"),
- "syntax error: missing '}' after \"FOO\"");
- DOCTEST_GCC_SUPPRESS_WARNING_POP
-}
-
TEST_CASE("Util::fallocate")
{
TestContext test_context;
REQUIRE(symlink("d", "s") == 0);
#endif
REQUIRE(chdir("d") == 0);
- Util::setenv("PWD", apparent_cwd);
+ util::setenv("PWD", apparent_cwd);
SUBCASE("No base directory")
{
--- /dev/null
+// Copyright (C) 2023 Joel Rosdahl and other contributors
+//
+// See doc/AUTHORS.adoc for a complete list of contributors.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include <util/environment.hpp>
+
+#include <third_party/doctest.h>
+
+TEST_SUITE_BEGIN("util");
+
+TEST_CASE("util::expand_environment_variables")
+{
+ util::setenv("FOO", "bar");
+
+ CHECK(util::expand_environment_variables("") == "");
+ CHECK(util::expand_environment_variables("$FOO") == "bar");
+ CHECK(util::expand_environment_variables("$$FOO") == "$FOO");
+ CHECK(util::expand_environment_variables("$$$FOO") == "$bar");
+ CHECK(util::expand_environment_variables("$ $$ $") == "$ $ $");
+ CHECK(util::expand_environment_variables("$FOO $FOO:$FOO") == "bar bar:bar");
+ CHECK(util::expand_environment_variables("x$FOO") == "xbar");
+ CHECK(util::expand_environment_variables("${FOO}x") == "barx");
+
+ DOCTEST_GCC_SUPPRESS_WARNING_PUSH
+ DOCTEST_GCC_SUPPRESS_WARNING("-Wunused-result")
+ CHECK_THROWS_WITH(
+ (void)util::expand_environment_variables("$surelydoesntexist"),
+ "environment variable \"surelydoesntexist\" not set");
+ CHECK_THROWS_WITH((void)util::expand_environment_variables("${FOO"),
+ "syntax error: missing '}' after \"FOO\"");
+ DOCTEST_GCC_SUPPRESS_WARNING_POP
+}
+
+TEST_SUITE_END();