summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/buildtool/main/TARGETS2
-rw-r--r--src/buildtool/main/main.cpp54
-rw-r--r--src/buildtool/serve_api/remote/TARGETS8
-rw-r--r--src/buildtool/serve_api/remote/config.hpp48
-rw-r--r--src/buildtool/serve_api/serve_service/TARGETS41
-rw-r--r--src/buildtool/serve_api/serve_service/just_serve.proto52
-rw-r--r--src/buildtool/serve_api/serve_service/serve_server_implementation.cpp126
-rw-r--r--src/buildtool/serve_api/serve_service/serve_server_implementation.hpp60
-rw-r--r--src/buildtool/serve_api/serve_service/target_level_cache_server.cpp78
-rw-r--r--src/buildtool/serve_api/serve_service/target_level_cache_server.hpp56
10 files changed, 525 insertions, 0 deletions
diff --git a/src/buildtool/main/TARGETS b/src/buildtool/main/TARGETS
index 1264bfb5..40d19095 100644
--- a/src/buildtool/main/TARGETS
+++ b/src/buildtool/main/TARGETS
@@ -22,6 +22,8 @@
, ["src/buildtool/execution_api/execution_service", "operation_cache"]
, ["src/buildtool/execution_api/local", "config"]
, ["src/buildtool/execution_api/remote", "config"]
+ , ["src/buildtool/serve_api/remote", "config"]
+ , ["src/buildtool/serve_api/serve_service", "serve_server_implementation"]
, "common"
, "cli"
, "version"
diff --git a/src/buildtool/main/main.cpp b/src/buildtool/main/main.cpp
index b2c04be7..8cc81449 100644
--- a/src/buildtool/main/main.cpp
+++ b/src/buildtool/main/main.cpp
@@ -49,6 +49,8 @@
#include "src/buildtool/graph_traverser/graph_traverser.hpp"
#include "src/buildtool/main/serve.hpp"
#include "src/buildtool/progress_reporting/progress_reporter.hpp"
+#include "src/buildtool/serve_api/remote/config.hpp"
+#include "src/buildtool/serve_api/serve_service/serve_server_implementation.hpp"
#include "src/buildtool/storage/garbage_collector.hpp"
#endif // BOOTSTRAP_BUILD_TOOL
#include "src/buildtool/logging/log_config.hpp"
@@ -132,6 +134,16 @@ void SetupExecutionConfig(EndpointArguments const& eargs,
}
}
+void SetupServeConfig(ServeArguments const& srvargs) {
+ using RemoteConfig = RemoteServeConfig;
+ if (not srvargs.repositories.empty() and
+ not RemoteConfig::SetKnownRepositories(srvargs.repositories)) {
+ Logger::Log(LogLevel::Error,
+ "setting serve service repositories failed.");
+ std::exit(kExitFailure);
+ }
+}
+
void SetupAuthConfig(CommonAuthArguments const& authargs,
ClientAuthArguments const& client_authargs,
ServerAuthArguments const& server_authargs) {
@@ -228,6 +240,39 @@ void SetupExecutionServiceConfig(ServiceArguments const& args) {
}
}
+void SetupServeServiceConfig(ServiceArguments const& args) {
+ if (args.port) {
+ if (!ServeServerImpl::SetPort(*args.port)) {
+ Logger::Log(LogLevel::Error, "Invalid port '{}'", *args.port);
+ std::exit(kExitFailure);
+ }
+ }
+ if (args.info_file) {
+ if (!ServeServerImpl::SetInfoFile(*args.info_file)) {
+ Logger::Log(LogLevel::Error,
+ "Invalid info-file '{}'",
+ args.info_file->string());
+ std::exit(kExitFailure);
+ }
+ }
+ if (args.interface) {
+ if (!ServeServerImpl::SetInterface(*args.interface)) {
+ Logger::Log(LogLevel::Error,
+ "Invalid interface '{}'",
+ args.info_file->string());
+ std::exit(kExitFailure);
+ }
+ }
+ if (args.pid_file) {
+ if (!ServeServerImpl::SetPidFile(*args.pid_file)) {
+ Logger::Log(LogLevel::Error,
+ "Invalid pid-file '{}'",
+ args.info_file->string());
+ std::exit(kExitFailure);
+ }
+ }
+}
+
void SetupHashFunction() {
HashFunction::SetHashType(Compatibility::IsCompatible()
? HashFunction::JustHash::Compatible
@@ -851,6 +896,7 @@ auto main(int argc, char* argv[]) -> int {
SetupHashFunction();
SetupExecutionConfig(
arguments.endpoint, arguments.build, arguments.rebuild);
+ SetupServeConfig(arguments.serve);
SetupAuthConfig(arguments.auth, arguments.cauth, arguments.sauth);
if (arguments.cmd == SubCommand::kGc) {
@@ -867,6 +913,14 @@ auto main(int argc, char* argv[]) -> int {
}
return kExitSuccess;
}
+
+ if (arguments.cmd == SubCommand::kServe) {
+ SetupServeServiceConfig(arguments.service);
+ if (!ServeServerImpl::Instance().Run()) {
+ return kExitFailure;
+ }
+ return kExitSuccess;
+ }
#endif // BOOTSTRAP_BUILD_TOOL
auto jobs = arguments.build.build_jobs > 0 ? arguments.build.build_jobs
diff --git a/src/buildtool/serve_api/remote/TARGETS b/src/buildtool/serve_api/remote/TARGETS
new file mode 100644
index 00000000..a56adf60
--- /dev/null
+++ b/src/buildtool/serve_api/remote/TARGETS
@@ -0,0 +1,8 @@
+{ "config":
+ { "type": ["@", "rules", "CC", "library"]
+ , "name": ["config"]
+ , "hdrs": ["config.hpp"]
+ , "deps": [["src/buildtool/execution_api/remote", "config"]]
+ , "stage": ["src", "buildtool", "serve_api", "remote"]
+ }
+}
diff --git a/src/buildtool/serve_api/remote/config.hpp b/src/buildtool/serve_api/remote/config.hpp
new file mode 100644
index 00000000..dac7fabf
--- /dev/null
+++ b/src/buildtool/serve_api/remote/config.hpp
@@ -0,0 +1,48 @@
+// Copyright 2023 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.
+
+#include <filesystem>
+#include <iterator>
+#include <vector>
+
+#include "src/buildtool/execution_api/remote/config.hpp"
+
+class RemoteServeConfig : public RemoteExecutionConfig {
+ public:
+ // Obtain global instance
+ [[nodiscard]] static auto Instance() noexcept -> RemoteServeConfig& {
+ static RemoteServeConfig config;
+ return config;
+ }
+
+ // Set the list of known repositories
+ [[nodiscard]] static auto SetKnownRepositories(
+ std::vector<std::filesystem::path> const& repos) noexcept -> bool {
+ auto& inst = Instance();
+ inst.repositories_ = std::vector<std::filesystem::path>(
+ std::make_move_iterator(repos.begin()),
+ std::make_move_iterator(repos.end()));
+ return repos.size() == inst.repositories_.size();
+ }
+
+ // Repositories known to 'just serve'
+ [[nodiscard]] static auto KnownRepositories() noexcept
+ -> const std::vector<std::filesystem::path>& {
+ return Instance().repositories_;
+ }
+
+ private:
+ // Known Git repositories to serve server.
+ std::vector<std::filesystem::path> repositories_{};
+};
diff --git a/src/buildtool/serve_api/serve_service/TARGETS b/src/buildtool/serve_api/serve_service/TARGETS
new file mode 100644
index 00000000..93155ae7
--- /dev/null
+++ b/src/buildtool/serve_api/serve_service/TARGETS
@@ -0,0 +1,41 @@
+{ "just_serve_proto":
+ { "type": ["@", "rules", "proto", "library"]
+ , "name": ["just_serve_proto"]
+ , "service": ["yes"]
+ , "srcs": ["just_serve.proto"]
+ , "deps": [["@", "bazel_remote_apis", "", "remote_execution_proto"]]
+ , "stage": ["justbuild", "just_serve"]
+ }
+, "target_level_cache_server":
+ { "type": ["@", "rules", "CC", "library"]
+ , "name": ["target_level_cache_server"]
+ , "hdrs": ["target_level_cache_server.hpp"]
+ , "srcs": ["target_level_cache_server.cpp"]
+ , "proto": ["just_serve_proto"]
+ , "deps": [["src/buildtool/logging", "logging"]]
+ , "stage": ["src", "buildtool", "serve_api", "serve_service"]
+ , "private-deps":
+ [ ["@", "fmt", "", "fmt"]
+ , ["src/buildtool/file_system", "git_repo"]
+ , ["src/buildtool/serve_api/remote", "config"]
+ , ["src/buildtool/storage", "config"]
+ ]
+ }
+, "serve_server_implementation":
+ { "type": ["@", "rules", "CC", "library"]
+ , "name": ["serve_server_implementation"]
+ , "hdrs": ["serve_server_implementation.hpp"]
+ , "srcs": ["serve_server_implementation.cpp"]
+ , "deps": [["src/buildtool/logging", "logging"]]
+ , "stage": ["src", "buildtool", "serve_api", "serve_service"]
+ , "private-deps":
+ [ "target_level_cache_server"
+ , ["@", "fmt", "", "fmt"]
+ , ["@", "grpc", "", "grpc++"]
+ , ["@", "json", "", "json"]
+ , ["src/buildtool/auth", "auth"]
+ , ["src/buildtool/common/remote", "port"]
+ , ["src/buildtool/compatibility", "compatibility"]
+ ]
+ }
+}
diff --git a/src/buildtool/serve_api/serve_service/just_serve.proto b/src/buildtool/serve_api/serve_service/just_serve.proto
new file mode 100644
index 00000000..3eca2954
--- /dev/null
+++ b/src/buildtool/serve_api/serve_service/just_serve.proto
@@ -0,0 +1,52 @@
+// Copyright 2023 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.
+
+syntax = "proto3";
+
+package justbuild.just_serve;
+
+import "google/rpc/status.proto";
+
+// A request message for
+// [TargetLevelCache.ServeCommitTree][justbuild.just_serve.TargetLevelCache.ServeCommitTree].
+message ServeCommitTreeRequest {
+ // The Git commit identifier to be searched on the server.
+ string commit = 1;
+
+ // Relative path of requested tree with respect to the commit root.
+ string subdir = 2;
+}
+
+// A response message for
+// [TargetLevelCache.ServeCommitTree][justbuild.just_serve.TargetLevelCache.ServeCommitTree].
+message ServeCommitTreeResponse {
+ // The requested Git tree hash.
+ string tree = 1;
+
+ // If the status has a code other than `OK`, it indicates that the tree hash
+ // could not be computed. In this case, the `tree` field is optional.
+ //
+ // If the status code is `NOT_FOUND`, it indicates that either the commit was
+ // not found, or the commit root tree does not contain the given relative
+ // path.
+ google.rpc.Status status = 2;
+}
+
+// Services for improved interaction with the target-level cache.
+service TargetLevelCache {
+ // Retrieve the Git-subtree identifier from a given Git commit.
+ //
+ // There are no method-specific errors.
+ rpc ServeCommitTree(ServeCommitTreeRequest) returns (ServeCommitTreeResponse) {}
+}
diff --git a/src/buildtool/serve_api/serve_service/serve_server_implementation.cpp b/src/buildtool/serve_api/serve_service/serve_server_implementation.cpp
new file mode 100644
index 00000000..3c9f5f21
--- /dev/null
+++ b/src/buildtool/serve_api/serve_service/serve_server_implementation.cpp
@@ -0,0 +1,126 @@
+// Copyright 2023 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.
+
+#include "src/buildtool/serve_api/serve_service/serve_server_implementation.hpp"
+
+#include <iostream>
+#include <memory>
+
+#include <sys/types.h>
+
+#include "fmt/core.h"
+#include "grpcpp/grpcpp.h"
+#include "nlohmann/json.hpp"
+#include "src/buildtool/auth/authentication.hpp"
+#include "src/buildtool/common/remote/port.hpp"
+#include "src/buildtool/compatibility/compatibility.hpp"
+#include "src/buildtool/logging/logger.hpp"
+#include "src/buildtool/serve_api/serve_service/target_level_cache_server.hpp"
+
+namespace {
+template <typename T>
+auto TryWrite(std::string const& file, T const& content) noexcept -> bool {
+ std::ofstream of{file};
+ if (!of.good()) {
+ Logger::Log(LogLevel::Error,
+ "Could not open {}. Make sure to have write permissions",
+ file);
+ return false;
+ }
+ of << content;
+ return true;
+}
+} // namespace
+
+auto ServeServerImpl::Run() -> bool {
+ TargetLevelCacheService tlc{};
+
+ grpc::ServerBuilder builder;
+
+ builder.RegisterService(&tlc);
+
+ std::shared_ptr<grpc::ServerCredentials> creds;
+ if (Auth::GetAuthMethod() == AuthMethod::kTLS) {
+ auto tls_opts = grpc::SslServerCredentialsOptions{};
+
+ tls_opts.pem_root_certs = Auth::TLS::CACert();
+ grpc::SslServerCredentialsOptions::PemKeyCertPair keycert = {
+ Auth::TLS::ServerKey(), Auth::TLS::ServerCert()};
+
+ tls_opts.pem_key_cert_pairs.emplace_back(keycert);
+
+ creds = grpc::SslServerCredentials(tls_opts);
+ }
+ else {
+ creds = grpc::InsecureServerCredentials();
+ }
+
+ builder.AddListeningPort(
+ fmt::format("{}:{}", interface_, port_), creds, &port_);
+
+ auto server = builder.BuildAndStart();
+ if (!server) {
+ Logger::Log(LogLevel::Error, "Could not start serve service");
+ return false;
+ }
+
+ auto pid = getpid();
+
+ nlohmann::json const& info = {
+ {"interface", interface_}, {"port", port_}, {"pid", pid}};
+
+ if (!pid_file_.empty()) {
+ if (!TryWrite(pid_file_, pid)) {
+ server->Shutdown();
+ return false;
+ }
+ }
+
+ auto const& info_str = nlohmann::to_string(info);
+ Logger::Log(LogLevel::Info,
+ fmt::format("{}serve service started: {}",
+ Compatibility::IsCompatible() ? "compatible " : "",
+ info_str));
+
+ if (!info_file_.empty()) {
+ if (!TryWrite(info_file_, info_str)) {
+ server->Shutdown();
+ return false;
+ }
+ }
+
+ server->Wait();
+ return true;
+}
+
+[[nodiscard]] auto ServeServerImpl::SetInfoFile(std::string const& x) noexcept
+ -> bool {
+ Instance().info_file_ = x;
+ return true;
+}
+
+[[nodiscard]] auto ServeServerImpl::SetPidFile(std::string const& x) noexcept
+ -> bool {
+ Instance().pid_file_ = x;
+ return true;
+}
+
+[[nodiscard]] auto ServeServerImpl::SetPort(int const x) noexcept -> bool {
+ auto port_num = ParsePort(x);
+ if (!port_num) {
+ return false;
+ }
+ Instance().port_ = static_cast<int>(*port_num);
+ return true;
+}
diff --git a/src/buildtool/serve_api/serve_service/serve_server_implementation.hpp b/src/buildtool/serve_api/serve_service/serve_server_implementation.hpp
new file mode 100644
index 00000000..f756a104
--- /dev/null
+++ b/src/buildtool/serve_api/serve_service/serve_server_implementation.hpp
@@ -0,0 +1,60 @@
+// Copyright 2023 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 SERVE_SERVER_IMPLEMENTATION_HPP
+#define SERVE_SERVER_IMPLEMENTATION_HPP
+
+#include <string>
+
+#include "src/buildtool/logging/logger.hpp"
+
+class ServeServerImpl {
+ public:
+ ServeServerImpl() noexcept = default;
+ [[nodiscard]] static auto Instance() noexcept -> ServeServerImpl& {
+ static ServeServerImpl x;
+ return x;
+ }
+
+ [[nodiscard]] static auto SetInterface(std::string const& x) noexcept
+ -> bool {
+ Instance().interface_ = x;
+ return true;
+ }
+
+ [[nodiscard]] static auto SetPidFile(std::string const& x) noexcept -> bool;
+
+ [[nodiscard]] static auto SetPort(int x) noexcept -> bool;
+
+ [[nodiscard]] static auto SetInfoFile(std::string const& x) noexcept
+ -> bool;
+
+ ServeServerImpl(ServeServerImpl const&) = delete;
+ auto operator=(ServeServerImpl const&) noexcept
+ -> ServeServerImpl& = delete;
+
+ ServeServerImpl(ServeServerImpl&&) noexcept = delete;
+ auto operator=(ServeServerImpl&&) noexcept -> ServeServerImpl& = delete;
+
+ auto Run() -> bool;
+ ~ServeServerImpl() = default;
+
+ private:
+ std::string interface_{"127.0.0.1"};
+ int port_{0};
+ std::string info_file_{};
+ std::string pid_file_{};
+};
+
+#endif // SERVE_SERVER_IMPLEMENTATION_HPP
diff --git a/src/buildtool/serve_api/serve_service/target_level_cache_server.cpp b/src/buildtool/serve_api/serve_service/target_level_cache_server.cpp
new file mode 100644
index 00000000..688a5c32
--- /dev/null
+++ b/src/buildtool/serve_api/serve_service/target_level_cache_server.cpp
@@ -0,0 +1,78 @@
+// Copyright 2023 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.
+
+#include "src/buildtool/serve_api/serve_service/target_level_cache_server.hpp"
+
+#include "fmt/core.h"
+#include "src/buildtool/file_system/git_repo.hpp"
+#include "src/buildtool/serve_api/remote/config.hpp"
+#include "src/buildtool/storage/config.hpp"
+
+auto TargetLevelCacheService::GetTreeFromCommit(
+ std::filesystem::path const& repo_path,
+ std::string const& commit,
+ std::string const& subdir,
+ std::shared_ptr<Logger> const& logger) -> std::optional<std::string> {
+ if (auto git_cas = GitCAS::Open(repo_path)) {
+ if (auto repo = GitRepo::Open(git_cas)) {
+ // wrap logger for GitRepo call
+ auto wrapped_logger = std::make_shared<GitRepo::anon_logger_t>(
+ [logger, repo_path, commit](auto const& msg, bool fatal) {
+ if (fatal) {
+ auto err = fmt::format(
+ "ServeCommitTree: While retrieving tree of commit "
+ "{} from repository {}:\n{}",
+ commit,
+ repo_path.string(),
+ msg);
+ logger->Emit(LogLevel::Trace, err);
+ }
+ });
+ if (auto tree_id = repo->GetSubtreeFromCommit(
+ commit, subdir, wrapped_logger)) {
+ return tree_id;
+ }
+ }
+ }
+ return std::nullopt;
+}
+
+auto TargetLevelCacheService::ServeCommitTree(
+ ::grpc::ServerContext* /* context */,
+ const ::justbuild::just_serve::ServeCommitTreeRequest* request,
+ ::justbuild::just_serve::ServeCommitTreeResponse* response)
+ -> ::grpc::Status {
+ auto const& commit{request->commit()};
+ auto const& subdir{request->subdir()};
+ // try in local build root Git cache
+ if (auto tree_id = GetTreeFromCommit(
+ StorageConfig::GitRoot(), commit, subdir, logger_)) {
+ *(response->mutable_tree()) = std::move(*tree_id);
+ response->mutable_status()->CopyFrom(google::rpc::Status{});
+ return ::grpc::Status::OK;
+ }
+ // try given extra repositories, in order
+ for (auto const& path : RemoteServeConfig::KnownRepositories()) {
+ if (auto tree_id = GetTreeFromCommit(path, commit, subdir, logger_)) {
+ *(response->mutable_tree()) = std::move(*tree_id);
+ response->mutable_status()->CopyFrom(google::rpc::Status{});
+ return ::grpc::Status::OK;
+ }
+ }
+ // commit not found
+ google::rpc::Status status;
+ status.set_code(grpc::StatusCode::NOT_FOUND);
+ response->mutable_status()->CopyFrom(status);
+ return ::grpc::Status::OK;
+}
diff --git a/src/buildtool/serve_api/serve_service/target_level_cache_server.hpp b/src/buildtool/serve_api/serve_service/target_level_cache_server.hpp
new file mode 100644
index 00000000..80d09647
--- /dev/null
+++ b/src/buildtool/serve_api/serve_service/target_level_cache_server.hpp
@@ -0,0 +1,56 @@
+// Copyright 2023 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 TARGET_LEVEL_CACHE_SERVER_HPP
+#define TARGET_LEVEL_CACHE_SERVER_HPP
+
+#include <filesystem>
+#include <memory>
+#include <optional>
+#include <string>
+#include <vector>
+
+#include "justbuild/just_serve/just_serve.grpc.pb.h"
+#include "src/buildtool/logging/logger.hpp"
+
+class TargetLevelCacheService final
+ : public justbuild::just_serve::TargetLevelCache::Service {
+
+ public:
+ // Retrieve the tree of a commit.
+ //
+ // This request interrogates the service whether it knows a given Git
+ // commit. If requested commit is found, it provides the commit's
+ // Git-tree identifier.
+ //
+ // Errors:
+ //
+ // * `NOT_FOUND`: The requested commit could not be found.
+ auto ServeCommitTree(
+ ::grpc::ServerContext* context,
+ const ::justbuild::just_serve::ServeCommitTreeRequest* request,
+ ::justbuild::just_serve::ServeCommitTreeResponse* response)
+ -> ::grpc::Status override;
+
+ private:
+ std::shared_ptr<Logger> logger_{std::make_shared<Logger>("serve-service")};
+
+ [[nodiscard]] static auto GetTreeFromCommit(
+ std::filesystem::path const& repo_path,
+ std::string const& commit,
+ std::string const& subdir,
+ std::shared_ptr<Logger> const& logger) -> std::optional<std::string>;
+};
+
+#endif // TARGET_LEVEL_CACHE_SERVER_HPP