summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPaul Cristian Sarbu <paul.cristian.sarbu@huawei.com>2023-08-01 11:08:04 +0200
committerPaul Cristian Sarbu <paul.cristian.sarbu@huawei.com>2023-08-07 17:01:01 +0200
commit2ab4fc7b08b47ca04007a56574bb263a1c7324da (patch)
treeca34623fc4ea26f3b6b93450e04ecfd76968a6b1 /src
parentc0226e230601972e0b4bf55f74a6514409d47bfe (diff)
downloadjustbuild-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.cpp113
-rw-r--r--src/buildtool/file_system/git_repo.hpp20
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.