diff options
Diffstat (limited to 'src/libgit2/transports/smart_protocol.c')
-rw-r--r-- | src/libgit2/transports/smart_protocol.c | 64 |
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) { |