summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/buildtool/serve_api/remote/serve_api.hpp5
-rw-r--r--src/buildtool/serve_api/remote/source_tree_client.cpp37
-rw-r--r--src/buildtool/serve_api/remote/source_tree_client.hpp7
-rw-r--r--src/buildtool/serve_api/serve_service/TARGETS1
-rw-r--r--src/buildtool/serve_api/serve_service/source_tree.cpp67
-rw-r--r--src/buildtool/serve_api/serve_service/source_tree.hpp11
6 files changed, 128 insertions, 0 deletions
diff --git a/src/buildtool/serve_api/remote/serve_api.hpp b/src/buildtool/serve_api/remote/serve_api.hpp
index 0c301ee6..d7fb1c9a 100644
--- a/src/buildtool/serve_api/remote/serve_api.hpp
+++ b/src/buildtool/serve_api/remote/serve_api.hpp
@@ -125,6 +125,11 @@ class ServeApi final {
return stc_.GetRemoteTree(digest);
}
+ [[nodiscard]] auto ComputeTreeStructure(ArtifactDigest const& digest)
+ const noexcept -> expected<ArtifactDigest, GitLookupError> {
+ return stc_.ComputeTreeStructure(digest);
+ }
+
[[nodiscard]] auto ServeTargetVariables(std::string const& target_root_id,
std::string const& target_file,
std::string const& target)
diff --git a/src/buildtool/serve_api/remote/source_tree_client.cpp b/src/buildtool/serve_api/remote/source_tree_client.cpp
index 73114350..bdf3fa57 100644
--- a/src/buildtool/serve_api/remote/source_tree_client.cpp
+++ b/src/buildtool/serve_api/remote/source_tree_client.cpp
@@ -360,4 +360,41 @@ auto SourceTreeClient::GetRemoteTree(
return true;
}
+auto SourceTreeClient::ComputeTreeStructure(ArtifactDigest const& tree)
+ const noexcept -> expected<ArtifactDigest, GitLookupError> {
+ justbuild::just_serve::ComputeTreeStructureRequest request{};
+ request.set_tree(tree.hash());
+
+ grpc::ClientContext context;
+ justbuild::just_serve::ComputeTreeStructureResponse response;
+ grpc::Status status =
+ stub_->ComputeTreeStructure(&context, request, &response);
+
+ if (not status.ok()) {
+ LogStatus(&logger_, LogLevel::Debug, status);
+ return unexpected{GitLookupError::Fatal};
+ }
+ if (response.status() !=
+ ::justbuild::just_serve::ComputeTreeStructureResponse::OK) {
+ logger_.Emit(LogLevel::Debug,
+ "ComputeTreeStructure response returned with {}",
+ static_cast<int>(response.status()));
+ return unexpected{response.status() !=
+ ::justbuild::just_serve::
+ ComputeTreeStructureResponse::NOT_FOUND
+ ? GitLookupError::Fatal
+ : GitLookupError::NotFound};
+ }
+ // ComputeTreeStructure operates on git digests.
+ auto digest = ArtifactDigestFactory::Create(HashFunction::Type::GitSHA1,
+ response.tree_structure_hash(),
+ /*size_unknown=*/0,
+ /*is_tree=*/true);
+ if (not digest) {
+ logger_.Emit(LogLevel::Debug, std::move(digest).error());
+ return unexpected{GitLookupError::Fatal};
+ }
+ return *std::move(digest);
+}
+
#endif // BOOTSTRAP_BUILD_TOOL
diff --git a/src/buildtool/serve_api/remote/source_tree_client.hpp b/src/buildtool/serve_api/remote/source_tree_client.hpp
index 32fb910c..e6ad6083 100644
--- a/src/buildtool/serve_api/remote/source_tree_client.hpp
+++ b/src/buildtool/serve_api/remote/source_tree_client.hpp
@@ -133,6 +133,13 @@ class SourceTreeClient {
[[nodiscard]] auto GetRemoteTree(
ArtifactDigest const& digest) const noexcept -> bool;
+ /// \brief Compute tree structure of a tree
+ /// \param tree Tree to compute
+ /// \return Git digest of the tree structure computed for tree on
+ /// success or an unexpected error on failure (fatal or content not found).
+ [[nodiscard]] auto ComputeTreeStructure(ArtifactDigest const& tree)
+ const noexcept -> expected<ArtifactDigest, GitLookupError>;
+
private:
HashFunction const& hash_function_; // hash function of the remote
std::unique_ptr<justbuild::just_serve::SourceTree::Stub> stub_;
diff --git a/src/buildtool/serve_api/serve_service/TARGETS b/src/buildtool/serve_api/serve_service/TARGETS
index b149c1f4..673553f8 100644
--- a/src/buildtool/serve_api/serve_service/TARGETS
+++ b/src/buildtool/serve_api/serve_service/TARGETS
@@ -50,6 +50,7 @@
, ["src/buildtool/storage", "garbage_collector"]
, ["src/buildtool/storage", "repository_garbage_collector"]
, ["src/buildtool/storage", "storage"]
+ , ["src/buildtool/tree_structure", "tree_structure_utils"]
, ["src/utils/archive", "archive_ops"]
, ["src/utils/cpp", "file_locking"]
, ["src/utils/cpp", "hex_string"]
diff --git a/src/buildtool/serve_api/serve_service/source_tree.cpp b/src/buildtool/serve_api/serve_service/source_tree.cpp
index ff12baee..8a45365d 100644
--- a/src/buildtool/serve_api/serve_service/source_tree.cpp
+++ b/src/buildtool/serve_api/serve_service/source_tree.cpp
@@ -44,6 +44,7 @@
#include "src/buildtool/storage/garbage_collector.hpp"
#include "src/buildtool/storage/repository_garbage_collector.hpp"
#include "src/buildtool/storage/storage.hpp"
+#include "src/buildtool/tree_structure/tree_structure_utils.hpp"
#include "src/utils/archive/archive_ops.hpp"
#include "src/utils/cpp/expected.hpp"
#include "src/utils/cpp/file_locking.hpp"
@@ -1669,4 +1670,70 @@ auto SourceTreeService::GetRemoteTree(
return ::grpc::Status::OK;
}
+auto SourceTreeService::ComputeTreeStructure(
+ ::grpc::ServerContext* /*context*/,
+ const ::justbuild::just_serve::ComputeTreeStructureRequest* request,
+ ComputeTreeStructureResponse* response) -> ::grpc::Status {
+ auto repo_lock = RepositoryGarbageCollector::SharedLock(
+ *native_context_->storage_config);
+ if (not repo_lock) {
+ logger_->Emit(LogLevel::Error, "Could not acquire repo gc SharedLock");
+ response->set_status(ComputeTreeStructureResponse::INTERNAL_ERROR);
+ return ::grpc::Status::OK;
+ }
+ // ensure Git cache exists
+ if (auto done = EnsureGitCacheRoot(); not done) {
+ logger_->Emit(LogLevel::Error, std::move(done).error());
+ response->set_status(ComputeTreeStructureResponse::INTERNAL_ERROR);
+ return ::grpc::Status::OK;
+ }
+ // get gc lock for native storage
+ auto lock = GarbageCollector::SharedLock(*native_context_->storage_config);
+ if (not lock) {
+ logger_->Emit(LogLevel::Error, "Could not acquire gc SharedLock");
+ response->set_status(ComputeTreeStructureResponse::INTERNAL_ERROR);
+ return ::grpc::Status::OK;
+ }
+
+ auto const tree_digest =
+ ArtifactDigestFactory::Create(HashFunction::Type::GitSHA1,
+ request->tree(),
+ /*size_unknown=*/0,
+ /*is_tree=*/true);
+ if (not tree_digest) {
+ logger_->Emit(LogLevel::Error, tree_digest.error());
+ response->set_status(ComputeTreeStructureResponse::INTERNAL_ERROR);
+ return ::grpc::Status::OK;
+ }
+
+ auto known_repositories = serve_config_.known_repositories;
+ known_repositories.push_back(native_context_->storage_config->GitRoot());
+
+ std::optional<ArtifactDigest> tree_structure;
+ if (auto from_local = TreeStructureUtils::ComputeStructureLocally(
+ *tree_digest,
+ known_repositories,
+ *native_context_->storage_config,
+ &mutex_)) {
+ tree_structure = std::move(from_local).value();
+ }
+ else {
+ // A critical error occurred:
+ logger_->Emit(LogLevel::Error, std::move(from_local).error());
+ response->set_status(ComputeTreeStructureResponse::INTERNAL_ERROR);
+ return ::grpc::Status::OK;
+ }
+
+ if (not tree_structure.has_value()) {
+ logger_->Emit(
+ LogLevel::Error, "Failed to find {}", tree_digest->hash());
+ response->set_status(ComputeTreeStructureResponse::NOT_FOUND);
+ return ::grpc::Status::OK;
+ }
+
+ response->set_tree_structure_hash(tree_structure->hash());
+ response->set_status(ComputeTreeStructureResponse::OK);
+ return ::grpc::Status::OK;
+}
+
#endif // BOOTSTRAP_BUILD_TOOL
diff --git a/src/buildtool/serve_api/serve_service/source_tree.hpp b/src/buildtool/serve_api/serve_service/source_tree.hpp
index 0f58a0a9..ea93cb54 100644
--- a/src/buildtool/serve_api/serve_service/source_tree.hpp
+++ b/src/buildtool/serve_api/serve_service/source_tree.hpp
@@ -59,6 +59,8 @@ class SourceTreeService final
::justbuild::just_serve::CheckRootTreeResponse;
using GetRemoteTreeResponse =
::justbuild::just_serve::GetRemoteTreeResponse;
+ using ComputeTreeStructureResponse =
+ ::justbuild::just_serve::ComputeTreeStructureResponse;
explicit SourceTreeService(
gsl::not_null<RemoteServeConfig const*> const& serve_config,
@@ -133,6 +135,15 @@ class SourceTreeService final
const ::justbuild::just_serve::GetRemoteTreeRequest* request,
GetRemoteTreeResponse* response) -> ::grpc::Status override;
+ // Compute the tree structure of the given tree and return the Git tree
+ // identifier of the resulting structure.
+ //
+ // There are no method-specific errors.
+ auto ComputeTreeStructure(
+ ::grpc::ServerContext* context,
+ const ::justbuild::just_serve::ComputeTreeStructureRequest* request,
+ ComputeTreeStructureResponse* response) -> ::grpc::Status override;
+
private:
RemoteServeConfig const& serve_config_;
ApiBundle const& apis_;