summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPaul Cristian Sarbu <paul.cristian.sarbu@huawei.com>2023-03-21 14:58:54 +0100
committerPaul Cristian Sarbu <paul.cristian.sarbu@huawei.com>2023-03-23 09:50:42 +0100
commit12d0c288ea23e1bd7e0401223ba413bca3d94869 (patch)
treeb6e16385368863b11ba8656b7b651440c9f5783b /src
parent17143ed02545efab55c175db66a9e31db4cce0f0 (diff)
downloadjustbuild-12d0c288ea23e1bd7e0401223ba413bca3d94869.tar.gz
just-mr: Shell out to system Git for update commit from SSH remote...
...due to limitations in SSH support in libgit2. In this case, we simply execute 'git ls-remote <repo> [<branch>]' and then parse the output. Remote interogation requires no local repository, so it is an asynchronious operation by default.
Diffstat (limited to 'src')
-rw-r--r--src/other_tools/git_operations/git_repo_remote.cpp118
-rw-r--r--src/other_tools/git_operations/git_repo_remote.hpp13
-rw-r--r--src/other_tools/ops_maps/git_update_map.cpp22
-rw-r--r--src/other_tools/ops_maps/git_update_map.hpp1
4 files changed, 111 insertions, 43 deletions
diff --git a/src/other_tools/git_operations/git_repo_remote.cpp b/src/other_tools/git_operations/git_repo_remote.cpp
index 6cff2a82..ab9d7ce2 100644
--- a/src/other_tools/git_operations/git_repo_remote.cpp
+++ b/src/other_tools/git_operations/git_repo_remote.cpp
@@ -387,46 +387,106 @@ auto GitRepoRemote::FetchFromRemote(std::shared_ptr<git_config> cfg,
}
auto GitRepoRemote::UpdateCommitViaTmpRepo(
- std::filesystem::path const& tmp_repo_path,
+ std::filesystem::path const& tmp_dir,
std::string const& repo_url,
std::string const& branch,
+ std::vector<std::string> const& launcher,
anon_logger_ptr const& logger) const noexcept
-> std::optional<std::string> {
try {
- // preferably with a "fake" repository!
- if (not IsRepoFake()) {
- Logger::Log(LogLevel::Debug,
- "Commit update called on a real repository");
+ // check for internally supported protocols
+ if (IsSupported(repo_url)) {
+ // preferably with a "fake" repository!
+ if (not IsRepoFake()) {
+ Logger::Log(LogLevel::Debug,
+ "Commit update called on a real repository");
+ }
+ // create the temporary real repository
+ auto tmp_repo =
+ GitRepoRemote::InitAndOpen(tmp_dir, /*is_bare=*/true);
+ if (tmp_repo == std::nullopt) {
+ return std::nullopt;
+ }
+ // setup wrapped logger
+ auto wrapped_logger = std::make_shared<anon_logger_t>(
+ [logger](auto const& msg, bool fatal) {
+ (*logger)(
+ fmt::format(
+ "While doing commit update via tmp repo:\n{}", msg),
+ fatal);
+ });
+ // get the config of the correct target repo
+ auto cfg = GetConfigSnapshot();
+ if (cfg == nullptr) {
+ (*logger)(
+ fmt::format("retrieving config object in update commit "
+ "via tmp repo failed with:\n{}",
+ GitLastError()),
+ true /*fatal*/);
+ return std::nullopt;
+ }
+ return tmp_repo->GetCommitFromRemote(
+ cfg, repo_url, branch, wrapped_logger);
+ }
+ // default to shelling out to git for non-explicitly supported protocols
+ auto cmdline = launcher;
+ cmdline.insert(cmdline.end(), {"git", "ls-remote", repo_url, branch});
+ // set up the system command
+ SystemCommand system{repo_url};
+ auto const command_output =
+ system.Execute(cmdline,
+ {}, // default env
+ GetGitPath(), // which path is not actually relevant
+ tmp_dir);
+ // output file can be read anyway
+ std::string out_str{};
+ auto cmd_out = FileSystemManager::ReadFile(command_output->stdout_file);
+ if (cmd_out) {
+ out_str = *cmd_out;
}
- // create the temporary real repository
- auto tmp_repo =
- GitRepoRemote::InitAndOpen(tmp_repo_path, /*is_bare=*/true);
- if (tmp_repo == std::nullopt) {
+ // check for command failure
+ if (not command_output) {
+ std::string err_str{};
+ auto cmd_err =
+ FileSystemManager::ReadFile(command_output->stderr_file);
+
+ if (cmd_err) {
+ err_str = *cmd_err;
+ }
+ std::string output{};
+ if (!out_str.empty() || !err_str.empty()) {
+ output = fmt::format(" with output:\n{}{}", out_str, err_str);
+ }
+ (*logger)(fmt::format("List remote commits command {} failed{}",
+ nlohmann::json(cmdline).dump(),
+ output),
+ /*fatal=*/true);
return std::nullopt;
}
- // setup wrapped logger
- auto wrapped_logger = std::make_shared<anon_logger_t>(
- [logger](auto const& msg, bool fatal) {
- (*logger)(
- fmt::format("While doing commit update via tmp repo:\n{}",
- msg),
- fatal);
- });
- // get the config of the correct target repo
- auto cfg = GetConfigSnapshot();
- if (cfg == nullptr) {
- (*logger)(fmt::format("retrieving config object in update commit "
- "via tmp repo failed with:\n{}",
- GitLastError()),
- true /*fatal*/);
+ // report failure to read generated output file or the file is empty
+ if (out_str.empty()) {
+ (*logger)(fmt::format("List remote commits command {} failed to "
+ "produce an output",
+ nlohmann::json(cmdline).dump()),
+ /*fatal=*/true);
+
return std::nullopt;
}
- return tmp_repo->GetCommitFromRemote(
- cfg, repo_url, branch, wrapped_logger);
+ // parse the output: it should contain two tab-separated columns,
+ // with the commit being the first entry
+ auto str_len = out_str.find('\t');
+ if (str_len == std::string::npos) {
+ (*logger)(fmt::format("List remote commits command {} produced "
+ "malformed output:\n{}",
+ out_str),
+ /*fatal=*/true);
+ return std::nullopt;
+ }
+ // success!
+ return out_str.substr(0, str_len);
} catch (std::exception const& ex) {
- Logger::Log(LogLevel::Error,
- "update commit via tmp repo failed with:\n{}",
- ex.what());
+ Logger::Log(
+ LogLevel::Error, "Update commit failed with:\n{}", ex.what());
return std::nullopt;
}
}
diff --git a/src/other_tools/git_operations/git_repo_remote.hpp b/src/other_tools/git_operations/git_repo_remote.hpp
index 64c827c4..9b68ada9 100644
--- a/src/other_tools/git_operations/git_repo_remote.hpp
+++ b/src/other_tools/git_operations/git_repo_remote.hpp
@@ -73,18 +73,21 @@ class GitRepoRemote : public GitRepo {
anon_logger_ptr const& logger) noexcept
-> bool;
- /// \brief Get commit from remote via a temporary repository.
- /// Calling it from a fake repository allows thread-safe use.
- /// Creates a temporary real repository at the given location and uses it to
- /// retrieve from the remote the commit of a branch given its name.
+ /// \brief Get commit from given branch on the remote. If URL is SSH, shells
+ /// out to system git to perform an ls-remote call, ensuring correct
+ /// handling of the remote connection settings (in particular proxy and
+ /// SSH). A temporary directory is needed to pipe the stdout and stderr to.
+ /// If URL is non-SSH, uses tmp dir to connect to remote and retrieve the
+ /// commit of a branch asynchronously using libgit2.
/// Caller needs to make sure the temporary directory exists and that the
/// given path is thread- and process-safe!
/// Returns the commit hash, as a string, or nullopt if failure.
/// It guarantees the logger is called exactly once with fatal if failure.
[[nodiscard]] auto UpdateCommitViaTmpRepo(
- std::filesystem::path const& tmp_repo_path,
+ std::filesystem::path const& tmp_dir,
std::string const& repo_url,
std::string const& branch,
+ std::vector<std::string> const& launcher,
anon_logger_ptr const& logger) const noexcept
-> std::optional<std::string>;
diff --git a/src/other_tools/ops_maps/git_update_map.cpp b/src/other_tools/ops_maps/git_update_map.cpp
index c4305e69..f096d3a9 100644
--- a/src/other_tools/ops_maps/git_update_map.cpp
+++ b/src/other_tools/ops_maps/git_update_map.cpp
@@ -21,13 +21,14 @@
#include "src/other_tools/just_mr/utils.hpp"
#include "src/utils/cpp/tmp_dir.hpp"
-auto CreateGitUpdateMap(GitCASPtr const& git_cas, std::size_t jobs)
- -> GitUpdateMap {
- auto update_commits = [git_cas](auto /* unused */,
- auto setter,
- auto logger,
- auto /* unused */,
- auto const& key) {
+auto CreateGitUpdateMap(GitCASPtr const& git_cas,
+ std::vector<std::string> const& launcher,
+ std::size_t jobs) -> GitUpdateMap {
+ auto update_commits = [git_cas, launcher](auto /* unused */,
+ auto setter,
+ auto logger,
+ auto /* unused */,
+ auto const& key) {
// perform git update commit
auto git_repo = GitRepoRemote::Open(git_cas); // wrap the tmp odb
if (not git_repo) {
@@ -55,8 +56,11 @@ auto CreateGitUpdateMap(GitCASPtr const& git_cas, std::size_t jobs)
// update commit
auto id = fmt::format("{}:{}", key.first, key.second);
JustMRProgress::Instance().TaskTracker().Start(id);
- auto new_commit = git_repo->UpdateCommitViaTmpRepo(
- tmp_dir->GetPath(), key.first, key.second, wrapped_logger);
+ auto new_commit = git_repo->UpdateCommitViaTmpRepo(tmp_dir->GetPath(),
+ key.first,
+ key.second,
+ launcher,
+ wrapped_logger);
JustMRProgress::Instance().TaskTracker().Stop(id);
if (not new_commit) {
return;
diff --git a/src/other_tools/ops_maps/git_update_map.hpp b/src/other_tools/ops_maps/git_update_map.hpp
index d4804545..93a5da30 100644
--- a/src/other_tools/ops_maps/git_update_map.hpp
+++ b/src/other_tools/ops_maps/git_update_map.hpp
@@ -38,6 +38,7 @@ struct hash<StringPair> {
} // namespace std
[[nodiscard]] auto CreateGitUpdateMap(GitCASPtr const& git_cas,
+ std::vector<std::string> const& launcher,
std::size_t jobs) -> GitUpdateMap;
#endif // INCLUDED_SRC_OTHER_TOOLS_OPS_MAPS_GIT_UPDATE_MAP_HPP \ No newline at end of file