mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-07 19:43:37 +00:00
Merge the push report into the refs to avoid a 3rd network call
This commit is contained in:
parent
ff9df88396
commit
df93a6810a
18
src/push.c
18
src/push.c
@ -14,6 +14,20 @@
|
||||
#include "vector.h"
|
||||
#include "push.h"
|
||||
|
||||
static int push_spec_rref_cmp(const void *a, const void *b)
|
||||
{
|
||||
const push_spec *push_spec_a = a, *push_spec_b = b;
|
||||
|
||||
return strcmp(push_spec_a->rref, push_spec_b->rref);
|
||||
}
|
||||
|
||||
static int push_status_ref_cmp(const void *a, const void *b)
|
||||
{
|
||||
const push_status *push_status_a = a, *push_status_b = b;
|
||||
|
||||
return strcmp(push_status_a->ref, push_status_b->ref);
|
||||
}
|
||||
|
||||
int git_push_new(git_push **out, git_remote *remote)
|
||||
{
|
||||
git_push *p;
|
||||
@ -27,12 +41,12 @@ int git_push_new(git_push **out, git_remote *remote)
|
||||
p->remote = remote;
|
||||
p->report_status = 1;
|
||||
|
||||
if (git_vector_init(&p->specs, 0, NULL) < 0) {
|
||||
if (git_vector_init(&p->specs, 0, push_spec_rref_cmp) < 0) {
|
||||
git__free(p);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (git_vector_init(&p->status, 0, NULL) < 0) {
|
||||
if (git_vector_init(&p->status, 0, push_status_ref_cmp) < 0) {
|
||||
git_vector_free(&p->specs);
|
||||
git__free(p);
|
||||
return -1;
|
||||
|
@ -294,6 +294,13 @@ static void git_smart__free(git_transport *transport)
|
||||
git__free(t);
|
||||
}
|
||||
|
||||
static int ref_name_cmp(const void *a, const void *b)
|
||||
{
|
||||
const git_pkt_ref *ref_a = a, *ref_b = b;
|
||||
|
||||
return strcmp(ref_a->head.name, ref_b->head.name);
|
||||
}
|
||||
|
||||
int git_transport_smart(git_transport **out, git_remote *owner, void *param)
|
||||
{
|
||||
transport_smart *t;
|
||||
@ -321,7 +328,7 @@ int git_transport_smart(git_transport **out, git_remote *owner, void *param)
|
||||
t->owner = owner;
|
||||
t->rpc = definition->rpc;
|
||||
|
||||
if (git_vector_init(&t->refs, 16, NULL) < 0) {
|
||||
if (git_vector_init(&t->refs, 16, ref_name_cmp) < 0) {
|
||||
git__free(t);
|
||||
return -1;
|
||||
}
|
||||
|
@ -628,6 +628,108 @@ static int parse_report(gitno_buffer *buf, git_push *push)
|
||||
}
|
||||
}
|
||||
|
||||
static int add_ref_from_push_spec(git_vector *refs, push_spec *push_spec)
|
||||
{
|
||||
git_pkt_ref *added = git__calloc(1, sizeof(git_pkt_ref));
|
||||
GITERR_CHECK_ALLOC(added);
|
||||
|
||||
added->type = GIT_PKT_REF;
|
||||
git_oid_cpy(&added->head.oid, &push_spec->loid);
|
||||
added->head.name = git__strdup(push_spec->rref);
|
||||
|
||||
if (!added->head.name ||
|
||||
git_vector_insert(refs, added) < 0) {
|
||||
git_pkt_free((git_pkt *)added);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int update_refs_from_report(
|
||||
git_vector *refs,
|
||||
git_vector *push_specs,
|
||||
git_vector *push_report)
|
||||
{
|
||||
git_pkt_ref *ref;
|
||||
push_spec *push_spec;
|
||||
push_status *push_status;
|
||||
size_t i, j, refs_len;
|
||||
int cmp;
|
||||
|
||||
/* For each push spec we sent to the server, we should have
|
||||
* gotten back a status packet in the push report */
|
||||
if (push_specs->length != push_report->length) {
|
||||
giterr_set(GITERR_NET, "report-status: protocol error");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* We require that push_specs be sorted with push_spec_rref_cmp,
|
||||
* and that push_report be sorted with push_status_ref_cmp */
|
||||
git_vector_sort(push_specs);
|
||||
git_vector_sort(push_report);
|
||||
|
||||
git_vector_foreach(push_specs, i, push_spec) {
|
||||
push_status = git_vector_get(push_report, i);
|
||||
|
||||
/* For each push spec we sent to the server, we should have
|
||||
* gotten back a status packet in the push report which matches */
|
||||
if (strcmp(push_spec->rref, push_status->ref)) {
|
||||
giterr_set(GITERR_NET, "report-status: protocol error");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* We require that refs be sorted with ref_name_cmp */
|
||||
git_vector_sort(refs);
|
||||
i = j = 0;
|
||||
refs_len = refs->length;
|
||||
|
||||
/* Merge join push_specs with refs */
|
||||
while (i < push_specs->length && j < refs_len) {
|
||||
push_spec = git_vector_get(push_specs, i);
|
||||
ref = git_vector_get(refs, j);
|
||||
|
||||
cmp = strcmp(push_spec->rref, ref->head.name);
|
||||
|
||||
/* Iterate appropriately */
|
||||
if (cmp <= 0) i++;
|
||||
if (cmp >= 0) j++;
|
||||
|
||||
/* Add case */
|
||||
if (cmp < 0 &&
|
||||
!push_status->msg &&
|
||||
add_ref_from_push_spec(refs, push_spec) < 0)
|
||||
return -1;
|
||||
|
||||
/* Update case, delete case */
|
||||
if (cmp == 0 &&
|
||||
!push_status->msg)
|
||||
git_oid_cpy(&ref->head.oid, &push_spec->loid);
|
||||
}
|
||||
|
||||
for (; i < push_specs->length; i++) {
|
||||
push_spec = git_vector_get(push_specs, i);
|
||||
|
||||
/* Add case */
|
||||
if (!push_status->msg &&
|
||||
add_ref_from_push_spec(refs, push_spec) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Remove any refs which we updated to have a zero OID. */
|
||||
git_vector_rforeach(refs, i, ref) {
|
||||
if (git_oid_iszero(&ref->head.oid)) {
|
||||
git_vector_remove(refs, i);
|
||||
git_pkt_free((git_pkt *)ref);
|
||||
}
|
||||
}
|
||||
|
||||
git_vector_sort(refs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stream_thunk(void *buf, size_t size, void *data)
|
||||
{
|
||||
git_smart_subtransport_stream *s = (git_smart_subtransport_stream *)data;
|
||||
@ -640,7 +742,6 @@ int git_smart__push(git_transport *transport, git_push *push)
|
||||
transport_smart *t = (transport_smart *)transport;
|
||||
git_smart_subtransport_stream *s;
|
||||
git_buf pktline = GIT_BUF_INIT;
|
||||
char *url = NULL;
|
||||
int error = -1;
|
||||
|
||||
#ifdef PUSH_DEBUG
|
||||
@ -678,25 +779,13 @@ int git_smart__push(git_transport *transport, git_push *push)
|
||||
else if (parse_report(&t->buffer, push) < 0)
|
||||
goto on_error;
|
||||
|
||||
/* If we updated at least one ref, then we need to re-acquire the list of
|
||||
* refs so the caller can call git_remote_update_tips afterward. TODO: Use
|
||||
* the data from the push report to do this without another network call */
|
||||
if (push->specs.length) {
|
||||
git_cred_acquire_cb cred_cb = t->cred_acquire_cb;
|
||||
void *cred_payload = t->cred_acquire_payload;
|
||||
int flags = t->flags;
|
||||
|
||||
url = git__strdup(t->url);
|
||||
|
||||
if (!url || t->parent.close(&t->parent) < 0 ||
|
||||
t->parent.connect(&t->parent, url, cred_cb, cred_payload, GIT_DIRECTION_PUSH, flags))
|
||||
goto on_error;
|
||||
}
|
||||
if (push->status.length &&
|
||||
update_refs_from_report(&t->refs, &push->specs, &push->status) < 0)
|
||||
goto on_error;
|
||||
|
||||
error = 0;
|
||||
|
||||
on_error:
|
||||
git__free(url);
|
||||
git_buf_free(&pktline);
|
||||
|
||||
return error;
|
||||
|
@ -64,7 +64,7 @@ GIT_INLINE(void *) git_vector_last(const git_vector *v)
|
||||
for ((iter) = 0; (iter) < (v)->length && ((elem) = (v)->contents[(iter)], 1); (iter)++ )
|
||||
|
||||
#define git_vector_rforeach(v, iter, elem) \
|
||||
for ((iter) = (v)->length; (iter) > 0 && ((elem) = (v)->contents[(iter)-1], 1); (iter)-- )
|
||||
for ((iter) = (v)->length - 1; (iter) < SIZE_MAX && ((elem) = (v)->contents[(iter)], 1); (iter)-- )
|
||||
|
||||
int git_vector_insert(git_vector *v, void *element);
|
||||
int git_vector_insert_sorted(git_vector *v, void *element,
|
||||
|
Loading…
Reference in New Issue
Block a user