Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

A real struct for indicating progress #890

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6,971 changes: 6,971 additions & 0 deletions TAGS

Large diffs are not rendered by default.

44 changes: 33 additions & 11 deletions examples/network/clone.c
Expand Up @@ -8,9 +8,9 @@
#include <unistd.h>

struct dl_data {
git_indexer_stats fetch_stats;
git_indexer_stats checkout_stats;
git_progress_multistage progress;
git_checkout_opts opts;

int ret;
int finished;
const char *url;
Expand All @@ -23,15 +23,41 @@ static void *clone_thread(void *ptr)
git_repository *repo = NULL;

// Kick off the clone
data->ret = git_clone(&repo, data->url, data->path,
&data->fetch_stats, &data->checkout_stats,
&data->opts);
data->ret = git_clone(&repo, data->url, data->path, &data->progress, &data->opts);
if (repo) git_repository_free(repo);
data->finished = 1;

pthread_exit(&data->ret);
}

void print_progress(git_progress_multistage *msp)
{
size_t composite_percentage = 0;
int i;

printf("Progress: ");
for (i=0; i < msp->count; i++) {
git_progress r = msp->stages[i];
size_t percentage;

if (i != 0) printf(" / ");

percentage = r.total == 0
? 0
: 100 * r.current / r.total;
composite_percentage += percentage;

/*printf(" %zu/%zu", r.current, r.total);*/
if (r.total == 0)
printf("---%%");
else
printf("%3zu%%", percentage);
}
printf(" ==> ");
/*printf("%zu/%zu ", t_num, t_den);*/
printf("(%3zu%%)\n", msp->count == 0 ? 0 : composite_percentage / msp->count);
}

int do_clone(git_repository *repo, int argc, char **argv)
{
struct dl_data data = {0};
Expand All @@ -55,13 +81,9 @@ int do_clone(git_repository *repo, int argc, char **argv)
// Watch for progress information
do {
usleep(10000);
printf("Fetch %d/%d – Checkout %d/%d\n",
data.fetch_stats.processed, data.fetch_stats.total,
data.checkout_stats.processed, data.checkout_stats.total);
print_progress(&data.progress);
} while (!data.finished);
printf("Fetch %d/%d – Checkout %d/%d\n",
data.fetch_stats.processed, data.fetch_stats.total,
data.checkout_stats.processed, data.checkout_stats.total);
print_progress(&data.progress);

return data.ret;
}
Expand Down
4 changes: 2 additions & 2 deletions examples/network/fetch.c
Expand Up @@ -107,15 +107,15 @@ int fetch(git_repository *repo, int argc, char **argv)
usleep(10000);

if (stats.total > 0)
printf("Received %d/%d objects (%d) in %d bytes\r",
printf("Received %u/%u objects (%u) in %lld bytes\r",
stats.received, stats.total, stats.processed, bytes);
} while (!data.finished);

if (data.ret < 0)
goto on_error;

pthread_join(worker, NULL);
printf("\rReceived %d/%d objects in %zu bytes\n", stats.processed, stats.total, bytes);
printf("\rReceived %u/%u objects in %lld bytes\n", stats.processed, stats.total, bytes);

// Disconnect the underlying connection to prevent from idling.
git_remote_disconnect(remote);
Expand Down
4 changes: 2 additions & 2 deletions include/git2/checkout.h
Expand Up @@ -44,7 +44,7 @@ typedef struct git_checkout_opts {
*/
GIT_EXTERN(int) git_checkout_head(git_repository *repo,
git_checkout_opts *opts,
git_indexer_stats *stats);
git_progress *progress);



Expand All @@ -58,7 +58,7 @@ GIT_EXTERN(int) git_checkout_head(git_repository *repo,
*/
GIT_EXTERN(int) git_checkout_reference(git_reference *ref,
git_checkout_opts *opts,
git_indexer_stats *stats);
git_progress *progress);


/** @} */
Expand Down
5 changes: 2 additions & 3 deletions include/git2/clone.h
Expand Up @@ -36,8 +36,7 @@ GIT_BEGIN_DECL
GIT_EXTERN(int) git_clone(git_repository **out,
const char *origin_url,
const char *workdir_path,
git_indexer_stats *fetch_stats,
git_indexer_stats *checkout_stats,
git_progress_multistage *progress,
git_checkout_opts *checkout_opts);

/**
Expand All @@ -52,7 +51,7 @@ GIT_EXTERN(int) git_clone(git_repository **out,
GIT_EXTERN(int) git_clone_bare(git_repository **out,
const char *origin_url,
const char *dest_path,
git_indexer_stats *fetch_stats);
git_progress_multistage *progress);

/** @} */
GIT_END_DECL
Expand Down
15 changes: 15 additions & 0 deletions include/git2/common.h
Expand Up @@ -90,6 +90,21 @@ typedef struct {
size_t count;
} git_strarray;

#define GIT_PROGRESS_STAGE_TRANSFER 0
#define GIT_PROGRESS_STAGE_INDEX 1
#define GIT_PROGRESS_STAGE_CHECKOUT 2

typedef struct git_progress {
size_t current;
size_t total;
} git_progress;

typedef struct git_progress_multistage {
size_t count;
git_progress stages[8];
int stage_types[8];
} git_progress_multistage;

GIT_EXTERN(void) git_strarray_free(git_strarray *array);
GIT_EXTERN(int) git_strarray_copy(git_strarray *tgt, const git_strarray *src);

Expand Down
2 changes: 1 addition & 1 deletion include/git2/index.h
Expand Up @@ -346,7 +346,7 @@ GIT_EXTERN(int) git_index_entry_stage(const git_index_entry *entry);
* @param stats structure that receives the total node count (may be NULL)
* @return 0 or an error code
*/
GIT_EXTERN(int) git_index_read_tree(git_index *index, git_tree *tree, git_indexer_stats *stats);
GIT_EXTERN(int) git_index_read_tree(git_index *index, git_tree *tree, size_t *total);

/** @} */
GIT_END_DECL
Expand Down
2 changes: 2 additions & 0 deletions include/git2/indexer.h
Expand Up @@ -20,6 +20,8 @@ typedef struct git_indexer_stats {
unsigned int total;
unsigned int processed;
unsigned int received;
git_progress *transfer_progress;
git_progress *index_progress;
} git_indexer_stats;


Expand Down
20 changes: 10 additions & 10 deletions src/checkout.c
Expand Up @@ -27,7 +27,7 @@ GIT_BEGIN_DECL

typedef struct tree_walk_data
{
git_indexer_stats *stats;
git_progress *progress;
git_checkout_opts *opts;
git_repository *repo;
git_odb *odb;
Expand Down Expand Up @@ -145,23 +145,23 @@ static int checkout_walker(const char *path, const git_tree_entry *entry, void *
}

git_buf_free(&fnbuf);
data->stats->processed++;
data->progress->current++;
return retcode;
}


int git_checkout_head(git_repository *repo, git_checkout_opts *opts, git_indexer_stats *stats)
int git_checkout_head(git_repository *repo, git_checkout_opts *opts, git_progress *progress)
{
int retcode = GIT_ERROR;
git_indexer_stats dummy_stats;
git_progress dummy_progress;
git_checkout_opts default_opts = {0};
git_tree *tree;
tree_walk_data payload;
git_config *cfg;

assert(repo);
if (!opts) opts = &default_opts;
if (!stats) stats = &dummy_stats;
if (!progress) progress = &dummy_progress;

/* Default options */
if (!opts->existing_file_action)
Expand All @@ -186,16 +186,16 @@ int git_checkout_head(git_repository *repo, git_checkout_opts *opts, git_indexer
}
}

stats->total = stats->processed = 0;
payload.stats = stats;
progress->current = progress->total = 0;
payload.progress = progress;
payload.opts = opts;
payload.repo = repo;
if (git_repository_odb(&payload.odb, repo) < 0) return GIT_ERROR;

if (!git_repository_head_tree(&tree, repo)) {
git_index *idx;
if (!(retcode = git_repository_index(&idx, repo))) {
if (!(retcode = git_index_read_tree(idx, tree, stats))) {
if (!(retcode = git_index_read_tree(idx, tree, &progress->total))) {
git_index_write(idx);
retcode = git_tree_walk(tree, checkout_walker, GIT_TREEWALK_POST, &payload);
}
Expand All @@ -211,7 +211,7 @@ int git_checkout_head(git_repository *repo, git_checkout_opts *opts, git_indexer

int git_checkout_reference(git_reference *ref,
git_checkout_opts *opts,
git_indexer_stats *stats)
git_progress *progress)
{
git_repository *repo= git_reference_owner(ref);
git_reference *head = NULL;
Expand All @@ -221,7 +221,7 @@ int git_checkout_reference(git_reference *ref,
git_reference_name(ref), true)) < 0)
return retcode;

retcode = git_checkout_head(git_reference_owner(ref), opts, stats);
retcode = git_checkout_head(git_reference_owner(ref), opts, progress);

git_reference_free(head);
return retcode;
Expand Down
38 changes: 24 additions & 14 deletions src/clone.c
Expand Up @@ -146,20 +146,26 @@ static int update_head_to_remote(git_repository *repo, git_remote *remote)

static int setup_remotes_and_fetch(git_repository *repo,
const char *origin_url,
git_indexer_stats *fetch_stats)
git_progress_multistage *progress)
{
int retcode = GIT_ERROR;
git_remote *origin = NULL;
git_off_t bytes = 0;
git_indexer_stats dummy_stats;
git_indexer_stats dummy_stats = {0};
git_progress_multistage dummy_progress = {0};

if (!fetch_stats) fetch_stats = &dummy_stats;
if (!progress) progress = &dummy_progress;

/* Set up indexer stats to update multistage progress directly */
dummy_stats.transfer_progress = &progress->stages[0];
dummy_stats.index_progress = &progress->stages[1];

/* Create the "origin" remote */
if (!git_remote_add(&origin, repo, "origin", origin_url)) {

/* Connect and download everything */
if (!git_remote_connect(origin, GIT_DIR_FETCH)) {
if (!git_remote_download(origin, &bytes, fetch_stats)) {
if (!git_remote_download(origin, &bytes, &dummy_stats)) {
/* Create "origin/foo" branches for all remote branches */
if (!git_remote_update_tips(origin)) {
/* Point HEAD to the same ref as the remote's head */
Expand Down Expand Up @@ -193,21 +199,26 @@ static bool path_is_okay(const char *path)
static int clone_internal(git_repository **out,
const char *origin_url,
const char *path,
git_indexer_stats *fetch_stats,
git_progress_multistage *progress,
int is_bare)
{
int retcode = GIT_ERROR;
git_repository *repo = NULL;
git_indexer_stats dummy_stats;
git_progress_multistage dummy_progress = {0};

if (!fetch_stats) fetch_stats = &dummy_stats;
if (!progress) progress = &dummy_progress;

if (!path_is_okay(path)) {
return GIT_ERROR;
}

progress->count = 3;
progress->stage_types[0] = GIT_PROGRESS_STAGE_TRANSFER;
progress->stage_types[1] = GIT_PROGRESS_STAGE_INDEX;
progress->stage_types[2] = GIT_PROGRESS_STAGE_CHECKOUT;

if (!(retcode = git_repository_init(&repo, path, is_bare))) {
if ((retcode = setup_remotes_and_fetch(repo, origin_url, fetch_stats)) < 0) {
if ((retcode = setup_remotes_and_fetch(repo, origin_url, progress)) < 0) {
/* Failed to fetch; clean up */
git_repository_free(repo);
git_futils_rmdir_r(path, GIT_DIRREMOVAL_FILES_AND_DIRS);
Expand All @@ -223,26 +234,25 @@ static int clone_internal(git_repository **out,
int git_clone_bare(git_repository **out,
const char *origin_url,
const char *dest_path,
git_indexer_stats *fetch_stats)
git_progress_multistage *progress)
{
assert(out && origin_url && dest_path);
return clone_internal(out, origin_url, dest_path, fetch_stats, 1);
return clone_internal(out, origin_url, dest_path, progress, 1);
}


int git_clone(git_repository **out,
const char *origin_url,
const char *workdir_path,
git_indexer_stats *fetch_stats,
git_indexer_stats *checkout_stats,
git_progress_multistage *progress,
git_checkout_opts *checkout_opts)
{
int retcode = GIT_ERROR;

assert(out && origin_url && workdir_path);

if (!(retcode = clone_internal(out, origin_url, workdir_path, fetch_stats, 0))) {
retcode = git_checkout_head(*out, checkout_opts, checkout_stats);
if (!(retcode = clone_internal(out, origin_url, workdir_path, progress, 0))) {
retcode = git_checkout_head(*out, checkout_opts, &progress->stages[2]);
}

return retcode;
Expand Down
7 changes: 6 additions & 1 deletion src/fetch.c
Expand Up @@ -332,7 +332,12 @@ int git_fetch__download_pack(
goto on_error;

git_buf_free(&path);
memset(stats, 0, sizeof(git_indexer_stats));
stats->processed = stats->received = stats->total = 0;
if (stats->transfer_progress)
stats->transfer_progress->current = stats->transfer_progress->total = 0;
if (stats->index_progress)
stats->index_progress->current = stats->index_progress->total = 0;

*bytes = 0;

/*
Expand Down
14 changes: 7 additions & 7 deletions src/index.c
Expand Up @@ -988,7 +988,7 @@ int git_index_entry_stage(const git_index_entry *entry)

typedef struct read_tree_data {
git_index *index;
git_indexer_stats *stats;
size_t *total;
} read_tree_data;

static int read_tree_cb(const char *root, const git_tree_entry *tentry, void *data)
Expand All @@ -997,7 +997,7 @@ static int read_tree_cb(const char *root, const git_tree_entry *tentry, void *da
git_index_entry *entry = NULL;
git_buf path = GIT_BUF_INIT;

rtd->stats->total++;
(*rtd->total)++;

if (git_tree_entry__is_tree(tentry))
return 0;
Expand All @@ -1021,14 +1021,14 @@ static int read_tree_cb(const char *root, const git_tree_entry *tentry, void *da
return 0;
}

int git_index_read_tree(git_index *index, git_tree *tree, git_indexer_stats *stats)
int git_index_read_tree(git_index *index, git_tree *tree, size_t *total)
{
git_indexer_stats dummy_stats;
size_t dummy_total = 0;
read_tree_data rtd = {index, NULL};

if (!stats) stats = &dummy_stats;
stats->total = 0;
rtd.stats = stats;
if (!total) total = &dummy_total;
*total = 0;
rtd.total = total;

git_index_clear(index);

Expand Down