Commit 9c258af0 by Russell Belfer

Merge pull request #1316 from ben/clone-cancel

Allow network operations to cancel
parents 40a60510 ea57f66b
...@@ -44,11 +44,12 @@ static void print_progress(const progress_data *pd) ...@@ -44,11 +44,12 @@ static void print_progress(const progress_data *pd)
pd->path); 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; progress_data *pd = (progress_data*)payload;
pd->fetch_progress = *stats; pd->fetch_progress = *stats;
print_progress(pd); print_progress(pd);
return 0;
} }
static void checkout_progress(const char *path, size_t cur, size_t tot, void *payload) static void checkout_progress(const char *path, size_t cur, size_t tot, void *payload)
{ {
......
...@@ -25,9 +25,13 @@ typedef struct git_transfer_progress { ...@@ -25,9 +25,13 @@ typedef struct git_transfer_progress {
/** /**
* Type for progress callbacks during indexing * Type for progress callbacks during indexing. Return a value less than zero
* to cancel the transfer.
*
* @param stats Structure containing information about the state of the transfer
* @param payload Payload provided by caller
*/ */
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 git_indexer;
typedef struct git_indexer_stream git_indexer_stream; typedef struct git_indexer_stream git_indexer_stream;
......
...@@ -355,8 +355,8 @@ static int setup_remotes_and_fetch( ...@@ -355,8 +355,8 @@ static int setup_remotes_and_fetch(
/* Connect and download everything */ /* Connect and download everything */
if (!git_remote_connect(origin, GIT_DIRECTION_FETCH)) { if (!git_remote_connect(origin, GIT_DIRECTION_FETCH)) {
if (!git_remote_download(origin, options->fetch_progress_cb, if (!(retcode = git_remote_download(origin, options->fetch_progress_cb,
options->fetch_progress_payload)) { options->fetch_progress_payload))) {
/* Create "origin/foo" branches for all remote branches */ /* Create "origin/foo" branches for all remote branches */
if (!git_remote_update_tips(origin)) { if (!git_remote_update_tips(origin)) {
/* Point HEAD to the requested branch */ /* Point HEAD to the requested branch */
......
...@@ -394,15 +394,15 @@ on_error: ...@@ -394,15 +394,15 @@ on_error:
return -1; 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; if (!idx->progress_cb) return 0;
idx->progress_cb(stats, idx->progress_payload); 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 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; struct git_pack_header hdr;
size_t processed; size_t processed;
git_mwindow_file *mwf = &idx->pack->mwf; 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 ...@@ -536,14 +536,17 @@ int git_indexer_stream_add(git_indexer_stream *idx, const void *data, size_t siz
} }
stats->received_objects++; stats->received_objects++;
do_progress_callback(idx, stats); if (do_progress_callback(idx, stats) != 0) {
error = GIT_EUSER;
goto on_error;
}
} }
return 0; return 0;
on_error: on_error:
git_mwindow_free_all(mwf); git_mwindow_free_all(mwf);
return -1; return error;
} }
static int index_path_stream(git_buf *path, git_indexer_stream *idx, const char *suffix) static int index_path_stream(git_buf *path, git_indexer_stream *idx, const char *suffix)
......
...@@ -493,7 +493,7 @@ int git_smart__download_pack( ...@@ -493,7 +493,7 @@ int git_smart__download_pack(
git__free(pkt); git__free(pkt);
} else if (pkt->type == GIT_PKT_DATA) { } else if (pkt->type == GIT_PKT_DATA) {
git_pkt_data *p = (git_pkt_data *) pkt; 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; goto on_error;
git__free(pkt); git__free(pkt);
......
...@@ -4,11 +4,12 @@ ...@@ -4,11 +4,12 @@
#include "path.h" #include "path.h"
#include "remote.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; int *callcount = (int*)payload;
GIT_UNUSED(stats); GIT_UNUSED(stats);
(*callcount)++; (*callcount)++;
return 0;
} }
static void cleanup_local_repo(void *path) static void cleanup_local_repo(void *path)
......
...@@ -81,11 +81,12 @@ static void checkout_progress(const char *path, size_t cur, size_t tot, void *pa ...@@ -81,11 +81,12 @@ static void checkout_progress(const char *path, size_t cur, size_t tot, void *pa
(*was_called) = true; (*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; bool *was_called = (bool*)payload;
GIT_UNUSED(stats); GIT_UNUSED(stats);
(*was_called) = true; (*was_called) = true;
return 0;
} }
void test_online_clone__can_checkout_a_cloned_repo(void) void test_online_clone__can_checkout_a_cloned_repo(void)
...@@ -182,3 +183,18 @@ void test_online_clone__bitbucket_style(void) ...@@ -182,3 +183,18 @@ void test_online_clone__bitbucket_style(void)
git_repository_free(g_repo); g_repo = NULL; git_repository_free(g_repo); g_repo = NULL;
cl_fixture_cleanup("./foo"); 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);
}
...@@ -25,10 +25,11 @@ static int update_tips(const char *refname, const git_oid *a, const git_oid *b, ...@@ -25,10 +25,11 @@ static int update_tips(const char *refname, const git_oid *a, const git_oid *b,
return 0; 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; size_t *bytes_received = (size_t *)payload;
*bytes_received = stats->received_bytes; *bytes_received = stats->received_bytes;
return 0;
} }
static void do_fetch(const char *url, git_remote_autotag_option_t flag, int n) 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) ...@@ -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); 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; bool *invoked = (bool *)payload;
GIT_UNUSED(stats); GIT_UNUSED(stats);
*invoked = true; *invoked = true;
return 0;
} }
void test_online_fetch__doesnt_retrieve_a_pack_when_the_repository_is_up_to_date(void) void test_online_fetch__doesnt_retrieve_a_pack_when_the_repository_is_up_to_date(void)
...@@ -110,3 +112,25 @@ void test_online_fetch__doesnt_retrieve_a_pack_when_the_repository_is_up_to_date ...@@ -110,3 +112,25 @@ void test_online_fetch__doesnt_retrieve_a_pack_when_the_repository_is_up_to_date
git_remote_free(remote); git_remote_free(remote);
git_repository_free(_repository); git_repository_free(_repository);
} }
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_fetch__can_cancel(void)
{
git_remote *remote;
size_t bytes_received = 0;
cl_git_pass(git_remote_create(&remote, _repo, "test",
"http://github.com/libgit2/TestGitRepository.git"));
cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH));
cl_git_fail_with(git_remote_download(remote, cancel_at_half, &bytes_received), GIT_EUSER);
git_remote_disconnect(remote);
git_remote_free(remote);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment