Commit 4a5b781a48a5c4371b6b634d1161390c2d593812

Carlos Martín Nieto 2015-05-07T13:44:28

local: use the packbuilder to push Instead of copying each object individually, as we'd been doing, use the packbuilder which should be faster and give us some feedback. While performing this change, we can hook up the packbuilder's writing to the push progress so the caller knows how far along we are.

diff --git a/src/transports/local.c b/src/transports/local.c
index 51e6540..bb9719c 100644
--- a/src/transports/local.c
+++ b/src/transports/local.c
@@ -289,50 +289,6 @@ static int local_negotiate_fetch(
 	return 0;
 }
 
-static int local_push_copy_object(
-	git_odb *local_odb,
-	git_odb *remote_odb,
-	git_pobject *obj)
-{
-	int error = 0;
-	git_odb_object *odb_obj = NULL;
-	git_odb_stream *odb_stream;
-	size_t odb_obj_size;
-	git_otype odb_obj_type;
-	git_oid remote_odb_obj_oid;
-
-	/* Object already exists in the remote ODB; do nothing and return 0*/
-	if (git_odb_exists(remote_odb, &obj->id))
-		return 0;
-
-	if ((error = git_odb_read(&odb_obj, local_odb, &obj->id)) < 0)
-		return error;
-
-	odb_obj_size = git_odb_object_size(odb_obj);
-	odb_obj_type = git_odb_object_type(odb_obj);
-
-	if ((error = git_odb_open_wstream(&odb_stream, remote_odb,
-		odb_obj_size, odb_obj_type)) < 0)
-		goto on_error;
-
-	if (git_odb_stream_write(odb_stream, (char *)git_odb_object_data(odb_obj),
-		odb_obj_size) < 0 ||
-		git_odb_stream_finalize_write(&remote_odb_obj_oid, odb_stream) < 0) {
-		error = -1;
-	} else if (git_oid__cmp(&obj->id, &remote_odb_obj_oid) != 0) {
-		giterr_set(GITERR_ODB, "Error when writing object to remote odb "
-			"during local push operation. Remote odb object oid does not "
-			"match local oid.");
-		error = -1;
-	}
-
-	git_odb_stream_free(odb_stream);
-
-on_error:
-	git_odb_object_free(odb_obj);
-	return error;
-}
-
 static int local_push_update_remote_ref(
 	git_repository *remote_repo,
 	const char *lref,
@@ -363,21 +319,29 @@ static int local_push_update_remote_ref(
 	return error;
 }
 
+static int transfer_to_push_transfer(const git_transfer_progress *stats, void *payload)
+{
+	const git_remote_callbacks *cbs = payload;
+
+	if (!cbs || !cbs->push_transfer_progress)
+		return 0;
+
+	return cbs->push_transfer_progress(stats->received_objects, stats->total_objects, stats->received_bytes,
+					   cbs->payload);
+}
+
 static int local_push(
 	git_transport *transport,
 	git_push *push,
 	const git_remote_callbacks *cbs)
 {
 	transport_local *t = (transport_local *)transport;
-	git_odb *remote_odb = NULL;
-	git_odb *local_odb = NULL;
 	git_repository *remote_repo = NULL;
 	push_spec *spec;
 	char *url = NULL;
 	const char *path;
-	git_buf buf = GIT_BUF_INIT;
+	git_buf buf = GIT_BUF_INIT, odb_path = GIT_BUF_INIT;
 	int error;
-	unsigned int i;
 	size_t j;
 
 	GIT_UNUSED(cbs);
@@ -408,15 +372,14 @@ static int local_push(
 		goto on_error;
 	}
 
-	if ((error = git_repository_odb__weakptr(&remote_odb, remote_repo)) < 0 ||
-		(error = git_repository_odb__weakptr(&local_odb, push->repo)) < 0)
+	if ((error = git_buf_joinpath(&odb_path, git_repository_path(remote_repo), "objects/pack")) < 0)
 		goto on_error;
 
-	for (i = 0; i < push->pb->nr_objects; i++) {
-		if ((error = local_push_copy_object(local_odb, remote_odb,
-			&push->pb->object_list[i])) < 0)
-			goto on_error;
-	}
+	error = git_packbuilder_write(push->pb, odb_path.ptr, 0, transfer_to_push_transfer, (void *) cbs);
+	git_buf_free(&odb_path);
+
+	if (error < 0)
+		goto on_error;
 
 	push->unpack_ok = 1;