Merge pull request #1919 from libgit2/cmn/multi-ack-detailed protocol: basic support for multi_ack_detailed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
diff --git a/src/transports/smart.h b/src/transports/smart.h
index 7fda27d..5232e54 100644
--- a/src/transports/smart.h
+++ b/src/transports/smart.h
@@ -16,6 +16,7 @@
#define GIT_CAP_OFS_DELTA "ofs-delta"
#define GIT_CAP_MULTI_ACK "multi_ack"
+#define GIT_CAP_MULTI_ACK_DETAILED "multi_ack_detailed"
#define GIT_CAP_SIDE_BAND "side-band"
#define GIT_CAP_SIDE_BAND_64K "side-band-64k"
#define GIT_CAP_INCLUDE_TAG "include-tag"
@@ -40,7 +41,7 @@ enum git_pkt_type {
GIT_PKT_UNPACK,
};
-/* Used for multi-ack */
+/* Used for multi_ack and mutli_ack_detailed */
enum git_ack_status {
GIT_ACK_NONE,
GIT_ACK_CONTINUE,
@@ -113,6 +114,7 @@ typedef struct transport_smart_caps {
int common:1,
ofs_delta:1,
multi_ack: 1,
+ multi_ack_detailed: 1,
side_band:1,
side_band_64k:1,
include_tag:1,
diff --git a/src/transports/smart_pkt.c b/src/transports/smart_pkt.c
index a1f623c..2bb09c7 100644
--- a/src/transports/smart_pkt.c
+++ b/src/transports/smart_pkt.c
@@ -39,7 +39,7 @@ static int flush_pkt(git_pkt **out)
return 0;
}
-/* the rest of the line will be useful for multi_ack */
+/* the rest of the line will be useful for multi_ack and multi_ack_detailed */
static int ack_pkt(git_pkt **out, const char *line, size_t len)
{
git_pkt_ack *pkt;
@@ -62,6 +62,10 @@ static int ack_pkt(git_pkt **out, const char *line, size_t len)
if (len >= 7) {
if (!git__prefixcmp(line + 1, "continue"))
pkt->status = GIT_ACK_CONTINUE;
+ if (!git__prefixcmp(line + 1, "common"))
+ pkt->status = GIT_ACK_COMMON;
+ if (!git__prefixcmp(line + 1, "ready"))
+ pkt->status = GIT_ACK_READY;
}
*out = (git_pkt *) pkt;
@@ -456,25 +460,27 @@ static int buffer_want_with_caps(const git_remote_head *head, transport_smart_ca
char oid[GIT_OID_HEXSZ +1] = {0};
unsigned int len;
- /* Prefer side-band-64k if the server supports both */
- if (caps->side_band) {
- if (caps->side_band_64k)
- git_buf_printf(&str, "%s ", GIT_CAP_SIDE_BAND_64K);
- else
- git_buf_printf(&str, "%s ", GIT_CAP_SIDE_BAND);
- }
- if (caps->ofs_delta)
- git_buf_puts(&str, GIT_CAP_OFS_DELTA " ");
-
- if (caps->multi_ack)
+ /* Prefer multi_ack_detailed */
+ if (caps->multi_ack_detailed)
+ git_buf_puts(&str, GIT_CAP_MULTI_ACK_DETAILED " ");
+ else if (caps->multi_ack)
git_buf_puts(&str, GIT_CAP_MULTI_ACK " ");
+ /* Prefer side-band-64k if the server supports both */
+ if (caps->side_band_64k)
+ git_buf_printf(&str, "%s ", GIT_CAP_SIDE_BAND_64K);
+ else if (caps->side_band)
+ git_buf_printf(&str, "%s ", GIT_CAP_SIDE_BAND);
+
if (caps->include_tag)
git_buf_puts(&str, GIT_CAP_INCLUDE_TAG " ");
if (caps->thin_pack)
git_buf_puts(&str, GIT_CAP_THIN_PACK " ");
+ if (caps->ofs_delta)
+ git_buf_puts(&str, GIT_CAP_OFS_DELTA " ");
+
if (git_buf_oom(&str))
return -1;
diff --git a/src/transports/smart_protocol.c b/src/transports/smart_protocol.c
index af6e35f..a129212 100644
--- a/src/transports/smart_protocol.c
+++ b/src/transports/smart_protocol.c
@@ -97,6 +97,13 @@ int git_smart__detect_caps(git_pkt_ref *pkt, transport_smart_caps *caps)
continue;
}
+ /* Keep multi_ack_detailed before multi_ack */
+ if (!git__prefixcmp(ptr, GIT_CAP_MULTI_ACK_DETAILED)) {
+ caps->common = caps->multi_ack_detailed = 1;
+ ptr += strlen(GIT_CAP_MULTI_ACK_DETAILED);
+ continue;
+ }
+
if (!git__prefixcmp(ptr, GIT_CAP_MULTI_ACK)) {
caps->common = caps->multi_ack = 1;
ptr += strlen(GIT_CAP_MULTI_ACK);
@@ -236,6 +243,32 @@ on_error:
return -1;
}
+static int wait_while_ack(gitno_buffer *buf)
+{
+ int error;
+ git_pkt_ack *pkt = NULL;
+
+ while (1) {
+ git__free(pkt);
+
+ if ((error = recv_pkt((git_pkt **)&pkt, buf)) < 0)
+ return error;
+
+ if (pkt->type == GIT_PKT_NAK)
+ break;
+
+ if (pkt->type == GIT_PKT_ACK &&
+ (pkt->status != GIT_ACK_CONTINUE ||
+ pkt->status != GIT_ACK_COMMON)) {
+ git__free(pkt);
+ break;
+ }
+ }
+
+ git__free(pkt);
+ return 0;
+}
+
int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, const git_remote_head * const *refs, size_t count)
{
transport_smart *t = (transport_smart *)transport;
@@ -287,7 +320,7 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c
goto on_error;
git_buf_clear(&data);
- if (t->caps.multi_ack) {
+ if (t->caps.multi_ack || t->caps.multi_ack_detailed) {
if ((error = store_common(t)) < 0)
goto on_error;
} else {
@@ -365,7 +398,7 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c
git_revwalk_free(walk);
/* Now let's eat up whatever the server gives us */
- if (!t->caps.multi_ack) {
+ if (!t->caps.multi_ack && !t->caps.multi_ack_detailed) {
pkt_type = recv_pkt(NULL, buf);
if (pkt_type < 0) {
@@ -375,22 +408,10 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c
return -1;
}
} else {
- git_pkt_ack *pkt;
- do {
- if ((error = recv_pkt((git_pkt **)&pkt, buf)) < 0)
- return error;
-
- if (pkt->type == GIT_PKT_NAK ||
- (pkt->type == GIT_PKT_ACK && pkt->status != GIT_ACK_CONTINUE)) {
- git__free(pkt);
- break;
- }
-
- git__free(pkt);
- } while (1);
+ error = wait_while_ack(buf);
}
- return 0;
+ return error;
on_error:
git_revwalk_free(walk);