diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/buildtool/execution_api/local/local_action.cpp | 21 | ||||
-rw-r--r-- | src/buildtool/execution_api/local/local_action.hpp | 10 | ||||
-rw-r--r-- | src/buildtool/storage/local_cas.hpp | 8 | ||||
-rw-r--r-- | src/buildtool/storage/local_cas.tpp | 52 |
4 files changed, 64 insertions, 27 deletions
diff --git a/src/buildtool/execution_api/local/local_action.cpp b/src/buildtool/execution_api/local/local_action.cpp index badc62e5..1d964533 100644 --- a/src/buildtool/execution_api/local/local_action.cpp +++ b/src/buildtool/execution_api/local/local_action.cpp @@ -176,8 +176,13 @@ auto LocalAction::Run(bazel_re::Digest const& action_id) const noexcept return std::nullopt; } -auto LocalAction::StageFile(std::filesystem::path const& target_path, - Artifact::ObjectInfo const& info) const -> bool { +auto LocalAction::StageInput(std::filesystem::path const& target_path, + Artifact::ObjectInfo const& info) const noexcept + -> bool { + if (IsTreeObject(info.type)) { + return FileSystemManager::CreateDirectory(target_path); + } + auto blob_path = storage_->CAS().BlobPath(info.digest, IsExecutableObject(info.type)); @@ -204,19 +209,19 @@ auto LocalAction::StageFile(std::filesystem::path const& target_path, FileSystemManager::CreateFileHardlink(*blob_path, target_path); } -auto LocalAction::StageInputFiles( +auto LocalAction::StageInputs( std::filesystem::path const& exec_path) const noexcept -> bool { if (FileSystemManager::IsRelativePath(exec_path)) { return false; } - auto infos = - storage_->CAS().RecursivelyReadTreeLeafs(root_digest_, exec_path); + auto infos = storage_->CAS().RecursivelyReadTreeLeafs( + root_digest_, exec_path, /*include_trees=*/true); if (not infos) { return false; } for (std::size_t i{}; i < infos->first.size(); ++i) { - if (not StageFile(infos->first.at(i), infos->second.at(i))) { + if (not StageInput(infos->first.at(i), infos->second.at(i))) { return false; } } @@ -237,8 +242,8 @@ auto LocalAction::CreateDirectoryStructure( return false; } - // stage input files to execution directory - if (not StageInputFiles(exec_path)) { + // stage inputs (files, leaf trees) to execution directory + if (not StageInputs(exec_path)) { logger_.Emit(LogLevel::Error, "failed to stage input files to exec_path"); return false; diff --git a/src/buildtool/execution_api/local/local_action.hpp b/src/buildtool/execution_api/local/local_action.hpp index 82101016..c4d9ecd1 100644 --- a/src/buildtool/execution_api/local/local_action.hpp +++ b/src/buildtool/execution_api/local/local_action.hpp @@ -101,16 +101,16 @@ class LocalAction final : public IExecutionAction { [[nodiscard]] auto Run(bazel_re::Digest const& action_id) const noexcept -> std::optional<Output>; - [[nodiscard]] auto StageFile(std::filesystem::path const& target_path, - Artifact::ObjectInfo const& info) const - -> bool; + [[nodiscard]] auto StageInput( + std::filesystem::path const& target_path, + Artifact::ObjectInfo const& info) const noexcept -> bool; - /// \brief Stage input artifacts to the execution directory. + /// \brief Stage input artifacts and leaf trees to the execution directory. /// Stage artifacts and their parent directory structure from CAS to the /// specified execution directory. The execution directory may no exist. /// \param[in] exec_path Absolute path to the execution directory. /// \returns Success indicator. - [[nodiscard]] auto StageInputFiles( + [[nodiscard]] auto StageInputs( std::filesystem::path const& exec_path) const noexcept -> bool; [[nodiscard]] auto CreateDirectoryStructure( diff --git a/src/buildtool/storage/local_cas.hpp b/src/buildtool/storage/local_cas.hpp index 4726f8b8..84de7e95 100644 --- a/src/buildtool/storage/local_cas.hpp +++ b/src/buildtool/storage/local_cas.hpp @@ -108,15 +108,17 @@ class LocalCAS { } /// \brief Traverses a tree recursively and retrieves object infos of all - /// found blobs (leafs). Tree objects are not added to the result list, but - /// converted to a path name. + /// 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 Pair of vectors, first containing filesystem paths, second /// containing object infos. [[nodiscard]] auto RecursivelyReadTreeLeafs( bazel_re::Digest const& tree_digest, - std::filesystem::path const& parent) const noexcept + std::filesystem::path const& parent, + bool include_trees = false) const noexcept -> std::optional<std::pair<std::vector<std::filesystem::path>, std::vector<Artifact::ObjectInfo>>>; diff --git a/src/buildtool/storage/local_cas.tpp b/src/buildtool/storage/local_cas.tpp index b3d95934..f1c7d1cb 100644 --- a/src/buildtool/storage/local_cas.tpp +++ b/src/buildtool/storage/local_cas.tpp @@ -126,35 +126,60 @@ template <class T_CAS> return false; } +[[nodiscard]] static inline auto IsDirectoryEmpty( + bazel_re::Directory const& dir) noexcept -> bool { + return dir.files().empty() and dir.directories().empty() and + dir.symlinks().empty(); +} + template <class T_CAS> auto ReadObjectInfosRecursively( T_CAS const& cas, BazelMsgFactory::InfoStoreFunc const& store_info, std::filesystem::path const& parent, - bazel_re::Digest const& digest) noexcept -> bool { + bazel_re::Digest const& digest, + bool const include_trees = false) -> bool { // read from CAS if (Compatibility::IsCompatible()) { if (auto dir = ReadDirectory(cas, digest)) { + if (include_trees and IsDirectoryEmpty(*dir)) { + if (not store_info( + parent, {ArtifactDigest{digest}, ObjectType::Tree})) { + return false; + } + } return BazelMsgFactory::ReadObjectInfosFromDirectory( - *dir, [&cas, &store_info, &parent](auto path, auto info) { + *dir, + [&cas, &store_info, &parent, include_trees](auto path, + auto info) { return IsTreeObject(info.type) ? ReadObjectInfosRecursively(cas, store_info, parent / path, - info.digest) + info.digest, + include_trees) : store_info(parent / path, info); }); } } else { if (auto entries = ReadGitTree(cas, digest)) { + if (include_trees and entries->empty()) { + if (not store_info( + parent, {ArtifactDigest{digest}, ObjectType::Tree})) { + return false; + } + } return BazelMsgFactory::ReadObjectInfosFromGitTree( - *entries, [&cas, &store_info, &parent](auto path, auto info) { + *entries, + [&cas, &store_info, &parent, include_trees](auto path, + auto info) { return IsTreeObject(info.type) ? ReadObjectInfosRecursively(cas, store_info, parent / path, - info.digest) + info.digest, + include_trees) : store_info(parent / path, info); }); } @@ -165,9 +190,10 @@ auto ReadObjectInfosRecursively( } // namespace detail template <bool kDoGlobalUplink> -auto LocalCAS<kDoGlobalUplink>::RecursivelyReadTreeLeafs( +[[nodiscard]] auto LocalCAS<kDoGlobalUplink>::RecursivelyReadTreeLeafs( bazel_re::Digest const& tree_digest, - std::filesystem::path const& parent) const noexcept + std::filesystem::path const& parent, + bool const include_trees) const noexcept -> std::optional<std::pair<std::vector<std::filesystem::path>, std::vector<Artifact::ObjectInfo>>> { std::vector<std::filesystem::path> paths{}; @@ -179,15 +205,19 @@ auto LocalCAS<kDoGlobalUplink>::RecursivelyReadTreeLeafs( return true; }; - if (detail::ReadObjectInfosRecursively( - *this, store_info, parent, tree_digest)) { - return std::make_pair(std::move(paths), std::move(infos)); + try { + if (detail::ReadObjectInfosRecursively( + *this, store_info, parent, tree_digest, include_trees)) { + return std::make_pair(std::move(paths), std::move(infos)); + } + } catch (...) { + // fallthrough } return std::nullopt; } template <bool kDoGlobalUplink> -auto LocalCAS<kDoGlobalUplink>::ReadDirectTreeEntries( +[[nodiscard]] auto LocalCAS<kDoGlobalUplink>::ReadDirectTreeEntries( bazel_re::Digest const& tree_digest, std::filesystem::path const& parent) const noexcept -> std::optional<std::pair<std::vector<std::filesystem::path>, |