Commit cd430bc786877794b820b045ce610d2ac78036b3

Edward Thomson 2015-05-13T14:26:20

Merge pull request #3103 from libgit2/cmn/local-push-message Use the packbuilder in local push

diff --git a/src/transports/local.c b/src/transports/local.c
index 9dd4486..3b031a5 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);
@@ -398,22 +362,24 @@ static int local_push(
 
 	/* We don't currently support pushing locally to non-bare repos. Proper
 	   non-bare repo push support would require checking configs to see if
-	   we should override the default 'don't let this happen' behavior */
+	   we should override the default 'don't let this happen' behavior.
+
+	   Note that this is only an issue when pushing to the current branch,
+	   but we forbid all pushes just in case */
 	if (!remote_repo->is_bare) {
 		error = GIT_EBAREREPO;
 		giterr_set(GITERR_INVALID, "Local push doesn't (yet) support pushing to non-bare repos.");
 		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;
 
diff --git a/tests/network/remote/local.c b/tests/network/remote/local.c
index 21cb93c..9d96184 100644
--- a/tests/network/remote/local.c
+++ b/tests/network/remote/local.c
@@ -217,7 +217,7 @@ void test_network_remote_local__push_to_bare_remote(void)
 	cl_git_pass(git_remote_connect(localremote, GIT_DIRECTION_PUSH, NULL));
 
 	/* Try to push */
-	cl_git_pass(git_remote_upload(remote, &push_array, NULL));
+	cl_git_pass(git_remote_upload(localremote, &push_array, NULL));
 
 	/* Clean up */
 	git_remote_free(localremote);
@@ -256,7 +256,7 @@ void test_network_remote_local__push_to_bare_remote_with_file_url(void)
 	cl_git_pass(git_remote_connect(localremote, GIT_DIRECTION_PUSH, NULL));
 
 	/* Try to push */
-	cl_git_pass(git_remote_upload(remote, &push_array, NULL));
+	cl_git_pass(git_remote_upload(localremote, &push_array, NULL));
 
 	/* Clean up */
 	git_remote_free(localremote);