LCOV - code coverage report
Current view: top level - src/esys/repo - githelper.cpp (source / functions) Hit Total Coverage
Test: esysrepo_coverage.info Lines: 333 473 70.4 %
Date: 2026-08-01 10:43:40 Functions: 48 61 78.7 %

          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         392 :     explicit PhaseTimer(uint64_t &slot)
      44         392 :         : m_slot(slot)
      45         392 :         , m_start(std::chrono::steady_clock::now())
      46             :     {
      47             :     }
      48             : 
      49         392 :     ~PhaseTimer()
      50             :     {
      51         784 :         m_slot += static_cast<uint64_t>(
      52         392 :             std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - m_start).count());
      53         392 :     }
      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         240 : GitHelper::GitHelper(std::shared_ptr<GitBase> git, std::shared_ptr<Logger_if> log_if, int repo_idx)
      87             :     : log::User()
      88         480 :     , m_git(git)
      89         478 :     , m_repo_idx(repo_idx)
      90             : {
      91         478 :     set_logger_if(log_if);
      92         240 : }
      93             : 
      94         240 : GitHelper::~GitHelper()
      95             : {
      96         330 :     if (get_auto_close() && get_git() && get_git()->is_open()) close_on_error(log::Level::DEBUG);
      97         480 : }
      98             : 
      99         135 : void GitHelper::debug(int level, const std::string &msg)
     100             : {
     101         135 :     std::ostringstream oss;
     102             : 
     103         135 :     init_oss(oss, msg);
     104             : 
     105         135 :     clean_cout();
     106         135 :     log::User::debug(level, oss.str());
     107         135 :     init_oss_clear();
     108         135 : }
     109             : 
     110           7 : void GitHelper::info(const std::string &msg)
     111             : {
     112           7 :     std::ostringstream oss;
     113             : 
     114           7 :     init_oss(oss, msg);
     115             : 
     116           7 :     clean_cout();
     117           7 :     log::User::info(oss.str());
     118           7 :     init_oss_clear();
     119           7 : }
     120             : 
     121           2 : void GitHelper::warn(const std::string &msg)
     122             : {
     123           2 :     std::ostringstream oss;
     124             : 
     125           2 :     init_oss(oss, msg);
     126             : 
     127           2 :     clean_cout();
     128           2 :     log::User::warn(oss.str());
     129           2 :     init_oss_clear();
     130           2 : }
     131             : 
     132           0 : void GitHelper::error(const std::string &msg)
     133             : {
     134           0 :     std::ostringstream oss;
     135             : 
     136           0 :     init_oss(oss, msg);
     137             : 
     138           0 :     clean_cout();
     139           0 :     log::User::error(oss.str());
     140           0 :     init_oss_clear();
     141           0 : }
     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        1247 : void GitHelper::log(const std::string &msg, log::Level level, int debug_level)
     166             : {
     167        1247 :     std::ostringstream oss;
     168             : 
     169        1247 :     init_oss(oss, msg);
     170             : 
     171        1247 :     clean_cout();
     172        1247 :     log::User::log(oss.str(), level, debug_level);
     173        1247 :     init_oss_clear();
     174        1247 : }
     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         134 : void GitHelper::done(const std::string &msg, const std::string &rel_path, uint64_t elapsed_time)
     188             : {
     189         134 :     ETRC_CALL(msg, rel_path, elapsed_time);
     190             : 
     191         134 :     std::ostringstream oss;
     192             : 
     193         134 :     init_oss(oss, msg);
     194             : 
     195         134 :     oss << " done.\n";
     196         134 :     oss << "    path : " << rel_path << "\n";
     197         134 :     oss << "    elapsed time (s): " << (elapsed_time / THOUSAND) << "." << (elapsed_time % THOUSAND);
     198         134 :     clean_cout();
     199         134 :     log::User::info(oss.str());
     200         134 : }
     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         154 : bool GitHelper::phase_timing_env_enabled()
     219             : {
     220         154 :     if (!g_phase_timing_env_cached.has_value()) g_phase_timing_env_cached = read_phase_timing_env();
     221         154 :     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         154 : bool GitHelper::phase_timing_enabled()
     235             : {
     236         154 :     if (g_phase_timing_override.has_value()) return *g_phase_timing_override;
     237         154 :     return phase_timing_env_enabled();
     238             : }
     239             : 
     240         120 : const GitPhaseTimings &GitHelper::get_phase_timings() const
     241             : {
     242         120 :     return m_phase_timings;
     243             : }
     244             : 
     245         120 : void GitHelper::log_phase_summary()
     246             : {
     247         120 :     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         201 : void GitHelper::absorb_refresh_ms()
     253             : {
     254         402 :     if (get_git() == nullptr) return;
     255         402 :     m_phase_timings.refresh_ms += get_git()->take_last_refresh_ms();
     256             : }
     257             : 
     258         123 : Result GitHelper::open(const std::string &folder, log::Level log_level, int debug_level)
     259             : {
     260         123 :     Result result;
     261         123 :     ETRC_CALL_RET(result, folder, log_level, debug_level);
     262             : 
     263         246 :     boost::filesystem::path rel_folder = boost::filesystem::relative(folder);
     264             : 
     265         123 :     std::string msg = "Opening ...\n    path  : " + rel_folder.string();
     266             : 
     267         123 :     log(msg, log_level, debug_level);
     268             : 
     269         123 :     {
     270         123 :         PhaseTimer timer(m_phase_timings.open_ms);
     271         123 :         result = get_git()->open(rel_folder.string());
     272         123 :     }
     273         123 :     if (result.error()) error("Failed with error ", result.get_result_code_int());
     274         369 :     return ETRC_RET(ESYSREPO_RESULT(result));
     275         123 : }
     276             : 
     277          22 : Result GitHelper::clone(const std::string &url, const std::string &path, bool do_close, log::Level log_level,
     278             :                         int debug_level)
     279             : {
     280          22 :     Result result;
     281          22 :     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          22 :     result = clone_rev(url, "", path, do_close, log_level, debug_level);
     296          66 :     return ETRC_RET(ESYSREPO_RESULT(result));
     297          22 : }
     298             : 
     299           0 : void GitHelper::cleanup_failed_clone(const std::string &path)
     300             : {
     301           0 :     close_on_error(log::Level::DEBUG);
     302           0 :     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         121 : 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         121 :     Result result;
     318         121 :     ETRC_CALL_RET(result, url, rev, path, do_close, log_level, debug_level);
     319             : 
     320         242 :     boost::filesystem::path rel_path = boost::filesystem::relative(path);
     321             : 
     322         121 :     std::string msg = "Cloning ...\n    path : " + rel_path.string();
     323         121 :     if (options.checkout_rev && !rev.empty()) msg += "\n    rev  : " + rev;
     324         121 :     if (options.checkout_rev && options.single_branch) msg += "\n    single-branch";
     325         242 :     msg += "\n    url  : " + url;
     326             : 
     327         121 :     log(msg, log_level, debug_level);
     328             : 
     329         121 :     const int attempts = get_attempts() < 1 ? 1 : get_attempts();
     330         121 :     for (int attempt = 1; attempt <= attempts; ++attempt)
     331             :     {
     332         121 :         const uint64_t clone_ms_before = m_phase_timings.clone_ms;
     333         121 :         {
     334         121 :             PhaseTimer timer(m_phase_timings.clone_ms);
     335         121 :             result = get_git()->clone(url, path, rev, options);
     336         121 :         }
     337         121 :         absorb_refresh_ms();
     338         121 :         if (result.ok())
     339             :         {
     340         121 :             done("Cloning", rel_path.string(), m_phase_timings.clone_ms - clone_ms_before);
     341         121 :             break;
     342             :         }
     343             : 
     344           0 :         std::ostringstream oss;
     345           0 :         oss << "Failed to clone (attempt " << attempt << "/" << attempts << "): " << result;
     346           0 :         if (attempt < attempts)
     347             :         {
     348           0 :             warn(oss.str());
     349           0 :             cleanup_failed_clone(path);
     350           0 :             std::this_thread::sleep_for(std::chrono::milliseconds(get_retry_delay_ms()));
     351             :         }
     352             :         else
     353             :         {
     354           0 :             error(oss.str());
     355           0 :             cleanup_failed_clone(path);
     356             :         }
     357           0 :     }
     358             : 
     359         240 :     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         121 : }
     363             : 
     364          13 : 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          13 :     Result result;
     368          13 :     ETRC_CALL_RET(result, url, temp_path, path, do_close, log_level, debug_level);
     369             : 
     370          13 :     auto start_time = std::chrono::steady_clock::now();
     371             : 
     372          26 :     boost::filesystem::path rel_temp_path = boost::filesystem::relative(temp_path);
     373             : 
     374          13 :     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          13 :     std::string clone_msg;
     404          26 :     boost::filesystem::path rel_path = boost::filesystem::relative(path);
     405             : 
     406          13 :     clone_msg = "Cloning ...\n    path : " + rel_path.string() + "\n    url  : " + url;
     407          13 :     log(clone_msg, log::Level::INFO);
     408             : 
     409          13 :     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          13 :     const int attempts = get_attempts() < 1 ? 1 : get_attempts();
     416          13 :     for (int attempt = 1; attempt <= attempts; ++attempt)
     417             :     {
     418          13 :         {
     419          13 :             PhaseTimer timer(m_phase_timings.clone_ms);
     420          13 :             result = get_git()->clone(url, temp_path);
     421          13 :         }
     422          13 :         absorb_refresh_ms();
     423          13 :         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          13 :     if (do_close) close_on_error(log::Level::DEBUG);
     442             : 
     443          13 :     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          13 :         int result = boost_no_all::move(temp_path, path, true);
     456          13 :         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          13 :         else if (result == -2)
     463           0 :             warn("Failed to delete temp_path : " + temp_path);
     464             :     }
     465          13 :     auto stop_time = std::chrono::steady_clock::now();
     466          13 :     auto d_milli = std::chrono::duration_cast<std::chrono::milliseconds>(stop_time - start_time).count();
     467             : 
     468          13 :     done("Cloning", rel_path.string(), static_cast<uint64_t>(d_milli));
     469          26 :     return ETRC_RET(ESYSREPO_RESULT(ResultCode::OK));
     470          26 : }
     471             : 
     472         172 : Result GitHelper::close(log::Level log_level, int debug_level)
     473             : {
     474         172 :     Result result;
     475         172 :     ETRC_CALL_RET(result, log_level, debug_level);
     476             : 
     477         344 :     if (!get_git()->is_open()) return ETRC_RET(ESYSREPO_RESULT(ResultCode::OK));
     478             : 
     479         172 :     log("Closing ...", log_level, debug_level);
     480             : 
     481         172 :     result = get_git()->close();
     482         172 :     std::string err_str;
     483         172 :     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         344 :         log("Closed.", log_level, debug_level);
     490             : 
     491         344 :     return ETRC_RET(ESYSREPO_RESULT(result, err_str));
     492         172 : }
     493             : 
     494          31 : void GitHelper::close_on_error(log::Level log_level, int debug_level)
     495             : {
     496          62 :     if (!get_git()->is_open())
     497             :     {
     498           0 :         log("Called instenal_close on not open repo ", log_level, debug_level);
     499           0 :         return;
     500             :     }
     501             : 
     502          31 :     log("Closing ...", log_level, debug_level);
     503             : 
     504          31 :     auto result = get_git()->close();
     505          31 :     std::string err_str;
     506          31 :     if (result.error())
     507             :     {
     508           0 :         error("Close git repo failed with error ", result.get_result_code_int());
     509             :     }
     510             :     else
     511          62 :         log("Closed.", log_level, debug_level);
     512          31 : }
     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          67 : Result GitHelper::fetch(const std::string &remote, log::Level log_level, int debug_level)
     534             : {
     535          67 :     Result result;
     536          67 :     ETRC_CALL_RET(result, remote, log_level, debug_level);
     537             : 
     538          67 :     log("Fetching ...", log_level, debug_level);
     539             : 
     540          67 :     const int attempts = get_attempts() < 1 ? 1 : get_attempts();
     541          67 :     for (int attempt = 1; attempt <= attempts; ++attempt)
     542             :     {
     543          67 :         {
     544          67 :             PhaseTimer timer(m_phase_timings.fetch_ms);
     545          67 :             result = get_git()->fetch(remote);
     546          67 :         }
     547          67 :         absorb_refresh_ms();
     548          67 :         if (result.ok())
     549             :         {
     550          67 :             log("Fetched successfully.", log_level, debug_level);
     551          67 :             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         201 :     return ETRC_RET(ESYSREPO_RESULT(result));
     568          67 : }
     569             : 
     570          66 : Result GitHelper::fetch(log::Level log_level, int debug_level)
     571             : {
     572         132 :     return fetch("", log_level, debug_level);
     573             : }
     574             : 
     575          86 : Result GitHelper::get_branches(git::Branches &branches, git::BranchType branch_type, log::Level log_level,
     576             :                                int debug_level)
     577             : {
     578          86 :     Result result;
     579          86 :     ETRC_CALL_RET_BEGIN(result, branches, branch_type, log_level, debug_level);
     580          86 :     ETRC_CALL_RET_OUT_END(branches);
     581             : 
     582          86 :     log("Getting branches ...", log::Level::DEBUG);
     583          86 :     result = get_git()->get_branches(branches, branch_type);
     584          86 :     if (result.error())
     585           0 :         error("Failed with error ", result.get_result_code_int());
     586             :     else
     587         172 :         log("Got branches.", log::Level::DEBUG);
     588             : 
     589         258 :     return ETRC_RET(ESYSREPO_RESULT(result));
     590          86 : }
     591             : 
     592          15 : Result_t<bool> GitHelper::has_branch(const std::string &name, git::BranchType branch_type, log::Level log_level,
     593             :                                      int debug_level)
     594             : {
     595          15 :     Result_t<bool> result(false);
     596          15 :     ETRC_CALL_RET(result, name, branch_type, log_level, debug_level);
     597             : 
     598          30 :     log("Check branch existance " + name + " ...", log::Level::DEBUG);
     599          30 :     result = get_git()->has_branch(name, branch_type);
     600          15 :     if (result)
     601          16 :         log("Found it.", log::Level::DEBUG);
     602             :     else
     603          14 :         log("Not Found", log::Level::DEBUG);
     604          30 :     return ETRC_RET(ESYSREPO_RESULT_T(result));
     605          15 : }
     606             : 
     607          26 : Result GitHelper::get_hash(const std::string &revision, std::string &hash, log::Level log_level, int debug_level)
     608             : {
     609          26 :     Result result;
     610          26 :     ETRC_CALL_RET_BEGIN(result, revision, hash, log_level, debug_level);
     611          26 :     ETRC_CALL_RET_OUT_END(hash);
     612             : 
     613          52 :     log("Check remote hash for " + revision + " ...", log::Level::DEBUG);
     614          26 :     result = get_git()->get_hash(revision, hash, git::BranchType::REMOTE);
     615          26 :     if (result.ok())
     616          52 :         log("Found it.", log::Level::DEBUG);
     617             :     else
     618           0 :         log("Not Found", log::Level::DEBUG);
     619          78 :     return ETRC_RET(ESYSREPO_RESULT(result));
     620          26 : }
     621             : 
     622           0 : Result GitHelper::get_hash_local(const std::string &revision, std::string &hash, log::Level log_level, int debug_level)
     623             : {
     624           0 :     Result result;
     625           0 :     ETRC_CALL_RET_BEGIN(result, revision, hash, log_level, debug_level);
     626           0 :     ETRC_CALL_RET_OUT_END(hash);
     627             : 
     628           0 :     log("Check local hash for " + revision + " ...", log::Level::DEBUG);
     629           0 :     result = get_git()->get_hash(revision, hash, git::BranchType::LOCAL);
     630           0 :     if (result.ok())
     631           0 :         log("Found it.", log::Level::DEBUG);
     632             :     else
     633           0 :         log("Not Found", log::Level::DEBUG);
     634           0 :     return ETRC_RET(ESYSREPO_RESULT(result));
     635           0 : }
     636             : 
     637          27 : Result GitHelper::is_dirty(bool &dirty, log::Level log_level, int debug_level)
     638             : {
     639          27 :     Result result;
     640          27 :     ETRC_CALL_RET_BEGIN(result, dirty, log_level, debug_level);
     641          27 :     ETRC_CALL_RET_OUT_END(dirty);
     642             : 
     643          27 :     result = get_git()->is_dirty(dirty);
     644          27 :     if (result.error())
     645           0 :         error("Failed to check there are changes in the git repo.");
     646             :     else
     647             :     {
     648          27 :         if (dirty)
     649           0 :             log("Dirty git repo", log_level, debug_level);
     650             :         else
     651          54 :             log("No changes in the git repo", log_level, debug_level);
     652             :     }
     653          81 :     return ETRC_RET(ESYSREPO_RESULT(result));
     654          27 : }
     655             : 
     656          26 : Result GitHelper::is_detached(bool &detached, log::Level log_level, int debug_level)
     657             : {
     658          26 :     Result result;
     659          26 :     ETRC_CALL_RET_BEGIN(result, detached, log_level, debug_level);
     660          26 :     ETRC_CALL_RET_OUT_END(detached);
     661             : 
     662          26 :     result = get_git()->is_detached(detached);
     663          26 :     if (result.error())
     664           0 :         error("Failed to check if the git repo is detached or not.");
     665             :     else
     666             :     {
     667          26 :         if (detached)
     668           6 :             log("Git repo is detached", log_level, debug_level);
     669             :         else
     670          46 :             log("Git repo is not detached", log_level, debug_level);
     671             :     }
     672          78 :     return ETRC_RET(ESYSREPO_RESULT(result));
     673          26 : }
     674             : 
     675          30 : Result GitHelper::get_status(git::RepoStatus &status, log::Level log_level, int debug_level)
     676             : {
     677          30 :     Result result;
     678          30 :     ETRC_CALL_RET_BEGIN(result, status, log_level, debug_level);
     679          30 :     ETRC_CALL_RET_OUT_END(status);
     680             : 
     681          30 :     result = get_git()->get_status(status);
     682          30 :     if (result.error())
     683           0 :         error("Failed to get the repo status");
     684             :     else
     685          60 :         log("Succeeded to get repo status", log_level, debug_level);
     686             : 
     687          90 :     return ETRC_RET(ESYSREPO_RESULT(result));
     688          30 : }
     689             : 
     690          66 : Result GitHelper::checkout(const std::string &branch, bool force, log::Level log_level, int debug_level)
     691             : {
     692          66 :     Result result;
     693          66 :     ETRC_CALL_RET(result, branch, force, log_level, debug_level);
     694             : 
     695          66 :     {
     696          66 :         PhaseTimer timer(m_phase_timings.checkout_ms);
     697          66 :         result = get_git()->checkout(branch, force);
     698          66 :     }
     699          66 :     if (result.error())
     700           0 :         error("Failed to checkout");
     701             :     else
     702         132 :         log("Checkout succeeded", log_level, debug_level);
     703         198 :     return ETRC_RET(ESYSREPO_RESULT(result));
     704          66 : }
     705             : 
     706          23 : Result GitHelper::merge_analysis(const std::vector<std::string> &refs, git::MergeAnalysisResult &merge_analysis_result,
     707             :                                  std::vector<git::CommitHash> &commits, log::Level log_level, int debug_level)
     708             : {
     709          23 :     Result result;
     710          23 :     ETRC_CALL_RET_BEGIN(result, refs, merge_analysis_result, commits, log_level, debug_level);
     711          23 :     ETRC_CALL_RET_OUT_END(merge_analysis_result, commits);
     712             : 
     713          23 :     result = get_git()->merge_analysis(refs, merge_analysis_result, commits);
     714          23 :     if (result.error())
     715           0 :         error("Merge analysis failed");
     716             :     else
     717          46 :         log("Merge analysis succeeded", log_level, debug_level);
     718          69 :     return ETRC_RET(ESYSREPO_RESULT(result));
     719          23 : }
     720             : 
     721          20 : Result GitHelper::move(const std::string &src, const std::string &dst, bool recursive, log::Level log_level,
     722             :                        int debug_level)
     723             : {
     724          20 :     Result rresult;
     725          20 :     ETRC_CALL_RET(rresult, src, dst, recursive, log_level, debug_level);
     726             : 
     727          40 :     boost::filesystem::path rel_src = boost::filesystem::relative(src);
     728          40 :     boost::filesystem::path rel_dst = boost::filesystem::relative(dst);
     729          20 :     std::ostringstream oss;
     730             : 
     731          20 :     init_oss(oss);
     732          20 :     oss << "Move:\n    src  : " << rel_src.string() << "\n    dest : " << rel_dst.string();
     733             : 
     734          20 :     int result = log_wrap(boost_no_all::move, log_level)(oss.str(), rel_src.string(), rel_dst.string(), true);
     735          20 :     if (result == -1) return ETRC_RET(ESYSREPO_RESULT(ResultCode::FAILED_TO_COPY));
     736          20 :     if (result == -1) return ETRC_RET(ESYSREPO_RESULT(ResultCode::FAILED_TO_REMOVE_ALL));
     737          40 :     return ETRC_RET(ESYSREPO_RESULT(ResultCode::OK));
     738          20 : }
     739             : 
     740           2 : void GitHelper::set_git(std::shared_ptr<GitBase> git)
     741             : {
     742           2 :     m_git = git;
     743           2 : }
     744             : 
     745        1507 : std::shared_ptr<GitBase> GitHelper::get_git() const
     746             : {
     747        1507 :     return m_git.lock();
     748             : }
     749             : 
     750          32 : void GitHelper::set_auto_close(bool auto_close)
     751             : {
     752          32 :     m_auto_close = auto_close;
     753          32 : }
     754             : 
     755         240 : bool GitHelper::get_auto_close() const
     756             : {
     757         240 :     return m_auto_close;
     758             : }
     759             : 
     760           0 : void GitHelper::set_repo_idx(int repo_idx)
     761             : {
     762           0 :     m_repo_idx = repo_idx;
     763           0 : }
     764             : 
     765        1987 : int GitHelper::get_repo_idx() const
     766             : {
     767        1987 :     return m_repo_idx;
     768             : }
     769             : 
     770           7 : void GitHelper::set_display_repo_idx(bool display_repo_idx)
     771             : {
     772           7 :     m_display_repo_idx = display_repo_idx;
     773           7 : }
     774             : 
     775         596 : bool GitHelper::get_display_repo_idx() const
     776             : {
     777         596 :     return m_display_repo_idx;
     778             : }
     779             : 
     780           0 : void GitHelper::set_attempts(int attempts)
     781             : {
     782           0 :     m_attempts = attempts;
     783           0 : }
     784             : 
     785         402 : int GitHelper::get_attempts() const
     786             : {
     787         402 :     return m_attempts;
     788             : }
     789             : 
     790           0 : void GitHelper::set_retry_delay_ms(int retry_delay_ms)
     791             : {
     792           0 :     m_retry_delay_ms = retry_delay_ms;
     793           0 : }
     794             : 
     795           0 : int GitHelper::get_retry_delay_ms() const
     796             : {
     797           0 :     return m_retry_delay_ms;
     798             : }
     799             : 
     800        1391 : void GitHelper::init_oss_done()
     801             : {
     802        1391 :     m_init_oss_done = true;
     803        1391 : }
     804             : 
     805        1391 : void GitHelper::init_oss_clear()
     806             : {
     807        1391 :     m_init_oss_done = false;
     808        1391 : }
     809             : 
     810        1545 : bool GitHelper::is_init_oss_done()
     811             : {
     812        1545 :     return m_init_oss_done;
     813             : }
     814             : 
     815        1545 : void GitHelper::init_oss(std::ostringstream &oss)
     816             : {
     817        1545 :     if (is_init_oss_done()) return;
     818             : 
     819        2782 :     oss.str("");
     820        1391 :     if ((get_repo_idx() != -1) && (get_display_repo_idx())) oss << "[" << get_repo_idx() << "] ";
     821        1391 :     init_oss_done();
     822             : }
     823             : 
     824        1525 : void GitHelper::init_oss(std::ostringstream &oss, const std::string &msg)
     825             : {
     826        1525 :     init_oss(oss);
     827             : 
     828        1525 :     oss << msg;
     829        1525 : }
     830             : 
     831        1525 : void GitHelper::clean_cout()
     832             : {
     833        1525 :     log::ConsoleLockGuard<log::User> lock(this);
     834             : 
     835        1525 :     std::string s = "             ";
     836        1525 :     std::cout << "\r";
     837             : 
     838       13725 :     for (int idx = 0; idx < CLEAN_OUT_REPETITION; ++idx) std::cout << s;
     839        1525 :     std::cout << "\r";
     840        1525 : }
     841             : 
     842           7 : GitHelper::AutoClose::AutoClose(GitHelper *git_helper)
     843           7 :     : m_git_helper(git_helper)
     844             : {
     845           7 : }
     846             : 
     847           7 : GitHelper::AutoClose::~AutoClose()
     848             : {
     849           7 :     if (m_git_helper != nullptr) m_git_helper->close(log::Level::DEBUG);
     850           7 : }
     851             : 
     852             : } // namespace esys::repo

Generated by: LCOV version 1.14