Line data Source code
1 : /*!
2 : * \file esys/repo/manifest/syncrepo_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/syncrepo.h"
20 : #include "esys/repo/manifest/location.h"
21 : #include "esys/repo/git/clonerev.h"
22 :
23 : #include "esys/repo/filesystem.h"
24 :
25 : #include <esys/trace/call.h>
26 : #include <esys/trace/macros.h>
27 :
28 : #include <boost/filesystem.hpp>
29 :
30 : #include <sstream>
31 : #include <string>
32 :
33 : namespace esys::repo::manifest
34 : {
35 :
36 122 : SyncRepo::SyncRepo()
37 122 : : log::User()
38 : {
39 122 : }
40 :
41 244 : SyncRepo::~SyncRepo() = default;
42 :
43 120 : int SyncRepo::run()
44 : {
45 120 : int result = 0;
46 120 : ETRC_CALL_RET_NP(result);
47 :
48 120 : return ETRC_RET(process_repo());
49 120 : }
50 :
51 120 : int SyncRepo::process_repo()
52 : {
53 120 : int result = 0;
54 120 : ETRC_CALL_RET_NP(result);
55 :
56 120 : boost::filesystem::path path = get_config_folder()->get_workspace_path();
57 345 : if (get_repo()->get_path() != ".") path /= get_repo()->get_path();
58 :
59 120 : if (!GitBase::is_repo(path.string()))
60 113 : result = clone();
61 : else
62 7 : result = fetch_update();
63 120 : if (result != 0) return ETRC_RET(result);
64 120 : return ETRC_RET(maybe_update_submodules(path.string()));
65 120 : }
66 :
67 0 : bool SyncRepo::has_branch(GitHelper &git_helper, const std::string &branch)
68 : {
69 0 : bool result_bool = false;
70 0 : ETRC_CALL_RET(result_bool, branch);
71 :
72 0 : git::Branches branches;
73 0 : Result result = git_helper.get_branches(branches, git::BranchType::REMOTE, log::Level::DEBUG);
74 0 : if (result.error())
75 : {
76 0 : git_helper.error("Couldn't get the list of local branches");
77 0 : return ETRC_RET(false);
78 : }
79 :
80 0 : branches.sort();
81 :
82 0 : auto branch_ptr = branches.find(branch);
83 :
84 0 : if (branch_ptr != nullptr)
85 : {
86 0 : git_helper.debug(0, "Branch found : " + branch);
87 0 : return ETRC_RET(true);
88 : }
89 0 : git_helper.debug(0, "Branch not found : " + branch);
90 0 : return ETRC_RET(false);
91 0 : }
92 :
93 121 : std::string SyncRepo::get_manifest_repo_revision()
94 : {
95 363 : if (m_manifest != nullptr && get_repo() != nullptr) return m_manifest->get_repo_revision(get_repo());
96 0 : if (get_repo() != nullptr) return get_repo()->get_revision();
97 121 : return {};
98 : }
99 :
100 40 : bool SyncRepo::is_pinned()
101 : {
102 80 : if (m_manifest == nullptr || get_repo() == nullptr) return false;
103 80 : return m_manifest->has_revision_pin(get_repo()->get_path());
104 : }
105 :
106 32 : std::string SyncRepo::get_checkout_revision(GitHelper &git_helper)
107 : {
108 32 : std::string result;
109 32 : ETRC_CALL_RET_NP(result);
110 :
111 : // Workspace pins win over sync --branch (ADR-0021)
112 32 : if (is_pinned()) return ETRC_RET(get_manifest_repo_revision());
113 :
114 82 : if (get_branch().empty()) return ETRC_RET(get_manifest_repo_revision());
115 :
116 7 : Result_t<bool> branch_exists =
117 7 : git_helper.has_branch(get_branch(), git::BranchType::REMOTE, esys::log::Level::DEBUG);
118 :
119 7 : std::ostringstream oss;
120 7 : oss << "branch_exists = " << branch_exists;
121 7 : debug(0, oss.str());
122 :
123 7 : if (branch_exists) return ETRC_RET(get_branch());
124 18 : return ETRC_RET(get_manifest_repo_revision());
125 39 : }
126 :
127 120 : std::shared_ptr<GitHelper> SyncRepo::new_git_helper()
128 : {
129 240 : auto git_helper = std::make_shared<GitHelper>(get_git(), get_logger_if(), static_cast<int>(get_repo_idx()));
130 :
131 360 : get_git()->set_logger_if(git_helper);
132 120 : return git_helper;
133 0 : }
134 :
135 120 : SyncRepo::PhaseCapture::PhaseCapture(SyncRepo &self, GitHelper &helper)
136 120 : : m_self(self)
137 120 : , m_helper(helper)
138 : {
139 120 : }
140 :
141 120 : SyncRepo::PhaseCapture::~PhaseCapture()
142 : {
143 120 : m_self.m_phase_timings = m_helper.get_phase_timings();
144 120 : m_helper.log_phase_summary();
145 120 : }
146 :
147 0 : const GitPhaseTimings &SyncRepo::get_phase_timings() const
148 : {
149 0 : return m_phase_timings;
150 : }
151 :
152 113 : int SyncRepo::clone()
153 : {
154 113 : int result = 0;
155 113 : ETRC_CALL_RET_NP(result);
156 :
157 113 : std::shared_ptr<GitHelper> git_helper = new_git_helper();
158 113 : PhaseCapture phase_capture(*this, *git_helper);
159 113 : std::string url = get_repo_url();
160 113 : std::string branch_to_checkout;
161 :
162 113 : boost::filesystem::path path = get_config_folder()->get_workspace_path();
163 226 : ETRC_MSG("path : " + get_repo()->get_path());
164 :
165 226 : if (get_repo()->get_path() != ".")
166 : {
167 : // A simple clone can be made
168 99 : path /= get_repo()->get_path();
169 :
170 : // Prefer tip-at-clone when SyncRepos enabled checkout_rev (ADR-0030 default).
171 : // Raw commit SHAs and empty revs force the legacy path for this repo.
172 99 : git::CloneOptions clone_opts = get_clone_options();
173 198 : git::CloneRevPlan plan = git::plan_clone_rev(clone_opts.checkout_rev, get_branch(),
174 99 : get_branch().empty() ? get_manifest_repo_revision()
175 99 : : std::string());
176 99 : std::string clone_rev = plan.clone_rev;
177 99 : if (!plan.use_tip) clone_opts.checkout_rev = false;
178 :
179 99 : Result rresult =
180 99 : git_helper->clone_rev(url, clone_rev, path.string(), false, log::Level::INFO, 0, clone_opts);
181 99 : if (rresult.error() && clone_opts.checkout_rev && !clone_rev.empty())
182 : {
183 : // Branch/tag missing on this remote (e.g. sync -b), or odd rev: fall back.
184 10 : git_helper->debug(0, "clone with rev '" + clone_rev + "' failed; cloning default");
185 5 : clone_rev.clear();
186 5 : clone_opts = git::CloneOptions();
187 5 : rresult = git_helper->clone_rev(url, "", path.string(), false, log::Level::INFO, 0, clone_opts);
188 : }
189 99 : if (rresult.error())
190 : {
191 0 : git_helper->close_on_error(log::Level::DEBUG);
192 0 : return ETRC_RET(rresult.get_result_code_int());
193 : }
194 :
195 99 : if (clone_opts.checkout_rev && !clone_rev.empty())
196 : {
197 : // Already on the requested branch/tag tip from clone.
198 81 : rresult = git_helper->close(log::Level::DEBUG);
199 81 : return ETRC_RET(rresult.get_result_code_int());
200 : }
201 :
202 18 : if (!get_branch().empty())
203 : {
204 5 : Result result = git_helper->fetch(get_log_level());
205 5 : if (result.error())
206 : {
207 0 : git_helper->close_on_error(log::Level::DEBUG);
208 0 : return ETRC_RET(result.get_result_code_int());
209 : }
210 5 : }
211 :
212 18 : branch_to_checkout = get_checkout_revision(*git_helper.get());
213 18 : git_helper->debug(0, "branch_to_checkout = " + branch_to_checkout);
214 18 : if (branch_to_checkout.empty()) return ETRC_RET(0);
215 :
216 18 : rresult = git_helper->checkout(branch_to_checkout, false, log::Level::INFO);
217 18 : if (rresult.error())
218 : {
219 0 : git_helper->close_on_error(log::Level::DEBUG);
220 0 : return ETRC_RET(rresult.get_result_code_int());
221 : }
222 18 : rresult = git_helper->close(log::Level::DEBUG);
223 18 : return ETRC_RET(rresult.get_result_code_int());
224 99 : }
225 :
226 14 : if (get_workspace_root_clone_method() == WorkspaceRootCloneMethod::InitFetch)
227 1 : return ETRC_RET(clone_workspace_root_init_fetch(*git_helper.get(), url, path.string()));
228 :
229 13 : return ETRC_RET(clone_workspace_root_temp_move(*git_helper.get(), url, path.string()));
230 226 : }
231 :
232 13 : int SyncRepo::clone_workspace_root_temp_move(GitHelper &git_helper, const std::string &url, const std::string &path)
233 : {
234 13 : int result = 0;
235 13 : ETRC_CALL_RET(result, url, path);
236 :
237 : // Folder is not empty (.esysrepo): clone into temp, then move into the workspace
238 13 : boost::filesystem::path temp_path = get_config_folder()->get_temp_path();
239 13 : std::ostringstream oss;
240 13 : oss << "repo_temp" << get_repo_idx();
241 13 : temp_path /= oss.str();
242 :
243 13 : Result rresult = git_helper.clone(url, temp_path.string(), path, true, get_log_level());
244 13 : if (rresult.error())
245 : {
246 0 : git_helper.close_on_error(log::Level::DEBUG);
247 0 : return ETRC_RET(rresult.get_result_code_int());
248 : }
249 :
250 13 : rresult = git_helper.open(path, esys::log::INFO);
251 13 : if (rresult.error()) return ETRC_RET(rresult.get_result_code_int());
252 :
253 13 : if (!get_branch().empty())
254 : {
255 2 : rresult = git_helper.fetch(get_log_level());
256 2 : if (rresult.error())
257 : {
258 0 : git_helper.close_on_error(log::Level::DEBUG);
259 0 : return ETRC_RET(rresult.get_result_code_int());
260 : }
261 : }
262 :
263 13 : return ETRC_RET(finish_workspace_root_clone(git_helper));
264 13 : }
265 :
266 1 : int SyncRepo::clone_workspace_root_init_fetch(GitHelper &git_helper, const std::string &url, const std::string &path)
267 : {
268 1 : int result = 0;
269 1 : ETRC_CALL_RET(result, url, path);
270 :
271 2 : git_helper.info("Init+fetch workspace root ...\n path : " + path + "\n url : " + url);
272 :
273 1 : Result rresult = git_helper.get_git()->init(path);
274 1 : if (rresult.error())
275 : {
276 0 : git_helper.error("Failed to init workspace root", rresult.get_result_code_int());
277 0 : git_helper.close_on_error(log::Level::DEBUG);
278 0 : return ETRC_RET(rresult.get_result_code_int());
279 : }
280 :
281 1 : rresult = git_helper.get_git()->add_remote("origin", url);
282 1 : if (rresult.error())
283 : {
284 0 : git_helper.error("Failed to add remote origin", rresult.get_result_code_int());
285 0 : git_helper.close_on_error(log::Level::DEBUG);
286 0 : return ETRC_RET(rresult.get_result_code_int());
287 : }
288 :
289 1 : rresult = git_helper.fetch("origin", get_log_level());
290 1 : if (rresult.error())
291 : {
292 0 : git_helper.close_on_error(log::Level::DEBUG);
293 0 : return ETRC_RET(rresult.get_result_code_int());
294 : }
295 :
296 1 : return ETRC_RET(finish_workspace_root_clone(git_helper));
297 1 : }
298 :
299 14 : int SyncRepo::finish_workspace_root_clone(GitHelper &git_helper)
300 : {
301 14 : int result = 0;
302 14 : ETRC_CALL_RET_NP(result);
303 :
304 14 : std::string branch_to_checkout = resolve_checkout_revision(git_helper);
305 14 : git_helper.debug(0, "branch_to_checkout = " + branch_to_checkout);
306 14 : if (branch_to_checkout.empty())
307 : {
308 0 : git_helper.error("No revision to checkout after workspace-root clone");
309 0 : git_helper.close_on_error(log::Level::DEBUG);
310 0 : return ETRC_RET(-1);
311 : }
312 :
313 14 : Result rresult = git_helper.checkout(branch_to_checkout, get_force(), log::Level::INFO);
314 14 : if (rresult.error())
315 : {
316 0 : git_helper.close_on_error(log::Level::DEBUG);
317 0 : return ETRC_RET(rresult.get_result_code_int());
318 : }
319 14 : rresult = git_helper.close(log::Level::DEBUG);
320 14 : return ETRC_RET(rresult.get_result_code_int());
321 28 : }
322 :
323 14 : std::string SyncRepo::resolve_checkout_revision(GitHelper &git_helper)
324 : {
325 14 : std::string rev = get_checkout_revision(git_helper);
326 :
327 14 : const std::string heads = "refs/heads/";
328 14 : if (rev.compare(0, heads.size(), heads) == 0) rev = rev.substr(heads.size());
329 28 : if (!rev.empty()) return rev;
330 :
331 : // Init-fetch leaves no default checkout (unlike clone). Pick a remote branch.
332 0 : git::Branches branches;
333 0 : Result rresult = git_helper.get_branches(branches, git::BranchType::REMOTE, log::Level::DEBUG);
334 0 : if (rresult.error() || branches.size() == 0) return {};
335 :
336 0 : auto short_name = [](const std::string &full) -> std::string {
337 0 : auto pos = full.rfind('/');
338 0 : if (pos == std::string::npos) return full;
339 0 : return full.substr(pos + 1);
340 : };
341 :
342 0 : auto find_named = [&](const std::string &want) -> std::string {
343 0 : for (const auto &branch : branches.get())
344 : {
345 0 : if (short_name(branch->get_name()) == want) return want;
346 : }
347 0 : return {};
348 0 : };
349 :
350 0 : rev = find_named("master");
351 0 : if (rev.empty()) rev = find_named("main");
352 0 : if (rev.empty()) rev = short_name(branches.get()[0]->get_name());
353 0 : return rev;
354 14 : }
355 :
356 7 : int SyncRepo::fetch_update()
357 : {
358 7 : int result_int = 0;
359 7 : ETRC_CALL_RET_NP(result_int);
360 :
361 7 : std::shared_ptr<GitHelper> git_helper = new_git_helper();
362 7 : PhaseCapture phase_capture(*this, *git_helper);
363 7 : git_helper->set_display_repo_idx(get_display_repo_idx());
364 :
365 7 : boost::filesystem::path path = get_config_folder()->get_workspace_path();
366 20 : if (get_repo()->get_path() != ".") path /= get_repo()->get_path();
367 :
368 7 : Result rresult = git_helper->open(path.string(), log::Level::INFO);
369 7 : if (rresult.error()) return ETRC_RET(rresult.get_result_code_int());
370 :
371 7 : bool dirty = false;
372 7 : rresult = git_helper->is_dirty(dirty, log::Level::DEBUG);
373 7 : if (rresult.error()) return ETRC_RET(rresult.get_result_code_int());
374 :
375 7 : if (dirty)
376 : {
377 0 : git_helper->warn("Changes detected in repo, no sync.");
378 0 : return ETRC_RET(0);
379 : }
380 :
381 7 : if (is_pinned()) return ETRC_RET(pin_sync(*git_helper.get()));
382 :
383 7 : if (get_branch().empty())
384 7 : return ETRC_RET(normal_sync(*git_helper.get()));
385 : else
386 0 : return ETRC_RET(branch_sync(*git_helper.get()));
387 14 : }
388 :
389 0 : int SyncRepo::pin_sync(GitHelper &git_helper)
390 : {
391 0 : int result_int = 0;
392 0 : ETRC_CALL_RET_NP(result_int);
393 :
394 0 : const std::string pin_rev = get_manifest_repo_revision();
395 0 : if (pin_rev.empty())
396 : {
397 0 : git_helper.error("Pinned repository has an empty revision.");
398 0 : return ETRC_RET(-1);
399 : }
400 :
401 0 : Result result = git_helper.fetch(log::Level::DEBUG);
402 0 : if (result.error())
403 : {
404 0 : git_helper.error("Fetch failed on the pinned git repo");
405 0 : return ETRC_RET(result.get_result_code_int());
406 : }
407 :
408 0 : git_helper.info("Checking out pinned revision " + pin_rev + " ...");
409 0 : result = git_helper.checkout(pin_rev, get_force(), log::Level::INFO);
410 0 : if (result.error())
411 : {
412 0 : git_helper.error("Failed to checkout pinned revision " + pin_rev + ".");
413 0 : return ETRC_RET(result.get_result_code_int());
414 : }
415 0 : git_helper.info("Pinned revision checkout completed.");
416 0 : return ETRC_RET(0);
417 0 : }
418 :
419 7 : int SyncRepo::normal_sync(GitHelper &git_helper)
420 : {
421 7 : int result_int = 0;
422 7 : ETRC_CALL_RET_NP(result_int);
423 :
424 7 : bool detached = false;
425 7 : Result result = git_helper.is_detached(detached, log::Level::DEBUG);
426 7 : if (result.error())
427 : {
428 0 : git_helper.error("Couldn't detect if the git repo is detached or not.");
429 0 : return ETRC_RET(result.get_result_code_int());
430 : }
431 :
432 7 : if (detached)
433 : {
434 : // Soft skip (same as dirty): detached HEADs are left alone on a normal sync
435 2 : git_helper.warn("Sync repo aborted: the git repo is detached.");
436 2 : return ETRC_RET(0);
437 : }
438 :
439 5 : result = git_helper.fetch(log::Level::DEBUG);
440 5 : if (result.error())
441 : {
442 0 : git_helper.error("Fetch failed on the git repo");
443 0 : return ETRC_RET(result.get_result_code_int());
444 : }
445 :
446 5 : git::Branches branches;
447 5 : result = git_helper.get_branches(branches, git::BranchType::LOCAL, log::Level::DEBUG);
448 5 : if (result.error())
449 : {
450 0 : git_helper.error("Couldn't get the list of local branches");
451 0 : return ETRC_RET(result.get_result_code_int());
452 : }
453 :
454 5 : branches.sort();
455 :
456 10 : if (branches.get_head() == nullptr)
457 : {
458 0 : git_helper.error("Couldn't get the HEAD.");
459 0 : return ETRC_RET(-4);
460 : }
461 :
462 5 : std::vector<std::string> refs;
463 5 : git::MergeAnalysisResult merge_analysis_result;
464 5 : std::vector<git::CommitHash> commits;
465 :
466 5 : refs.push_back(branches.get_head()->get_remote_branch());
467 :
468 5 : result = git_helper.merge_analysis(refs, merge_analysis_result, commits, log::Level::DEBUG);
469 5 : if (result.error())
470 : {
471 0 : git_helper.error("Merge analysis failed.");
472 0 : return ETRC_RET(-5);
473 : }
474 :
475 5 : if (merge_analysis_result == git::MergeAnalysisResult::UP_TO_DATE)
476 : {
477 4 : git_helper.info("Git repo up to date.");
478 4 : return ETRC_RET(0);
479 : }
480 1 : if (merge_analysis_result != git::MergeAnalysisResult::FASTFORWARD)
481 : {
482 0 : git_helper.warn("Sync manifest aborted: can't be fastforwarded.");
483 0 : return ETRC_RET(-6);
484 : }
485 :
486 : // For a fastforward, there should be only one commit
487 1 : if (commits.size() != 1)
488 : {
489 0 : git_helper.error("Fast forward failed.");
490 0 : return ETRC_RET(-7);
491 : }
492 :
493 1 : git_helper.info("Fast forwarding git repo ...");
494 :
495 1 : result = git_helper.fastforward(commits[0], log::Level::DEBUG);
496 1 : if (result.error())
497 : {
498 0 : git_helper.error("Fast forward failed.");
499 0 : return ETRC_RET(-8);
500 : }
501 1 : git_helper.info("Fast forward completed.");
502 1 : return ETRC_RET(0);
503 7 : }
504 :
505 0 : int SyncRepo::branch_sync(GitHelper &git_helper)
506 : {
507 0 : int result_int = false;
508 0 : ETRC_CALL_RET_NP(result_int);
509 :
510 0 : if (!has_branch(git_helper, get_branch())) return ETRC_RET(normal_sync(git_helper));
511 :
512 0 : Result result = git_helper.checkout(get_branch(), get_force(), log::Level::DEBUG);
513 0 : if (result.ok())
514 0 : info("Checkout branch " + get_branch() + ".");
515 : else
516 0 : error("Failed to checkout branch " + get_branch() + ".");
517 0 : return ETRC_RET(result.get_result_code_int());
518 0 : }
519 :
520 0 : void SyncRepo::set_log_level(log::Level log_level)
521 : {
522 0 : m_log_level = log_level;
523 0 : }
524 :
525 21 : log::Level SyncRepo::get_log_level()
526 : {
527 21 : return m_log_level;
528 : }
529 :
530 120 : void SyncRepo::set_repo_idx(std::size_t repo_idx)
531 : {
532 120 : m_repo_idx = repo_idx;
533 120 : }
534 :
535 0 : std::size_t SyncRepo::get_repo_idx() const
536 : {
537 0 : return m_repo_idx;
538 : }
539 :
540 253 : std::size_t &SyncRepo::get_repo_idx()
541 : {
542 253 : return m_repo_idx;
543 : }
544 :
545 120 : void SyncRepo::set_display_repo_idx(bool display_repo_idx)
546 : {
547 120 : m_display_repo_idx = display_repo_idx;
548 120 : }
549 :
550 7 : bool SyncRepo::get_display_repo_idx() const
551 : {
552 7 : return m_display_repo_idx;
553 : }
554 :
555 113 : std::string SyncRepo::get_repo_url()
556 : {
557 113 : assert(get_repo() != nullptr);
558 113 : assert(get_repo()->get_location() != nullptr);
559 :
560 113 : std::string url;
561 113 : if (!get_alt_address())
562 339 : url = get_repo()->get_location()->get_address();
563 : else
564 0 : url = get_repo()->get_location()->get_alt_address();
565 :
566 226 : url += "/" + get_repo()->get_name();
567 :
568 113 : return url;
569 0 : }
570 :
571 13 : void SyncRepo::set_branch(const std::string &branch)
572 : {
573 13 : m_branch = branch;
574 13 : }
575 :
576 276 : const std::string &SyncRepo::get_branch() const
577 : {
578 276 : return m_branch;
579 : }
580 :
581 120 : void SyncRepo::set_alt_address(bool alt_address)
582 : {
583 120 : m_alt_address = alt_address;
584 120 : }
585 :
586 113 : bool SyncRepo::get_alt_address() const
587 : {
588 113 : return m_alt_address;
589 : }
590 :
591 122 : void SyncRepo::set_manifest(std::shared_ptr<Manifest> manifest)
592 : {
593 122 : m_manifest = manifest;
594 122 : }
595 :
596 0 : std::shared_ptr<Manifest> SyncRepo::get_manifest() const
597 : {
598 0 : return m_manifest;
599 : }
600 :
601 0 : void SyncRepo::set_force(bool force)
602 : {
603 0 : m_force = force;
604 0 : }
605 :
606 14 : bool SyncRepo::get_force() const
607 : {
608 14 : return m_force;
609 : }
610 :
611 120 : void SyncRepo::set_workspace_root_clone_method(WorkspaceRootCloneMethod method)
612 : {
613 120 : m_workspace_root_clone_method = method;
614 120 : }
615 :
616 14 : WorkspaceRootCloneMethod SyncRepo::get_workspace_root_clone_method() const
617 : {
618 14 : return m_workspace_root_clone_method;
619 : }
620 :
621 120 : void SyncRepo::set_clone_options(const git::CloneOptions &options)
622 : {
623 120 : m_clone_options = options;
624 120 : }
625 :
626 99 : const git::CloneOptions &SyncRepo::get_clone_options() const
627 : {
628 99 : return m_clone_options;
629 : }
630 :
631 120 : void SyncRepo::set_update_submodules(bool update)
632 : {
633 120 : m_update_submodules = update;
634 120 : }
635 :
636 120 : bool SyncRepo::get_update_submodules() const
637 : {
638 120 : return m_update_submodules;
639 : }
640 :
641 120 : int SyncRepo::maybe_update_submodules(const std::string &abs_path)
642 : {
643 120 : int result = 0;
644 120 : ETRC_CALL_RET(result, abs_path);
645 :
646 120 : if (!get_update_submodules()) return ETRC_RET(0);
647 :
648 0 : auto git = get_git();
649 0 : if (git == nullptr) return ETRC_RET(-1);
650 :
651 0 : Result rresult = git->update_submodules(abs_path, true);
652 0 : if (rresult.error())
653 : {
654 0 : error("Failed to update Git submodules for '" + abs_path + "'");
655 0 : return ETRC_RET(rresult.get_result_code_int());
656 : }
657 0 : return ETRC_RET(0);
658 120 : }
659 :
660 : } // namespace esys::repo::manifest
|