diff options
author | Paul Cristian Sarbu <paul.cristian.sarbu@huawei.com> | 2023-08-01 11:08:04 +0200 |
---|---|---|
committer | Paul Cristian Sarbu <paul.cristian.sarbu@huawei.com> | 2023-08-07 17:01:01 +0200 |
commit | 2ab4fc7b08b47ca04007a56574bb263a1c7324da (patch) | |
tree | ca34623fc4ea26f3b6b93450e04ecfd76968a6b1 /src | |
parent | c0226e230601972e0b4bf55f74a6514409d47bfe (diff) | |
download | justbuild-2ab4fc7b08b47ca04007a56574bb263a1c7324da.tar.gz |
GitRepo: Add method for reading object from tree by its path
Diffstat (limited to 'src')
-rw-r--r-- | src/buildtool/file_system/git_repo.cpp | 113 | ||||
-rw-r--r-- | src/buildtool/file_system/git_repo.hpp | 20 |
2 files changed, 131 insertions, 2 deletions
diff --git a/src/buildtool/file_system/git_repo.cpp b/src/buildtool/file_system/git_repo.cpp index bb60c68b..a989c608 100644 --- a/src/buildtool/file_system/git_repo.cpp +++ b/src/buildtool/file_system/git_repo.cpp @@ -1169,6 +1169,119 @@ auto GitRepo::CheckTreeExists(std::string const& tree_id, #endif // BOOTSTRAP_BUILD_TOOL } +auto GitRepo::GetObjectByPathFromTree(std::string const& tree_id, + std::string const& rel_path) noexcept + -> std::optional<TreeEntryInfo> { +#ifdef BOOTSTRAP_BUILD_TOOL + return std::nullopt; +#else + try { + std::string entry_id{tree_id}; + ObjectType entry_type{ObjectType::Tree}; + + // preferably with a "fake" repository! + if (not IsRepoFake()) { + Logger::Log(LogLevel::Debug, + "Subtree id retrieval from tree called on a real " + "repository"); + } + // check if path is not trivial + if (rel_path != ".") { + // share the odb lock + std::shared_lock lock{GetGitCAS()->mutex_}; + + // get tree object from tree id + git_oid tree_oid; + if (git_oid_fromstr(&tree_oid, tree_id.c_str()) != 0) { + Logger::Log(LogLevel::Trace, + "tree ID parsing in git repository {} failed " + "with:\n{}", + GetGitCAS()->git_path_.string(), + GitLastError()); + return std::nullopt; + } + + git_tree* tree_ptr{nullptr}; + if (git_tree_lookup(&tree_ptr, repo_->Ptr(), &tree_oid) != 0) { + Logger::Log(LogLevel::Trace, + "retrieving tree {} in git repository {} " + "failed with:\n{}", + tree_id, + GetGitCAS()->git_path_.string(), + GitLastError()); + // cleanup resources + git_tree_free(tree_ptr); + return std::nullopt; + } + auto tree = std::unique_ptr<git_tree, decltype(&tree_closer)>( + tree_ptr, tree_closer); + + // get hash for actual entry + git_tree_entry* entry_ptr{nullptr}; + if (git_tree_entry_bypath( + &entry_ptr, tree.get(), rel_path.c_str()) != 0) { + Logger::Log(LogLevel::Trace, + "retrieving entry at {} in git repository {} " + "failed with:\n{}", + rel_path, + GetGitCAS()->git_path_.string(), + GitLastError()); + // cleanup resources + git_tree_entry_free(entry_ptr); + return std::nullopt; + } + + auto entry = + std::unique_ptr<git_tree_entry, decltype(&tree_entry_closer)>( + entry_ptr, tree_entry_closer); + + // get id + entry_id = + std::string(git_oid_tostr_s(git_tree_entry_id(entry.get()))); + + // get type + if (auto e_type = GitFileModeToObjectType( + git_tree_entry_filemode(entry.get()))) { + entry_type = *e_type; + } + else { + Logger::Log(LogLevel::Trace, + "retrieving type of entry {} in git repository " + "{} failed with:\n{}", + entry_id, + GetGitCAS()->git_path_.string(), + GitLastError()); + return std::nullopt; + } + } + + // if symlink, also read target + if (IsSymlinkObject(entry_type)) { + if (auto target = + GetGitCAS()->ReadObject(entry_id, /*is_hex_id=*/true)) { + return TreeEntryInfo{.id = entry_id, + .type = entry_type, + .symlink_content = *target}; + } + Logger::Log( + LogLevel::Trace, + "failed to read target for symlink {} in git repository {}", + entry_id, + GetGitCAS()->git_path_.string()); + return std::nullopt; + } + return TreeEntryInfo{.id = entry_id, + .type = entry_type, + .symlink_content = std::nullopt}; + } catch (std::exception const& ex) { + Logger::Log(LogLevel::Debug, + "get entry by path from tree failed with:\n{}", + ex.what()); + return std::nullopt; + } +#endif // BOOTSTRAP_BUILD_TOOL +} + auto GitRepo::IsRepoFake() const noexcept -> bool { return is_repo_fake_; } diff --git a/src/buildtool/file_system/git_repo.hpp b/src/buildtool/file_system/git_repo.hpp index e96f401b..b2e12934 100644 --- a/src/buildtool/file_system/git_repo.hpp +++ b/src/buildtool/file_system/git_repo.hpp @@ -49,8 +49,16 @@ class GitRepo { using tree_entries_t = std::unordered_map<std::string, std::vector<tree_entry_t>>; - // Checks whether a list of symlinks given by their hashes are non-upwards, - // based on content read from an actual backend. + // Stores the info of an object read by its path. + struct TreeEntryInfo { + std::string id{}; + ObjectType type; + // if type is symlink, read it in advance + std::optional<std::string> symlink_content{std::nullopt}; + }; + + // Checks whether a list of symlinks given by their hashes are + // non-upwards, based on content read from an actual backend. using SymlinksCheckFunc = std::function<bool(std::vector<bazel_re::Digest> const&)>; @@ -211,6 +219,14 @@ class GitRepo { anon_logger_ptr const& logger) noexcept -> std::optional<bool>; + /// \brief Get the object info related to a given path inside a Git tree. + /// Unlike GetSubtreeFromTree, we here ignore errors and only return a value + /// when all is successful. + /// Calling it from a fake repository allows thread-safe use. + [[nodiscard]] auto GetObjectByPathFromTree( + std::string const& tree_id, + std::string const& rel_path) noexcept -> std::optional<TreeEntryInfo>; + private: /// \brief Wrapped git_repository with guarded destructor. /// Kept privately nested to avoid misuse of its raw pointer members. |