Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ set(GIT2CPP_SRC
${GIT2CPP_SOURCE_DIR}/utils/common.hpp
${GIT2CPP_SOURCE_DIR}/utils/git_exception.cpp
${GIT2CPP_SOURCE_DIR}/utils/git_exception.hpp
${GIT2CPP_SOURCE_DIR}/utils/output.hpp
${GIT2CPP_SOURCE_DIR}/wrapper/annotated_commit_wrapper.cpp
${GIT2CPP_SOURCE_DIR}/wrapper/annotated_commit_wrapper.hpp
${GIT2CPP_SOURCE_DIR}/wrapper/branch_wrapper.cpp
Expand Down
87 changes: 85 additions & 2 deletions src/subcommand/clone_subcommand.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#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)
Expand All @@ -13,9 +14,90 @@ clone_subcommand::clone_subcommand(const libgit2_object&, CLI::App& app)
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_clone_options opts = GIT_CLONE_OPTIONS_INIT;
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())
{
Expand All @@ -27,5 +109,6 @@ void clone_subcommand::run()
m_directory = get_current_git_path() + '/' + short_name;
}
std::cout << "Cloning into '" + short_name + "'..." << std::endl;
repository_wrapper::clone(m_repository, m_directory, opts);
cursor_hider ch;
repository_wrapper::clone(m_repository, m_directory, clone_opts);
}
20 changes: 20 additions & 0 deletions src/utils/output.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#pragma once

#include <iostream>
#include "common.hpp"

// Scope object to hide the cursor. This avoids
// cursor twinkling when rewritting the same line
// too frequently.
struct cursor_hider : noncopyable_nonmovable
{
cursor_hider()
{
std::cout << "\e[?25l";
}

~cursor_hider()
{
std::cout << "\e[?25h";
}
};