Commit 216863c48fd05b08e9b0083d61dcb163a2add62a

Ben Straub 2012-10-17T14:02:24

Fetch/indexer: progress callbacks

diff --git a/include/git2/indexer.h b/include/git2/indexer.h
index 87f48fe..0d3c9dd 100644
--- a/include/git2/indexer.h
+++ b/include/git2/indexer.h
@@ -23,6 +23,11 @@ typedef struct git_indexer_stats {
 } git_indexer_stats;
 
 
+/**
+ * Type for progress callbacks during indexing
+ */
+typedef void (*git_indexer_progress_callback)(const git_indexer_stats *stats, void *payload);
+
 typedef struct git_indexer git_indexer;
 typedef struct git_indexer_stream git_indexer_stream;
 
@@ -31,8 +36,14 @@ typedef struct git_indexer_stream git_indexer_stream;
  *
  * @param out where to store the indexer instance
  * @param path to the directory where the packfile should be stored
+ * @param progress_cb function to call with progress information
+ * @param progress_payload payload for the progress callback
  */
-GIT_EXTERN(int) git_indexer_stream_new(git_indexer_stream **out, const char *path);
+GIT_EXTERN(int) git_indexer_stream_new(
+		git_indexer_stream **out,
+		const char *path,
+		git_indexer_progress_callback progress_cb,
+		void *progress_callback_payload);
 
 /**
  * Add data to the indexer
diff --git a/include/git2/remote.h b/include/git2/remote.h
index 9327320..ca75126 100644
--- a/include/git2/remote.h
+++ b/include/git2/remote.h
@@ -184,9 +184,15 @@ GIT_EXTERN(int) git_remote_ls(git_remote *remote, git_headlist_cb list_cb, void 
  *
  * @param remote the remote to download from
  * @param filename where to store the temporary filename
+ * @param progress_cb function to call with progress information
+ * @param progress_payload payload for the progress callback
  * @return 0 or an error code
  */
-GIT_EXTERN(int) git_remote_download(git_remote *remote, git_off_t *bytes);
+GIT_EXTERN(int) git_remote_download(
+		git_remote *remote,
+		git_off_t *bytes,
+		git_indexer_progress_callback progress_cb,
+		void *progress_payload);
 
 /**
  * Check whether the remote is connected
diff --git a/src/clone.c b/src/clone.c
index 2000de6..0acf588 100644
--- a/src/clone.c
+++ b/src/clone.c
@@ -258,7 +258,7 @@ static int setup_remotes_and_fetch(git_repository *repo, const char *origin_url)
 	if (!git_remote_add(&origin, repo, GIT_REMOTE_ORIGIN, origin_url)) {
 		/* Connect and download everything */
 		if (!git_remote_connect(origin, GIT_DIR_FETCH)) {
-			if (!git_remote_download(origin, &bytes)) {
+			if (!git_remote_download(origin, &bytes, NULL, NULL)) {
 				/* 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 */
diff --git a/src/fetch.c b/src/fetch.c
index 2429463..583c79a 100644
--- a/src/fetch.c
+++ b/src/fetch.c
@@ -302,7 +302,11 @@ on_error:
 	return error;
 }
 
-int git_fetch_download_pack(git_remote *remote, git_off_t *bytes)
+int git_fetch_download_pack(
+		git_remote *remote,
+		git_off_t *bytes,
+		git_indexer_progress_callback progress_cb,
+		void *progress_payload)
 {
 	git_transport *t = remote->transport;
 
@@ -312,7 +316,8 @@ int git_fetch_download_pack(git_remote *remote, git_off_t *bytes)
 	if (t->own_logic)
 		return t->download_pack(t, remote->repo, bytes, &remote->stats);
 
-	return git_fetch__download_pack(t, remote->repo, bytes, &remote->stats);
+	return git_fetch__download_pack(t, remote->repo, bytes, &remote->stats,
+			progress_cb, progress_payload);
 
 }
 
@@ -348,7 +353,9 @@ int git_fetch__download_pack(
 	git_transport *t,
 	git_repository *repo,
 	git_off_t *bytes,
-	git_indexer_stats *stats)
+	git_indexer_stats *stats,
+	git_indexer_progress_callback progress_cb,
+	void *progress_payload)
 {
 	git_buf path = GIT_BUF_INIT;
 	gitno_buffer *buf = &t->buffer;
@@ -358,7 +365,7 @@ int git_fetch__download_pack(
 	if (git_buf_joinpath(&path, git_repository_path(repo), "objects/pack") < 0)
 		return -1;
 
-	if (git_indexer_stream_new(&idx, git_buf_cstr(&path)) < 0)
+	if (git_indexer_stream_new(&idx, git_buf_cstr(&path), progress_cb, progress_payload) < 0)
 		goto on_error;
 
 	git_buf_free(&path);
diff --git a/src/fetch.h b/src/fetch.h
index ae030c6..c109734 100644
--- a/src/fetch.h
+++ b/src/fetch.h
@@ -10,9 +10,21 @@
 #include "netops.h"
 
 int git_fetch_negotiate(git_remote *remote);
-int git_fetch_download_pack(git_remote *remote, git_off_t *bytes);
 
-int git_fetch__download_pack(git_transport *t, git_repository *repo, git_off_t *bytes, git_indexer_stats *stats);
+int git_fetch_download_pack(
+		git_remote *remote,
+		git_off_t *bytes,
+		git_indexer_progress_callback progress_cb,
+		void *progress_payload);
+
+int git_fetch__download_pack(
+		git_transport *t,
+		git_repository *repo,
+		git_off_t *bytes,
+		git_indexer_stats *stats,
+		git_indexer_progress_callback progress_cb,
+		void *progress_payload);
+
 int git_fetch_setup_walk(git_revwalk **out, git_repository *repo);
 
 #endif
diff --git a/src/indexer.c b/src/indexer.c
index 7d4e18d..2d032fb 100644
--- a/src/indexer.c
+++ b/src/indexer.c
@@ -49,6 +49,8 @@ struct git_indexer_stream {
 	git_vector deltas;
 	unsigned int fanout[256];
 	git_oid hash;
+	git_indexer_progress_callback progress_cb;
+	void *progress_payload;
 };
 
 struct delta_info {
@@ -138,7 +140,11 @@ static int cache_cmp(const void *a, const void *b)
 	return git_oid_cmp(&ea->sha1, &eb->sha1);
 }
 
-int git_indexer_stream_new(git_indexer_stream **out, const char *prefix)
+int git_indexer_stream_new(
+		git_indexer_stream **out,
+		const char *prefix,
+		git_indexer_progress_callback progress_cb,
+		void *progress_payload)
 {
 	git_indexer_stream *idx;
 	git_buf path = GIT_BUF_INIT;
@@ -147,6 +153,8 @@ int git_indexer_stream_new(git_indexer_stream **out, const char *prefix)
 
 	idx = git__calloc(1, sizeof(git_indexer_stream));
 	GITERR_CHECK_ALLOC(idx);
+	idx->progress_cb = progress_cb;
+	idx->progress_payload = progress_payload;
 
 	error = git_buf_joinpath(&path, prefix, suff);
 	if (error < 0)
@@ -273,6 +281,12 @@ on_error:
 	return -1;
 }
 
+static void do_progress_callback(git_indexer_stream *idx, git_indexer_stats *stats)
+{
+	if (!idx->progress_cb) return;
+	idx->progress_cb(stats, idx->progress_payload);
+}
+
 int git_indexer_stream_add(git_indexer_stream *idx, const void *data, size_t size, git_indexer_stats *stats)
 {
 	int error;
@@ -326,6 +340,7 @@ int git_indexer_stream_add(git_indexer_stream *idx, const void *data, size_t siz
 
 		memset(stats, 0, sizeof(git_indexer_stats));
 		stats->total = (unsigned int)idx->nr_objects;
+		do_progress_callback(idx, stats);
 	}
 
 	/* Now that we have data in the pack, let's try to parse it */
@@ -362,6 +377,7 @@ int git_indexer_stream_add(git_indexer_stream *idx, const void *data, size_t siz
 				return error;
 
 			stats->received++;
+			do_progress_callback(idx, stats);
 			continue;
 		}
 
@@ -381,6 +397,7 @@ int git_indexer_stream_add(git_indexer_stream *idx, const void *data, size_t siz
 
 		stats->processed = (unsigned int)++processed;
 		stats->received++;
+		do_progress_callback(idx, stats);
 	}
 
 	return 0;
diff --git a/src/remote.c b/src/remote.c
index 4b40441..662b8cc 100644
--- a/src/remote.c
+++ b/src/remote.c
@@ -433,7 +433,11 @@ int git_remote_ls(git_remote *remote, git_headlist_cb list_cb, void *payload)
 	return 0;
 }
 
-int git_remote_download(git_remote *remote, git_off_t *bytes)
+int git_remote_download(
+		git_remote *remote,
+		git_off_t *bytes,
+		git_indexer_progress_callback progress_cb,
+		void *progress_payload)
 {
 	int error;
 
@@ -442,7 +446,7 @@ int git_remote_download(git_remote *remote, git_off_t *bytes)
 	if ((error = git_fetch_negotiate(remote)) < 0)
 		return error;
 
-	return git_fetch_download_pack(remote, bytes);
+	return git_fetch_download_pack(remote, bytes, progress_cb, progress_payload);
 }
 
 int git_remote_update_tips(git_remote *remote)
diff --git a/tests-clar/network/fetch.c b/tests-clar/network/fetch.c
index 1e9a232..134e8fe 100644
--- a/tests-clar/network/fetch.c
+++ b/tests-clar/network/fetch.c
@@ -28,11 +28,19 @@ static int update_tips(const char *refname, const git_oid *a, const git_oid *b, 
 	return 0;
 }
 
+static void progress(const git_indexer_stats *stats, void *payload)
+{
+	GIT_UNUSED(stats);
+	bool *was_called = (bool*)payload;
+	*was_called = true;
+}
+
 static void do_fetch(const char *url, int flag, int n)
 {
 	git_remote *remote;
 	git_off_t bytes;
 	git_remote_callbacks callbacks;
+	bool progress_was_called = false;
 
 	memset(&callbacks, 0, sizeof(git_remote_callbacks));
 	callbacks.update_tips = update_tips;
@@ -42,10 +50,11 @@ static void do_fetch(const char *url, int flag, int n)
 	git_remote_set_callbacks(remote, &callbacks);
 	git_remote_set_autotag(remote, flag);
 	cl_git_pass(git_remote_connect(remote, GIT_DIR_FETCH));
-	cl_git_pass(git_remote_download(remote, &bytes));
+	cl_git_pass(git_remote_download(remote, &bytes, progress, &progress_was_called));
 	git_remote_disconnect(remote);
 	cl_git_pass(git_remote_update_tips(remote));
 	cl_assert_equal_i(counter, n);
+	cl_assert_equal_i(progress_was_called, true);
 
 	git_remote_free(remote);
 }