LCOV - code coverage report
Current view: top level - src/esys/repo/manifest - syncrepos_manifest.cpp (source / functions) Hit Total Coverage
Test: esysrepo_coverage.info Lines: 177 361 49.0 %
Date: 2026-08-01 10:43:40 Functions: 35 54 64.8 %

          Line data    Source code
       1             : /*!
       2             :  * \file esys/repo/manifest/syncrepos_manifest.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/manifest/syncrepos.h"
      20             : #include "esys/repo/manifest/location.h"
      21             : #include "esys/repo/gitmngr.h"
      22             : #include "esys/repo/githelper.h"
      23             : #include "esys/repo/gitphasetimings.h"
      24             : #include "esys/repo/tui/is_tty.h"
      25             : #include "esys/repo/tui/run_compact_sync_tui.h"
      26             : 
      27             : #include "esys/repo/filesystem.h"
      28             : 
      29             : #include <esys/trace/call.h>
      30             : #include <esys/trace/macros.h>
      31             : 
      32             : #include <boost/filesystem.hpp>
      33             : 
      34             : #include <algorithm>
      35             : #include <cstdlib>
      36             : #include <iostream>
      37             : #include <sstream>
      38             : 
      39             : namespace esys::repo::manifest
      40             : {
      41             : 
      42          20 : SyncRepos::SyncRepos()
      43          20 :     : log::User()
      44             : {
      45          20 : }
      46             : 
      47          80 : SyncRepos::~SyncRepos() = default;
      48             : 
      49          20 : void SyncRepos::set_manifest(std::shared_ptr<Manifest> manifest)
      50             : {
      51          20 :     m_manifest = manifest;
      52          20 : }
      53             : 
      54          60 : std::shared_ptr<Manifest> SyncRepos::get_manifest() const
      55             : {
      56          60 :     return m_manifest;
      57             : }
      58             : 
      59          20 : void SyncRepos::set_config_folder(std::shared_ptr<ConfigFolder> config_folder)
      60             : {
      61          20 :     m_config_folder = config_folder;
      62          20 : }
      63             : 
      64         140 : std::shared_ptr<ConfigFolder> SyncRepos::get_config_folder()
      65             : {
      66         140 :     return m_config_folder;
      67             : }
      68             : 
      69          20 : void SyncRepos::set_git(std::shared_ptr<GitBase> git)
      70             : {
      71          20 :     m_git = git;
      72          20 : }
      73             : 
      74          40 : std::shared_ptr<GitBase> SyncRepos::get_git() const
      75             : {
      76          40 :     return m_git;
      77             : }
      78             : 
      79           0 : std::shared_ptr<GitBase> SyncRepos::get_git_or_new()
      80             : {
      81           0 :     if (get_git() != nullptr) return get_git();
      82             : 
      83           0 :     return new_git();
      84             : }
      85             : 
      86           0 : void SyncRepos::set_git_generator(GitBase::GeneratorType git_generator)
      87             : {
      88           0 :     m_git_generator = git_generator;
      89           0 : }
      90             : 
      91         120 : GitBase::GeneratorType SyncRepos::get_git_generator()
      92             : {
      93         120 :     return m_git_generator;
      94             : }
      95             : 
      96         120 : std::shared_ptr<GitBase> SyncRepos::new_git()
      97             : {
      98         120 :     if (get_git_generator() != nullptr) return get_git_generator()();
      99             : 
     100         120 :     return GitMngr::new_ptr();
     101             : }
     102             : 
     103          20 : bool SyncRepos::check_if_ssh_auth_needed_and_ok()
     104             : {
     105          20 :     bool result = false;
     106          20 :     ETRC_CALL_RET_NP(result);
     107             : 
     108          40 :     for (auto location : get_manifest()->get_locations())
     109             :     {
     110          28 :         for (auto repo : location->get_repos())
     111             :         {
     112          84 :             if (!is_repo_to_be_synced(repo)) continue;
     113             : 
     114          20 :             if (location->is_address_ssh())
     115             :             {
     116          20 :                 if (!get_alt_address()) return ETRC_RET(false);
     117           0 :                 if (location->is_alt_address_ssh()) return ETRC_RET(false);
     118             :             }
     119          28 :         }
     120          20 :     }
     121           0 :     return ETRC_RET(true);
     122          20 : }
     123             : 
     124          20 : Result SyncRepos::run()
     125             : {
     126          20 :     Result result;
     127          20 :     ETRC_CALL_RET_NP(result);
     128             : 
     129          40 :     if (get_manifest() == nullptr) return ETRC_RET(ESYSREPO_RESULT(ResultCode::MANIFEST_IS_NULLPTR));
     130          40 :     if (get_config_folder() == nullptr) return ETRC_RET(ESYSREPO_RESULT(ResultCode::CONFIG_FOLDER_IS_NULLPTR));
     131          40 :     if (get_git() == nullptr) return ETRC_RET(ESYSREPO_RESULT(ResultCode::GIT_IS_NULLPTR));
     132             : 
     133          20 :     apply_workspace_root_env();
     134             : 
     135          80 :     if (!check_if_ssh_auth_needed_and_ok() && !get_git()->is_ssh_agent_running())
     136           0 :         warn("SSH authentication is only supported with a SSH agent. Git repos with SSH access won't be synced.");
     137          20 :     bool display_repo_idx = true;
     138             : 
     139          20 :     if (get_run_tasks().get_job_count() == 1) display_repo_idx = false;
     140             : 
     141          20 :     std::vector<std::shared_ptr<SyncRepo>> root_tasks;
     142          20 :     std::vector<std::shared_ptr<SyncRepo>> other_tasks;
     143             : 
     144          20 :     set_repo_idx(0);
     145          66 :     for (auto location : get_manifest()->get_locations())
     146             :     {
     147         169 :         for (auto repo : location->get_repos())
     148             :         {
     149         429 :             if (!is_repo_to_be_synced(repo)) continue;
     150             : 
     151         240 :             std::shared_ptr<SyncRepo> sync_repo = make_sync_repo(repo, display_repo_idx);
     152         120 :             if (repo->get_path() == ".")
     153          15 :                 root_tasks.push_back(sync_repo);
     154             :             else
     155         105 :                 other_tasks.push_back(sync_repo);
     156             : 
     157         120 :             ++get_repo_idx();
     158         263 :         }
     159          26 :     }
     160             : 
     161          20 :     const std::size_t parallel_jobs = get_job_count();
     162             : 
     163          20 :     if (get_tui())
     164           0 :         return ETRC_RET(ESYSREPO_RESULT(run_sync_with_tui(root_tasks, other_tasks, parallel_jobs)));
     165             : 
     166          40 :     auto run_root = [this, &root_tasks]() { return run_sync_tasks(root_tasks, 1); };
     167          20 :     auto run_others = [this, &other_tasks, parallel_jobs]() { return run_sync_tasks(other_tasks, parallel_jobs); };
     168             : 
     169          20 :     if (get_workspace_root_order() == WorkspaceRootOrder::Last)
     170             :     {
     171           0 :         result = run_others();
     172           0 :         if (result.error()) return ETRC_RET(ESYSREPO_RESULT(result));
     173           0 :         result = run_root();
     174             :     }
     175             :     else
     176             :     {
     177          20 :         result = run_root();
     178          20 :         if (result.error()) return ETRC_RET(ESYSREPO_RESULT(result));
     179          20 :         result = run_others();
     180             :     }
     181             : 
     182          40 :     return ETRC_RET(ESYSREPO_RESULT(result));
     183          20 : }
     184             : 
     185          20 : void SyncRepos::apply_workspace_root_env()
     186             : {
     187          20 :     if (const char *order_env = std::getenv("ESYSREPO_WORKSPACE_ROOT_ORDER"))
     188             :     {
     189           0 :         WorkspaceRootOrder order = m_workspace_root_order;
     190           0 :         if (parse_workspace_root_order(order_env, order))
     191             :         {
     192           0 :             m_workspace_root_order = order;
     193           0 :             std::ostringstream oss;
     194           0 :             oss << "Workspace root order: " << order << " (ESYSREPO_WORKSPACE_ROOT_ORDER)";
     195           0 :             info(oss.str());
     196           0 :         }
     197             :         else
     198           0 :             warn(std::string("Unknown ESYSREPO_WORKSPACE_ROOT_ORDER='") + order_env + "' (use first|last)");
     199             :     }
     200             : 
     201          20 :     if (const char *clone_env = std::getenv("ESYSREPO_WORKSPACE_ROOT_CLONE"))
     202             :     {
     203           2 :         WorkspaceRootCloneMethod method = m_workspace_root_clone_method;
     204           2 :         if (parse_workspace_root_clone_method(clone_env, method))
     205             :         {
     206           2 :             m_workspace_root_clone_method = method;
     207           2 :             std::ostringstream oss;
     208           2 :             oss << "Workspace root clone: " << method << " (ESYSREPO_WORKSPACE_ROOT_CLONE)";
     209           2 :             info(oss.str());
     210           2 :         }
     211             :         else
     212           0 :             warn(std::string("Unknown ESYSREPO_WORKSPACE_ROOT_CLONE='") + clone_env
     213           0 :                  + "' (use temp-move|init-fetch)");
     214             :     }
     215             : 
     216          20 :     if (const char *checkout_env = std::getenv("ESYSREPO_CLONE_CHECKOUT_REV"))
     217             :     {
     218           0 :         std::string text = checkout_env;
     219           0 :         for (char &c : text)
     220             :         {
     221           0 :             if (c >= 'A' && c <= 'Z') c = static_cast<char>(c - 'A' + 'a');
     222             :         }
     223           0 :         if (text == "1" || text == "true" || text == "yes" || text == "tip")
     224             :         {
     225           0 :             m_clone_options.checkout_rev = true;
     226           0 :             m_clone_options.single_branch = true;
     227           0 :             info("Clone checkout_rev=true single_branch=true (ESYSREPO_CLONE_CHECKOUT_REV)");
     228             :         }
     229           0 :         else if (text == "0" || text == "false" || text == "no" || text == "default")
     230             :         {
     231           0 :             m_clone_options.checkout_rev = false;
     232           0 :             m_clone_options.single_branch = false;
     233           0 :             info("Clone checkout_rev=false (ESYSREPO_CLONE_CHECKOUT_REV) — legacy path");
     234             :         }
     235             :         else
     236           0 :             warn(std::string("Unknown ESYSREPO_CLONE_CHECKOUT_REV='") + checkout_env
     237           0 :                  + "' (use tip|default or 1|0)");
     238           0 :     }
     239          20 : }
     240             : 
     241         120 : std::shared_ptr<SyncRepo> SyncRepos::make_sync_repo(std::shared_ptr<manifest::Repository> repo, bool display_repo_idx)
     242             : {
     243         120 :     std::shared_ptr<SyncRepo> sync_repo = std::make_shared<SyncRepo>();
     244             : 
     245         240 :     sync_repo->set_repo(repo);
     246         120 :     sync_repo->set_repo_idx(get_repo_idx());
     247         120 :     sync_repo->set_display_repo_idx(display_repo_idx);
     248         120 :     sync_repo->set_config_folder(get_config_folder());
     249         120 :     sync_repo->set_git(new_git());
     250         240 :     sync_repo->get_git()->set_logger_if(get_logger_if());
     251         120 :     sync_repo->set_logger_if(get_logger_if());
     252         120 :     sync_repo->set_workspace_root_clone_method(get_workspace_root_clone_method());
     253         120 :     sync_repo->set_clone_options(get_clone_options());
     254             : 
     255         120 :     if (!get_branch().empty()) sync_repo->set_branch(get_branch());
     256             : 
     257         120 :     sync_repo->set_alt_address(get_alt_address());
     258         120 :     return sync_repo;
     259           0 : }
     260             : 
     261          40 : Result SyncRepos::run_sync_tasks(const std::vector<std::shared_ptr<SyncRepo>> &tasks, std::size_t job_count)
     262             : {
     263          40 :     Result result;
     264          40 :     ETRC_CALL_RET_NP(result);
     265             : 
     266          46 :     if (tasks.empty()) return ETRC_RET(ESYSREPO_RESULT(ResultCode::OK));
     267             : 
     268          34 :     RunTasks run_tasks;
     269          34 :     run_tasks.set_logger_if(get_logger_if());
     270          34 :     run_tasks.set_job_count(job_count);
     271         274 :     for (const auto &task : tasks) run_tasks.add(task, task->get_repo_idx());
     272             : 
     273          34 :     result = run_tasks.run();
     274          34 :     log_phase_totals(tasks);
     275             : 
     276          68 :     return ETRC_RET(ESYSREPO_RESULT(result));
     277          40 : }
     278             : 
     279          34 : void SyncRepos::log_phase_totals(const std::vector<std::shared_ptr<SyncRepo>> &tasks)
     280             : {
     281          34 :     if (!GitHelper::phase_timing_enabled()) return;
     282             : 
     283           0 :     GitPhaseTimings totals;
     284           0 :     for (const auto &task : tasks) totals.add(task->get_phase_timings());
     285           0 :     if (totals.total_ms() != 0 || totals.refresh_ms != 0) info(totals.format("sync phase totals (ms):"));
     286             : }
     287             : 
     288           0 : Result SyncRepos::run_with_session(progress::ProgressSession &session, tui::SyncTuiControl *control)
     289             : {
     290           0 :     Result result;
     291           0 :     ETRC_CALL_RET_NP(result);
     292             : 
     293           0 :     if (get_manifest() == nullptr) return ETRC_RET(ESYSREPO_RESULT(ResultCode::MANIFEST_IS_NULLPTR));
     294           0 :     if (get_config_folder() == nullptr) return ETRC_RET(ESYSREPO_RESULT(ResultCode::CONFIG_FOLDER_IS_NULLPTR));
     295           0 :     if (get_git() == nullptr) return ETRC_RET(ESYSREPO_RESULT(ResultCode::GIT_IS_NULLPTR));
     296             : 
     297           0 :     apply_workspace_root_env();
     298             : 
     299           0 :     if (!check_if_ssh_auth_needed_and_ok() && !get_git()->is_ssh_agent_running())
     300           0 :         warn("SSH authentication is only supported with a SSH agent. Git repos with SSH access won't be synced.");
     301             : 
     302           0 :     bool display_repo_idx = true;
     303           0 :     if (get_run_tasks().get_job_count() == 1) display_repo_idx = false;
     304             : 
     305           0 :     std::vector<std::shared_ptr<SyncRepo>> root_tasks;
     306           0 :     std::vector<std::shared_ptr<SyncRepo>> other_tasks;
     307             : 
     308           0 :     set_repo_idx(0);
     309           0 :     for (auto location : get_manifest()->get_locations())
     310             :     {
     311           0 :         for (auto repo : location->get_repos())
     312             :         {
     313           0 :             if (!is_repo_to_be_synced(repo)) continue;
     314             : 
     315           0 :             std::shared_ptr<SyncRepo> sync_repo = make_sync_repo(repo, display_repo_idx);
     316           0 :             if (repo->get_path() == ".")
     317           0 :                 root_tasks.push_back(sync_repo);
     318             :             else
     319           0 :                 other_tasks.push_back(sync_repo);
     320             : 
     321           0 :             ++get_repo_idx();
     322           0 :         }
     323           0 :     }
     324             : 
     325           0 :     const std::size_t parallel_jobs = get_job_count();
     326             : 
     327           0 :     auto task_name = [](const std::shared_ptr<SyncRepo> &task) -> std::string {
     328           0 :         std::string name;
     329           0 :         if (task->get_repo() != nullptr)
     330             :         {
     331           0 :             name = task->get_repo()->get_path();
     332           0 :             if (name.empty()) name = task->get_repo()->get_name();
     333             :         }
     334           0 :         if (name.empty()) name = "repo";
     335           0 :         return name;
     336           0 :     };
     337             : 
     338           0 :     std::vector<std::string> names;
     339           0 :     auto note_task = [&](const std::shared_ptr<SyncRepo> &task) {
     340           0 :         const std::size_t idx = task->get_repo_idx();
     341           0 :         if (names.size() <= idx) names.resize(idx + 1, "repo");
     342           0 :         names[idx] = task_name(task);
     343           0 :     };
     344           0 :     for (const auto &task : root_tasks) note_task(task);
     345           0 :     for (const auto &task : other_tasks) note_task(task);
     346             : 
     347           0 :     const std::size_t ui_workers =
     348           0 :         other_tasks.empty() ? 1 : (std::min)(parallel_jobs == 0 ? std::size_t{1} : parallel_jobs, other_tasks.size());
     349             : 
     350           0 :     if (control != nullptr)
     351             :     {
     352           0 :         if (control->reset_repos) control->reset_repos(names, ui_workers);
     353           0 :         if (control->set_phase) control->set_phase("Sync in progress…");
     354             :     }
     355             : 
     356           0 :     if (names.empty()) return ETRC_RET(ESYSREPO_RESULT(ResultCode::OK));
     357             : 
     358           0 :     auto run_batch = [this](const std::vector<std::shared_ptr<SyncRepo>> &tasks, std::size_t job_count,
     359           0 :                             progress::ProgressSession &sess) -> Result {
     360           0 :         if (tasks.empty()) return ESYSREPO_RESULT(ResultCode::OK);
     361             : 
     362           0 :         RunTasks run_tasks;
     363           0 :         run_tasks.set_logger_if(get_logger_if());
     364           0 :         run_tasks.set_job_count(job_count);
     365           0 :         run_tasks.set_progress_session(&sess);
     366           0 :         run_tasks.set_console_progress(false);
     367           0 :         for (const auto &task : tasks) run_tasks.add(task, task->get_repo_idx());
     368           0 :         auto batch_result = run_tasks.run();
     369           0 :         log_phase_totals(tasks);
     370           0 :         return batch_result;
     371           0 :     };
     372             : 
     373           0 :     if (get_workspace_root_order() == WorkspaceRootOrder::Last)
     374             :     {
     375           0 :         result = run_batch(other_tasks, parallel_jobs, session);
     376           0 :         if (result.error()) return ETRC_RET(ESYSREPO_RESULT(result));
     377           0 :         result = run_batch(root_tasks, 1, session);
     378             :     }
     379             :     else
     380             :     {
     381           0 :         result = run_batch(root_tasks, 1, session);
     382           0 :         if (result.error()) return ETRC_RET(ESYSREPO_RESULT(result));
     383           0 :         result = run_batch(other_tasks, parallel_jobs, session);
     384             :     }
     385             : 
     386           0 :     return ETRC_RET(ESYSREPO_RESULT(result));
     387           0 : }
     388             : 
     389           0 : Result SyncRepos::run_sync_with_tui(const std::vector<std::shared_ptr<SyncRepo>> &root_tasks,
     390             :                                    const std::vector<std::shared_ptr<SyncRepo>> &other_tasks,
     391             :                                    std::size_t parallel_jobs)
     392             : {
     393           0 :     Result result;
     394           0 :     ETRC_CALL_RET_NP(result);
     395             : 
     396             : #ifndef ESYSREPO_HAVE_TUI
     397             :     error("--tui requested but esysrepo was built without FTXUI (Conan with_tui / ESYSREPO_WITH_TUI)");
     398             :     return ETRC_RET(ESYSREPO_RESULT(ResultCode::NOT_IMPLEMENTED));
     399             : #else
     400           0 :     if (!tui::is_tty())
     401             :     {
     402           0 :         const char *msg =
     403             :             "--tui requires a real Win32 console (cmd.exe, PowerShell, or Windows "
     404             :             "Terminal). Git Bash/mintty and redirected stdout are not supported.";
     405           0 :         error(msg);
     406           0 :         std::cerr << "ERROR: " << msg << std::endl;
     407           0 :         return ETRC_RET(ESYSREPO_RESULT(ResultCode::GENERIC_ERROR));
     408             :     }
     409             : 
     410           0 :     auto task_name = [](const std::shared_ptr<SyncRepo> &task) -> std::string {
     411           0 :         std::string name;
     412           0 :         if (task->get_repo() != nullptr)
     413             :         {
     414           0 :             name = task->get_repo()->get_path();
     415           0 :             if (name.empty()) name = task->get_repo()->get_name();
     416             :         }
     417           0 :         if (name.empty()) name = "repo";
     418           0 :         return name;
     419           0 :     };
     420             : 
     421           0 :     std::vector<std::string> names;
     422           0 :     auto note_task = [&](const std::shared_ptr<SyncRepo> &task) {
     423           0 :         const std::size_t idx = task->get_repo_idx();
     424           0 :         if (names.size() <= idx) names.resize(idx + 1, "repo");
     425           0 :         names[idx] = task_name(task);
     426           0 :     };
     427           0 :     for (const auto &task : root_tasks) note_task(task);
     428           0 :     for (const auto &task : other_tasks) note_task(task);
     429             : 
     430           0 :     if (names.empty()) return ETRC_RET(ESYSREPO_RESULT(ResultCode::OK));
     431             : 
     432           0 :     const std::size_t ui_workers =
     433           0 :         other_tasks.empty() ? 1 : (std::min)(parallel_jobs == 0 ? std::size_t{1} : parallel_jobs, other_tasks.size());
     434             : 
     435           0 :     auto run_batch = [this](const std::vector<std::shared_ptr<SyncRepo>> &tasks, std::size_t job_count,
     436           0 :                             progress::ProgressSession &session) -> Result {
     437           0 :         if (tasks.empty()) return ESYSREPO_RESULT(ResultCode::OK);
     438             : 
     439           0 :         RunTasks run_tasks;
     440           0 :         run_tasks.set_logger_if(get_logger_if());
     441           0 :         run_tasks.set_job_count(job_count);
     442           0 :         run_tasks.set_progress_session(&session);
     443           0 :         run_tasks.set_console_progress(false);
     444           0 :         for (const auto &task : tasks) run_tasks.add(task, task->get_repo_idx());
     445           0 :         auto batch_result = run_tasks.run();
     446           0 :         log_phase_totals(tasks);
     447           0 :         return batch_result;
     448           0 :     };
     449             : 
     450           0 :     auto work = [this, &root_tasks, &other_tasks, parallel_jobs, &run_batch](
     451           0 :                     progress::ProgressSession &session, tui::SyncTuiControl &control) -> Result {
     452           0 :         if (control.logger) set_logger_if(control.logger);
     453           0 :         if (control.set_phase) control.set_phase("Sync in progress…");
     454             : 
     455           0 :         Result phase;
     456           0 :         if (get_workspace_root_order() == WorkspaceRootOrder::Last)
     457             :         {
     458           0 :             phase = run_batch(other_tasks, parallel_jobs, session);
     459           0 :             if (phase.error()) return phase;
     460           0 :             return run_batch(root_tasks, 1, session);
     461             :         }
     462           0 :         phase = run_batch(root_tasks, 1, session);
     463           0 :         if (phase.error()) return phase;
     464           0 :         return run_batch(other_tasks, parallel_jobs, session);
     465           0 :     };
     466             : 
     467           0 :     result = tui::run_compact_sync_tui(work, names, ui_workers, get_logger_if());
     468           0 :     return ETRC_RET(ESYSREPO_RESULT(result));
     469             : #endif
     470           0 : }
     471             : 
     472          16 : void SyncRepos::set_log_level(log::Level log_level)
     473             : {
     474          16 :     m_log_level = log_level;
     475          16 : }
     476             : 
     477           0 : log::Level SyncRepos::get_log_level()
     478             : {
     479           0 :     return m_log_level;
     480             : }
     481             : 
     482          20 : void SyncRepos::set_repo_idx(std::size_t repo_idx)
     483             : {
     484          20 :     m_repo_idx = repo_idx;
     485          20 : }
     486             : 
     487           0 : std::size_t SyncRepos::get_repo_idx() const
     488             : {
     489           0 :     return m_repo_idx;
     490             : }
     491             : 
     492         240 : std::size_t &SyncRepos::get_repo_idx()
     493             : {
     494         240 :     return m_repo_idx;
     495             : }
     496             : 
     497          62 : bool SyncRepos::globly_match(const std::string &text, const std::string &glob)
     498             : {
     499          62 :     const char *text_backup = nullptr;
     500          62 :     const char *glob_backup = nullptr;
     501          62 :     const char *text_ = text.c_str();
     502          62 :     const char *glob_ = glob.c_str();
     503             : 
     504         312 :     while (*text_ != '\0')
     505             :     {
     506         302 :         if (*glob_ == '*')
     507             :         {
     508             :             // new star-loop: backup positions in pattern and text
     509           8 :             text_backup = text_;
     510           8 :             glob_backup = ++glob_;
     511             :         }
     512         294 :         else if ((*glob_ == '?' && *text_ != '/') || *glob_ == *text_)
     513             :         {
     514             :             // ? matched any character except /, or we matched the current non-NUL character
     515         226 :             text_++;
     516         226 :             glob_++;
     517             :         }
     518             :         else
     519             :         {
     520          68 :             if (glob_backup == nullptr || *text_backup == '/') return false;
     521             :             // star-loop: backtrack to the last * but do not jump over /
     522          16 :             text_ = ++text_backup;
     523          16 :             glob_ = glob_backup;
     524             :         }
     525             :     }
     526             :     // ignore trailing stars
     527          10 :     while (*glob_ == '*') glob_++;
     528             :     // at end of text means success if nothing else is left to match
     529          10 :     return *glob_ == '\0' ? true : false;
     530             : }
     531             : 
     532         171 : bool SyncRepos::is_repo_to_be_synced(std::shared_ptr<manifest::Repository> repo) const
     533             : {
     534         171 :     bool result = false;
     535         171 :     ETRC_CALL_RET(result, repo);
     536             : 
     537         171 :     if (m_map_folders_to_sync.size() == 0) return ETRC_RET(true);
     538             : 
     539          50 :     auto it = m_map_folders_to_sync.find(repo->get_path());
     540             : 
     541          50 :     if (it != m_map_folders_to_sync.end()) return ETRC_RET(true);
     542             : 
     543          35 :     result = false;
     544             :     // Now let's see if glob filter were used in the sync command
     545          88 :     for (auto &str : get_folders_to_sync())
     546             :     {
     547          57 :         result = globly_match(repo->get_path(), str);
     548          57 :         if (result) return ETRC_RET(true);
     549             :     }
     550          31 :     return ETRC_RET(false);
     551         171 : }
     552             : 
     553           6 : void SyncRepos::set_folders_to_sync(std::vector<std::string> folders_to_sync)
     554             : {
     555           6 :     m_folders_to_sync = folders_to_sync;
     556           6 :     m_map_folders_to_sync.clear();
     557             : 
     558          17 :     for (auto &folder : folders_to_sync) m_map_folders_to_sync[folder] = true;
     559           6 : }
     560             : 
     561          35 : const std::vector<std::string> &SyncRepos::get_folders_to_sync() const
     562             : {
     563          35 :     return m_folders_to_sync;
     564             : }
     565             : 
     566          20 : void SyncRepos::set_job_count(std::size_t job_count)
     567             : {
     568          20 :     m_run_tasks.set_job_count(job_count);
     569          20 : }
     570             : 
     571          20 : std::size_t SyncRepos::get_job_count() const
     572             : {
     573          20 :     return m_run_tasks.get_job_count();
     574             : }
     575             : 
     576           2 : void SyncRepos::set_branch(const std::string &branch)
     577             : {
     578           2 :     m_branch = branch;
     579           2 : }
     580             : 
     581         133 : const std::string &SyncRepos::get_branch() const
     582             : {
     583         133 :     return m_branch;
     584             : }
     585             : 
     586           0 : void SyncRepos::set_alt_address(bool alt_address)
     587             : {
     588           0 :     m_alt_address = alt_address;
     589           0 : }
     590             : 
     591         140 : bool SyncRepos::get_alt_address() const
     592             : {
     593         140 :     return m_alt_address;
     594             : }
     595             : 
     596          20 : RunTasks &SyncRepos::get_run_tasks()
     597             : {
     598          20 :     return m_run_tasks;
     599             : }
     600             : 
     601           0 : const RunTasks &SyncRepos::get_run_tasks() const
     602             : {
     603           0 :     return m_run_tasks;
     604             : }
     605             : 
     606           0 : void SyncRepos::set_workspace_root_order(WorkspaceRootOrder order)
     607             : {
     608           0 :     m_workspace_root_order = order;
     609           0 : }
     610             : 
     611          20 : WorkspaceRootOrder SyncRepos::get_workspace_root_order() const
     612             : {
     613          20 :     return m_workspace_root_order;
     614             : }
     615             : 
     616           0 : void SyncRepos::set_workspace_root_clone_method(WorkspaceRootCloneMethod method)
     617             : {
     618           0 :     m_workspace_root_clone_method = method;
     619           0 : }
     620             : 
     621         120 : WorkspaceRootCloneMethod SyncRepos::get_workspace_root_clone_method() const
     622             : {
     623         120 :     return m_workspace_root_clone_method;
     624             : }
     625             : 
     626           0 : void SyncRepos::set_clone_options(const git::CloneOptions &options)
     627             : {
     628           0 :     m_clone_options = options;
     629           0 : }
     630             : 
     631         120 : const git::CloneOptions &SyncRepos::get_clone_options() const
     632             : {
     633         120 :     return m_clone_options;
     634             : }
     635             : 
     636          20 : void SyncRepos::set_tui(bool tui)
     637             : {
     638          20 :     m_tui = tui;
     639          20 : }
     640             : 
     641          20 : bool SyncRepos::get_tui() const
     642             : {
     643          20 :     return m_tui;
     644             : }
     645             : 
     646             : } // namespace esys::repo::manifest

Generated by: LCOV version 1.14