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: 206 377 54.6 %
Date: 2026-08-12 14:26:50 Functions: 38 56 67.9 %

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

Generated by: LCOV version 1.14