[vcpkg] Use XDG/LOCALAPPDATA for default binary caching path (#12091)

* [vcpkg] Use XDG Base Directory Specification on non-Windows

* [vcpkg] Move user-wide binary cache on Windows to $LOCALAPPDATA/vcpkg/archives

* [vcpkg] Address code review comments; refactor other uses of LOCALAPPDATA

* [vcpkg] Address code review comments

* [vcpkg] filesystem::path::append() accepts string arguments, not paths.

Co-authored-by: Robert Schumacher <roschuma@microsoft.com>
This commit is contained in:
ras0219 2020-06-26 11:26:38 -07:00 committed by GitHub
parent 9f8cc9ee88
commit 4c527e49c4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 105 additions and 47 deletions

View File

@ -9,7 +9,13 @@ namespace vcpkg::System
{
Optional<std::string> get_environment_variable(ZStringView varname) noexcept;
ExpectedS<std::string> get_home_dir() noexcept;
const ExpectedS<fs::path>& get_home_dir() noexcept;
const ExpectedS<fs::path>& get_platform_cache_home() noexcept;
#ifdef _WIN32
const ExpectedS<fs::path>& get_appdata_local() noexcept;
#endif
Optional<std::string> get_registry_string(void* base_hkey, StringView subkey, StringView valuename);

View File

@ -105,17 +105,92 @@ namespace vcpkg
#endif // defined(_WIN32)
}
ExpectedS<std::string> System::get_home_dir() noexcept
const ExpectedS<fs::path>& System::get_home_dir() noexcept
{
static ExpectedS<fs::path> s_home = []() -> ExpectedS<fs::path> {
#ifdef _WIN32
#define HOMEVAR "%USERPROFILE%"
auto maybe_home = System::get_environment_variable("USERPROFILE");
if (!maybe_home.has_value() || maybe_home.get()->empty())
return {"unable to read " HOMEVAR, ExpectedRightTag{}};
#else
#define HOMEVAR "$HOME"
auto maybe_home = System::get_environment_variable("HOME");
if (!maybe_home.has_value() || maybe_home.get()->empty())
return {"unable to read " HOMEVAR, ExpectedRightTag{}};
#endif
auto p = fs::u8path(*maybe_home.get());
if (!p.is_absolute()) return {HOMEVAR " was not an absolute path", ExpectedRightTag{}};
return {std::move(p), ExpectedLeftTag{}};
}();
return s_home;
#undef HOMEVAR
}
#ifdef _WIN32
const ExpectedS<fs::path>& System::get_appdata_local() noexcept
{
static ExpectedS<fs::path> s_home = []() -> ExpectedS<fs::path> {
auto maybe_home = System::get_environment_variable("LOCALAPPDATA");
if (!maybe_home.has_value() || maybe_home.get()->empty())
return {"unable to read %LOCALAPPDATA%", ExpectedRightTag{}};
auto p = fs::u8path(*maybe_home.get());
if (!p.is_absolute()) return {"%LOCALAPPDATA% was not an absolute path", ExpectedRightTag{}};
return {std::move(p), ExpectedLeftTag{}};
}();
return s_home;
}
#else
static const ExpectedS<fs::path>& get_xdg_config_home() noexcept
{
static ExpectedS<fs::path> s_home = [] {
auto maybe_home = System::get_environment_variable("XDG_CONFIG_HOME");
if (auto p = maybe_home.get())
{
return ExpectedS<fs::path>(fs::u8path(*p));
}
else
{
return System::get_home_dir().map([](fs::path home) {
home /= fs::u8path(".config");
return home;
});
}
}();
return s_home;
}
static const ExpectedS<fs::path>& get_xdg_cache_home() noexcept
{
static ExpectedS<fs::path> s_home = [] {
auto maybe_home = System::get_environment_variable("XDG_CACHE_HOME");
if (auto p = maybe_home.get())
{
return ExpectedS<fs::path>(fs::u8path(*p));
}
else
{
return System::get_home_dir().map([](fs::path home) {
home /= fs::u8path(".cache");
return home;
});
}
}();
return s_home;
}
#endif
const ExpectedS<fs::path>& System::get_platform_cache_home() noexcept
{
#ifdef _WIN32
auto maybe_home = System::get_environment_variable("USERPROFILE");
if (!maybe_home.has_value() || maybe_home.get()->empty())
return {"unable to read %USERPROFILE%", ExpectedRightTag{}};
return System::get_appdata_local();
#else
auto maybe_home = System::get_environment_variable("HOME");
if (!maybe_home.has_value() || maybe_home.get()->empty()) return {"unable to read $HOME", ExpectedRightTag{}};
return get_xdg_cache_home();
#endif
return {std::move(*maybe_home.get()), ExpectedLeftTag{}};
}
#if defined(_WIN32)
@ -150,7 +225,7 @@ namespace vcpkg
ret.pop_back(); // remove extra trailing null byte
return Strings::to_utf8(ret);
}
#else // ^^^ defined(_WIN32) / !defined(_WIN32) vvv
#else // ^^^ defined(_WIN32) / !defined(_WIN32) vvv
Optional<std::string> System::get_registry_string(void*, StringView, StringView) { return nullopt; }
#endif // defined(_WIN32)

View File

@ -392,10 +392,11 @@ ExpectedS<std::unique_ptr<IBinaryProvider>> vcpkg::create_binary_provider_from_c
return add_error("unexpected arguments: binary config 'default' does not take more than 1 argument",
segments[0].first);
auto maybe_home = System::get_home_dir();
auto&& maybe_home = System::get_platform_cache_home();
if (!maybe_home.has_value()) return add_error(maybe_home.error(), segments[0].first);
auto p = fs::u8path(maybe_home.value_or_exit(VCPKG_LINE_INFO)) / fs::u8path(".vcpkg/archives");
auto p = *maybe_home.get();
p /= fs::u8path("vcpkg/archives");
if (!p.is_absolute())
return add_error("default path was not absolute: " + p.u8string(), segments[0].first);
if (segments.size() == 2)

View File

@ -155,17 +155,13 @@ namespace vcpkg::Commands::Integrate
#if defined(_WIN32)
static fs::path get_appdata_targets_path()
{
static const fs::path LOCAL_APP_DATA =
fs::u8path(System::get_environment_variable("LOCALAPPDATA").value_or_exit(VCPKG_LINE_INFO));
return LOCAL_APP_DATA / fs::u8path("vcpkg/vcpkg.user.targets");
return System::get_appdata_local().value_or_exit(VCPKG_LINE_INFO) / fs::u8path("vcpkg/vcpkg.user.targets");
}
#endif
#if defined(_WIN32)
static fs::path get_appdata_props_path()
{
static const fs::path LOCAL_APP_DATA =
fs::u8path(System::get_environment_variable("LOCALAPPDATA").value_or_exit(VCPKG_LINE_INFO));
return LOCAL_APP_DATA / "vcpkg" / "vcpkg.user.props";
return System::get_appdata_local().value_or_exit(VCPKG_LINE_INFO) / fs::u8path("vcpkg/vcpkg.user.props");
}
#endif
@ -277,19 +273,20 @@ namespace vcpkg::Commands::Integrate
const fs::path appdata_src_path2 = tmp_dir / "vcpkg.user.props";
fs.write_contents(appdata_src_path2,
create_appdata_shortcut(paths.buildsystems_msbuild_props.u8string()),
VCPKG_LINE_INFO);
VCPKG_LINE_INFO);
auto appdata_dst_path2 = get_appdata_props_path();
const auto rc2 = fs.copy_file(appdata_src_path2, appdata_dst_path2, fs::copy_options::overwrite_existing, ec);
const auto rc2 =
fs.copy_file(appdata_src_path2, appdata_dst_path2, fs::copy_options::overwrite_existing, ec);
if (!rc2 || ec)
{
System::print2(System::Color::error,
"Error: Failed to copy file: ",
appdata_src_path2.u8string(),
" -> ",
appdata_dst_path2.u8string(),
"\n");
"Error: Failed to copy file: ",
appdata_src_path2.u8string(),
" -> ",
appdata_dst_path2.u8string(),
"\n");
Checks::exit_fail(VCPKG_LINE_INFO);
}
}

View File

@ -4,35 +4,14 @@
#include <vcpkg/base/lazy.h>
#include <vcpkg/paragraphs.h>
#include <vcpkg/userconfig.h>
#if defined(_WIN32)
namespace
{
static vcpkg::Lazy<fs::path> s_localappdata;
static const fs::path& get_localappdata()
{
return s_localappdata.get_lazy([]() {
fs::path localappdata;
{
// Config path in AppDataLocal
wchar_t* localappdatapath = nullptr;
if (S_OK != SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, nullptr, &localappdatapath)) __fastfail(1);
localappdata = localappdatapath;
CoTaskMemFree(localappdatapath);
}
return localappdata;
});
}
}
#endif
#include <vcpkg/base/system.h>
namespace vcpkg
{
fs::path get_user_dir()
{
#if defined(_WIN32)
return get_localappdata() / "vcpkg";
return System::get_appdata_local().value_or_exit(VCPKG_LINE_INFO) / "vcpkg";
#else
auto maybe_home = System::get_environment_variable("HOME");
return fs::path(maybe_home.value_or("/var")) / ".vcpkg";