src/esys/repo/githelper.cpp

1 error line(s), 1 error(s)

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