summaryrefslogtreecommitdiff
path: root/src/other_tools/git_operations/git_repo_remote.cpp
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/other_tools/git_operations/git_repo_remote.cpp
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/other_tools/git_operations/git_repo_remote.cpp')
-rw-r--r--src/other_tools/git_operations/git_repo_remote.cpp118
1 files changed, 89 insertions, 29 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;
}
}