// Copyright 2024 Huawei Cloud Computing Technology Co., Ltd. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef INCLUDED_SRC_BUILDTOOL_EXECUTION_API_COMMON_TREE_READER_HPP #define INCLUDED_SRC_BUILDTOOL_EXECUTION_API_COMMON_TREE_READER_HPP #include #include #include #include #include #include "src/buildtool/common/artifact.hpp" #include "src/buildtool/common/bazel_types.hpp" #include "src/buildtool/execution_api/bazel_msg/bazel_msg_factory.hpp" #include "src/buildtool/file_system/git_repo.hpp" #include "src/buildtool/file_system/object_type.hpp" struct ReadTreeResult final { std::vector paths; std::vector infos; }; template class TreeReader final { public: template explicit TreeReader(Args&&... args) noexcept : impl_(std::forward(args)...) {} /// \brief Reads the flat content of a tree and returns object infos of all /// its direct entries (trees and blobs). /// \param tree_digest Digest of the tree. /// \param parent Local parent path. /// \returns A struct containing filesystem paths and object infos. [[nodiscard]] auto ReadDirectTreeEntries( ArtifactDigest const& digest, std::filesystem::path const& parent) const noexcept -> std::optional { ReadTreeResult result; BazelMsgFactory::InfoStoreFunc store_info = [&result, &parent](std::filesystem::path const& path, Artifact::ObjectInfo const& info) { result.paths.emplace_back(parent / path); result.infos.emplace_back(info); return true; }; if (Compatibility::IsCompatible()) { auto tree = impl_.ReadDirectory(digest); if (tree and not BazelMsgFactory::ReadObjectInfosFromDirectory( *tree, store_info)) { return std::nullopt; } } else { auto tree = impl_.ReadGitTree(digest); if (tree and not BazelMsgFactory::ReadObjectInfosFromGitTree( *tree, store_info)) { return std::nullopt; } } return result; } /// \brief Traverses a tree recursively and retrieves object infos of all /// found blobs (leafs). Tree objects are by default not added to the result /// list, but converted to a path name. /// \param tree_digest Digest of the tree. /// \param parent Local parent path. /// \param include_trees Include leaf tree objects (empty trees). /// \returns A struct containing filesystem paths and object infos. [[nodiscard]] auto RecursivelyReadTreeLeafs( ArtifactDigest const& digest, std::filesystem::path const& parent, bool include_trees = false) const noexcept -> std::optional { ReadTreeResult result; auto store = [&result](std::filesystem::path const& path, Artifact::ObjectInfo const& info) { result.paths.emplace_back(path); result.infos.emplace_back(info); return true; }; try { if (ReadObjectInfosRecursively( store, parent, digest, include_trees)) { return result; } } catch (...) { // fallthrough } return std::nullopt; } private: TImpl impl_; [[nodiscard]] static inline auto IsDirectoryEmpty( bazel_re::Directory const& dir) noexcept -> bool { return dir.files().empty() and dir.directories().empty() and dir.symlinks().empty(); } [[nodiscard]] auto ReadObjectInfosRecursively( BazelMsgFactory::InfoStoreFunc const& store, std::filesystem::path const& parent, ArtifactDigest const& digest, bool const include_trees) const -> bool { BazelMsgFactory::InfoStoreFunc internal_store = [this, &store, &parent, include_trees]( std::filesystem::path const& path, Artifact::ObjectInfo const& info) -> bool { return IsTreeObject(info.type) ? ReadObjectInfosRecursively( store, parent / path, info.digest, include_trees) : store(parent / path, info); }; if (Compatibility::IsCompatible()) { if (auto tree = impl_.ReadDirectory(digest)) { if (include_trees and IsDirectoryEmpty(*tree)) { if (not store(parent, {digest, ObjectType::Tree})) { return false; } } return BazelMsgFactory::ReadObjectInfosFromDirectory( *tree, internal_store); } } else { if (auto tree = impl_.ReadGitTree(digest)) { if (include_trees and tree->empty()) { if (not store(parent, {digest, ObjectType::Tree})) { return false; } } return BazelMsgFactory::ReadObjectInfosFromGitTree( *tree, internal_store); } } return false; } }; #endif // INCLUDED_SRC_BUILDTOOL_EXECUTION_API_COMMON_TREE_READER_HPP