From fe95ac1b6750a29d4a132d265ec1d050f49b69e8 Mon Sep 17 00:00:00 2001 From: Ben Straub Date: Tue, 5 Feb 2013 10:59:58 -0800 Subject: [PATCH] Allow progress callback to cancel fetch This works by having the indexer watch the return code of the callback, so will only take effect on object boundaries. --- examples/network/clone.c | 3 ++- include/git2/indexer.h | 2 +- src/clone.c | 4 ++-- src/indexer.c | 15 +++++++++------ src/transports/smart_protocol.c | 2 +- tests-clar/network/fetchlocal.c | 3 ++- tests-clar/online/clone.c | 18 +++++++++++++++++- tests-clar/online/fetch.c | 6 ++++-- 8 files changed, 38 insertions(+), 15 deletions(-) diff --git a/examples/network/clone.c b/examples/network/clone.c index 5b0a81073..80e80af27 100644 --- a/examples/network/clone.c +++ b/examples/network/clone.c @@ -44,11 +44,12 @@ static void print_progress(const progress_data *pd) pd->path); } -static void fetch_progress(const git_transfer_progress *stats, void *payload) +static int fetch_progress(const git_transfer_progress *stats, void *payload) { progress_data *pd = (progress_data*)payload; pd->fetch_progress = *stats; print_progress(pd); + return 0; } static void checkout_progress(const char *path, size_t cur, size_t tot, void *payload) { diff --git a/include/git2/indexer.h b/include/git2/indexer.h index c428d43a8..0e62835ce 100644 --- a/include/git2/indexer.h +++ b/include/git2/indexer.h @@ -27,7 +27,7 @@ typedef struct git_transfer_progress { /** * Type for progress callbacks during indexing */ -typedef void (*git_transfer_progress_callback)(const git_transfer_progress *stats, void *payload); +typedef int (*git_transfer_progress_callback)(const git_transfer_progress *stats, void *payload); typedef struct git_indexer git_indexer; typedef struct git_indexer_stream git_indexer_stream; diff --git a/src/clone.c b/src/clone.c index 333bf2148..c7a24f40a 100644 --- a/src/clone.c +++ b/src/clone.c @@ -355,8 +355,8 @@ static int setup_remotes_and_fetch( /* Connect and download everything */ if (!git_remote_connect(origin, GIT_DIRECTION_FETCH)) { - if (!git_remote_download(origin, options->fetch_progress_cb, - options->fetch_progress_payload)) { + if (!(retcode = git_remote_download(origin, options->fetch_progress_cb, + options->fetch_progress_payload))) { /* Create "origin/foo" branches for all remote branches */ if (!git_remote_update_tips(origin)) { /* Point HEAD to the requested branch */ diff --git a/src/indexer.c b/src/indexer.c index 3f6b1076e..08c88ba18 100644 --- a/src/indexer.c +++ b/src/indexer.c @@ -394,15 +394,15 @@ on_error: return -1; } -static void do_progress_callback(git_indexer_stream *idx, git_transfer_progress *stats) +static int do_progress_callback(git_indexer_stream *idx, git_transfer_progress *stats) { - if (!idx->progress_cb) return; - idx->progress_cb(stats, idx->progress_payload); + if (!idx->progress_cb) return 0; + return idx->progress_cb(stats, idx->progress_payload); } int git_indexer_stream_add(git_indexer_stream *idx, const void *data, size_t size, git_transfer_progress *stats) { - int error; + int error = -1; struct git_pack_header hdr; size_t processed; git_mwindow_file *mwf = &idx->pack->mwf; @@ -536,14 +536,17 @@ int git_indexer_stream_add(git_indexer_stream *idx, const void *data, size_t siz } stats->received_objects++; - do_progress_callback(idx, stats); + if (do_progress_callback(idx, stats) < 0) { + error = GIT_EUSER; + goto on_error; + } } return 0; on_error: git_mwindow_free_all(mwf); - return -1; + return error; } static int index_path_stream(git_buf *path, git_indexer_stream *idx, const char *suffix) diff --git a/src/transports/smart_protocol.c b/src/transports/smart_protocol.c index 184b21a0b..a68d242bc 100644 --- a/src/transports/smart_protocol.c +++ b/src/transports/smart_protocol.c @@ -493,7 +493,7 @@ int git_smart__download_pack( git__free(pkt); } else if (pkt->type == GIT_PKT_DATA) { git_pkt_data *p = (git_pkt_data *) pkt; - if (writepack->add(writepack, p->data, p->len, stats) < 0) + if ((error = writepack->add(writepack, p->data, p->len, stats)) < 0) goto on_error; git__free(pkt); diff --git a/tests-clar/network/fetchlocal.c b/tests-clar/network/fetchlocal.c index ee3bd9db3..e2ba675e1 100644 --- a/tests-clar/network/fetchlocal.c +++ b/tests-clar/network/fetchlocal.c @@ -4,11 +4,12 @@ #include "path.h" #include "remote.h" -static void transfer_cb(const git_transfer_progress *stats, void *payload) +static int transfer_cb(const git_transfer_progress *stats, void *payload) { int *callcount = (int*)payload; GIT_UNUSED(stats); (*callcount)++; + return 0; } static void cleanup_local_repo(void *path) diff --git a/tests-clar/online/clone.c b/tests-clar/online/clone.c index 6a46fa511..020c29e9f 100644 --- a/tests-clar/online/clone.c +++ b/tests-clar/online/clone.c @@ -81,11 +81,12 @@ static void checkout_progress(const char *path, size_t cur, size_t tot, void *pa (*was_called) = true; } -static void fetch_progress(const git_transfer_progress *stats, void *payload) +static int fetch_progress(const git_transfer_progress *stats, void *payload) { bool *was_called = (bool*)payload; GIT_UNUSED(stats); (*was_called) = true; + return 0; } void test_online_clone__can_checkout_a_cloned_repo(void) @@ -182,3 +183,18 @@ void test_online_clone__bitbucket_style(void) git_repository_free(g_repo); g_repo = NULL; cl_fixture_cleanup("./foo"); } + +static int cancel_at_half(const git_transfer_progress *stats, void *payload) +{ + GIT_UNUSED(payload); + + if (stats->received_objects > (stats->total_objects/2)) + return -1; + return 0; +} + +void test_online_clone__can_cancel(void) +{ + g_options.fetch_progress_cb = cancel_at_half; + cl_git_fail_with(git_clone(&g_repo, LIVE_REPO_URL, "./foo", &g_options), GIT_EUSER); +} diff --git a/tests-clar/online/fetch.c b/tests-clar/online/fetch.c index 41cdb30e1..d07532778 100644 --- a/tests-clar/online/fetch.c +++ b/tests-clar/online/fetch.c @@ -25,10 +25,11 @@ static int update_tips(const char *refname, const git_oid *a, const git_oid *b, return 0; } -static void progress(const git_transfer_progress *stats, void *payload) +static int progress(const git_transfer_progress *stats, void *payload) { size_t *bytes_received = (size_t *)payload; *bytes_received = stats->received_bytes; + return 0; } static void do_fetch(const char *url, git_remote_autotag_option_t flag, int n) @@ -73,12 +74,13 @@ void test_online_fetch__no_tags_http(void) do_fetch("http://github.com/libgit2/TestGitRepository.git", GIT_REMOTE_DOWNLOAD_TAGS_NONE, 3); } -static void transferProgressCallback(const git_transfer_progress *stats, void *payload) +static int transferProgressCallback(const git_transfer_progress *stats, void *payload) { bool *invoked = (bool *)payload; GIT_UNUSED(stats); *invoked = true; + return 0; } void test_online_fetch__doesnt_retrieve_a_pack_when_the_repository_is_up_to_date(void)