Skip to content

Commit

Permalink
[vcpkg] Use XDG/LOCALAPPDATA for default binary caching path (#12091)
Browse files Browse the repository at this point in the history
* [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 <[email protected]>
  • Loading branch information
ras0219 and ras0219-msft authored Jun 26, 2020
1 parent 9f8cc9e commit 4c527e4
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 47 deletions.
8 changes: 7 additions & 1 deletion toolsrc/include/vcpkg/base/system.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
91 changes: 83 additions & 8 deletions toolsrc/src/vcpkg/base/system.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
auto maybe_home = System::get_environment_variable("USERPROFILE");
if (!maybe_home.has_value() || maybe_home.get()->empty())
return {"unable to read %USERPROFILE%", ExpectedRightTag{}};
#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
auto maybe_home = System::get_environment_variable("HOME");
if (!maybe_home.has_value() || maybe_home.get()->empty()) return {"unable to read $HOME", ExpectedRightTag{}};
#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
return System::get_appdata_local();
#else
return get_xdg_cache_home();
#endif
return {std::move(*maybe_home.get()), ExpectedLeftTag{}};
}

#if defined(_WIN32)
Expand Down Expand Up @@ -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)

Expand Down
5 changes: 3 additions & 2 deletions toolsrc/src/vcpkg/binarycaching.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
23 changes: 10 additions & 13 deletions toolsrc/src/vcpkg/commands.integrate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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);
}
}
Expand Down
25 changes: 2 additions & 23 deletions toolsrc/src/vcpkg/userconfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down

0 comments on commit 4c527e4

Please sign in to comment.