-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathclone_subcommand.cpp
More file actions
114 lines (99 loc) · 3.65 KB
/
clone_subcommand.cpp
File metadata and controls
114 lines (99 loc) · 3.65 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#include <iostream>
#include "../subcommand/clone_subcommand.hpp"
#include "../utils/output.hpp"
#include "../wrapper/repository_wrapper.hpp"
clone_subcommand::clone_subcommand(const libgit2_object&, CLI::App& app)
{
auto* sub = app.add_subcommand("clone", "Clone a directory into a new repository");
sub->add_option("<repository>", m_repository, "The (possibly remote) repository to clone from.")->required();
sub->add_option("<directory>", m_directory, "The name of a new directory to clone into.");
sub->callback([this]() { this->run(); });
}
namespace
{
int sideband_progress(const char* str, int len, void*)
{
printf("remote: %.*s", len, str);
fflush(stdout);
return 0;
}
int fetch_progress(const git_indexer_progress* stats, void* payload)
{
static bool done = false;
// We need to copy stats into payload even if the fetch is done,
// because the checkout_progress callback will be called with the
// same payload and needs the data to be up do date.
auto* pr = reinterpret_cast<git_indexer_progress*>(payload);
*pr = *stats;
if (done)
{
return 0;
}
int network_percent = pr->total_objects > 0 ?
(100 * pr->received_objects / pr->total_objects)
: 0;
size_t mbytes = pr->received_bytes / (1024*1024);
std::cout << "Receiving objects: " << std::setw(4) << network_percent
<< "% (" << pr->received_objects << "/" << pr->total_objects << "), "
<< mbytes << " MiB";
if (pr->received_objects == pr->total_objects)
{
std::cout << ", done." << std::endl;
done = true;
}
else
{
std::cout << '\r';
}
return 0;
}
void checkout_progress(const char* path, size_t cur, size_t tot, void* payload)
{
static bool done = false;
if (done)
{
return;
}
auto* pr = reinterpret_cast<git_indexer_progress*>(payload);
int deltas_percent = pr->total_deltas > 0 ?
(100 * pr->indexed_deltas / pr->total_deltas)
: 0;
std::cout << "Resolving deltas: " << std::setw(4) << deltas_percent
<< "% (" << pr->indexed_deltas << "/" << pr->total_deltas << ")";
if (pr->indexed_deltas == pr->total_deltas)
{
std::cout << ", done." << std::endl;
done = true;
}
else
{
std::cout << '\r';
}
}
}
void clone_subcommand::run()
{
git_indexer_progress pd;
git_clone_options clone_opts = GIT_CLONE_OPTIONS_INIT;
git_checkout_options checkout_opts = GIT_CHECKOUT_OPTIONS_INIT;
checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE;
checkout_opts.progress_cb = checkout_progress;
checkout_opts.progress_payload = &pd;
clone_opts.checkout_opts = checkout_opts;
clone_opts.fetch_opts.callbacks.sideband_progress = sideband_progress;
clone_opts.fetch_opts.callbacks.transfer_progress = fetch_progress;
clone_opts.fetch_opts.callbacks.payload = &pd;
std::string short_name = m_directory;
if (m_directory.empty())
{
auto size = m_repository.size();
auto begin = m_repository.find_last_of('/') + 1;
auto end = m_repository.ends_with(".git") ? size - 4 : size;
auto count = end - begin;
short_name = m_repository.substr(begin, count);
m_directory = get_current_git_path() + '/' + short_name;
}
std::cout << "Cloning into '" + short_name + "'..." << std::endl;
cursor_hider ch;
repository_wrapper::clone(m_repository, m_directory, clone_opts);
}