diff options
author | Paul Cristian Sarbu <paul.cristian.sarbu@huawei.com> | 2022-11-17 10:21:26 +0100 |
---|---|---|
committer | Paul Cristian Sarbu <paul.cristian.sarbu@huawei.com> | 2022-12-21 14:42:19 +0100 |
commit | 84c4ae51a3f4aa60f08c576d955e200909798d7c (patch) | |
tree | c180df2e5c2bdd2559486d3a1a9b3261eb1d60bc /src | |
parent | 341a001d336025ea769c9d397a1fd82f753136ea (diff) | |
download | justbuild-84c4ae51a3f4aa60f08c576d955e200909798d7c.tar.gz |
Just-MR: Add logic for critical git ops
Diffstat (limited to 'src')
-rw-r--r-- | src/other_tools/git_operations/TARGETS | 14 | ||||
-rw-r--r-- | src/other_tools/git_operations/git_operations.cpp | 178 | ||||
-rw-r--r-- | src/other_tools/git_operations/git_operations.hpp | 65 |
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 |