summaryrefslogtreecommitdiff
path: root/src/libgit2/transports/smart_protocol.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libgit2/transports/smart_protocol.c')
-rw-r--r--src/libgit2/transports/smart_protocol.c64
1 files changed, 60 insertions, 4 deletions
diff --git a/src/libgit2/transports/smart_protocol.c b/src/libgit2/transports/smart_protocol.c
index 09778b335..a44d0c853 100644
--- a/src/libgit2/transports/smart_protocol.c
+++ b/src/libgit2/transports/smart_protocol.c
@@ -214,6 +214,11 @@ int git_smart__detect_caps(git_pkt_ref *pkt, transport_smart_caps *caps, git_vec
if (!git__prefixcmp(ptr, GIT_CAP_WANT_REACHABLE_SHA1)) {
caps->common = caps->want_reachable_sha1 = 1;
ptr += strlen(GIT_CAP_DELETE_REFS);
+ }
+
+ if (!git__prefixcmp(ptr, GIT_CAP_SHALLOW)) {
+ caps->common = caps->shallow = 1;
+ ptr += strlen(GIT_CAP_SHALLOW);
continue;
}
@@ -317,7 +322,26 @@ static int wait_while_ack(gitno_buffer *buf)
return 0;
}
-int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, const git_remote_head * const *wants, size_t count)
+static int cap_not_sup_err(const char *cap_name)
+{
+ git_error_set(GIT_ERROR_NET, "server doesn't support %s", cap_name);
+ return GIT_EINVALID;
+}
+
+/* Disables server capabilities we're not interested in */
+static int setup_caps(transport_smart_caps *caps, const git_fetch_negotiation *wants)
+{
+ if (wants->depth) {
+ if (!caps->shallow)
+ return cap_not_sup_err(GIT_CAP_SHALLOW);
+ } else {
+ caps->shallow = 0;
+ }
+
+ return 0;
+}
+
+int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, const git_fetch_negotiation *wants)
{
transport_smart *t = (transport_smart *)transport;
git_revwalk__push_options opts = GIT_REVWALK__PUSH_OPTIONS_INIT;
@@ -329,7 +353,10 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c
unsigned int i;
git_oid oid;
- if ((error = git_pkt_buffer_wants(wants, count, &t->caps, &data)) < 0)
+ if ((error = setup_caps(&t->caps, wants)) < 0)
+ return error;
+
+ if ((error = git_pkt_buffer_wants(wants, &t->caps, &data)) < 0)
return error;
if ((error = git_revwalk_new(&walk, repo)) < 0)
@@ -339,6 +366,35 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c
if ((error = git_revwalk__push_glob(walk, "refs/*", &opts)) < 0)
goto on_error;
+ if (wants->depth > 0) {
+ git_pkt_shallow *pkt;
+
+ if ((error = git_smart__negotiation_step(&t->parent, data.ptr, data.size)) < 0)
+ goto on_error;
+
+ while ((error = recv_pkt((git_pkt **)&pkt, NULL, buf)) == 0) {
+
+ if (pkt->type == GIT_PKT_SHALLOW) {
+ git_shallowarray_add(wants->shallow_roots, &pkt->oid);
+ } else if (pkt->type == GIT_PKT_UNSHALLOW) {
+ git_shallowarray_remove(wants->shallow_roots, &pkt->oid);
+ } else if (pkt->type == GIT_PKT_FLUSH) {
+ /* Server is done, stop processing shallow oids */
+ break;
+ } else {
+ git_error_set(GIT_ERROR_NET, "Unexpected pkt type");
+ goto on_error;
+ }
+
+ git_pkt_free((git_pkt *) pkt);
+ }
+
+ git_pkt_free((git_pkt *) pkt);
+
+ if (error < 0) {
+ goto on_error;
+ }
+ }
/*
* Our support for ACK extensions is simply to parse them. On
* the first ACK we will accept that as enough common
@@ -401,7 +457,7 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c
git_pkt_ack *pkt;
unsigned int j;
- if ((error = git_pkt_buffer_wants(wants, count, &t->caps, &data)) < 0)
+ if ((error = git_pkt_buffer_wants(wants, &t->caps, &data)) < 0)
goto on_error;
git_vector_foreach(&t->common, j, pkt) {
@@ -421,7 +477,7 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c
git_pkt_ack *pkt;
unsigned int j;
- if ((error = git_pkt_buffer_wants(wants, count, &t->caps, &data)) < 0)
+ if ((error = git_pkt_buffer_wants(wants, &t->caps, &data)) < 0)
goto on_error;
git_vector_foreach(&t->common, j, pkt) {