summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/buildtool/file_system/symlinks_map/TARGETS7
-rw-r--r--src/buildtool/file_system/symlinks_map/resolve_symlinks_map.cpp184
-rw-r--r--src/buildtool/file_system/symlinks_map/resolve_symlinks_map.hpp20
-rw-r--r--src/buildtool/serve_api/serve_service/source_tree.cpp29
-rw-r--r--src/buildtool/serve_api/serve_service/source_tree.hpp3
-rw-r--r--src/other_tools/root_maps/content_git_map.cpp9
-rw-r--r--src/other_tools/root_maps/fpath_git_map.cpp115
7 files changed, 275 insertions, 92 deletions
diff --git a/src/buildtool/file_system/symlinks_map/TARGETS b/src/buildtool/file_system/symlinks_map/TARGETS
index 125a4f52..0d958168 100644
--- a/src/buildtool/file_system/symlinks_map/TARGETS
+++ b/src/buildtool/file_system/symlinks_map/TARGETS
@@ -5,6 +5,7 @@
, "srcs": ["resolve_symlinks_map.cpp"]
, "deps":
[ "pragma_special"
+ , ["src/buildtool/file_system", "git_cas"]
, ["src/buildtool/file_system", "git_repo"]
, ["src/buildtool/file_system", "object_type"]
, ["src/buildtool/multithreading", "async_map_consumer"]
@@ -14,7 +15,11 @@
]
, "stage": ["src", "buildtool", "file_system", "symlinks_map"]
, "private-deps":
- [["@", "fmt", "", "fmt"], ["src/buildtool/storage", "config"]]
+ [ ["@", "fmt", "", "fmt"]
+ , ["src/buildtool/file_system", "object_type"]
+ , ["src/buildtool/storage", "config"]
+ , ["src/utils/cpp", "gsl"]
+ ]
}
, "pragma_special":
{ "type": ["@", "rules", "CC", "library"]
diff --git a/src/buildtool/file_system/symlinks_map/resolve_symlinks_map.cpp b/src/buildtool/file_system/symlinks_map/resolve_symlinks_map.cpp
index 5c9dd89b..198629bb 100644
--- a/src/buildtool/file_system/symlinks_map/resolve_symlinks_map.cpp
+++ b/src/buildtool/file_system/symlinks_map/resolve_symlinks_map.cpp
@@ -15,19 +15,104 @@
#include "src/buildtool/file_system/symlinks_map/resolve_symlinks_map.hpp"
#include "fmt/core.h"
-#include "src/buildtool/file_system/git_repo.hpp"
+#include "src/buildtool/file_system/object_type.hpp"
#include "src/buildtool/storage/config.hpp"
+#include "src/utils/cpp/gsl.hpp"
namespace {
+/// \brief Ensures that a given blob is in the target repo.
+/// On errors, calls logger with fatal and returns false.
+[[nodiscard]] auto EnsureBlobExists(GitObjectToResolve const& obj,
+ GitRepo::TreeEntryInfo const& entry_info,
+ ResolveSymlinksMap::LoggerPtr const& logger)
+ -> bool {
+ ExpectsAudit(IsBlobObject(entry_info.type));
+ // check if entry is in target repo
+ auto target_git_repo = GitRepo::Open(obj.target_cas);
+ if (not target_git_repo) {
+ (*logger)("ResolveSymlinks: could not open target Git repository!",
+ /*fatal=*/true);
+ return false;
+ }
+ auto wrapped_logger = std::make_shared<GitRepo::anon_logger_t>(
+ [logger, id = entry_info.id](auto const& msg, bool fatal) {
+ (*logger)(fmt::format("ResolveSymlinks: while checking blob {} "
+ "exists in target Git repository:\n{}",
+ id,
+ msg),
+ fatal);
+ });
+ auto has_blob =
+ target_git_repo->CheckBlobExists(entry_info.id, wrapped_logger);
+ if (not has_blob) {
+ return false;
+ }
+ if (not *has_blob) {
+ // copy blob from source repo to target repo, if source is not target
+ if (obj.source_cas.get() == obj.target_cas.get()) {
+ (*logger)(
+ fmt::format("ResolveSymlinks: unexpectedly missing blob {} in "
+ "both source and target Git repositories",
+ entry_info.id),
+ /*fatal=*/true);
+ return false;
+ }
+ auto source_git_repo = GitRepo::Open(obj.source_cas);
+ if (not source_git_repo) {
+ (*logger)("ResolveSymlinks: could not open source Git repository",
+ /*fatal=*/true);
+ return false;
+ }
+ wrapped_logger = std::make_shared<GitRepo::anon_logger_t>(
+ [logger, id = entry_info.id](auto const& msg, bool fatal) {
+ (*logger)(fmt::format("ResolveSymlinks: while checking blob {} "
+ "exists in source Git repository:\n{}",
+ id,
+ msg),
+ fatal);
+ });
+ auto res = source_git_repo->TryReadBlob(entry_info.id, wrapped_logger);
+ if (not res.first) {
+ return false; // fatal failure
+ }
+ if (not res.second.has_value()) {
+ (*logger)(fmt::format("ResolveSymlinks: unexpectedly missing "
+ "blob {} in source Git repository",
+ entry_info.id),
+ /*fatal=*/true);
+ return false;
+ }
+ // write blob in target repository
+ wrapped_logger = std::make_shared<GitRepo::anon_logger_t>(
+ [logger, id = entry_info.id](auto const& msg, bool fatal) {
+ (*logger)(fmt::format("ResolveSymlinks: while writing blob "
+ "{} into Git cache:\n{}",
+ id,
+ msg),
+ fatal);
+ });
+ if (not target_git_repo->WriteBlob(res.second.value(),
+ wrapped_logger)) {
+ return false;
+ }
+ }
+ return true; // success!
+}
+
+/// \brief Method to handle entries by their known type.
+/// Guarantees to either call logger with fatal or call setter on returning.
void ResolveKnownEntry(GitObjectToResolve const& obj,
GitRepo::TreeEntryInfo const& entry_info,
- GitCASPtr const& just_git_cas,
ResolveSymlinksMap::SetterPtr const& setter,
ResolveSymlinksMap::LoggerPtr const& logger,
ResolveSymlinksMap::SubCallerPtr const& subcaller) {
// differentiated treatment based on object type
if (IsFileObject(entry_info.type)) {
+ // ensure target repository has the entry
+ if (not EnsureBlobExists(obj, entry_info, logger)) {
+ return;
+ }
// files are already resolved, so return the hash directly
(*setter)(ResolvedGitObject{.id = entry_info.id,
.type = entry_info.type,
@@ -36,13 +121,13 @@ void ResolveKnownEntry(GitObjectToResolve const& obj,
else if (IsTreeObject(entry_info.type)) {
// for tree types we resolve by rebuilding the tree from the
// resolved children
- auto just_git_repo = GitRepo::Open(just_git_cas);
- if (not just_git_repo) {
- (*logger)("ResolveSymlinks: could not open Git cache repository!",
+ auto source_git_repo = GitRepo::Open(obj.source_cas);
+ if (not source_git_repo) {
+ (*logger)("ResolveSymlinks: could not open source Git repository!",
/*fatal=*/true);
return;
}
- auto children = just_git_repo->ReadTree(
+ auto children = source_git_repo->ReadTree(
entry_info.id,
[](std::vector<bazel_re::Digest> const& /*unused*/) {
return true;
@@ -66,7 +151,7 @@ void ResolveKnownEntry(GitObjectToResolve const& obj,
obj.pragma_special != PragmaSpecial::Ignore) {
// children info is known, so pass this forward
if (IsSymlinkObject(e.type)) {
- if (auto target = just_git_cas->ReadObject(raw_id)) {
+ if (auto target = obj.source_cas->ReadObject(raw_id)) {
children_info.emplace_back(
obj.root_tree_id,
obj.rel_path / e.name,
@@ -74,7 +159,9 @@ void ResolveKnownEntry(GitObjectToResolve const& obj,
std::make_optional(GitRepo::TreeEntryInfo{
.id = ToHexString(raw_id),
.type = e.type,
- .symlink_content = *target}));
+ .symlink_content = *target}),
+ obj.source_cas,
+ obj.target_cas);
}
else {
(*logger)(
@@ -94,14 +181,16 @@ void ResolveKnownEntry(GitObjectToResolve const& obj,
GitRepo::TreeEntryInfo{
.id = ToHexString(raw_id),
.type = e.type,
- .symlink_content = std::nullopt});
+ .symlink_content = std::nullopt},
+ obj.source_cas,
+ obj.target_cas);
}
}
}
}
(*subcaller)(
children_info,
- [children_info, parent = obj, just_git_cas, setter, logger](
+ [children_info, parent = obj, setter, logger](
auto const& resolved_entries) {
// create the entries map of the children
GitRepo::tree_entries_t entries{};
@@ -114,18 +203,18 @@ void ResolveKnownEntry(GitObjectToResolve const& obj,
p.filename().string(), // we only need the name
resolved_entries[i]->type);
}
- // create the tree inside our Git CAS, which is already
- // existing by this point. Also, this operation is
- // guarded internally, so no need for the
- // critical_git_op map
- auto just_git_repo = GitRepo::Open(just_git_cas);
- if (not just_git_repo) {
+ // create the tree inside target repo, which should already be
+ // existing. This operation is guarded internally, so no need
+ // for extra locking
+ auto target_git_repo = GitRepo::Open(parent.target_cas);
+ if (not target_git_repo) {
(*logger)(
- "ResolveSymlinks: could not open Git cache repository!",
+ "ResolveSymlinks: could not open target Git "
+ "repository!",
/*fatal=*/true);
return;
}
- auto tree_raw_id = just_git_repo->CreateTree(entries);
+ auto tree_raw_id = target_git_repo->CreateTree(entries);
if (not tree_raw_id) {
(*logger)(fmt::format("ResolveSymlinks: failed to create "
"resolved tree {} in root tree {}",
@@ -170,9 +259,13 @@ void ResolveKnownEntry(GitObjectToResolve const& obj,
/*fatal=*/true);
return;
}
- // if partially resolved, return non-upwards symlinks as-is
+ // if resolving partially, return a non-upwards symlink as-is
if (obj.pragma_special == PragmaSpecial::ResolvePartially and
PathIsNonUpwards(*entry_info.symlink_content)) {
+ // ensure target repository has the entry
+ if (not EnsureBlobExists(obj, entry_info, logger)) {
+ return;
+ }
// return as symlink object
(*setter)(ResolvedGitObject{.id = entry_info.id,
.type = ObjectType::Symlink,
@@ -186,7 +279,9 @@ void ResolveKnownEntry(GitObjectToResolve const& obj,
{GitObjectToResolve(obj.root_tree_id,
n_target,
obj.pragma_special,
- /*known_info=*/std::nullopt)},
+ /*known_info=*/std::nullopt,
+ obj.source_cas,
+ obj.target_cas)},
[setter](auto const& values) {
(*setter)(ResolvedGitObject{*values[0]});
},
@@ -202,31 +297,26 @@ auto CreateResolveSymlinksMap() -> ResolveSymlinksMap {
auto logger,
auto subcaller,
auto const& key) {
- // look up entry by its relative path
- auto just_git_cas = GitCAS::Open(StorageConfig::GitRoot());
- if (not just_git_cas) {
- (*logger)("ResolveSymlinks: could not open Git cache database!",
- /*fatal=*/true);
- return;
- }
- auto just_git_repo = GitRepo::Open(just_git_cas);
- if (not just_git_repo) {
- (*logger)("ResolveSymlinks: could not open Git cache repository!",
- /*fatal=*/true);
- return;
+ auto entry_info = key.known_info;
+ if (not entry_info) {
+ // look up entry by its relative path inside root tree if not known
+ auto source_git_repo = GitRepo::Open(key.source_cas);
+ if (not source_git_repo) {
+ (*logger)(
+ "ResolveSymlinks: could not open source Git repository!",
+ /*fatal=*/true);
+ return;
+ }
+ entry_info = source_git_repo->GetObjectByPathFromTree(
+ key.root_tree_id, key.rel_path);
}
- auto entry_info = key.known_info
- ? key.known_info
- : just_git_repo->GetObjectByPathFromTree(
- key.root_tree_id, key.rel_path);
// differentiate between existing path and non-existing
if (entry_info) {
- ResolveKnownEntry(
- key, *entry_info, just_git_cas, setter, logger, subcaller);
+ ResolveKnownEntry(key, *entry_info, setter, logger, subcaller);
}
else {
- // non-existing paths come from symlinks, so treat accordingly
+ // non-existing paths come from symlinks, so treat accordingly;
// sanity check: pragma ignore special should not be set if here
if (key.pragma_special == PragmaSpecial::Ignore) {
(*logger)(
@@ -251,11 +341,12 @@ auto CreateResolveSymlinksMap() -> ResolveSymlinksMap {
{GitObjectToResolve(key.root_tree_id,
parent_path,
key.pragma_special,
- /*known_info=*/std::nullopt)},
+ /*known_info=*/std::nullopt,
+ key.source_cas,
+ key.target_cas)},
[key,
parent_path,
filename = key.rel_path.filename(),
- just_git_cas,
setter,
logger,
subcaller](auto const& values) {
@@ -271,24 +362,25 @@ auto CreateResolveSymlinksMap() -> ResolveSymlinksMap {
return;
}
// check if filename exists in resolved parent tree
- auto just_git_repo = GitRepo::Open(just_git_cas);
- if (not just_git_repo) {
+ auto target_git_repo = GitRepo::Open(key.target_cas);
+ if (not target_git_repo) {
(*logger)(
"ResolveSymlinks: could not open Git cache "
"repository!",
/*fatal=*/true);
return;
}
- auto entry_info = just_git_repo->GetObjectByPathFromTree(
+ auto entry_info = target_git_repo->GetObjectByPathFromTree(
resolved_parent.id, filename);
if (entry_info) {
ResolveKnownEntry(
GitObjectToResolve(key.root_tree_id,
resolved_parent.path / filename,
key.pragma_special,
- /*known_info=*/std::nullopt),
+ /*known_info=*/std::nullopt,
+ key.source_cas,
+ key.target_cas),
std::move(*entry_info),
- just_git_cas,
setter,
logger,
subcaller);
diff --git a/src/buildtool/file_system/symlinks_map/resolve_symlinks_map.hpp b/src/buildtool/file_system/symlinks_map/resolve_symlinks_map.hpp
index 41986c23..fc706268 100644
--- a/src/buildtool/file_system/symlinks_map/resolve_symlinks_map.hpp
+++ b/src/buildtool/file_system/symlinks_map/resolve_symlinks_map.hpp
@@ -22,6 +22,7 @@
#include <string>
#include <utility> // std::move
+#include "src/buildtool/file_system/git_cas.hpp"
#include "src/buildtool/file_system/git_repo.hpp"
#include "src/buildtool/file_system/object_type.hpp"
#include "src/buildtool/file_system/symlinks_map/pragma_special.hpp"
@@ -31,7 +32,9 @@
#include "src/utils/cpp/path_hash.hpp"
/// \brief Information needed to resolve an object (blob or tree) given its
-/// path relative to the path of a root tree in a given CAS.
+/// path relative to the path of a root tree in a given CAS. The unresolved
+/// entries should be available in the specified source Git repository, and the
+/// resolved entries being made available in the target Git repository.
struct GitObjectToResolve {
// hash of the root tree
std::string root_tree_id{}; /* key */
@@ -42,17 +45,28 @@ struct GitObjectToResolve {
// sometimes the info of the object at the required path is already known,
// so leverage this to avoid extra work
std::optional<GitRepo::TreeEntryInfo> known_info{std::nullopt};
+ // object db to use as source of unresolved entries; it is guaranteed that
+ // this repository is treated as read-only if it differs from target_cas
+ GitCASPtr source_cas{};
+ // object db to use as target for resolved entries; can be the same as
+ // source_cas and usually it is the Git cache; as the caller has access to
+ // such a pointer, it reduces the overhead from opening the Git cache often
+ GitCASPtr target_cas{};
GitObjectToResolve() = default; // needed for cycle detection only!
GitObjectToResolve(std::string root_tree_id_,
std::filesystem::path const& rel_path_,
PragmaSpecial const& pragma_special_,
- std::optional<GitRepo::TreeEntryInfo> known_info_)
+ std::optional<GitRepo::TreeEntryInfo> known_info_,
+ GitCASPtr source_cas_,
+ GitCASPtr target_cas_)
: root_tree_id{std::move(root_tree_id_)},
rel_path{ToNormalPath(rel_path_)},
pragma_special{pragma_special_},
- known_info{std::move(known_info_)} {};
+ known_info{std::move(known_info_)},
+ source_cas{std::move(source_cas_)},
+ target_cas{std::move(target_cas_)} {};
[[nodiscard]] auto operator==(
GitObjectToResolve const& other) const noexcept -> bool {
diff --git a/src/buildtool/serve_api/serve_service/source_tree.cpp b/src/buildtool/serve_api/serve_service/source_tree.cpp
index 7a4a8828..4eeadf3f 100644
--- a/src/buildtool/serve_api/serve_service/source_tree.cpp
+++ b/src/buildtool/serve_api/serve_service/source_tree.cpp
@@ -375,6 +375,7 @@ auto SourceTreeService::SyncArchive(std::string const& tree_id,
auto SourceTreeService::ResolveContentTree(
std::string const& tree_id,
std::filesystem::path const& repo_path,
+ bool repo_is_git_cache,
std::optional<PragmaSpecial> const& resolve_special,
bool sync_tree,
ServeArchiveTreeResponse* response) -> ::grpc::Status {
@@ -396,7 +397,26 @@ auto SourceTreeService::ResolveContentTree(
return SyncArchive(
*resolved_tree_id, repo_path, sync_tree, response);
}
- // resolve tree
+ // resolve tree; target repository is always the Git cache
+ auto target_cas = GitCAS::Open(StorageConfig::GitRoot());
+ if (not target_cas) {
+ auto str = fmt::format("Failed to open Git ODB at {}",
+ StorageConfig::GitRoot().string());
+ logger_->Emit(LogLevel::Error, str);
+ response->set_status(ServeArchiveTreeResponse::INTERNAL_ERROR);
+ return ::grpc::Status::OK;
+ }
+ auto source_cas = target_cas;
+ if (not repo_is_git_cache) {
+ source_cas = GitCAS::Open(repo_path);
+ if (not source_cas) {
+ auto str = fmt::format("Failed to open Git ODB at {}",
+ repo_path.string());
+ logger_->Emit(LogLevel::Error, str);
+ response->set_status(ServeArchiveTreeResponse::INTERNAL_ERROR);
+ return ::grpc::Status::OK;
+ }
+ }
ResolvedGitObject resolved_tree{};
bool failed{false};
{
@@ -406,7 +426,9 @@ auto SourceTreeService::ResolveContentTree(
{GitObjectToResolve{tree_id,
".",
*resolve_special,
- /*known_info=*/std::nullopt}},
+ /*known_info=*/std::nullopt,
+ source_cas,
+ target_cas}},
[&resolved_tree](auto hashes) { resolved_tree = *hashes[0]; },
[logger = logger_, tree_id, &failed](auto const& msg,
bool fatal) {
@@ -625,6 +647,7 @@ auto SourceTreeService::ArchiveImportToGit(
}
return ResolveContentTree(*subtree_id,
StorageConfig::GitRoot(),
+ /*repo_is_git_cache=*/true,
resolve_special,
sync_tree,
response);
@@ -689,6 +712,7 @@ auto SourceTreeService::ServeArchiveTree(
if (std::holds_alternative<std::string>(res)) {
return ResolveContentTree(std::get<std::string>(res), // tree_id
StorageConfig::GitRoot(),
+ /*repo_is_git_cache=*/true,
resolve_special,
request->sync_tree(),
response);
@@ -709,6 +733,7 @@ auto SourceTreeService::ServeArchiveTree(
return ResolveContentTree(
std::get<std::string>(res), // tree_id
path,
+ /*repo_is_git_cache=*/false,
resolve_special,
request->sync_tree(),
response);
diff --git a/src/buildtool/serve_api/serve_service/source_tree.hpp b/src/buildtool/serve_api/serve_service/source_tree.hpp
index f2585f40..d8d117e0 100644
--- a/src/buildtool/serve_api/serve_service/source_tree.hpp
+++ b/src/buildtool/serve_api/serve_service/source_tree.hpp
@@ -173,9 +173,12 @@ class SourceTreeService final
ServeArchiveTreeResponse* response)
-> ::grpc::Status;
+ /// \brief Resolves a tree from given repository with respect to symlinks.
+ /// The resolved tree will always be placed in the Git cache.
[[nodiscard]] auto ResolveContentTree(
std::string const& tree_id,
std::filesystem::path const& repo_path,
+ bool repo_is_git_cache,
std::optional<PragmaSpecial> const& resolve_special,
bool sync_tree,
ServeArchiveTreeResponse* response) -> ::grpc::Status;
diff --git a/src/other_tools/root_maps/content_git_map.cpp b/src/other_tools/root_maps/content_git_map.cpp
index 2a6cad56..d3b0e35b 100644
--- a/src/other_tools/root_maps/content_git_map.cpp
+++ b/src/other_tools/root_maps/content_git_map.cpp
@@ -171,6 +171,7 @@ void EnsureRootAsAbsent(
void ResolveContentTree(
ArchiveRepoInfo const& key,
std::string const& tree_hash,
+ GitCASPtr const& just_git_cas,
bool is_cache_hit,
bool is_absent,
bool serve_api_exists,
@@ -212,13 +213,15 @@ void ResolveContentTree(
}
}
else {
- // resolve tree
+ // resolve tree; both source and target repos are the Git cache
resolve_symlinks_map->ConsumeAfterKeysReady(
ts,
{GitObjectToResolve(tree_hash,
".",
*key.pragma_special,
- /*known_info=*/std::nullopt)},
+ /*known_info=*/std::nullopt,
+ just_git_cas,
+ just_git_cas)},
[resolve_symlinks_map,
tree_hash,
tree_id_file,
@@ -357,6 +360,7 @@ void WriteIdFileAndSetWSRoot(
// resolve tree and set workspace root
ResolveContentTree(key,
*subtree_hash,
+ just_git_cas,
false, /*is_cache_hit*/
is_absent,
serve_api_exists,
@@ -543,6 +547,7 @@ auto CreateContentGitMap(
ResolveContentTree(
key,
*subtree_hash,
+ op_result.git_cas,
/*is_cache_hit = */ true,
/*is_absent = */ (key.absent and not fetch_absent),
serve_api_exists,
diff --git a/src/other_tools/root_maps/fpath_git_map.cpp b/src/other_tools/root_maps/fpath_git_map.cpp
index 7f05e8b5..a38a2255 100644
--- a/src/other_tools/root_maps/fpath_git_map.cpp
+++ b/src/other_tools/root_maps/fpath_git_map.cpp
@@ -95,6 +95,8 @@ void ResolveFilePathTree(
std::string const& target_path,
std::string const& tree_hash,
std::optional<PragmaSpecial> const& pragma_special,
+ GitCASPtr const& source_cas,
+ GitCASPtr const& target_cas,
bool absent,
gsl::not_null<ResolveSymlinksMap*> const& resolve_symlinks_map,
bool serve_api_exists,
@@ -117,9 +119,10 @@ void ResolveFilePathTree(
return;
}
// if serve endpoint is given, try to ensure it has this tree
- // available to be able to build against it
+ // available to be able to build against it; the tree is resolved,
+ // so it is in our Git cache
CheckServeAndSetRoot(*resolved_tree_id,
- repo_root,
+ StorageConfig::GitRoot().string(),
absent,
serve_api_exists,
remote_api,
@@ -133,10 +136,11 @@ void ResolveFilePathTree(
{GitObjectToResolve(tree_hash,
".",
*pragma_special,
- /*known_info=*/std::nullopt)},
+ /*known_info=*/std::nullopt,
+ source_cas,
+ target_cas)},
[resolve_symlinks_map,
tree_hash,
- repo_root,
tree_id_file,
absent,
serve_api_exists,
@@ -173,9 +177,10 @@ void ResolveFilePathTree(
return;
}
// if serve endpoint is given, try to ensure it has this
- // tree available to be able to build against it
+ // tree available to be able to build against it; the
+ // resolved tree is in the Git cache
CheckServeAndSetRoot(resolved_tree.id,
- repo_root,
+ StorageConfig::GitRoot().string(),
absent,
serve_api_exists,
remote_api,
@@ -243,22 +248,6 @@ auto CreateFilePathGitMap(
return;
}
if (not repo_root->empty()) { // if repo root found
- auto git_cas = GitCAS::Open(*repo_root);
- if (not git_cas) {
- (*logger)(fmt::format("Could not open object database for "
- "repository {}",
- repo_root->string()),
- /*fatal=*/true);
- return;
- }
- auto git_repo =
- GitRepoRemote::Open(git_cas); // link fake repo to odb
- if (not git_repo) {
- (*logger)(fmt::format("Could not open repository {}",
- repo_root->string()),
- /*fatal=*/true);
- return;
- }
// get head commit
GitOpKey op_key = {.params =
{
@@ -273,8 +262,8 @@ auto CreateFilePathGitMap(
[fpath = key.fpath,
pragma_special = key.pragma_special,
absent = key.absent,
- git_cas = std::move(git_cas),
repo_root = std::move(*repo_root),
+ critical_git_op_map,
resolve_symlinks_map,
serve_api_exists,
remote_api,
@@ -288,8 +277,8 @@ auto CreateFilePathGitMap(
/*fatal=*/true);
return;
}
- auto git_repo =
- GitRepoRemote::Open(git_cas); // link fake repo to odb
+ auto git_repo = GitRepoRemote::Open(
+ op_result.git_cas); // link fake repo to odb
if (not git_repo) {
(*logger)(fmt::format("Could not open repository {}",
repo_root.string()),
@@ -312,18 +301,65 @@ auto CreateFilePathGitMap(
if (not tree_hash) {
return;
}
- // resolve tree and set workspace root
- ResolveFilePathTree(repo_root.string(),
- fpath.string(),
- *tree_hash,
- pragma_special,
- absent,
- resolve_symlinks_map,
- serve_api_exists,
- remote_api,
- ts,
- setter,
- logger);
+ // resolve tree and set workspace root; tree gets resolved
+ // from source repo into the Git cache, which we first need
+ // to ensure is initialized
+ GitOpKey op_key = {
+ .params =
+ {
+ StorageConfig::GitRoot(), // target_path
+ "", // git_hash
+ "", // branch
+ std::nullopt, // message
+ true // init_bare
+ },
+ .op_type = GitOpType::ENSURE_INIT};
+ critical_git_op_map->ConsumeAfterKeysReady(
+ ts,
+ {std::move(op_key)},
+ [repo_root,
+ fpath,
+ tree_hash,
+ pragma_special,
+ source_cas = op_result.git_cas,
+ absent,
+ resolve_symlinks_map,
+ serve_api_exists,
+ remote_api,
+ ts,
+ setter,
+ logger](auto const& values) {
+ GitOpValue op_result = *values[0];
+ // check flag
+ if (not op_result.result) {
+ (*logger)("Git init failed",
+ /*fatal=*/true);
+ return;
+ }
+ ResolveFilePathTree(
+ repo_root.string(),
+ fpath.string(),
+ *tree_hash,
+ pragma_special,
+ source_cas,
+ op_result.git_cas, /*just_git_cas*/
+ absent,
+ resolve_symlinks_map,
+ serve_api_exists,
+ remote_api,
+ ts,
+ setter,
+ logger);
+ },
+ [logger, target_path = StorageConfig::GitRoot()](
+ auto const& msg, bool fatal) {
+ (*logger)(
+ fmt::format("While running critical Git op "
+ "ENSURE_INIT for target {}:\n{}",
+ target_path.string(),
+ msg),
+ fatal);
+ });
},
[logger, target_path = *repo_root](auto const& msg,
bool fatal) {
@@ -388,11 +424,14 @@ auto CreateFilePathGitMap(
}
// we only need the tree
std::string tree = values[0]->first;
- // resolve tree and set workspace root
+ // resolve tree and set workspace root;
+ // we work on the Git CAS directly
ResolveFilePathTree(StorageConfig::GitRoot().string(),
fpath.string(),
tree,
pragma_special,
+ values[0]->second, /*source_cas*/
+ values[0]->second, /*target_cas*/
absent,
resolve_symlinks_map,
serve_api_exists,