summaryrefslogtreecommitdiff
path: root/src/other_tools/git_operations
diff options
context:
space:
mode:
authorPaul Cristian Sarbu <paul.cristian.sarbu@huawei.com>2022-11-17 10:21:26 +0100
committerPaul Cristian Sarbu <paul.cristian.sarbu@huawei.com>2022-12-21 14:42:19 +0100
commit84c4ae51a3f4aa60f08c576d955e200909798d7c (patch)
treec180df2e5c2bdd2559486d3a1a9b3261eb1d60bc /src/other_tools/git_operations
parent341a001d336025ea769c9d397a1fd82f753136ea (diff)
downloadjustbuild-84c4ae51a3f4aa60f08c576d955e200909798d7c.tar.gz
Just-MR: Add logic for critical git ops
Diffstat (limited to 'src/other_tools/git_operations')
-rw-r--r--src/other_tools/git_operations/TARGETS14
-rw-r--r--src/other_tools/git_operations/git_operations.cpp178
-rw-r--r--src/other_tools/git_operations/git_operations.hpp65
3 files changed, 257 insertions, 0 deletions
diff --git a/src/other_tools/git_operations/TARGETS b/src/other_tools/git_operations/TARGETS
index c016d1dd..ac41c117 100644
--- a/src/other_tools/git_operations/TARGETS
+++ b/src/other_tools/git_operations/TARGETS
@@ -6,4 +6,18 @@
[["src/buildtool/file_system", "git_cas"], ["src/utils/cpp", "path"]]
, "stage": ["src", "other_tools", "git_operations"]
}
+, "git_operations":
+ { "type": ["@", "rules", "CC", "library"]
+ , "name": ["git_operations"]
+ , "hdrs": ["git_operations.hpp"]
+ , "srcs": ["git_operations.cpp"]
+ , "deps":
+ [["src/buildtool/multithreading", "async_map_consumer"], "git_ops_types"]
+ , "stage": ["src", "other_tools", "git_operations"]
+ , "private-deps":
+ [ ["src/buildtool/file_system", "file_system_manager"]
+ , ["src/buildtool/file_system", "git_repo"]
+ , ["src/buildtool/logging", "logging"]
+ ]
+ }
}
diff --git a/src/other_tools/git_operations/git_operations.cpp b/src/other_tools/git_operations/git_operations.cpp
new file mode 100644
index 00000000..2b519691
--- /dev/null
+++ b/src/other_tools/git_operations/git_operations.cpp
@@ -0,0 +1,178 @@
+// Copyright 2022 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/other_tools/git_operations/git_operations.hpp"
+
+#include <vector>
+
+#include "src/buildtool/file_system/file_system_manager.hpp"
+#include "src/buildtool/file_system/git_repo.hpp"
+#include "src/buildtool/logging/logger.hpp"
+
+auto CriticalGitOps::GitInitialCommit(GitOpParams const& crit_op_params,
+ AsyncMapConsumerLoggerPtr const& logger)
+ -> GitOpValue {
+ // Create and open a GitRepo at given target location
+ auto git_repo =
+ GitRepo::InitAndOpen(crit_op_params.target_path, /*is_bare=*/false);
+ if (git_repo == std::nullopt) {
+ (*logger)(fmt::format("could not initialize git repository {}",
+ crit_op_params.target_path.string()),
+ true /*fatal*/);
+ return GitOpValue({nullptr, std::nullopt});
+ }
+ // setup wrapped logger
+ auto wrapped_logger = std::make_shared<AsyncMapConsumerLogger>(
+ [&logger](auto const& msg, bool fatal) {
+ (*logger)(
+ fmt::format("While doing initial commit Git op:\n{}", msg),
+ fatal);
+ });
+ // Stage and commit all at the target location
+ auto commit_hash = git_repo->StageAndCommitAllAnonymous(
+ crit_op_params.message.value(), wrapped_logger);
+ if (commit_hash == std::nullopt) {
+ return GitOpValue({nullptr, std::nullopt});
+ }
+ // success
+ return GitOpValue({git_repo->GetGitCAS(), commit_hash.value()});
+}
+
+auto CriticalGitOps::GitEnsureInit(GitOpParams const& crit_op_params,
+ AsyncMapConsumerLoggerPtr const& logger)
+ -> GitOpValue {
+ // Make sure folder we want to access exists
+ if (not FileSystemManager::CreateDirectory(crit_op_params.target_path)) {
+ (*logger)(fmt::format("target directory {} could not be created",
+ crit_op_params.target_path.string()),
+ true /*fatal*/);
+ return GitOpValue({nullptr, std::nullopt});
+ }
+ // Create and open a GitRepo at given target location
+ auto git_repo =
+ GitRepo::InitAndOpen(crit_op_params.target_path,
+ /*is_bare=*/crit_op_params.init_bare.value());
+ if (git_repo == std::nullopt) {
+ (*logger)(
+ fmt::format("could not initialize {} git repository {}",
+ crit_op_params.init_bare.value() ? "bare" : "non-bare",
+ crit_op_params.target_path.string()),
+ true /*fatal*/);
+ return GitOpValue({nullptr, std::nullopt});
+ }
+ // success
+ return GitOpValue({git_repo->GetGitCAS(), ""});
+}
+
+auto CriticalGitOps::GitKeepTag(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 GitOpValue({nullptr, std::nullopt});
+ }
+ // Open a GitRepo at given location
+ auto git_repo = GitRepo::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 GitOpValue({nullptr, std::nullopt});
+ }
+ // setup wrapped logger
+ auto wrapped_logger = std::make_shared<AsyncMapConsumerLogger>(
+ [&logger](auto const& msg, bool fatal) {
+ (*logger)(fmt::format("While doing keep tag Git op:\n{}", msg),
+ fatal);
+ });
+ // Create tag of given commit
+ if (not git_repo->KeepTag(crit_op_params.git_hash,
+ crit_op_params.message.value(),
+ wrapped_logger)) {
+ return GitOpValue({nullptr, std::nullopt});
+ }
+ // success
+ return GitOpValue({git_repo->GetGitCAS(), ""});
+}
+
+auto CriticalGitOps::GitGetHeadId(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 GitOpValue({nullptr, std::nullopt});
+ }
+ // Open a GitRepo at given location
+ auto git_repo = GitRepo::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 GitOpValue({nullptr, std::nullopt});
+ }
+ // setup wrapped logger
+ auto wrapped_logger = std::make_shared<AsyncMapConsumerLogger>(
+ [&logger](auto const& msg, bool fatal) {
+ (*logger)(fmt::format("While doing get HEAD id Git op:\n{}", msg),
+ fatal);
+ });
+ // Get head commit
+ auto head_commit = git_repo->GetHeadCommit(wrapped_logger);
+ if (head_commit == std::nullopt) {
+ return GitOpValue({nullptr, std::nullopt});
+ }
+ // success
+ return GitOpValue({git_repo->GetGitCAS(), *head_commit});
+}
+
+auto CriticalGitOps::GitGetBranchRefname(
+ 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 GitOpValue{nullptr, std::nullopt};
+ }
+ // Open a GitRepo at given location
+ auto git_repo = GitRepo::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 GitOpValue{nullptr, std::nullopt};
+ }
+ // setup wrapped logger
+ auto wrapped_logger = std::make_shared<AsyncMapConsumerLogger>(
+ [&logger](auto const& msg, bool fatal) {
+ (*logger)(
+ fmt::format("While doing get branch refname Git op:\n{}", msg),
+ fatal);
+ });
+ // Get branch refname
+ auto branch_refname =
+ git_repo->GetBranchLocalRefname(crit_op_params.branch, wrapped_logger);
+ if (branch_refname == std::nullopt) {
+ return GitOpValue{nullptr, std::nullopt};
+ }
+ // success
+ return GitOpValue{git_repo->GetGitCAS(), *branch_refname};
+}
diff --git a/src/other_tools/git_operations/git_operations.hpp b/src/other_tools/git_operations/git_operations.hpp
new file mode 100644
index 00000000..a7b7f61a
--- /dev/null
+++ b/src/other_tools/git_operations/git_operations.hpp
@@ -0,0 +1,65 @@
+// Copyright 2022 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 INCLUDED_SRC_OTHER_TOOLS_GIT_OPERATIONS_GIT_OPERATIONS_HPP
+#define INCLUDED_SRC_OTHER_TOOLS_GIT_OPERATIONS_GIT_OPERATIONS_HPP
+
+#include "src/buildtool/multithreading/async_map_consumer.hpp"
+#include "src/other_tools/git_operations/git_ops_types.hpp"
+
+/// \brief Class defining the critical Git operations, i.e., those which write
+/// to the underlying Git ODB.
+/// The target_path is a mandatory argument, as it is used in a file locking
+/// mechanism, ensuring only one process at a time works on a particular
+/// repository on the file system.
+class CriticalGitOps {
+ public:
+ // This operations needs the params: target_path, message
+ // Will perform: "git init && git add . && git commit -m <message>".
+ // Called to setup first commit in new repository. Assumes folder exists.
+ // It guarantees the logger is called exactly once with fatal if failure.
+ [[nodiscard]] static auto GitInitialCommit(
+ GitOpParams const& crit_op_params,
+ AsyncMapConsumerLoggerPtr const& logger) -> GitOpValue;
+
+ // This operation needs the params: target_path
+ // Called to initialize a repository. Creates folder if not there.
+ // It guarantees the logger is called exactly once with fatal if failure.
+ [[nodiscard]] static auto GitEnsureInit(
+ GitOpParams const& crit_op_params,
+ AsyncMapConsumerLoggerPtr const& logger) -> GitOpValue;
+
+ // This operation needs the params: target_path, git_hash (commit), message
+ // Called after a git fetch to retain the commit. Assumes folder exists.
+ // It guarantees the logger is called exactly once with fatal if failure.
+ [[nodiscard]] static auto GitKeepTag(
+ GitOpParams const& crit_op_params,
+ AsyncMapConsumerLoggerPtr const& logger) -> GitOpValue;
+
+ // This operations needs the params: target_path
+ // Called to retrieve the HEAD commit hash. Assumes folder exists.
+ // It guarantees the logger is called exactly once with fatal if failure.
+ [[nodiscard]] static auto GitGetHeadId(
+ GitOpParams const& crit_op_params,
+ AsyncMapConsumerLoggerPtr const& logger) -> GitOpValue;
+
+ // This operation needs the params: target_path, branch
+ // Called to retrieve the refname of a local branch. Assumes folder exists.
+ // It guarantees the logger is called exactly once with fatal if failure.
+ [[nodiscard]] static auto GitGetBranchRefname(
+ 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