VojtechStep created this revision. VojtechStep added reviewers: sammccall, chandlerc, Bigcheese. VojtechStep added a project: clang-tools-extra. Herald added subscribers: cfe-commits, usaxena95, ormris, kadircet, arphaman, dexonsmith, jkorous, MaskRay, ilya-biryukov, hiraditya. Herald added a project: clang.
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. Previous discussion is here <https://github.com/clangd/clangd/issues/341> Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D78501 Files: clang-tools-extra/clangd/index/BackgroundIndexStorage.cpp llvm/include/llvm/Support/Path.h llvm/lib/Support/Unix/Path.inc llvm/lib/Support/Windows/Path.inc llvm/unittests/Support/Path.cpp
Index: llvm/unittests/Support/Path.cpp =================================================================== --- llvm/unittests/Support/Path.cpp +++ llvm/unittests/Support/Path.cpp @@ -358,6 +358,136 @@ } #endif +TEST(Support, CacheDirectoryWithEnv) { + + std::string expected; + + // The value of the environment variable is set to a non-standard + // location for the test, so we have to store the original value + // even if it's not set. + // Use an std::string to copy the data + +#ifdef _WIN32 + std::wstring OriginalStorage; + if (wchar_t const *path = ::_wgetenv(L"XDG_CACHE_HOME")) { + OriginalStorage = path; + } + + ::_wputenv("XDG_CACHE_HOME", L"C:\\xdg\\cache"); + + if (wchar_t const *localAppData = ::_wgetenv(L"LOCALAPPDATA")) { + auto pathLen = ::wcslen(path); + ArrayRef<char> ref{reinterpret_cast<char const *>(path), + pathLen * sizeof(wchar_t)}; + convertUTF16ToUTF8String(ref, expected); + } + + // LocalAppData should always be set, but better safe than sorry + if (!expected.empty()) { + SmallString<128> CacheDir; + auto status = path::cache_directory(CacheDir); + EXPECT_TRUE(status); + EXPECT_EQ(expected, CacheDir); + } + + if (!OriginalStorage.empty()) { + ::_wputenv("XDG_CACHE_HOME", OriginalStorage.c_str()); + } else { + ::_wputenv("XDG_CACHE_HOME", nullptr); + } +#else + std::string OriginalStorage; + if (char const *path = ::getenv("XDG_CACHE_HOME")) { + OriginalStorage = path; + } + + expected = "/xdg/cache"; + ::setenv("XDG_CACHE_HOME", expected.c_str(), 1); + EXPECT_EQ(expected, std::string(::getenv("XDG_CACHE_HOME"))); + + { + SmallString<128> CacheDir; + auto status = path::cache_directory(CacheDir); + EXPECT_TRUE(status); + EXPECT_EQ(expected, CacheDir); + } + + if (!OriginalStorage.empty()) { + ::setenv("XDG_CACHE_HOME", OriginalStorage.c_str(), 1); + } else { + ::unsetenv("XDG_CACHE_HOME"); + } +#endif +} + +TEST(Support, CacheDirectoryNoEnv) { + std::string expected; +#ifdef _WIN32 + std::wstring OriginalStorage; + if (wchar_t const *path = ::_wgetenv(L"XDG_CACHE_HOME")) { + OriginalStorage = path; + } + + ::_wputenv("XDG_CACHE_HOME", nullptr); + EXPECT_EQ(nullptr, ::_wgetenv("XDG_CACHE_HOME")); + + if (wchar_t const *localAppData = ::_wgetenv(L"LOCALAPPDATA")) { + auto pathLen = ::wcslen(path); + ArrayRef<char> ref{reinterpret_cast<char const *>(path), + pathLen * sizeof(wchar_t)}; + convertUTF16ToUTF8String(ref, expected); + } + + // LocalAppData should always be set, but better safe than sorry + if (!expected.empty()) { + SmallString<128> CacheDir; + auto status = path::cache_directory(CacheDir); + EXPECT_TRUE(status); + EXPECT_EQ(expected, CacheDir); + } + + if (!OriginalStorage.empty()) { + ::_wputenv("XDG_CACHE_HOME", OriginalStorage.c_str()); + } else { + ::_wputenv("XDG_CACHE_HOME", nullptr); + } +#else + std::string OriginalStorage; + if (char const *path = ::getenv("XDG_CACHE_HOME")) { + OriginalStorage = path; + } + + ::unsetenv("XDG_CACHE_HOME"); + EXPECT_EQ(nullptr, ::getenv("XDG_CACHE_HOME")); + + SmallString<128> HomeDir; + if (path::home_directory(HomeDir)) { + path::append(HomeDir, ".cache"); + expected = std::string(HomeDir.str()); + } + + if (!expected.empty()) { + SmallString<128> CacheDir; + auto status = path::cache_directory(CacheDir); + EXPECT_TRUE(status); + EXPECT_EQ(expected, CacheDir); + } + + { + SmallString<128> CacheDir; + auto status = path::cache_directory(CacheDir); + EXPECT_TRUE(status); + EXPECT_EQ(expected, CacheDir); + } + + if (!OriginalStorage.empty()) { + ::setenv("XDG_CACHE_HOME", OriginalStorage.c_str(), 1); + } else { + ::unsetenv("XDG_CACHE_HOME"); + } +#endif +} + TEST(Support, TempDirectory) { SmallString<32> TempDir; path::system_temp_directory(false, TempDir); Index: llvm/lib/Support/Windows/Path.inc =================================================================== --- llvm/lib/Support/Windows/Path.inc +++ llvm/lib/Support/Windows/Path.inc @@ -1372,6 +1372,10 @@ 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; Index: llvm/lib/Support/Unix/Path.inc =================================================================== --- llvm/lib/Support/Unix/Path.inc +++ llvm/lib/Support/Unix/Path.inc @@ -1138,6 +1138,20 @@ return true; } +bool cache_directory(SmallVectorImpl<char> &result) { + char *RequestedDir = getenv("XDG_CACHE_HOME"); + if (RequestedDir) { + 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. Index: llvm/include/llvm/Support/Path.h =================================================================== --- llvm/include/llvm/Support/Path.h +++ llvm/include/llvm/Support/Path.h @@ -368,6 +368,13 @@ /// @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. +/// +/// @param result Holds the resulting path name. +/// @result True if the appropriate directory was found. +bool cache_directory(SmallVectorImpl<char> &result); + /// Has root name? /// /// root_name != "" Index: clang-tools-extra/clangd/index/BackgroundIndexStorage.cpp =================================================================== --- clang-tools-extra/clangd/index/BackgroundIndexStorage.cpp +++ clang-tools-extra/clangd/index/BackgroundIndexStorage.cpp @@ -106,15 +106,15 @@ std::function<llvm::Optional<ProjectInfo>(PathRef)> GetProjectInfo) : IndexStorageMapMu(std::make_unique<std::mutex>()), GetProjectInfo(std::move(GetProjectInfo)) { - llvm::SmallString<128> HomeDir; - llvm::sys::path::home_directory(HomeDir); - this->HomeDir = HomeDir.str().str(); + llvm::SmallString<128> CacheDir; + llvm::sys::path::cache_directory(CacheDir); + this->CacheDir = CacheDir.str().str(); } // Creates or fetches to storage from cache for the specified project. BackgroundIndexStorage *operator()(PathRef File) { std::lock_guard<std::mutex> Lock(*IndexStorageMapMu); - Path CDBDirectory = HomeDir; + Path CDBDirectory = CacheDir; if (auto PI = GetProjectInfo(File)) CDBDirectory = PI->SourceRoot; auto &IndexStorage = IndexStorageMap[CDBDirectory]; @@ -132,7 +132,7 @@ return std::make_unique<DiskBackedIndexStorage>(CDBDirectory); } - Path HomeDir; + Path CacheDir; llvm::StringMap<std::unique_ptr<BackgroundIndexStorage>> IndexStorageMap; std::unique_ptr<std::mutex> IndexStorageMapMu;
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits