summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorCarlos Martín Nieto <carlos@cmartin.tk>2011-08-05 15:45:05 +0200
committerVicent Marti <tanoku@gmail.com>2011-08-18 02:34:08 +0200
commit0437d991bfb67ffd2d3bb3d5a2cf21261ea42029 (patch)
tree0f608c415479b3a1be2e98a339d4ce10ca22f43a /src
parent48a65a071d9d6689a0ebb7891a20e8dab5fd3cdd (diff)
downloadlibgit2-0437d991bfb67ffd2d3bb3d5a2cf21261ea42029.tar.gz
Use common capabilities
Signed-off-by: Carlos Martín Nieto <carlos@cmartin.tk>
Diffstat (limited to 'src')
-rw-r--r--src/pkt.c36
-rw-r--r--src/pkt.h3
-rw-r--r--src/transport.h7
-rw-r--r--src/transport_git.c37
4 files changed, 78 insertions, 5 deletions
diff --git a/src/pkt.c b/src/pkt.c
index fa0ee7701..12f1478b8 100644
--- a/src/pkt.c
+++ b/src/pkt.c
@@ -269,13 +269,35 @@ int git_pkt_send_flush(int s)
return gitno_send(s, flush, STRLEN(flush), 0);
}
+static int send_want_with_caps(git_remote_head *head, git_transport_caps *caps, int fd)
+{
+ char capstr[20]; /* Longer than we need */
+ char oid[GIT_OID_HEXSZ +1] = {0}, *cmd;
+ int error, len;
+
+ if (caps->ofs_delta)
+ strcpy(capstr, GIT_CAP_OFS_DELTA);
+
+ len = STRLEN("XXXXwant ") + GIT_OID_HEXSZ + 1 /* NUL */ + strlen(capstr) + 1 /* LF */;
+ cmd = git__malloc(len + 1);
+ if (cmd == NULL)
+ return GIT_ENOMEM;
+
+ git_oid_fmt(oid, &head->oid);
+ memset(cmd, 0x0, len + 1);
+ snprintf(cmd, len + 1, "%04xwant %s%c%s\n", len, oid, 0, capstr);
+ error = gitno_send(fd, cmd, len, 0);
+ free(cmd);
+ return error;
+}
+
/*
* All "want" packets have the same length and format, so what we do
* is overwrite the OID each time.
*/
#define WANT_PREFIX "0032want "
-int git_pkt_send_wants(git_headarray *refs, int fd)
+int git_pkt_send_wants(git_headarray *refs, git_transport_caps *caps, int fd)
{
unsigned int i;
int ret = GIT_SUCCESS;
@@ -286,10 +308,18 @@ int git_pkt_send_wants(git_headarray *refs, int fd)
buf[sizeof(buf) - 2] = '\n';
buf[sizeof(buf) - 1] = '\0';
- for (i = 0; i < refs->len; ++i) {
+ if (refs->len > 0 && caps->common) {
+ /* Some capabilities are active, so we need to send what we support */
+ send_want_with_caps(refs->heads[0], caps, fd);
+ i = 1;
+ } else {
+ i = 0;
+ }
+
+ for (; i < refs->len; ++i) {
head = refs->heads[i];
if (head->type != GIT_WHN_WANT)
- continue;
+ continue; /* FIXME: return? refs shouldn't have any other type */
git_oid_fmt(buf + STRLEN(WANT_PREFIX), &head->oid);
gitno_send(fd, buf, STRLEN(buf), 0);
diff --git a/src/pkt.h b/src/pkt.h
index 3a8fac5e1..1c6a20659 100644
--- a/src/pkt.h
+++ b/src/pkt.h
@@ -27,6 +27,7 @@
#define INCLUDE_pkt_h__
#include "common.h"
+#include "transport.h"
#include "git2/net.h"
enum git_pkt_type {
@@ -76,7 +77,7 @@ typedef struct {
int git_pkt_parse_line(git_pkt **head, const char *line, const char **out, size_t len);
int git_pkt_send_flush(int s);
int git_pkt_send_done(int s);
-int git_pkt_send_wants(git_headarray *refs, int fd);
+int git_pkt_send_wants(git_headarray *refs, git_transport_caps *caps, int fd);
int git_pkt_send_have(git_oid *oid, int fd);
void git_pkt_free(git_pkt *pkt);
diff --git a/src/transport.h b/src/transport.h
index 0e0869752..e809734a7 100644
--- a/src/transport.h
+++ b/src/transport.h
@@ -5,6 +5,13 @@
#include "git2/net.h"
#include "vector.h"
+#define GIT_CAP_OFS_DELTA "ofs-delta"
+
+typedef struct git_transport_caps {
+ int common:1,
+ ofs_delta:1;
+} git_transport_caps;
+
/*
* A day in the life of a network operation
* ========================================
diff --git a/src/transport_git.c b/src/transport_git.c
index 46678a28e..4a10f17cd 100644
--- a/src/transport_git.c
+++ b/src/transport_git.c
@@ -41,6 +41,7 @@ typedef struct {
int socket;
git_vector refs;
git_remote_head **heads;
+ git_transport_caps caps;
} transport_git;
/*
@@ -218,6 +219,36 @@ static int store_refs(transport_git *t)
return error;
}
+static int detect_caps(transport_git *t)
+{
+ git_vector *refs = &t->refs;
+ git_pkt_ref *pkt;
+ git_transport_caps *caps = &t->caps;
+ const char *ptr;
+
+ pkt = git_vector_get(refs, 0);
+ /* No refs or capabilites, odd but not a problem */
+ if (pkt == NULL || pkt->capabilities == NULL)
+ return GIT_SUCCESS;
+
+ ptr = pkt->capabilities;
+ while (ptr != NULL && *ptr != '\0') {
+ if (*ptr == ' ')
+ ptr++;
+
+ if(!git__prefixcmp(ptr, GIT_CAP_OFS_DELTA)) {
+ caps->common = caps->ofs_delta = 1;
+ ptr += STRLEN(GIT_CAP_OFS_DELTA);
+ continue;
+ }
+
+ /* We don't know this capability, so skip it */
+ ptr = strchr(ptr, ' ');
+ }
+
+ return GIT_SUCCESS;
+}
+
/*
* Since this is a network connection, we need to parse and store the
* pkt-lines at this stage and keep them there.
@@ -242,6 +273,10 @@ static int git_connect(git_transport *transport, int direction)
t->parent.connected = 1;
error = store_refs(t);
+ if (error < GIT_SUCCESS)
+ return error;
+
+ error = detect_caps(t);
cleanup:
if (error < GIT_SUCCESS) {
@@ -280,7 +315,7 @@ static int git_send_wants(git_transport *transport, git_headarray *array)
{
transport_git *t = (transport_git *) transport;
- return git_pkt_send_wants(array, t->socket);
+ return git_pkt_send_wants(array, &t->caps, t->socket);
}
static int git_send_have(git_transport *transport, git_oid *oid)