1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2025-01-31 20:51:52 +01:00

Add a facility to get system cache directory and use it in clangd

Summary:
This patch adds a function that is similar to `llvm::sys::path::home_directory`, but provides access to the system cache directory.

For Windows, that is %LOCALAPPDATA%, and applications should put their files under %LOCALAPPDATA%\Organization\Product\.

For *nixes, it adheres to the XDG Base Directory Specification, so it first looks at the XDG_CACHE_HOME environment variable and falls back to ~/.cache/.

Subsequently, the Clangd Index storage leverages this new API to put index files somewhere else than the users home directory.

Fixes https://github.com/clangd/clangd/issues/341

Reviewers: sammccall, chandlerc, Bigcheese

Reviewed By: sammccall

Subscribers: hiraditya, ilya-biryukov, MaskRay, jkorous, dexonsmith, arphaman, kadircet, ormris, usaxena95, cfe-commits, llvm-commits

Tags: #clang-tools-extra, #clang, #llvm

Differential Revision: https://reviews.llvm.org/D78501
This commit is contained in:
Vojtěch Štěpančík 2020-04-28 22:03:30 +02:00 committed by Sam McCall
parent ee9dafae48
commit 8c739867e7
4 changed files with 92 additions and 19 deletions

View File

@ -368,6 +368,13 @@ void system_temp_directory(bool erasedOnReboot, SmallVectorImpl<char> &result);
/// @result True if a home directory is set, false otherwise.
bool home_directory(SmallVectorImpl<char> &result);
/// Get the directory where installed packages should put their
/// machine-local cache, e.g. $XDG_CACHE_HOME.
///
/// @param result Holds the resulting path name.
/// @result True if the appropriate path was determined, it need not exist.
bool cache_directory(SmallVectorImpl<char> &result);
/// Has root name?
///
/// root_name != ""

View File

@ -1138,6 +1138,19 @@ bool home_directory(SmallVectorImpl<char> &result) {
return true;
}
bool cache_directory(SmallVectorImpl<char> &result) {
if (const char *RequestedDir = getenv("XDG_CACHE_HOME")) {
result.clear();
result.append(RequestedDir, RequestedDir + strlen(RequestedDir));
return true;
}
if (!home_directory(result)) {
return false;
}
append(result, ".cache");
return true;
}
static bool getDarwinConfDir(bool TempDir, SmallVectorImpl<char> &Result) {
#if defined(_CS_DARWIN_USER_TEMP_DIR) && defined(_CS_DARWIN_USER_CACHE_DIR)
// On Darwin, use DARWIN_USER_TEMP_DIR or DARWIN_USER_CACHE_DIR.

View File

@ -1372,6 +1372,10 @@ bool home_directory(SmallVectorImpl<char> &result) {
return getKnownFolderPath(FOLDERID_Profile, result);
}
bool cache_directory(SmallVectorImpl<char> &result) {
return getKnownFolderPath(FOLDERID_LocalAppData, result);
}
static bool getTempDirEnvVar(const wchar_t *Var, SmallVectorImpl<char> &Res) {
SmallVector<wchar_t, 1024> Buf;
size_t Size = 1024;

View File

@ -13,6 +13,7 @@
#include "llvm/ADT/Triple.h"
#include "llvm/BinaryFormat/Magic.h"
#include "llvm/Config/llvm-config.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/Errc.h"
#include "llvm/Support/ErrorHandling.h"
@ -305,15 +306,46 @@ TEST(Support, AbsolutePathIteratorEnd) {
}
}
TEST(Support, HomeDirectory) {
std::string expected;
#ifdef _WIN32
if (wchar_t const *path = ::_wgetenv(L"USERPROFILE")) {
std::string getEnvWin(const wchar_t *Var) {
std::string expected;
if (wchar_t const *path = ::_wgetenv(Var)) {
auto pathLen = ::wcslen(path);
ArrayRef<char> ref{reinterpret_cast<char const *>(path),
pathLen * sizeof(wchar_t)};
convertUTF16ToUTF8String(ref, expected);
}
return expected;
}
#else
// RAII helper to set and restore an environment variable.
class WithEnv {
const char *Var;
llvm::Optional<std::string> OriginalValue;
public:
WithEnv(const char *Var, const char *Value) : Var(Var) {
if (const char *V = ::getenv(Var))
OriginalValue.emplace(V);
if (Value)
::setenv(Var, Value, 1);
else
::unsetenv(Var);
set(Value);
}
~WithEnv() {
if (OriginalValue)
::setenv(Var, OriginalValue->c_str(), 1);
else
::unsetenv(Var);
}
};
#endif
TEST(Support, HomeDirectory) {
std::string expected;
#ifdef _WIN32
expected = getEnvWin(L"USERPROFILE");
#else
if (char const *path = ::getenv("HOME"))
expected = path;
@ -330,31 +362,48 @@ TEST(Support, HomeDirectory) {
#ifdef LLVM_ON_UNIX
TEST(Support, HomeDirectoryWithNoEnv) {
std::string OriginalStorage;
char const *OriginalEnv = ::getenv("HOME");
if (OriginalEnv) {
// We're going to unset it, so make a copy and save a pointer to the copy
// so that we can reset it at the end of the test.
OriginalStorage = OriginalEnv;
OriginalEnv = OriginalStorage.c_str();
}
WithEnv Env("HOME", nullptr);
// Don't run the test if we have nothing to compare against.
struct passwd *pw = getpwuid(getuid());
if (!pw || !pw->pw_dir) return;
::unsetenv("HOME");
EXPECT_EQ(nullptr, ::getenv("HOME"));
std::string PwDir = pw->pw_dir;
SmallString<128> HomeDir;
auto status = path::home_directory(HomeDir);
EXPECT_TRUE(status);
EXPECT_TRUE(path::home_directory(HomeDir));
EXPECT_EQ(PwDir, HomeDir);
}
// Now put the environment back to its original state (meaning that if it was
// unset before, we don't reset it).
if (OriginalEnv) ::setenv("HOME", OriginalEnv, 1);
TEST(Support, CacheDirectoryWithEnv) {
WithEnv Env("XDG_CACHE_HOME", "/xdg/cache");
SmallString<128> CacheDir;
EXPECT_TRUE(path::cache_directory(CacheDir));
EXPECT_EQ("/xdg/cache", CacheDir);
}
TEST(Support, CacheDirectoryNoEnv) {
WithEnv Env("XDG_CACHE_HOME", nullptr);
SmallString<128> Fallback;
ASSERT_TRUE(path::home_directory(Fallback));
path::append(Fallback, ".cache");
SmallString<128> CacheDir;
EXPECT_TRUE(path::cache_directory(CacheDir));
EXPECT_EQ(Fallback, CacheDir);
}
#endif
#ifdef _WIN32
TEST(Support, CacheDirectory) {
std::string Expected = getEnvWin(L"LOCALAPPDATA");
// Do not try to test it if we don't know what to expect.
if (!Expected.empty()) {
SmallString<128> CacheDir;
EXPECT_TRUE(path::cache_directory(CacheDir));
EXPECT_EQ(Expected, CacheDir);
}
}
#endif