aboutsummaryrefslogtreecommitdiff
path: root/toolsrc/src
diff options
context:
space:
mode:
authornicole mazzuca <mazzucan@outlook.com>2021-01-14 19:50:31 -0800
committerGitHub <noreply@github.com>2021-01-14 19:50:31 -0800
commita5971344505757e4868e14d112362326610b98e5 (patch)
tree2bfe83c1ff297b4e5335ac90a11e0e9adf72e823 /toolsrc/src
parent2f6537fa2b8928d2329e827f862692112793435d (diff)
downloadvcpkg-a5971344505757e4868e14d112362326610b98e5.tar.gz
vcpkg-a5971344505757e4868e14d112362326610b98e5.zip
[vcpkg registries] Add git registries (#15054)
* [vcpkg registries] Add git registries support * Add git registries support to the registries module of vcpkg. * add e2e tests for git registries * fix vcpkg.cmake for registries * fix CRs, remove a thing * better error messages * Billy CRs * fix Robert's CR comment * I learned about `-c` today * format * fix baseline.json * failing to find baseline is technically not a bug
Diffstat (limited to 'toolsrc/src')
-rw-r--r--toolsrc/src/vcpkg/base/system.cpp9
-rw-r--r--toolsrc/src/vcpkg/install.cpp10
-rw-r--r--toolsrc/src/vcpkg/registries.cpp241
-rw-r--r--toolsrc/src/vcpkg/vcpkgpaths.cpp159
4 files changed, 401 insertions, 18 deletions
diff --git a/toolsrc/src/vcpkg/base/system.cpp b/toolsrc/src/vcpkg/base/system.cpp
index 9429752be..c400815be 100644
--- a/toolsrc/src/vcpkg/base/system.cpp
+++ b/toolsrc/src/vcpkg/base/system.cpp
@@ -10,6 +10,15 @@ using namespace vcpkg::System;
namespace vcpkg
{
+ long System::get_process_id()
+ {
+#ifdef _WIN32
+ return ::_getpid();
+#else
+ return ::getpid();
+#endif
+ }
+
Optional<CPUArchitecture> System::to_cpu_architecture(StringView arch)
{
if (Strings::case_insensitive_ascii_equals(arch, "x86")) return CPUArchitecture::X86;
diff --git a/toolsrc/src/vcpkg/install.cpp b/toolsrc/src/vcpkg/install.cpp
index 51c7b8289..80b4eae3a 100644
--- a/toolsrc/src/vcpkg/install.cpp
+++ b/toolsrc/src/vcpkg/install.cpp
@@ -1,5 +1,6 @@
#include <vcpkg/base/files.h>
#include <vcpkg/base/hash.h>
+#include <vcpkg/base/system.debug.h>
#include <vcpkg/base/system.print.h>
#include <vcpkg/base/util.h>
@@ -844,15 +845,18 @@ namespace vcpkg::Install
features.erase(core_it);
}
- if (args.versions_enabled())
+ if (args.versions_enabled() || args.registries_enabled())
{
- auto verprovider = PortFileProvider::make_versioned_portfile_provider(paths);
- auto baseprovider = PortFileProvider::make_baseline_provider(paths);
if (auto p_baseline = manifest_scf.core_paragraph->extra_info.get("$x-default-baseline"))
{
paths.get_configuration().registry_set.experimental_set_builtin_registry_baseline(
p_baseline->string());
}
+ }
+ if (args.versions_enabled())
+ {
+ auto verprovider = PortFileProvider::make_versioned_portfile_provider(paths);
+ auto baseprovider = PortFileProvider::make_baseline_provider(paths);
auto oprovider = PortFileProvider::make_overlay_provider(paths, args.overlay_ports);
auto install_plan =
diff --git a/toolsrc/src/vcpkg/registries.cpp b/toolsrc/src/vcpkg/registries.cpp
index 7f84b5075..b9afa089b 100644
--- a/toolsrc/src/vcpkg/registries.cpp
+++ b/toolsrc/src/vcpkg/registries.cpp
@@ -25,10 +25,13 @@ namespace
// when `BuiltinRegistryEntry` is using a port versions file for a port,
// it uses this as it's underlying type;
// when `BuiltinRegistryEntry` is using a port tree, it uses the scfl
- struct GitRegistryEntry
+ struct GitRegistryEntry final : RegistryEntry
{
explicit GitRegistryEntry(std::string&& port_name) : port_name(port_name) { }
+ View<VersionT> get_port_versions() const override { return port_versions; }
+ ExpectedS<fs::path> get_path_to_version(const VcpkgPaths&, const VersionT& version) const override;
+
std::string port_name;
// these two map port versions to git trees
@@ -37,6 +40,67 @@ namespace
std::vector<std::string> git_trees;
};
+ struct GitRegistry final : RegistryImplementation
+ {
+ GitRegistry(std::string&& repo, std::string&& baseline)
+ : m_repo(std::move(repo)), m_baseline_identifier(std::move(baseline))
+ {
+ }
+
+ std::unique_ptr<RegistryEntry> get_port_entry(const VcpkgPaths&, StringView) const override;
+
+ void get_all_port_names(std::vector<std::string>&, const VcpkgPaths&) const override;
+
+ Optional<VersionT> get_baseline_version(const VcpkgPaths&, StringView) const override;
+
+ StringView get_commit_of_repo(const VcpkgPaths& paths) const
+ {
+ return m_commit.get([this, &paths]() -> std::string {
+ auto maybe_hash = paths.git_fetch_from_remote_registry(m_repo);
+ if (!maybe_hash.has_value())
+ {
+ Checks::exit_with_message(VCPKG_LINE_INFO,
+ "Error: Failed to fetch from remote registry `%s`: %s",
+ m_repo,
+ maybe_hash.error());
+ }
+ return std::move(*maybe_hash.get());
+ });
+ }
+
+ fs::path get_versions_tree_path(const VcpkgPaths& paths) const
+ {
+ return m_versions_tree.get([this, &paths]() -> fs::path {
+ auto maybe_tree = paths.git_find_object_id_for_remote_registry_path(get_commit_of_repo(paths),
+ fs::u8path("port_versions"));
+ if (!maybe_tree)
+ {
+ Checks::exit_with_message(
+ VCPKG_LINE_INFO,
+ "Error: could not find the git tree for `port_versions` in repo `%s` at commit `%s`: %s",
+ m_repo,
+ get_commit_of_repo(paths),
+ maybe_tree.error());
+ }
+ auto maybe_path = paths.git_checkout_object_from_remote_registry(*maybe_tree.get());
+ if (!maybe_path)
+ {
+ Checks::exit_with_message(VCPKG_LINE_INFO,
+ "Error: failed to check out `port_versions` from repo %s: %s",
+ m_repo,
+ maybe_path.error());
+ }
+ return std::move(*maybe_path.get());
+ });
+ }
+
+ std::string m_repo;
+ DelayedInit<std::string> m_commit; // TODO: eventually this should end up in the vcpkg-lock.json file
+ DelayedInit<fs::path> m_versions_tree;
+ std::string m_baseline_identifier;
+ DelayedInit<Baseline> m_baseline;
+ };
+
struct BuiltinRegistryEntry final : RegistryEntry
{
explicit BuiltinRegistryEntry(std::unique_ptr<GitRegistryEntry>&& entry)
@@ -195,8 +259,7 @@ namespace
std::unique_ptr<RegistryEntry> BuiltinRegistry::get_port_entry(const VcpkgPaths& paths, StringView port_name) const
{
auto versions_path = paths.builtin_port_versions / relative_path_to_versions(port_name);
- if ((paths.get_feature_flags().registries || paths.get_feature_flags().versions) &&
- paths.get_filesystem().exists(versions_path))
+ if (!m_baseline_identifier.empty() && paths.get_filesystem().exists(versions_path))
{
auto maybe_version_entries =
load_versions_file(paths.get_filesystem(), VersionDbType::Git, paths.builtin_port_versions, port_name);
@@ -247,6 +310,7 @@ namespace
ExpectedS<Baseline> try_parse_builtin_baseline(const VcpkgPaths& paths, StringView baseline_identifier)
{
+ if (baseline_identifier.size() == 0) return Baseline{};
auto path_to_baseline = paths.builtin_port_versions / fs::u8path("baseline.json");
auto res_baseline = load_baseline_versions(paths, path_to_baseline, baseline_identifier);
@@ -261,15 +325,10 @@ namespace
return std::move(*p);
}
- if (baseline_identifier.size() == 0)
- {
- return {{}, expected_left_tag};
- }
-
if (baseline_identifier == "default")
{
- return Strings::format("Couldn't find explicitly specified baseline `\"default\"` in the baseline file.",
- baseline_identifier);
+ return Strings::format("Couldn't find explicitly specified baseline `\"default\"` in baseline file: %s",
+ fs::u8string(path_to_baseline));
}
// attempt to check out the baseline:
@@ -305,6 +364,7 @@ namespace
}
Optional<VersionT> BuiltinRegistry::get_baseline_version(const VcpkgPaths& paths, StringView port_name) const
{
+ Debug::print("Baseline version: \"", m_baseline_identifier, "\"\n");
if (!m_baseline_identifier.empty())
{
const auto& baseline = m_baseline.get(
@@ -318,7 +378,7 @@ namespace
}
else
{
- // fall back to using the ports directory version
+ // if a baseline is not specified, use the ports directory version
auto maybe_scf = Paragraphs::try_load_port(paths.get_filesystem(),
paths.builtin_ports_directory() / fs::u8path(port_name));
if (auto pscf = maybe_scf.get())
@@ -333,8 +393,7 @@ namespace
void BuiltinRegistry::get_all_port_names(std::vector<std::string>& out, const VcpkgPaths& paths) const
{
- if ((paths.get_feature_flags().registries || paths.get_feature_flags().versions) &&
- paths.get_filesystem().exists(paths.builtin_port_versions))
+ if (!m_baseline_identifier.empty() && paths.get_filesystem().exists(paths.builtin_port_versions))
{
load_all_port_names_from_port_versions(out, paths, paths.builtin_port_versions);
}
@@ -415,6 +474,118 @@ namespace
}
// } FilesystemRegistry::RegistryImplementation
+ // { GitRegistry::RegistryImplementation
+ std::unique_ptr<RegistryEntry> GitRegistry::get_port_entry(const VcpkgPaths& paths, StringView port_name) const
+ {
+ auto port_versions = get_versions_tree_path(paths);
+ auto maybe_version_entries =
+ load_versions_file(paths.get_filesystem(), VersionDbType::Git, port_versions, port_name);
+ Checks::check_exit(
+ VCPKG_LINE_INFO, maybe_version_entries.has_value(), "Error: %s", maybe_version_entries.error());
+ auto version_entries = std::move(maybe_version_entries).value_or_exit(VCPKG_LINE_INFO);
+
+ auto res = std::make_unique<GitRegistryEntry>(port_name.to_string());
+ for (auto&& version_entry : version_entries)
+ {
+ res->port_versions.push_back(version_entry.version);
+ res->git_trees.push_back(version_entry.git_tree);
+ }
+ return res;
+ }
+
+ Optional<VersionT> GitRegistry::get_baseline_version(const VcpkgPaths& paths, StringView port_name) const
+ {
+ const auto& baseline = m_baseline.get([this, &paths]() -> Baseline {
+ auto baseline_file = get_versions_tree_path(paths) / fs::u8path("baseline.json");
+
+ auto res_baseline = load_baseline_versions(paths, baseline_file, m_baseline_identifier);
+
+ if (!res_baseline.has_value())
+ {
+ Checks::exit_with_message(VCPKG_LINE_INFO, res_baseline.error());
+ }
+ auto opt_baseline = res_baseline.get();
+ if (auto p = opt_baseline->get())
+ {
+ return std::move(*p);
+ }
+
+ if (m_baseline_identifier.empty())
+ {
+ return {};
+ }
+
+ if (m_baseline_identifier == "default")
+ {
+ Checks::exit_with_message(
+ VCPKG_LINE_INFO,
+ "Couldn't find explicitly specified baseline `\"default\"` in the baseline file.",
+ m_baseline_identifier);
+ }
+
+ // attempt to check out the baseline:
+ auto explicit_hash = paths.git_fetch_from_remote_registry(m_repo, m_baseline_identifier);
+ if (!explicit_hash.has_value())
+ {
+ Checks::exit_with_message(
+ VCPKG_LINE_INFO,
+ "Error: Couldn't find explicitly specified baseline `\"%s\"` in the baseline file for repo %s, "
+ "and that commit doesn't exist.\n%s",
+ m_baseline_identifier,
+ m_repo,
+ explicit_hash.error());
+ }
+ auto path_to_baseline = fs::u8path("port_versions") / fs::u8path("baseline.json");
+ auto maybe_contents = paths.git_show_from_remote_registry(*explicit_hash.get(), path_to_baseline);
+ if (!maybe_contents.has_value())
+ {
+ Checks::exit_with_message(
+ VCPKG_LINE_INFO,
+ "Error: Couldn't find explicitly specified baseline `\"%s\"` in the baseline file for repo %s, "
+ "and the baseline file doesn't exist at that commit.\n%s\n",
+ m_baseline_identifier,
+ m_repo,
+ maybe_contents.error());
+ }
+
+ auto contents = maybe_contents.get();
+ res_baseline = parse_baseline_versions(*contents, {});
+ if (!res_baseline.has_value())
+ {
+ Checks::exit_with_message(VCPKG_LINE_INFO, res_baseline.error());
+ }
+ opt_baseline = res_baseline.get();
+ if (auto p = opt_baseline->get())
+ {
+ return std::move(*p);
+ }
+ else
+ {
+ Checks::exit_with_message(
+ VCPKG_LINE_INFO,
+ "Couldn't find explicitly specified baseline `\"%s\"` in the baseline file for repo %s, "
+ "and the `\"default\"` baseline does not exist at that commit.",
+ m_baseline_identifier,
+ m_repo);
+ }
+ });
+
+ auto it = baseline.find(port_name);
+ if (it != baseline.end())
+ {
+ return it->second;
+ }
+
+ return nullopt;
+ }
+
+ void GitRegistry::get_all_port_names(std::vector<std::string>& out, const VcpkgPaths& paths) const
+ {
+ auto versions_path = get_versions_tree_path(paths);
+ load_all_port_names_from_port_versions(out, paths, versions_path);
+ }
+ // } GitRegistry::RegistryImplementation
+
// } RegistryImplementation
// { RegistryEntry
@@ -464,6 +635,20 @@ namespace
}
// } FilesystemRegistryEntry::RegistryEntry
+ // { GitRegistryEntry::RegistryEntry
+ ExpectedS<fs::path> GitRegistryEntry::get_path_to_version(const VcpkgPaths& paths, const VersionT& version) const
+ {
+ auto it = std::find(port_versions.begin(), port_versions.end(), version);
+ if (it == port_versions.end())
+ {
+ return Strings::concat("Error: No version entry for ", port_name, " at version ", version, ".");
+ }
+
+ const auto& git_tree = git_trees[it - port_versions.begin()];
+ return paths.git_checkout_object_from_remote_registry(git_tree);
+ }
+ // } GitRegistryEntry::RegistryEntry
+
// } RegistryEntry
}
@@ -601,9 +786,11 @@ namespace
constexpr static StringLiteral KIND = "kind";
constexpr static StringLiteral BASELINE = "baseline";
constexpr static StringLiteral PATH = "path";
+ constexpr static StringLiteral REPO = "repository";
constexpr static StringLiteral KIND_BUILTIN = "builtin";
constexpr static StringLiteral KIND_FILESYSTEM = "filesystem";
+ constexpr static StringLiteral KIND_GIT = "git";
virtual StringView type_name() const override { return "a registry"; }
virtual View<StringView> valid_fields() const override;
@@ -620,8 +807,10 @@ namespace
constexpr StringLiteral RegistryImplDeserializer::KIND;
constexpr StringLiteral RegistryImplDeserializer::BASELINE;
constexpr StringLiteral RegistryImplDeserializer::PATH;
+ constexpr StringLiteral RegistryImplDeserializer::REPO;
constexpr StringLiteral RegistryImplDeserializer::KIND_BUILTIN;
constexpr StringLiteral RegistryImplDeserializer::KIND_FILESYSTEM;
+ constexpr StringLiteral RegistryImplDeserializer::KIND_GIT;
struct RegistryDeserializer final : Json::IDeserializer<Registry>
{
@@ -640,7 +829,7 @@ namespace
View<StringView> RegistryImplDeserializer::valid_fields() const
{
- static const StringView t[] = {KIND, BASELINE, PATH};
+ static const StringView t[] = {KIND, BASELINE, PATH, REPO};
return t;
}
View<StringView> valid_builtin_fields()
@@ -662,6 +851,16 @@ namespace
};
return t;
}
+ View<StringView> valid_git_fields()
+ {
+ static const StringView t[] = {
+ RegistryImplDeserializer::KIND,
+ RegistryImplDeserializer::BASELINE,
+ RegistryImplDeserializer::REPO,
+ RegistryDeserializer::PACKAGES,
+ };
+ return t;
+ }
Optional<std::unique_ptr<RegistryImplementation>> RegistryImplDeserializer::visit_null(Json::Reader&)
{
@@ -695,9 +894,19 @@ namespace
res = std::make_unique<FilesystemRegistry>(config_directory / path, std::move(baseline));
}
+ else if (kind == KIND_GIT)
+ {
+ r.check_for_unexpected_fields(obj, valid_git_fields(), "a git registry");
+
+ std::string repo;
+ Json::StringDeserializer repo_des{"a git repository URL"};
+ r.required_object_field("a git registry", obj, REPO, repo, repo_des);
+
+ res = std::make_unique<GitRegistry>(std::move(repo), std::move(baseline));
+ }
else
{
- StringLiteral valid_kinds[] = {KIND_BUILTIN, KIND_FILESYSTEM};
+ StringLiteral valid_kinds[] = {KIND_BUILTIN, KIND_FILESYSTEM, KIND_GIT};
r.add_generic_error(type_name(),
"Field \"kind\" did not have an expected value (expected one of: \"",
Strings::join("\", \"", valid_kinds),
@@ -716,6 +925,7 @@ namespace
RegistryImplDeserializer::KIND,
RegistryImplDeserializer::BASELINE,
RegistryImplDeserializer::PATH,
+ RegistryImplDeserializer::REPO,
PACKAGES,
};
return t;
@@ -853,6 +1063,7 @@ namespace
}
else if (maybe_contents.error() == std::errc::no_such_file_or_directory)
{
+ Debug::print("Failed to find baseline.json\n");
return {nullopt, expected_left_tag};
}
else
diff --git a/toolsrc/src/vcpkg/vcpkgpaths.cpp b/toolsrc/src/vcpkg/vcpkgpaths.cpp
index 1c65cd170..afd724765 100644
--- a/toolsrc/src/vcpkg/vcpkgpaths.cpp
+++ b/toolsrc/src/vcpkg/vcpkgpaths.cpp
@@ -202,6 +202,11 @@ namespace vcpkg
, m_env_cache(ff_settings.compiler_tracking)
, m_ff_settings(ff_settings)
{
+ const auto& cache_root =
+ System::get_platform_cache_home().value_or_exit(VCPKG_LINE_INFO) / fs::u8path("vcpkg");
+ registries_work_tree_dir = cache_root / fs::u8path("registries") / fs::u8path("git");
+ registries_dot_git_dir = registries_work_tree_dir / fs::u8path(".git");
+ registries_git_trees = cache_root / fs::u8path("registries") / fs::u8path("git-trees");
}
Lazy<std::vector<VcpkgPaths::TripletFile>> available_triplets;
@@ -224,6 +229,10 @@ namespace vcpkg
Configuration m_config;
FeatureFlagSettings m_ff_settings;
+
+ fs::path registries_work_tree_dir;
+ fs::path registries_dot_git_dir;
+ fs::path registries_git_trees;
};
}
@@ -726,6 +735,156 @@ If you wish to silence this error and use classic mode, you can:
return destination;
}
+ ExpectedS<std::string> VcpkgPaths::git_fetch_from_remote_registry(StringView repo, StringView treeish) const
+ {
+ auto& fs = get_filesystem();
+
+ auto work_tree = m_pimpl->registries_work_tree_dir;
+ fs.create_directories(work_tree, VCPKG_LINE_INFO);
+ auto dot_git_dir = m_pimpl->registries_dot_git_dir;
+
+ System::CmdLineBuilder init_registries_git_dir =
+ git_cmd_builder(*this, dot_git_dir, work_tree).string_arg("init");
+ auto init_output = System::cmd_execute_and_capture_output(init_registries_git_dir);
+ if (init_output.exit_code != 0)
+ {
+ return {Strings::format("Error: Failed to initialize local repository %s.\n%s\n",
+ fs::u8string(work_tree),
+ init_output.output),
+ expected_right_tag};
+ }
+
+ auto lock_file = work_tree / fs::u8path(".vcpkg-lock");
+
+ std::error_code ec;
+ auto guard = Files::ExclusiveFileLock(Files::ExclusiveFileLock::Wait::Yes, fs, lock_file, ec);
+
+ System::CmdLineBuilder fetch_git_ref =
+ git_cmd_builder(*this, dot_git_dir, work_tree).string_arg("fetch").string_arg("--").string_arg(repo);
+ if (treeish.size() != 0)
+ {
+ fetch_git_ref.string_arg(treeish);
+ }
+
+ auto fetch_output = System::cmd_execute_and_capture_output(fetch_git_ref);
+ if (fetch_output.exit_code != 0)
+ {
+ return {Strings::format("Error: Failed to fetch %s%s from repository %s.\n%s\n",
+ treeish.size() != 0 ? "ref " : "",
+ treeish,
+ repo,
+ fetch_output.output),
+ expected_right_tag};
+ }
+
+ System::CmdLineBuilder get_fetch_head =
+ git_cmd_builder(*this, dot_git_dir, work_tree).string_arg("rev-parse").string_arg("FETCH_HEAD");
+ auto fetch_head_output = System::cmd_execute_and_capture_output(get_fetch_head);
+ if (fetch_head_output.exit_code != 0)
+ {
+ return {Strings::format("Error: Failed to rev-parse FETCH_HEAD.\n%s\n", fetch_head_output.output),
+ expected_right_tag};
+ }
+ return {Strings::trim(fetch_head_output.output).to_string(), expected_left_tag};
+ }
+ // returns an error if there was an unexpected error; returns nullopt if the file doesn't exist at the specified
+ // hash
+ ExpectedS<std::string> VcpkgPaths::git_show_from_remote_registry(StringView hash,
+ const fs::path& relative_path) const
+ {
+ auto revision = Strings::format("%s:%s", hash, fs::generic_u8string(relative_path));
+ System::CmdLineBuilder git_show =
+ git_cmd_builder(*this, m_pimpl->registries_dot_git_dir, m_pimpl->registries_work_tree_dir)
+ .string_arg("show")
+ .string_arg(revision);
+
+ auto git_show_output = System::cmd_execute_and_capture_output(git_show);
+ if (git_show_output.exit_code != 0)
+ {
+ return {git_show_output.output, expected_right_tag};
+ }
+ return {git_show_output.output, expected_left_tag};
+ }
+ ExpectedS<std::string> VcpkgPaths::git_find_object_id_for_remote_registry_path(StringView hash,
+ const fs::path& relative_path) const
+ {
+ auto revision = Strings::format("%s:%s", hash, fs::generic_u8string(relative_path));
+ System::CmdLineBuilder git_rev_parse =
+ git_cmd_builder(*this, m_pimpl->registries_dot_git_dir, m_pimpl->registries_work_tree_dir)
+ .string_arg("rev-parse")
+ .string_arg(revision);
+
+ auto git_rev_parse_output = System::cmd_execute_and_capture_output(git_rev_parse);
+ if (git_rev_parse_output.exit_code != 0)
+ {
+ return {git_rev_parse_output.output, expected_right_tag};
+ }
+ return {Strings::trim(git_rev_parse_output.output).to_string(), expected_left_tag};
+ }
+ ExpectedS<fs::path> VcpkgPaths::git_checkout_object_from_remote_registry(StringView object) const
+ {
+ auto& fs = get_filesystem();
+ fs.create_directories(m_pimpl->registries_git_trees, VCPKG_LINE_INFO);
+
+ auto git_tree_final = m_pimpl->registries_git_trees / fs::u8path(object);
+ if (fs.exists(git_tree_final))
+ {
+ return std::move(git_tree_final);
+ }
+
+ auto pid = System::get_process_id();
+
+ fs::path git_tree_temp = fs::u8path(Strings::format("%s.tmp%ld", fs::u8string(git_tree_final), pid));
+ fs::path git_tree_temp_tar = fs::u8path(Strings::format("%s.tmp%ld.tar", fs::u8string(git_tree_final), pid));
+ fs.remove_all(git_tree_temp, VCPKG_LINE_INFO);
+ fs.create_directory(git_tree_temp, VCPKG_LINE_INFO);
+
+ auto dot_git_dir = m_pimpl->registries_dot_git_dir;
+ System::CmdLineBuilder git_archive = git_cmd_builder(*this, dot_git_dir, m_pimpl->registries_work_tree_dir)
+ .string_arg("archive")
+ .string_arg("--format")
+ .string_arg("tar")
+ .string_arg(object)
+ .string_arg("--output")
+ .path_arg(git_tree_temp_tar);
+ auto git_archive_output = System::cmd_execute_and_capture_output(git_archive);
+ if (git_archive_output.exit_code != 0)
+ {
+ return {Strings::format("git archive failed with message:\n%s", git_archive_output.output),
+ expected_right_tag};
+ }
+
+ auto untar = System::CmdLineBuilder{get_tool_exe(Tools::CMAKE)}
+ .string_arg("-E")
+ .string_arg("tar")
+ .string_arg("xf")
+ .path_arg(git_tree_temp_tar);
+
+ auto untar_output = System::cmd_execute_and_capture_output(untar, System::InWorkingDirectory{git_tree_temp});
+ if (untar_output.exit_code != 0)
+ {
+ return {Strings::format("cmake's untar failed with message:\n%s", untar_output.output), expected_right_tag};
+ }
+
+ std::error_code ec;
+ fs.rename(git_tree_temp, git_tree_final, ec);
+
+ if (fs.exists(git_tree_final))
+ {
+ return git_tree_final;
+ }
+ if (ec)
+ {
+ return {
+ Strings::format("rename to %s failed with message:\n%s", fs::u8string(git_tree_final), ec.message()),
+ expected_right_tag};
+ }
+ else
+ {
+ return {"Unknown error", expected_right_tag};
+ }
+ }
+
Optional<const Json::Object&> VcpkgPaths::get_manifest() const
{
if (auto p = m_pimpl->m_manifest_doc.get())