summaryrefslogtreecommitdiff
path: root/src/buildtool/file_system/git_cas.cpp
diff options
context:
space:
mode:
authorPaul Cristian Sarbu <paul.cristian.sarbu@huawei.com>2022-08-29 11:35:15 +0200
committerPaul Cristian Sarbu <paul.cristian.sarbu@huawei.com>2022-12-21 14:41:57 +0100
commit1f344bd93258fac03b6ea82c15dd5dad41ee20fa (patch)
treea6696ca58ec9da63d4e1829bb2163c4e60811438 /src/buildtool/file_system/git_cas.cpp
parentaf20b222322d943595cd580404eda7be7a0b5ba4 (diff)
downloadjustbuild-1f344bd93258fac03b6ea82c15dd5dad41ee20fa.tar.gz
Git CAS: Move Git tree ops to fake repo wrapper class
Diffstat (limited to 'src/buildtool/file_system/git_cas.cpp')
-rw-r--r--src/buildtool/file_system/git_cas.cpp367
1 files changed, 0 insertions, 367 deletions
diff --git a/src/buildtool/file_system/git_cas.cpp b/src/buildtool/file_system/git_cas.cpp
index e03cece8..d0bda197 100644
--- a/src/buildtool/file_system/git_cas.cpp
+++ b/src/buildtool/file_system/git_cas.cpp
@@ -26,7 +26,6 @@
extern "C" {
#include <git2.h>
-#include <git2/sys/odb_backend.h>
}
namespace {
@@ -69,56 +68,6 @@ constexpr std::size_t kOIDHexSize{GIT_OID_HEXSZ};
return std::nullopt;
}
-[[nodiscard]] auto ToHexString(git_oid const& oid) noexcept
- -> std::optional<std::string> {
- std::string hex_id(GIT_OID_HEXSZ, '\0');
- if (git_oid_fmt(hex_id.data(), &oid) != 0) {
- return std::nullopt;
- }
- return hex_id;
-}
-
-[[nodiscard]] auto ToRawString(git_oid const& oid) noexcept
- -> std::optional<std::string> {
- if (auto hex_id = ToHexString(oid)) {
- return FromHexString(*hex_id);
- }
- return std::nullopt;
-}
-
-[[nodiscard]] auto GitFileModeToObjectType(git_filemode_t const& mode) noexcept
- -> std::optional<ObjectType> {
- switch (mode) {
- case GIT_FILEMODE_BLOB:
- return ObjectType::File;
- case GIT_FILEMODE_BLOB_EXECUTABLE:
- return ObjectType::Executable;
- case GIT_FILEMODE_TREE:
- return ObjectType::Tree;
- default: {
- std::ostringstream str;
- str << std::oct << static_cast<int>(mode);
- Logger::Log(
- LogLevel::Error, "unsupported git filemode {}", str.str());
- return std::nullopt;
- }
- }
-}
-
-[[nodiscard]] constexpr auto ObjectTypeToGitFileMode(ObjectType type) noexcept
- -> git_filemode_t {
- switch (type) {
- case ObjectType::File:
- return GIT_FILEMODE_BLOB;
- case ObjectType::Executable:
- return GIT_FILEMODE_BLOB_EXECUTABLE;
- case ObjectType::Tree:
- return GIT_FILEMODE_TREE;
- }
-
- return GIT_FILEMODE_UNREADABLE; // make gcc happy
-}
-
[[nodiscard]] auto GitTypeToObjectType(git_object_t const& type) noexcept
-> std::optional<ObjectType> {
switch (type) {
@@ -134,169 +83,6 @@ constexpr std::size_t kOIDHexSize{GIT_OID_HEXSZ};
}
}
-[[maybe_unused]] [[nodiscard]] auto ValidateEntries(
- GitCAS::tree_entries_t const& entries) -> bool {
- return std::all_of(entries.begin(), entries.end(), [](auto entry) {
- auto const& [id, nodes] = entry;
- // for a given raw id, either all entries are trees or none of them
- return std::all_of(
- nodes.begin(),
- nodes.end(),
- [](auto entry) { return IsTreeObject(entry.type); }) or
- std::none_of(nodes.begin(), nodes.end(), [](auto entry) {
- return IsTreeObject(entry.type);
- });
- });
-}
-
-auto const repo_closer = [](gsl::owner<git_repository*> repo) {
- if (repo != nullptr) {
- git_repository_free(repo);
- }
-};
-
-auto const tree_closer = [](gsl::owner<git_tree*> tree) {
- if (tree != nullptr) {
- git_tree_free(tree);
- }
-};
-
-auto const treebuilder_closer = [](gsl::owner<git_treebuilder*> builder) {
- if (builder != nullptr) {
- git_treebuilder_free(builder);
- }
-};
-
-[[nodiscard]] auto flat_tree_walker(const char* /*root*/,
- const git_tree_entry* entry,
- void* payload) noexcept -> int {
- auto* entries =
- reinterpret_cast<GitCAS::tree_entries_t*>(payload); // NOLINT
-
- std::string name = git_tree_entry_name(entry);
- auto const* oid = git_tree_entry_id(entry);
- if (auto raw_id = ToRawString(*oid)) {
- if (auto type =
- GitFileModeToObjectType(git_tree_entry_filemode(entry))) {
- (*entries)[*raw_id].emplace_back(std::move(name), *type);
- return 1; // return >=0 on success, 1 == skip subtrees (flat)
- }
- }
- return -1; // fail
-}
-
-struct InMemoryODBBackend {
- git_odb_backend parent;
- GitCAS::tree_entries_t const* entries{nullptr}; // object headers
- std::unordered_map<std::string, std::string> trees{}; // solid tree objects
-};
-
-[[nodiscard]] auto backend_read_header(size_t* len_p,
- git_object_t* type_p,
- git_odb_backend* _backend,
- const git_oid* oid) -> int {
- if (len_p != nullptr and type_p != nullptr and _backend != nullptr and
- oid != nullptr) {
- auto* b = reinterpret_cast<InMemoryODBBackend*>(_backend); // NOLINT
- if (auto id = ToRawString(*oid)) {
- if (auto it = b->trees.find(*id); it != b->trees.end()) {
- *type_p = GIT_OBJECT_TREE;
- *len_p = it->second.size();
- return GIT_OK;
- }
- if (b->entries != nullptr) {
- if (auto it = b->entries->find(*id); it != b->entries->end()) {
- if (not it->second.empty()) {
- // pretend object is in database, size is ignored.
- *type_p = IsTreeObject(it->second.front().type)
- ? GIT_OBJECT_TREE
- : GIT_OBJECT_BLOB;
- *len_p = 0;
- return GIT_OK;
- }
- }
- }
- return GIT_ENOTFOUND;
- }
- }
- return GIT_ERROR;
-}
-
-[[nodiscard]] auto backend_read(void** data_p,
- size_t* len_p,
- git_object_t* type_p,
- git_odb_backend* _backend,
- const git_oid* oid) -> int {
- if (data_p != nullptr and len_p != nullptr and type_p != nullptr and
- _backend != nullptr and oid != nullptr) {
- auto* b = reinterpret_cast<InMemoryODBBackend*>(_backend); // NOLINT
- if (auto id = ToRawString(*oid)) {
- if (auto it = b->trees.find(*id); it != b->trees.end()) {
- *type_p = GIT_OBJECT_TREE;
- *len_p = it->second.size();
- *data_p = git_odb_backend_data_alloc(_backend, *len_p);
- if (*data_p == nullptr) {
- return GIT_ERROR;
- }
- std::memcpy(*data_p, it->second.data(), *len_p);
- return GIT_OK;
- }
- return GIT_ENOTFOUND;
- }
- }
- return GIT_ERROR;
-}
-
-[[nodiscard]] auto backend_exists(git_odb_backend* _backend, const git_oid* oid)
- -> int {
- if (_backend != nullptr and oid != nullptr) {
- auto* b = reinterpret_cast<InMemoryODBBackend*>(_backend); // NOLINT
- if (auto id = ToRawString(*oid)) {
- return (b->entries != nullptr and b->entries->contains(*id)) or
- b->trees.contains(*id)
- ? 1
- : 0;
- }
- }
- return GIT_ERROR;
-}
-
-[[nodiscard]] auto backend_write(git_odb_backend* _backend,
- const git_oid* oid,
- const void* data,
- size_t len,
- git_object_t type) -> int {
- if (data != nullptr and _backend != nullptr and oid != nullptr) {
- auto* b = reinterpret_cast<InMemoryODBBackend*>(_backend); // NOLINT
- if (auto id = ToRawString(*oid)) {
- if (auto t = GitTypeToObjectType(type)) {
- std::string s(static_cast<char const*>(data), len);
- if (type == GIT_OBJECT_TREE) {
- b->trees.emplace(std::move(*id), std::move(s));
- return GIT_OK;
- }
- }
- }
- }
- return GIT_ERROR;
-}
-
-void backend_free(git_odb_backend* /*_backend*/) {}
-
-[[nodiscard]] auto CreateInMemoryODBParent() -> git_odb_backend {
- git_odb_backend b{};
- b.version = GIT_ODB_BACKEND_VERSION;
- b.read_header = &backend_read_header;
- b.read = &backend_read;
- b.exists = &backend_exists;
- b.write = &backend_write;
- b.free = &backend_free;
- return b;
-}
-
-// A backend that can be used to read and create tree objects in-memory.
-auto const kInMemoryODBParent = CreateInMemoryODBParent();
-
} // namespace
#endif // BOOTSTRAP_BUILD_TOOL
@@ -358,55 +144,6 @@ auto GitCAS::ReadObject(std::string const& id, bool is_hex_id) const noexcept
#endif
}
-auto GitCAS::ReadTree(std::string const& id, bool is_hex_id) const noexcept
- -> std::optional<tree_entries_t> {
-#ifdef BOOTSTRAP_BUILD_TOOL
- return std::nullopt;
-#else
- // create object id
- auto oid = GitObjectID(id, is_hex_id);
- if (not oid) {
- return std::nullopt;
- }
-
- // create fake repository from ODB
- git_repository* repo_ptr{nullptr};
- if (git_repository_wrap_odb(&repo_ptr, odb_) != 0) {
- Logger::Log(LogLevel::Debug,
- "failed to create fake Git repository from object db");
- return std::nullopt;
- }
- auto fake_repo = std::unique_ptr<git_repository, decltype(repo_closer)>{
- repo_ptr, repo_closer};
-
- // lookup tree
- git_tree* tree_ptr{nullptr};
- if (git_tree_lookup(&tree_ptr, fake_repo.get(), &(*oid)) != 0) {
- Logger::Log(LogLevel::Debug,
- "failed to lookup Git tree {}",
- is_hex_id ? std::string{id} : ToHexString(id));
- return std::nullopt;
- }
- auto tree =
- std::unique_ptr<git_tree, decltype(tree_closer)>{tree_ptr, tree_closer};
-
- // walk tree (flat) and create entries
- tree_entries_t entries{};
- entries.reserve(git_tree_entrycount(tree.get()));
- if (git_tree_walk(
- tree.get(), GIT_TREEWALK_PRE, flat_tree_walker, &entries) != 0) {
- Logger::Log(LogLevel::Debug,
- "failed to walk Git tree {}",
- is_hex_id ? std::string{id} : ToHexString(id));
- return std::nullopt;
- }
-
- gsl_EnsuresAudit(ValidateEntries(entries));
-
- return entries;
-#endif
-}
-
auto GitCAS::ReadHeader(std::string const& id, bool is_hex_id) const noexcept
-> std::optional<std::pair<std::size_t, ObjectType>> {
#ifndef BOOTSTRAP_BUILD_TOOL
@@ -437,62 +174,6 @@ auto GitCAS::ReadHeader(std::string const& id, bool is_hex_id) const noexcept
return std::nullopt;
}
-auto GitCAS::CreateTree(GitCAS::tree_entries_t const& entries) const noexcept
- -> std::optional<std::string> {
-#ifdef BOOTSTRAP_BUILD_TOOL
- return std::nullopt;
-#else
- gsl_ExpectsAudit(ValidateEntries(entries));
-
- // create fake repository from ODB
- git_repository* repo_ptr{nullptr};
- if (git_repository_wrap_odb(&repo_ptr, odb_) != 0) {
- Logger::Log(LogLevel::Debug,
- "failed to create fake Git repository from object db");
- return std::nullopt;
- }
- auto fake_repo = std::unique_ptr<git_repository, decltype(repo_closer)>{
- repo_ptr, repo_closer};
-
- git_treebuilder* builder_ptr{nullptr};
- if (git_treebuilder_new(&builder_ptr, fake_repo.get(), nullptr) != 0) {
- Logger::Log(LogLevel::Debug, "failed to create Git tree builder");
- return std::nullopt;
- }
- auto builder =
- std::unique_ptr<git_treebuilder, decltype(treebuilder_closer)>{
- builder_ptr, treebuilder_closer};
-
- for (auto const& [raw_id, es] : entries) {
- auto id = GitObjectID(raw_id, /*is_hex_id=*/false);
- for (auto const& entry : es) {
- git_tree_entry const* tree_entry{nullptr};
- if (not id or git_treebuilder_insert(
- &tree_entry,
- builder.get(),
- entry.name.c_str(),
- &(*id),
- ObjectTypeToGitFileMode(entry.type)) != 0) {
- Logger::Log(LogLevel::Debug,
- "failed adding object {} to Git tree",
- ToHexString(raw_id));
- return std::nullopt;
- }
- }
- }
-
- git_oid oid;
- if (git_treebuilder_write(&oid, builder.get()) != 0) {
- return std::nullopt;
- }
- auto raw_id = ToRawString(oid);
- if (not raw_id) {
- return std::nullopt;
- }
- return std::move(*raw_id);
-#endif
-}
-
auto GitCAS::OpenODB(std::filesystem::path const& repo_path) noexcept -> bool {
static std::mutex repo_mutex{};
#ifdef BOOTSTRAP_BUILD_TOOL
@@ -525,51 +206,3 @@ auto GitCAS::OpenODB(std::filesystem::path const& repo_path) noexcept -> bool {
return true;
#endif
}
-
-auto GitCAS::ReadTreeData(std::string const& data,
- std::string const& id,
- bool is_hex_id) noexcept
- -> std::optional<tree_entries_t> {
-#ifndef BOOTSTRAP_BUILD_TOOL
- InMemoryODBBackend b{kInMemoryODBParent};
- GitCAS cas{};
- if (auto raw_id = is_hex_id ? FromHexString(id) : std::make_optional(id)) {
- try {
- b.trees.emplace(*raw_id, data);
- } catch (...) {
- return std::nullopt;
- }
- // create a GitCAS from a special-purpose in-memory object database.
- if (git_odb_new(&cas.odb_) == 0 and
- git_odb_add_backend(
- cas.odb_,
- reinterpret_cast<git_odb_backend*>(&b), // NOLINT
- 0) == 0) {
- return cas.ReadTree(*raw_id, /*is_hex_id=*/false);
- }
- }
-#endif
- return std::nullopt;
-}
-
-auto GitCAS::CreateShallowTree(GitCAS::tree_entries_t const& entries) noexcept
- -> std::optional<std::pair<std::string, std::string>> {
-#ifndef BOOTSTRAP_BUILD_TOOL
- InMemoryODBBackend b{kInMemoryODBParent, &entries};
- GitCAS cas{};
- // create a GitCAS from a special-purpose in-memory object database.
- if (git_odb_new(&cas.odb_) == 0 and
- git_odb_add_backend(cas.odb_,
- reinterpret_cast<git_odb_backend*>(&b), // NOLINT
- 0) == 0) {
- if (auto raw_id = cas.CreateTree(entries)) {
- // read result from in-memory trees
- if (auto it = b.trees.find(*raw_id); it != b.trees.end()) {
- return std::make_pair(std::move(*raw_id),
- std::move(it->second));
- }
- }
- }
-#endif
- return std::nullopt;
-}