#ifndef INCLUDED_SRC_BUILDTOOL_EXECUTION_API_LOCAL_LOCAL_API_HPP #define INCLUDED_SRC_BUILDTOOL_EXECUTION_API_LOCAL_LOCAL_API_HPP #include #include #include #include #include "gsl-lite/gsl-lite.hpp" #include "src/buildtool/compatibility/native_support.hpp" #include "src/buildtool/execution_api/bazel_msg/bazel_blob.hpp" #include "src/buildtool/execution_api/common/execution_api.hpp" #include "src/buildtool/execution_api/common/local_tree_map.hpp" #include "src/buildtool/execution_api/local/local_action.hpp" #include "src/buildtool/execution_api/local/local_storage.hpp" /// \brief API for local execution. class LocalApi final : public IExecutionApi { public: auto CreateAction( ArtifactDigest const& root_digest, std::vector const& command, std::vector const& output_files, std::vector const& output_dirs, std::map const& env_vars, std::map const& properties) noexcept -> IExecutionAction::Ptr final { return IExecutionAction::Ptr{new LocalAction{storage_, tree_map_, root_digest, command, output_files, output_dirs, env_vars, properties}}; } // NOLINTNEXTLINE(misc-no-recursion) [[nodiscard]] auto RetrieveToPaths( std::vector const& artifacts_info, std::vector const& output_paths) noexcept -> bool final { if (artifacts_info.size() != output_paths.size()) { Logger::Log(LogLevel::Error, "different number of digests and output paths."); return false; } for (std::size_t i{}; i < artifacts_info.size(); ++i) { auto const& info = artifacts_info[i]; if (IsTreeObject(info.type)) { // read object infos from sub tree and call retrieve recursively auto const infos = storage_->ReadTreeInfos(info.digest, output_paths[i]); if (not infos or not RetrieveToPaths(infos->second, infos->first)) { return false; } } else { auto const blob_path = storage_->BlobPath( info.digest, IsExecutableObject(info.type)); if (not blob_path or not FileSystemManager::CreateDirectory( output_paths[i].parent_path()) or not FileSystemManager::CopyFileAs( *blob_path, output_paths[i], info.type)) { return false; } } } return true; } [[nodiscard]] auto RetrieveToFds( std::vector const& artifacts_info, std::vector const& fds, bool raw_tree) noexcept -> bool final { if (artifacts_info.size() != fds.size()) { Logger::Log(LogLevel::Error, "different number of digests and file descriptors."); return false; } for (std::size_t i{}; i < artifacts_info.size(); ++i) { auto fd = fds[i]; auto const& info = artifacts_info[i]; if (gsl::owner out = fdopen(fd, "wb")) { // NOLINT auto const success = storage_->DumpToStream(info, out, raw_tree); std::fclose(out); if (not success) { Logger::Log(LogLevel::Error, "dumping {} {} to file descriptor {} failed.", IsTreeObject(info.type) ? "tree" : "blob", info.ToString(), fd); return false; } } else { Logger::Log(LogLevel::Error, "dumping to file descriptor {} failed.", fd); return false; } } return true; } [[nodiscard]] auto Upload(BlobContainer const& blobs, bool /*skip_find_missing*/) noexcept -> bool final { for (auto const& blob : blobs) { auto const is_tree = NativeSupport::IsTree(blob.digest.hash()); auto cas_digest = is_tree ? storage_->StoreTree(blob.data) : storage_->StoreBlob(blob.data); if (not cas_digest or not std::equal_to{}( *cas_digest, blob.digest)) { return false; } } return true; } [[nodiscard]] auto UploadTree( std::vector const& artifacts) noexcept -> std::optional final { BlobContainer blobs{}; auto tree = tree_map_->CreateTree(); auto digest = BazelMsgFactory::CreateDirectoryDigestFromTree( artifacts, [&blobs](BazelBlob&& blob) { blobs.Emplace(std::move(blob)); }, [&tree](auto path, auto info) { return tree.AddInfo(path, info); }); if (not digest) { Logger::Log(LogLevel::Debug, "failed to create digest for tree."); return std::nullopt; } if (not Upload(blobs, /*skip_find_missing=*/false)) { Logger::Log(LogLevel::Debug, "failed to upload blobs for tree."); return std::nullopt; } if (tree_map_->AddTree(*digest, std::move(tree))) { return ArtifactDigest{*digest}; } return std::nullopt; } [[nodiscard]] auto IsAvailable(ArtifactDigest const& digest) const noexcept -> bool final { return static_cast(digest.is_tree() ? storage_->TreePath(digest) : storage_->BlobPath(digest, false)); } [[nodiscard]] auto IsAvailable(std::vector const& digests) const noexcept -> std::vector final { std::vector result; for (auto const& digest : digests) { if (not storage_->BlobPath(digest, false).has_value()) { result.push_back(digest); } } return result; } private: std::shared_ptr tree_map_{std::make_shared()}; std::shared_ptr storage_{ std::make_shared(tree_map_)}; }; #endif // INCLUDED_SRC_BUILDTOOL_EXECUTION_API_LOCAL_LOCAL_API_HPP