summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/buildtool/execution_api/local/local_action.cpp21
-rw-r--r--src/buildtool/execution_api/local/local_action.hpp10
-rw-r--r--src/buildtool/storage/local_cas.hpp8
-rw-r--r--src/buildtool/storage/local_cas.tpp52
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>,