summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/other_tools/git_operations/git_operations.cpp34
-rw-r--r--src/other_tools/git_operations/git_operations.hpp8
-rw-r--r--src/other_tools/git_operations/git_ops_types.hpp3
-rw-r--r--src/other_tools/ops_maps/critical_git_op_map.cpp3
-rw-r--r--test/other_tools/git_operations/critical_git_ops.test.cpp154
5 files changed, 132 insertions, 70 deletions
diff --git a/src/other_tools/git_operations/git_operations.cpp b/src/other_tools/git_operations/git_operations.cpp
index 74f1d323..81375130 100644
--- a/src/other_tools/git_operations/git_operations.cpp
+++ b/src/other_tools/git_operations/git_operations.cpp
@@ -143,3 +143,37 @@ auto CriticalGitOps::GitGetHeadId(GitOpParams const& crit_op_params,
// success
return {.git_cas = git_repo->GetGitCAS(), .result = *head_commit};
}
+
+auto CriticalGitOps::GitKeepTree(GitOpParams const& crit_op_params,
+ AsyncMapConsumerLoggerPtr const& logger)
+ -> GitOpValue {
+ // Make sure folder we want to access exists
+ if (not FileSystemManager::Exists(crit_op_params.target_path)) {
+ (*logger)(fmt::format("target directory {} does not exist!",
+ crit_op_params.target_path.string()),
+ true /*fatal*/);
+ return {.git_cas = nullptr, .result = std::nullopt};
+ }
+ // Open a GitRepo at given location
+ auto git_repo = GitRepoRemote::Open(crit_op_params.target_path);
+ if (git_repo == std::nullopt) {
+ (*logger)(fmt::format("could not open git repository {}",
+ crit_op_params.target_path.string()),
+ true /*fatal*/);
+ return {.git_cas = nullptr, .result = std::nullopt};
+ }
+ // setup wrapped logger
+ auto wrapped_logger = std::make_shared<AsyncMapConsumerLogger>(
+ [logger](auto const& msg, bool fatal) {
+ (*logger)(fmt::format("While doing keep tree Git op:\n{}", msg),
+ fatal);
+ });
+ // Create tag for given tree
+ if (not git_repo->KeepTree(crit_op_params.git_hash,
+ crit_op_params.message.value(),
+ wrapped_logger)) {
+ return {.git_cas = nullptr, .result = std::nullopt};
+ }
+ // success
+ return {.git_cas = git_repo->GetGitCAS(), .result = ""};
+}
diff --git a/src/other_tools/git_operations/git_operations.hpp b/src/other_tools/git_operations/git_operations.hpp
index e034664e..44eec96a 100644
--- a/src/other_tools/git_operations/git_operations.hpp
+++ b/src/other_tools/git_operations/git_operations.hpp
@@ -53,6 +53,14 @@ class CriticalGitOps {
[[nodiscard]] static auto GitGetHeadId(
GitOpParams const& crit_op_params,
AsyncMapConsumerLoggerPtr const& logger) -> GitOpValue;
+
+ // This operation needs the params: target_path, git_hash (tree), message
+ // Called after resolving symlinks in a tree to retain the resolved tree
+ // by tagging it. Assumes folder exists.
+ // It guarantees the logger is called exactly once with fatal if failure.
+ [[nodiscard]] static auto GitKeepTree(
+ GitOpParams const& crit_op_params,
+ AsyncMapConsumerLoggerPtr const& logger) -> GitOpValue;
};
#endif // INCLUDED_SRC_OTHER_TOOLS_GIT_OPERATIONS_GIT_OPERATIONS_HPP \ No newline at end of file
diff --git a/src/other_tools/git_operations/git_ops_types.hpp b/src/other_tools/git_operations/git_ops_types.hpp
index 0147ee57..c30d5819 100644
--- a/src/other_tools/git_operations/git_ops_types.hpp
+++ b/src/other_tools/git_operations/git_ops_types.hpp
@@ -57,7 +57,8 @@ enum class GitOpType {
INITIAL_COMMIT,
ENSURE_INIT,
KEEP_TAG,
- GET_HEAD_ID
+ GET_HEAD_ID,
+ KEEP_TREE
};
/// \brief Common return value for all critical Git operations
diff --git a/src/other_tools/ops_maps/critical_git_op_map.cpp b/src/other_tools/ops_maps/critical_git_op_map.cpp
index 7fd3df20..cbab7c42 100644
--- a/src/other_tools/ops_maps/critical_git_op_map.cpp
+++ b/src/other_tools/ops_maps/critical_git_op_map.cpp
@@ -19,7 +19,8 @@ GitOpKeyMap const GitOpKey::map_ = {
{GitOpType::INITIAL_COMMIT, CriticalGitOps::GitInitialCommit},
{GitOpType::ENSURE_INIT, CriticalGitOps::GitEnsureInit},
{GitOpType::KEEP_TAG, CriticalGitOps::GitKeepTag},
- {GitOpType::GET_HEAD_ID, CriticalGitOps::GitGetHeadId}};
+ {GitOpType::GET_HEAD_ID, CriticalGitOps::GitGetHeadId},
+ {GitOpType::KEEP_TREE, CriticalGitOps::GitKeepTree}};
/// \brief Create a CriticalOpMap object
auto CreateCriticalGitOpMap(CriticalGitOpGuardPtr const& crit_git_op_ptr)
diff --git a/test/other_tools/git_operations/critical_git_ops.test.cpp b/test/other_tools/git_operations/critical_git_ops.test.cpp
index 8c712d22..36a95af4 100644
--- a/test/other_tools/git_operations/critical_git_ops.test.cpp
+++ b/test/other_tools/git_operations/critical_git_ops.test.cpp
@@ -17,6 +17,7 @@
#include <cstddef>
#include <cstdlib> // std::system
#include <filesystem>
+#include <numeric>
#include <optional>
#include <string>
#include <thread>
@@ -36,6 +37,7 @@ auto const kBundlePath =
std::string{"test/buildtool/file_system/data/test_repo_symlinks.bundle"};
auto const kRootCommit =
std::string{"3ecce3f5b19ad7941c6354d65d841590662f33ef"};
+auto const kBazSymId = std::string{"1868f82682c290f0b1db3cacd092727eef1fa57f"};
} // namespace
@@ -123,22 +125,25 @@ TEST_CASE("Critical git operations", "[critical_git_op_map]") {
// create the target paths for the various critical ops
// IMPORTANT! For non-init critical ops the paths need to exist already!
- // 1. Initial commit -> needs a path containing some files
+ // 0. Initial commit -> needs a path containing some files
// This has to be process unique, as the commit will fail otherwise!
auto path_init_commit = TestUtilsMP::GetRepoPathUnique(*prefix);
REQUIRE(FileSystemManager::WriteFile(
"test no 1", path_init_commit / "test1.txt", true));
REQUIRE(FileSystemManager::WriteFile(
"test no 2", path_init_commit / "test2.txt", true));
- // 2 & 3. Initializing repos -> need only the paths
+ // 1 & 2. Initializing repos -> need only the paths
auto path_init_bare = TestUtilsMP::GetRepoPath(*prefix);
auto path_init_non_bare = TestUtilsMP::GetRepoPath(*prefix);
- // 4. Tag a commit -> needs a repo with a commit
+ // 3. Tag a commit -> needs a repo with a commit
auto path_keep_tag = TestUtilsMP::CreateTestRepo(*prefix, true);
REQUIRE(path_keep_tag);
- // 5. Get head commit -> needs a repo with a commit
+ // 4. Get head commit -> needs a repo with HEAD ref available
auto path_get_head_id = TestUtilsMP::CreateTestRepoWithCheckout(*prefix);
REQUIRE(path_get_head_id);
+ // 5. Tag a tree -> needs a repo with a tree
+ auto path_keep_tree = TestUtilsMP::CreateTestRepo(*prefix, true);
+ REQUIRE(path_keep_tree);
// create the map
auto crit_op_guard = std::make_shared<CriticalGitOpGuard>();
@@ -147,78 +152,91 @@ TEST_CASE("Critical git operations", "[critical_git_op_map]") {
// Add ops to the map. None should throw, as repeating the same operation
// should retrieve the value from the map, not call the operation again.
// helper lists
- const std::vector<std::size_t> ops_all{
- 0, 1, 2, 3, 4}; // indices of all ops tested
+ constexpr auto NUM_METHODS = 6;
+ std::vector<std::size_t> ops_all(NUM_METHODS); // indices of all ops tested
+ std::iota(ops_all.begin(), ops_all.end(), 0);
+
const std::vector<std::size_t> ops_with_result{
0, 4}; // indices of ops that return a non-empty string
+
// Add to the map all ops multiple times
- for ([[maybe_unused]] auto const& i :
- {0, 0, 0}) { // replace once ranges are available
- // (https://en.cppreference.com/w/cpp/ranges/iota_view)
+ constexpr auto REPEATS = 3;
+ for ([[maybe_unused]] auto k = REPEATS; k > 0; --k) {
auto error = false;
auto error_msg = std::string("NONE");
{
TaskSystem ts;
- crit_op_map.ConsumeAfterKeysReady(
- &ts,
- {GitOpKey{.params =
- {
- path_init_commit, // target_path
- "", // git_hash
- "", // branch
- "Init commit" // message
- },
- .op_type = GitOpType::INITIAL_COMMIT},
- GitOpKey{.params =
- {
- path_init_bare, // target_path
- "", // git_hash
- "", // branch
- std::nullopt, // message
- true // init_bare
- },
- .op_type = GitOpType::ENSURE_INIT},
- GitOpKey{.params =
- {
- path_init_non_bare, // target_path
- "", // git_hash
- "", // branch
- std::nullopt, // message
- false // init_bare
- },
- .op_type = GitOpType::ENSURE_INIT},
- GitOpKey{.params =
- {
- *path_keep_tag, // target_path
- kRootCommit, // git_hash
- "", // branch
- "keep-me" // message
- },
- .op_type = GitOpType::KEEP_TAG},
- GitOpKey{.params =
- {
- *path_get_head_id, // target_path
- "", // git_hash
- "", // branch
- },
- .op_type = GitOpType::GET_HEAD_ID}},
- [&ops_all, &ops_with_result](auto const& values) {
- // check operations
- for (std::size_t const& i : ops_all) {
- auto res = *values[i];
- REQUIRE(res.git_cas);
- REQUIRE(res.result);
- if (std::find(ops_with_result.begin(),
- ops_with_result.end(),
- i) != ops_with_result.end()) {
- CHECK(not res.result->empty());
+ for ([[maybe_unused]] auto j = REPEATS; j > 0; --j) {
+ crit_op_map.ConsumeAfterKeysReady(
+ &ts,
+ {GitOpKey{.params =
+ {
+ path_init_commit, // target_path
+ "", // git_hash
+ "", // branch
+ "Init commit" // message
+ },
+ .op_type = GitOpType::INITIAL_COMMIT},
+ GitOpKey{.params =
+ {
+ path_init_bare, // target_path
+ "", // git_hash
+ "", // branch
+ std::nullopt, // message
+ true // init_bare
+ },
+ .op_type = GitOpType::ENSURE_INIT},
+ GitOpKey{.params =
+ {
+ path_init_non_bare, // target_path
+ "", // git_hash
+ "", // branch
+ std::nullopt, // message
+ false // init_bare
+ },
+ .op_type = GitOpType::ENSURE_INIT},
+ GitOpKey{.params =
+ {
+ *path_keep_tag, // target_path
+ kRootCommit, // git_hash
+ "", // branch
+ "keep-commit" // message
+ },
+ .op_type = GitOpType::KEEP_TAG},
+ GitOpKey{.params =
+ {
+ *path_get_head_id, // target_path
+ "", // git_hash
+ "", // branch
+ },
+ .op_type = GitOpType::GET_HEAD_ID},
+ GitOpKey{.params =
+ {
+ *path_keep_tree, // target_path
+ kBazSymId, // git_hash
+ "", // branch
+ "keep-tree" // message
+ },
+ .op_type = GitOpType::KEEP_TREE}},
+ [&ops_all, &ops_with_result](auto const& values) {
+ // check operations
+ for (std::size_t const& i : ops_all) {
+ auto res = *values[i];
+ REQUIRE(res.git_cas);
+ REQUIRE(res.result);
+ if (std::find(ops_with_result.begin(),
+ ops_with_result.end(),
+ i) != ops_with_result.end()) {
+ CHECK(not res.result->empty());
+ }
}
- }
- },
- [&error, &error_msg](std::string const& msg, bool /*unused*/) {
- error = true;
- error_msg = msg;
- });
+ },
+ [&error, &error_msg](std::string const& msg,
+ bool /*unused*/) {
+ error = true;
+ error_msg = msg;
+ });
+ }
}
CHECK_FALSE(error);
CHECK(error_msg == "NONE");