LCOV - code coverage report
Current view: top level - src/esys/repo - githelper.cpp (source / functions) Hit Total Coverage
Test: esysrepo_coverage.info Lines: 367 485 75.7 %
Date: 2026-09-26 15:38:18 Functions: 52 62 83.9 %

          Line data    Source code
       1             : /*!
       2             :  * \file esys/repo/githelper.cpp
       3             :  * \brief
       4             :  *
       5             :  * \cond
       6             :  * __legal_b__
       7             :  *
       8             :  * Copyright (c) 2020-2023 Michel Gillet
       9             :  * Distributed under the MIT License.
      10             :  * (See accompanying file LICENSE.txt or
      11             :  * copy at https://opensource.org/licenses/MIT)
      12             :  *
      13             :  * __legal_e__
      14             :  * \endcond
      15             :  *
      16             :  */
      17             : 
      18             : #include "esys/repo/esysrepo_prec.h"
      19             : #include "esys/repo/githelper.h"
      20             : #include "esys/repo/filesystem.h"
      21             : 
      22             : #include <esys/log/consolelockguard.h>
      23             : 
      24             : #include <esys/trace/call.h>
      25             : #include <esys/trace/macros.h>
      26             : 
      27             : #include <boost/filesystem.hpp>
      28             : 
      29             : #include <chrono>
      30             : #include <cctype>
      31             : #include <cstdlib>
      32             : #include <optional>
      33             : #include <sstream>
      34             : #include <thread>
      35             : #include <iostream>
      36             : 
      37             : namespace
      38             : {
      39             : 
      40             : class PhaseTimer
      41             : {
      42             : public:
      43         491 :     explicit PhaseTimer(uint64_t &slot)
      44         491 :         : m_slot(slot)
      45         491 :         , m_start(std::chrono::steady_clock::now())
      46             :     {
      47             :     }
      48             : 
      49         491 :     ~PhaseTimer()
      50             :     {
      51         982 :         m_slot += static_cast<uint64_t>(
      52         491 :             std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - m_start).count());
      53         491 :     }
      54             : 
      55             :     PhaseTimer(const PhaseTimer &) = delete;
      56             :     PhaseTimer &operator=(const PhaseTimer &) = delete;
      57             : 
      58             : private:
      59             :     uint64_t &m_slot;
      60             :     std::chrono::steady_clock::time_point m_start;
      61             : };
      62             : 
      63             : } // namespace
      64             : 
      65             : namespace std
      66             : {
      67             : 
      68             : static ostream &operator<<(ostream &os, const vector<string> &strings)
      69             : {
      70             :     os << "{" << std::endl;
      71             : 
      72             :     for (auto idx = 0; idx < strings.size(); ++idx)
      73             :     {
      74             :         if (idx != 0) os << "," << std::endl;
      75             :         os << "    " << strings[idx];
      76             :     }
      77             :     os << std::endl << "}";
      78             :     return os;
      79             : }
      80             : 
      81             : } // namespace std
      82             : 
      83             : namespace esys::repo
      84             : {
      85             : 
      86         292 : GitHelper::GitHelper(std::shared_ptr<GitBase> git, std::shared_ptr<Logger_if> log_if, int repo_idx)
      87             :     : log::User()
      88         584 :     , m_git(git)
      89         582 :     , m_repo_idx(repo_idx)
      90             : {
      91         582 :     set_logger_if(log_if);
      92         292 : }
      93             : 
      94         292 : GitHelper::~GitHelper()
      95             : {
      96         382 :     if (get_auto_close() && get_git() && get_git()->is_open()) close_on_error(log::Level::DEBUG);
      97         584 : }
      98             : 
      99         317 : void GitHelper::debug(int level, const std::string &msg)
     100             : {
     101         317 :     std::ostringstream oss;
     102             : 
     103         317 :     init_oss(oss, msg);
     104             : 
     105         317 :     clean_cout();
     106         317 :     log::User::debug(level, oss.str());
     107         317 :     init_oss_clear();
     108         317 : }
     109             : 
     110           9 : void GitHelper::info(const std::string &msg)
     111             : {
     112           9 :     std::ostringstream oss;
     113             : 
     114           9 :     init_oss(oss, msg);
     115             : 
     116           9 :     clean_cout();
     117           9 :     log::User::info(oss.str());
     118           9 :     init_oss_clear();
     119           9 : }
     120             : 
     121          23 : void GitHelper::warn(const std::string &msg)
     122             : {
     123          23 :     std::ostringstream oss;
     124             : 
     125          23 :     init_oss(oss, msg);
     126             : 
     127          23 :     clean_cout();
     128          23 :     log::User::warn(oss.str());
     129          23 :     init_oss_clear();
     130          23 : }
     131             : 
     132          10 : void GitHelper::error(const std::string &msg)
     133             : {
     134          10 :     std::ostringstream oss;
     135             : 
     136          10 :     init_oss(oss, msg);
     137             : 
     138          10 :     clean_cout();
     139          10 :     log::User::error(oss.str());
     140          10 :     init_oss_clear();
     141          10 : }
     142             : 
     143           0 : void GitHelper::critical(const std::string &msg)
     144             : {
     145           0 :     std::ostringstream oss;
     146             : 
     147           0 :     init_oss(oss, msg);
     148             : 
     149           0 :     clean_cout();
     150           0 :     log::User::critical(oss.str());
     151           0 :     init_oss_clear();
     152           0 : }
     153             : 
     154           0 : void GitHelper::log(log::Level level, const std::string &msg)
     155             : {
     156           0 :     std::ostringstream oss;
     157             : 
     158           0 :     init_oss(oss, msg);
     159             : 
     160           0 :     clean_cout();
     161           0 :     log::User::log(level, oss.str());
     162           0 :     init_oss_clear();
     163           0 : }
     164             : 
     165        1633 : void GitHelper::log(const std::string &msg, log::Level level, int debug_level)
     166             : {
     167        1633 :     std::ostringstream oss;
     168             : 
     169        1633 :     init_oss(oss, msg);
     170             : 
     171        1633 :     clean_cout();
     172        1633 :     log::User::log(oss.str(), level, debug_level);
     173        1633 :     init_oss_clear();
     174        1633 : }
     175             : 
     176           0 : void GitHelper::error(const std::string &msg, int result)
     177             : {
     178           0 :     std::ostringstream oss;
     179             : 
     180           0 :     init_oss(oss, msg);
     181             : 
     182           0 :     clean_cout();
     183           0 :     log::User::error(oss.str(), result);
     184           0 :     init_oss_clear();
     185           0 : }
     186             : 
     187         165 : void GitHelper::done(const std::string &msg, const std::string &rel_path, uint64_t elapsed_time)
     188             : {
     189         165 :     ETRC_CALL(msg, rel_path, elapsed_time);
     190             : 
     191         165 :     std::ostringstream oss;
     192             : 
     193         165 :     init_oss(oss, msg);
     194             : 
     195         165 :     oss << " done.\n";
     196         165 :     oss << "    path : " << rel_path << "\n";
     197         165 :     oss << "    elapsed time (s): " << (elapsed_time / THOUSAND) << "." << (elapsed_time % THOUSAND);
     198         165 :     clean_cout();
     199         165 :     log::User::info(oss.str());
     200         165 : }
     201             : 
     202             : namespace
     203             : {
     204             : std::optional<bool> g_phase_timing_override;
     205             : std::optional<bool> g_phase_timing_env_cached;
     206             : 
     207           1 : bool read_phase_timing_env()
     208             : {
     209           1 :     const char *value = std::getenv("ESYSREPO_SYNC_PHASE_TIMING");
     210           1 :     if (value == nullptr || value[0] == '\0') return false;
     211             : 
     212           0 :     std::string s(value);
     213           0 :     for (char &c : s) c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
     214           0 :     return s == "1" || s == "true" || s == "yes" || s == "on";
     215           1 : }
     216             : } // namespace
     217             : 
     218         197 : bool GitHelper::phase_timing_env_enabled()
     219             : {
     220         197 :     if (!g_phase_timing_env_cached.has_value()) g_phase_timing_env_cached = read_phase_timing_env();
     221         197 :     return *g_phase_timing_env_cached;
     222             : }
     223             : 
     224           0 : void GitHelper::set_phase_timing(std::optional<bool> enabled)
     225             : {
     226           0 :     g_phase_timing_override = enabled;
     227           0 : }
     228             : 
     229           0 : std::optional<bool> GitHelper::get_phase_timing()
     230             : {
     231           0 :     return g_phase_timing_override;
     232             : }
     233             : 
     234         197 : bool GitHelper::phase_timing_enabled()
     235             : {
     236         197 :     if (g_phase_timing_override.has_value()) return *g_phase_timing_override;
     237         197 :     return phase_timing_env_enabled();
     238             : }
     239             : 
     240         152 : const GitPhaseTimings &GitHelper::get_phase_timings() const
     241             : {
     242         152 :     return m_phase_timings;
     243             : }
     244             : 
     245         152 : void GitHelper::log_phase_summary()
     246             : {
     247         152 :     if (!phase_timing_enabled()) return;
     248           0 :     if (m_phase_timings.total_ms() == 0 && m_phase_timings.refresh_ms == 0) return;
     249           0 :     info(m_phase_timings.format());
     250             : }
     251             : 
     252         278 : void GitHelper::absorb_refresh_ms()
     253             : {
     254         556 :     if (get_git() == nullptr) return;
     255         556 :     m_phase_timings.refresh_ms += get_git()->take_last_refresh_ms();
     256             : }
     257             : 
     258         158 : Result GitHelper::open(const std::string &folder, log::Level log_level, int debug_level)
     259             : {
     260         158 :     Result result;
     261         158 :     ETRC_CALL_RET(result, folder, log_level, debug_level);
     262             : 
     263         316 :     boost::filesystem::path rel_folder = boost::filesystem::relative(folder);
     264             : 
     265         158 :     std::string msg = "Opening ...\n    path  : " + rel_folder.string();
     266             : 
     267         158 :     log(msg, log_level, debug_level);
     268             : 
     269         158 :     {
     270         158 :         PhaseTimer timer(m_phase_timings.open_ms);
     271         158 :         result = get_git()->open(rel_folder.string());
     272         158 :     }
     273         158 :     if (result.error()) error("Failed with error ", result.get_result_code_int());
     274         474 :     return ETRC_RET(ESYSREPO_RESULT(result));
     275         158 : }
     276             : 
     277          27 : Result GitHelper::clone(const std::string &url, const std::string &path, bool do_close, log::Level log_level,
     278             :                         int debug_level)
     279             : {
     280          27 :     Result result;
     281          27 :     ETRC_CALL_RET(result, url, path, do_close, log_level, debug_level);
     282             :     /*boost::filesystem::path rel_path = boost::filesystem::relative(path);
     283             : 
     284             :     std::string msg = "Cloning ...\n    url  : " + url + "\n    path : " + rel_path.string();
     285             : 
     286             :     log(msg, log_level, debug_level);
     287             : 
     288             :     int result = get_git()->clone(url, path);
     289             :     if (result < 0)
     290             :         error("Failed with error ", result);
     291             :     else
     292             :         done("Cloning", get_git()->get_last_cmd_elapsed_time());
     293             :     if (!do_close) return result;
     294             :     return close(log::Level::DEBUG);*/
     295          27 :     result = clone_rev(url, "", path, do_close, log_level, debug_level);
     296          81 :     return ETRC_RET(ESYSREPO_RESULT(result));
     297          27 : }
     298             : 
     299          31 : void GitHelper::cleanup_failed_clone(const std::string &path)
     300             : {
     301          31 :     close_on_error(log::Level::DEBUG);
     302          93 :     if (path.empty() || !boost::filesystem::exists(path)) return;
     303             : 
     304           0 :     boost::system::error_code ec;
     305           0 :     boost::filesystem::remove_all(path, ec);
     306           0 :     if (ec)
     307             :     {
     308           0 :         std::ostringstream oss;
     309           0 :         oss << "Failed to remove partial clone path '" << path << "': " << ec.message();
     310           0 :         warn(oss.str());
     311           0 :     }
     312             : }
     313             : 
     314         158 : Result GitHelper::clone_rev(const std::string &url, const std::string &rev, const std::string &path, bool do_close,
     315             :                             log::Level log_level, int debug_level, const git::CloneOptions &options)
     316             : {
     317         158 :     Result result;
     318         158 :     ETRC_CALL_RET(result, url, rev, path, do_close, log_level, debug_level);
     319             : 
     320         316 :     boost::filesystem::path rel_path = boost::filesystem::relative(path);
     321             : 
     322         158 :     std::string msg = "Cloning ...\n    path : " + rel_path.string();
     323         262 :     if (options.checkout_rev && !rev.empty()) msg += "\n    rev  : " + rev;
     324         158 :     if (options.checkout_rev && options.single_branch) msg += "\n    single-branch";
     325         316 :     msg += "\n    url  : " + url;
     326             : 
     327         158 :     log(msg, log_level, debug_level);
     328             : 
     329         158 :     const int attempts = get_attempts() < 1 ? 1 : get_attempts();
     330         189 :     for (int attempt = 1; attempt <= attempts; ++attempt)
     331             :     {
     332         179 :         const uint64_t clone_ms_before = m_phase_timings.clone_ms;
     333         179 :         {
     334         179 :             PhaseTimer timer(m_phase_timings.clone_ms);
     335         179 :             result = get_git()->clone(url, path, rev, options);
     336         179 :         }
     337         179 :         absorb_refresh_ms();
     338         179 :         if (result.ok())
     339             :         {
     340         148 :             done("Cloning", rel_path.string(), m_phase_timings.clone_ms - clone_ms_before);
     341         148 :             break;
     342             :         }
     343             : 
     344          31 :         std::ostringstream oss;
     345          31 :         oss << "Failed to clone (attempt " << attempt << "/" << attempts << "): " << result;
     346          31 :         if (attempt < attempts)
     347             :         {
     348          21 :             warn(oss.str());
     349          21 :             cleanup_failed_clone(path);
     350          21 :             std::this_thread::sleep_for(std::chrono::milliseconds(get_retry_delay_ms()));
     351             :         }
     352             :         else
     353             :         {
     354          10 :             error(oss.str());
     355          10 :             cleanup_failed_clone(path);
     356             :         }
     357          31 :     }
     358             : 
     359         314 :     if (!do_close) return ETRC_RET(ESYSREPO_RESULT(result));
     360           2 :     if (result.error()) return ETRC_RET(ESYSREPO_RESULT(result));
     361           4 :     return ETRC_RET(ESYSREPO_RESULT(close(log::Level::DEBUG)));
     362         158 : }
     363             : 
     364          17 : Result GitHelper::clone(const std::string &url, const std::string &temp_path, const std::string &path, bool do_close,
     365             :                         log::Level log_level, int debug_level)
     366             : {
     367          17 :     Result result;
     368          17 :     ETRC_CALL_RET(result, url, temp_path, path, do_close, log_level, debug_level);
     369             : 
     370          17 :     auto start_time = std::chrono::steady_clock::now();
     371             : 
     372          34 :     boost::filesystem::path rel_temp_path = boost::filesystem::relative(temp_path);
     373             : 
     374          17 :     if (boost::filesystem::exists(temp_path))
     375             :     {
     376           0 :         if (log_level == log::Level::DEBUG)
     377             :         {
     378           0 :             std::ostringstream oss;
     379             : 
     380           0 :             init_oss(oss);
     381           0 :             oss << "Remove all: " << rel_temp_path.string();
     382             : 
     383           0 :             int result = log_wrap(boost_no_all::remove_all, log::Level::DEBUG)(oss.str(), temp_path);
     384           0 :             if (result < 0)
     385             :             {
     386           0 :                 std::string err_str = "Failed to remove all : " + rel_temp_path.string();
     387           0 :                 error(err_str);
     388           0 :                 return ETRC_RET(ESYSREPO_RESULT(ResultCode::RAW_INT_ERROR, result, err_str));
     389           0 :             }
     390           0 :         }
     391             :         else
     392             :         {
     393           0 :             int result = boost_no_all::remove_all(temp_path);
     394           0 :             if (result < 0)
     395             :             {
     396           0 :                 std::string err_str = "Failed to delete path : " + temp_path;
     397           0 :                 error(err_str);
     398           0 :                 return ETRC_RET(ESYSREPO_RESULT(ResultCode::RAW_INT_ERROR, result, err_str));
     399           0 :             }
     400             :         }
     401             :     }
     402             : 
     403          17 :     std::string clone_msg;
     404          34 :     boost::filesystem::path rel_path = boost::filesystem::relative(path);
     405             : 
     406          17 :     clone_msg = "Cloning ...\n    path : " + rel_path.string() + "\n    url  : " + url;
     407          17 :     log(clone_msg, log::Level::INFO);
     408             : 
     409          17 :     if (log_level == log::Level::DEBUG)
     410             :     {
     411           0 :         clone_msg = "Cloning ...\n    path : " + rel_temp_path.string() + "\n    url  : " + url;
     412           0 :         log(clone_msg, log::Level::DEBUG);
     413             :     }
     414             : 
     415          17 :     const int attempts = get_attempts() < 1 ? 1 : get_attempts();
     416          17 :     for (int attempt = 1; attempt <= attempts; ++attempt)
     417             :     {
     418          17 :         {
     419          17 :             PhaseTimer timer(m_phase_timings.clone_ms);
     420          17 :             result = get_git()->clone(url, temp_path);
     421          17 :         }
     422          17 :         absorb_refresh_ms();
     423          17 :         if (result.ok()) break;
     424             : 
     425           0 :         std::ostringstream oss;
     426           0 :         oss << "Failed to clone (attempt " << attempt << "/" << attempts << "): " << result;
     427           0 :         if (attempt < attempts)
     428             :         {
     429           0 :             warn(oss.str());
     430           0 :             cleanup_failed_clone(temp_path);
     431           0 :             std::this_thread::sleep_for(std::chrono::milliseconds(get_retry_delay_ms()));
     432             :         }
     433             :         else
     434             :         {
     435           0 :             error(oss.str());
     436           0 :             cleanup_failed_clone(temp_path);
     437           0 :             return ETRC_RET(ESYSREPO_RESULT(result));
     438             :         }
     439           0 :     }
     440             : 
     441          17 :     if (do_close) close_on_error(log::Level::DEBUG);
     442             : 
     443          17 :     if (log_level == log::Level::DEBUG)
     444             :     {
     445           0 :         std::ostringstream oss;
     446             : 
     447           0 :         init_oss(oss);
     448           0 :         oss << "Move:\n    src  : " << rel_temp_path.string() << "\n    dest : " << rel_path.string();
     449             : 
     450           0 :         int result = log_wrap(boost_no_all::move, log::Level::DEBUG)(oss.str(), temp_path, path, true);
     451           0 :         if (result < 0) return ETRC_RET(ESYSREPO_RESULT(ResultCode::RAW_INT_ERROR, result));
     452           0 :     }
     453             :     else
     454             :     {
     455          17 :         int result = boost_no_all::move(temp_path, path, true);
     456          17 :         if (result == -1)
     457             :         {
     458           0 :             std::string err_str = "Failed to copy from temp_path to path : " + temp_path + " -> " + path;
     459           0 :             error(err_str);
     460           0 :             return ETRC_RET(ESYSREPO_RESULT(ResultCode::RAW_INT_ERROR, result, err_str));
     461           0 :         }
     462          17 :         else if (result == -2)
     463           0 :             warn("Failed to delete temp_path : " + temp_path);
     464             :     }
     465          17 :     auto stop_time = std::chrono::steady_clock::now();
     466          17 :     auto d_milli = std::chrono::duration_cast<std::chrono::milliseconds>(stop_time - start_time).count();
     467             : 
     468          17 :     done("Cloning", rel_path.string(), static_cast<uint64_t>(d_milli));
     469          34 :     return ETRC_RET(ESYSREPO_RESULT(ResultCode::OK));
     470          34 : }
     471             : 
     472         272 : Result GitHelper::close(log::Level log_level, int debug_level)
     473             : {
     474         272 :     Result result;
     475         272 :     ETRC_CALL_RET(result, log_level, debug_level);
     476             : 
     477         544 :     if (!get_git()->is_open()) return ETRC_RET(ESYSREPO_RESULT(ResultCode::OK));
     478             : 
     479         272 :     log("Closing ...", log_level, debug_level);
     480             : 
     481         272 :     result = get_git()->close();
     482         272 :     std::string err_str;
     483         272 :     if (result.error())
     484             :     {
     485           0 :         err_str = "Close git repo failed with error ";
     486           0 :         error("Close git repo failed with error ", result.get_result_code_int());
     487             :     }
     488             :     else
     489         544 :         log("Closed.", log_level, debug_level);
     490             : 
     491         544 :     return ETRC_RET(ESYSREPO_RESULT(result, err_str));
     492         272 : }
     493             : 
     494          70 : void GitHelper::close_on_error(log::Level log_level, int debug_level)
     495             : {
     496         140 :     if (!get_git()->is_open())
     497             :     {
     498          31 :         log("Called instenal_close on not open repo ", log_level, debug_level);
     499          31 :         return;
     500             :     }
     501             : 
     502          39 :     log("Closing ...", log_level, debug_level);
     503             : 
     504          39 :     auto result = get_git()->close();
     505          39 :     std::string err_str;
     506          39 :     if (result.error())
     507             :     {
     508           0 :         error("Close git repo failed with error ", result.get_result_code_int());
     509             :     }
     510             :     else
     511          78 :         log("Closed.", log_level, debug_level);
     512          39 : }
     513             : 
     514           2 : Result GitHelper::fastforward(const git::CommitHash &commit, log::Level log_level, int debug_level)
     515             : {
     516           2 :     Result result;
     517           2 :     ETRC_CALL_RET(result, commit, log_level, debug_level);
     518             : 
     519           2 :     log("Fast forwarding ...", log_level, debug_level);
     520             : 
     521           2 :     {
     522           2 :         PhaseTimer timer(m_phase_timings.fastforward_ms);
     523           2 :         result = get_git()->fastforward(commit);
     524           2 :     }
     525           2 :     if (result.error())
     526           0 :         error("Failed with error ", result.get_result_code_int());
     527             :     else
     528           4 :         log("Fast forwarded successfully.", log_level, debug_level);
     529             : 
     530           6 :     return ETRC_RET(ESYSREPO_RESULT(result));
     531           2 : }
     532             : 
     533          82 : Result GitHelper::fetch(const std::string &remote, log::Level log_level, int debug_level)
     534             : {
     535          82 :     Result result;
     536          82 :     ETRC_CALL_RET(result, remote, log_level, debug_level);
     537             : 
     538          82 :     log("Fetching ...", log_level, debug_level);
     539             : 
     540          82 :     const int attempts = get_attempts() < 1 ? 1 : get_attempts();
     541          82 :     for (int attempt = 1; attempt <= attempts; ++attempt)
     542             :     {
     543          82 :         {
     544          82 :             PhaseTimer timer(m_phase_timings.fetch_ms);
     545          82 :             result = get_git()->fetch(remote);
     546          82 :         }
     547          82 :         absorb_refresh_ms();
     548          82 :         if (result.ok())
     549             :         {
     550          82 :             log("Fetched successfully.", log_level, debug_level);
     551          82 :             break;
     552             :         }
     553             : 
     554           0 :         std::ostringstream oss;
     555           0 :         oss << "Failed to fetch (attempt " << attempt << "/" << attempts << "): " << result;
     556           0 :         if (attempt < attempts)
     557             :         {
     558           0 :             warn(oss.str());
     559           0 :             std::this_thread::sleep_for(std::chrono::milliseconds(get_retry_delay_ms()));
     560             :         }
     561             :         else
     562             :         {
     563           0 :             error(oss.str());
     564             :         }
     565           0 :     }
     566             : 
     567         246 :     return ETRC_RET(ESYSREPO_RESULT(result));
     568          82 : }
     569             : 
     570          81 : Result GitHelper::fetch(log::Level log_level, int debug_level)
     571             : {
     572         162 :     return fetch("", log_level, debug_level);
     573             : }
     574             : 
     575           2 : Result GitHelper::fetch_refspec(const std::string &refspec, log::Level log_level, int debug_level)
     576             : {
     577           2 :     Result result;
     578           2 :     ETRC_CALL_RET(result, refspec, log_level, debug_level);
     579             : 
     580           4 :     log("Fetching " + refspec + " ...", log_level, debug_level);
     581           2 :     result = get_git()->fetch_refspec(refspec);
     582           2 :     if (result.error())
     583           0 :         log("Fetch refspec failed.", log::Level::DEBUG);
     584             :     else
     585           4 :         log("Fetched " + refspec + ".", log_level, debug_level);
     586           6 :     return ETRC_RET(ESYSREPO_RESULT(result));
     587           2 : }
     588             : 
     589          77 : Result GitHelper::get_branches(git::Branches &branches, git::BranchType branch_type, log::Level log_level,
     590             :                                int debug_level)
     591             : {
     592          77 :     Result result;
     593          77 :     ETRC_CALL_RET_BEGIN(result, branches, branch_type, log_level, debug_level);
     594          77 :     ETRC_CALL_RET_OUT_END(branches);
     595             : 
     596          77 :     log("Getting branches ...", log::Level::DEBUG);
     597          77 :     result = get_git()->get_branches(branches, branch_type);
     598          77 :     if (result.error())
     599           0 :         error("Failed with error ", result.get_result_code_int());
     600             :     else
     601         154 :         log("Got branches.", log::Level::DEBUG);
     602             : 
     603         231 :     return ETRC_RET(ESYSREPO_RESULT(result));
     604          77 : }
     605             : 
     606          33 : Result_t<bool> GitHelper::has_branch(const std::string &name, git::BranchType branch_type, log::Level log_level,
     607             :                                      int debug_level)
     608             : {
     609          33 :     Result_t<bool> result(false);
     610          33 :     ETRC_CALL_RET(result, name, branch_type, log_level, debug_level);
     611             : 
     612          66 :     log("Check branch existance " + name + " ...", log::Level::DEBUG);
     613          66 :     result = get_git()->has_branch(name, branch_type);
     614          33 :     if (result)
     615          26 :         log("Found it.", log::Level::DEBUG);
     616             :     else
     617          40 :         log("Not Found", log::Level::DEBUG);
     618          66 :     return ETRC_RET(ESYSREPO_RESULT_T(result));
     619          33 : }
     620             : 
     621          26 : Result GitHelper::get_hash(const std::string &revision, std::string &hash, log::Level log_level, int debug_level)
     622             : {
     623          26 :     Result result;
     624          26 :     ETRC_CALL_RET_BEGIN(result, revision, hash, log_level, debug_level);
     625          26 :     ETRC_CALL_RET_OUT_END(hash);
     626             : 
     627          52 :     log("Check remote hash for " + revision + " ...", log::Level::DEBUG);
     628          26 :     result = get_git()->get_hash(revision, hash, git::BranchType::REMOTE);
     629          26 :     if (result.ok())
     630          52 :         log("Found it.", log::Level::DEBUG);
     631             :     else
     632           0 :         log("Not Found", log::Level::DEBUG);
     633          78 :     return ETRC_RET(ESYSREPO_RESULT(result));
     634          26 : }
     635             : 
     636           0 : Result GitHelper::get_hash_local(const std::string &revision, std::string &hash, log::Level log_level, int debug_level)
     637             : {
     638           0 :     Result result;
     639           0 :     ETRC_CALL_RET_BEGIN(result, revision, hash, log_level, debug_level);
     640           0 :     ETRC_CALL_RET_OUT_END(hash);
     641             : 
     642           0 :     log("Check local hash for " + revision + " ...", log::Level::DEBUG);
     643           0 :     result = get_git()->get_hash(revision, hash, git::BranchType::LOCAL);
     644           0 :     if (result.ok())
     645           0 :         log("Found it.", log::Level::DEBUG);
     646             :     else
     647           0 :         log("Not Found", log::Level::DEBUG);
     648           0 :     return ETRC_RET(ESYSREPO_RESULT(result));
     649           0 : }
     650             : 
     651          38 : Result GitHelper::is_dirty(bool &dirty, log::Level log_level, int debug_level)
     652             : {
     653          38 :     Result result;
     654          38 :     ETRC_CALL_RET_BEGIN(result, dirty, log_level, debug_level);
     655          38 :     ETRC_CALL_RET_OUT_END(dirty);
     656             : 
     657          38 :     result = get_git()->is_dirty(dirty);
     658          38 :     if (result.error())
     659           0 :         error("Failed to check there are changes in the git repo.");
     660             :     else
     661             :     {
     662          38 :         if (dirty)
     663           0 :             log("Dirty git repo", log_level, debug_level);
     664             :         else
     665          76 :             log("No changes in the git repo", log_level, debug_level);
     666             :     }
     667         114 :     return ETRC_RET(ESYSREPO_RESULT(result));
     668          38 : }
     669             : 
     670          30 : Result GitHelper::is_detached(bool &detached, log::Level log_level, int debug_level)
     671             : {
     672          30 :     Result result;
     673          30 :     ETRC_CALL_RET_BEGIN(result, detached, log_level, debug_level);
     674          30 :     ETRC_CALL_RET_OUT_END(detached);
     675             : 
     676          30 :     result = get_git()->is_detached(detached);
     677          30 :     if (result.error())
     678           0 :         error("Failed to check if the git repo is detached or not.");
     679             :     else
     680             :     {
     681          30 :         if (detached)
     682           6 :             log("Git repo is detached", log_level, debug_level);
     683             :         else
     684          54 :             log("Git repo is not detached", log_level, debug_level);
     685             :     }
     686          90 :     return ETRC_RET(ESYSREPO_RESULT(result));
     687          30 : }
     688             : 
     689          30 : Result GitHelper::get_status(git::RepoStatus &status, log::Level log_level, int debug_level)
     690             : {
     691          30 :     Result result;
     692          30 :     ETRC_CALL_RET_BEGIN(result, status, log_level, debug_level);
     693          30 :     ETRC_CALL_RET_OUT_END(status);
     694             : 
     695          30 :     result = get_git()->get_status(status);
     696          30 :     if (result.error())
     697           0 :         error("Failed to get the repo status");
     698             :     else
     699          60 :         log("Succeeded to get repo status", log_level, debug_level);
     700             : 
     701          90 :     return ETRC_RET(ESYSREPO_RESULT(result));
     702          30 : }
     703             : 
     704          53 : Result GitHelper::checkout(const std::string &branch, bool force, log::Level log_level, int debug_level)
     705             : {
     706          53 :     Result result;
     707          53 :     ETRC_CALL_RET(result, branch, force, log_level, debug_level);
     708             : 
     709          53 :     {
     710          53 :         PhaseTimer timer(m_phase_timings.checkout_ms);
     711          53 :         result = get_git()->checkout(branch, force);
     712          53 :     }
     713          53 :     if (result.error())
     714           0 :         error("Failed to checkout");
     715             :     else
     716         106 :         log("Checkout succeeded", log_level, debug_level);
     717         159 :     return ETRC_RET(ESYSREPO_RESULT(result));
     718          53 : }
     719             : 
     720          27 : Result GitHelper::merge_analysis(const std::vector<std::string> &refs, git::MergeAnalysisResult &merge_analysis_result,
     721             :                                  std::vector<git::CommitHash> &commits, log::Level log_level, int debug_level)
     722             : {
     723          27 :     Result result;
     724          27 :     ETRC_CALL_RET_BEGIN(result, refs, merge_analysis_result, commits, log_level, debug_level);
     725          27 :     ETRC_CALL_RET_OUT_END(merge_analysis_result, commits);
     726             : 
     727          27 :     result = get_git()->merge_analysis(refs, merge_analysis_result, commits);
     728          27 :     if (result.error())
     729           0 :         error("Merge analysis failed");
     730             :     else
     731          54 :         log("Merge analysis succeeded", log_level, debug_level);
     732          81 :     return ETRC_RET(ESYSREPO_RESULT(result));
     733          27 : }
     734             : 
     735          25 : Result GitHelper::move(const std::string &src, const std::string &dst, bool recursive, log::Level log_level,
     736             :                        int debug_level)
     737             : {
     738          25 :     Result rresult;
     739          25 :     ETRC_CALL_RET(rresult, src, dst, recursive, log_level, debug_level);
     740             : 
     741          50 :     boost::filesystem::path abs_src = boost::filesystem::absolute(src);
     742          50 :     boost::filesystem::path abs_dst = boost::filesystem::absolute(dst);
     743          50 :     boost::filesystem::path rel_src = boost::filesystem::relative(abs_src);
     744          50 :     boost::filesystem::path rel_dst = boost::filesystem::relative(abs_dst);
     745          25 :     std::ostringstream oss;
     746             : 
     747          25 :     init_oss(oss);
     748          25 :     oss << "Move:\n    src  : " << rel_src.string() << "\n    dest : " << rel_dst.string();
     749             : 
     750             :     // Use absolute paths: relative paths break if cwd is not the workspace root, and
     751             :     // follow-copy of Git symlinks must operate on the real tree being installed.
     752          25 :     int result = log_wrap(boost_no_all::move, log_level)(oss.str(), abs_src.string(), abs_dst.string(), true);
     753          25 :     if (result == -1) return ETRC_RET(ESYSREPO_RESULT(ResultCode::FAILED_TO_COPY));
     754          25 :     if (result == -1) return ETRC_RET(ESYSREPO_RESULT(ResultCode::FAILED_TO_REMOVE_ALL));
     755          50 :     return ETRC_RET(ESYSREPO_RESULT(ResultCode::OK));
     756          25 : }
     757             : 
     758           2 : void GitHelper::set_git(std::shared_ptr<GitBase> git)
     759             : {
     760           2 :     m_git = git;
     761           2 : }
     762             : 
     763        2101 : std::shared_ptr<GitBase> GitHelper::get_git() const
     764             : {
     765        2101 :     return m_git.lock();
     766             : }
     767             : 
     768          32 : void GitHelper::set_auto_close(bool auto_close)
     769             : {
     770          32 :     m_auto_close = auto_close;
     771          32 : }
     772             : 
     773         292 : bool GitHelper::get_auto_close() const
     774             : {
     775         292 :     return m_auto_close;
     776             : }
     777             : 
     778           0 : void GitHelper::set_repo_idx(int repo_idx)
     779             : {
     780           0 :     m_repo_idx = repo_idx;
     781           0 : }
     782             : 
     783        3014 : int GitHelper::get_repo_idx() const
     784             : {
     785        3014 :     return m_repo_idx;
     786             : }
     787             : 
     788          13 : void GitHelper::set_display_repo_idx(bool display_repo_idx)
     789             : {
     790          13 :     m_display_repo_idx = display_repo_idx;
     791          13 : }
     792             : 
     793        1022 : bool GitHelper::get_display_repo_idx() const
     794             : {
     795        1022 :     return m_display_repo_idx;
     796             : }
     797             : 
     798           0 : void GitHelper::set_attempts(int attempts)
     799             : {
     800           0 :     m_attempts = attempts;
     801           0 : }
     802             : 
     803         514 : int GitHelper::get_attempts() const
     804             : {
     805         514 :     return m_attempts;
     806             : }
     807             : 
     808           0 : void GitHelper::set_retry_delay_ms(int retry_delay_ms)
     809             : {
     810           0 :     m_retry_delay_ms = retry_delay_ms;
     811           0 : }
     812             : 
     813          21 : int GitHelper::get_retry_delay_ms() const
     814             : {
     815          21 :     return m_retry_delay_ms;
     816             : }
     817             : 
     818        1992 : void GitHelper::init_oss_done()
     819             : {
     820        1992 :     m_init_oss_done = true;
     821        1992 : }
     822             : 
     823        1992 : void GitHelper::init_oss_clear()
     824             : {
     825        1992 :     m_init_oss_done = false;
     826        1992 : }
     827             : 
     828        2182 : bool GitHelper::is_init_oss_done()
     829             : {
     830        2182 :     return m_init_oss_done;
     831             : }
     832             : 
     833        2182 : void GitHelper::init_oss(std::ostringstream &oss)
     834             : {
     835        2182 :     if (is_init_oss_done()) return;
     836             : 
     837        3984 :     oss.str("");
     838        1992 :     if ((get_repo_idx() != -1) && (get_display_repo_idx())) oss << "[" << get_repo_idx() << "] ";
     839        1992 :     init_oss_done();
     840             : }
     841             : 
     842        2157 : void GitHelper::init_oss(std::ostringstream &oss, const std::string &msg)
     843             : {
     844        2157 :     init_oss(oss);
     845             : 
     846        2157 :     oss << msg;
     847        2157 : }
     848             : 
     849        2157 : void GitHelper::clean_cout()
     850             : {
     851        2157 :     log::ConsoleLockGuard<log::User> lock(this);
     852             : 
     853        2157 :     std::string s = "             ";
     854        2157 :     std::cout << "\r";
     855             : 
     856       19413 :     for (int idx = 0; idx < CLEAN_OUT_REPETITION; ++idx) std::cout << s;
     857        2157 :     std::cout << "\r";
     858        2157 : }
     859             : 
     860          27 : GitHelper::AutoClose::AutoClose(GitHelper *git_helper)
     861          27 :     : m_git_helper(git_helper)
     862             : {
     863          27 : }
     864             : 
     865          27 : GitHelper::AutoClose::~AutoClose()
     866             : {
     867          27 :     if (m_git_helper != nullptr) m_git_helper->close(log::Level::DEBUG);
     868          27 : }
     869             : 
     870             : } // namespace esys::repo

Generated by: LCOV version 1.14