vendor/libgit2/src/fetch.c in rugged-0.17.0.b6 vs vendor/libgit2/src/fetch.c in rugged-0.17.0.b7

- old
+ new

@@ -19,30 +19,33 @@ #include "netops.h" #include "pkt.h" struct filter_payload { git_remote *remote; - const git_refspec *spec; + const git_refspec *spec, *tagspec; git_odb *odb; int found_head; }; static int filter_ref__cb(git_remote_head *head, void *payload) { struct filter_payload *p = payload; + int match = 0; - if (!p->found_head && strcmp(head->name, GIT_HEAD_FILE) == 0) { + if (!git_reference_is_valid_name(head->name)) + return 0; + + if (!p->found_head && strcmp(head->name, GIT_HEAD_FILE) == 0) p->found_head = 1; - } else { - /* If it doesn't match the refpec, we don't want it */ - if (!git_refspec_src_matches(p->spec, head->name)) - return 0; + else if (git_refspec_src_matches(p->spec, head->name)) + match = 1; + else if (p->remote->download_tags == GIT_REMOTE_DOWNLOAD_TAGS_ALL && + git_refspec_src_matches(p->tagspec, head->name)) + match = 1; - /* Don't even try to ask for the annotation target */ - if (!git__suffixcmp(head->name, "^{}")) - return 0; - } + if (!match) + return 0; /* If we have the object, mark it so we don't ask for it */ if (git_odb_exists(p->odb, &head->oid)) head->local = 1; else @@ -52,27 +55,37 @@ } static int filter_wants(git_remote *remote) { struct filter_payload p; + git_refspec tagspec; + int error = -1; git_vector_clear(&remote->refs); + if (git_refspec__parse(&tagspec, GIT_REFSPEC_TAGS, true) < 0) + return error; /* * The fetch refspec can be NULL, and what this means is that the * user didn't specify one. This is fine, as it means that we're * not interested in any particular branch but just the remote's * HEAD, which will be stored in FETCH_HEAD after the fetch. */ p.spec = git_remote_fetchspec(remote); + p.tagspec = &tagspec; p.found_head = 0; p.remote = remote; if (git_repository_odb__weakptr(&p.odb, remote->repo) < 0) - return -1; + goto cleanup; - return git_remote_ls(remote, filter_ref__cb, &p); + error = git_remote_ls(remote, filter_ref__cb, &p); + +cleanup: + git_refspec__free(&tagspec); + + return error; } /* Wait until we get an ack from the */ static int recv_pkt(git_pkt **out, gitno_buffer *buf) { @@ -137,11 +150,11 @@ { git_transport *t = remote->transport; gitno_buffer *buf = &t->buffer; git_buf data = GIT_BUF_INIT; git_revwalk *walk = NULL; - int error, pkt_type; + int error = -1, pkt_type; unsigned int i; git_oid oid; if (filter_wants(remote) < 0) { giterr_set(GITERR_NET, "Failed to filter the reference list for wants"); @@ -175,10 +188,16 @@ i = 0; while ((error = git_revwalk_next(&oid, walk)) == 0) { git_pkt_buffer_have(&oid, &data); i++; if (i % 20 == 0) { + if (t->cancel.val) { + giterr_set(GITERR_NET, "The fetch was cancelled by the user"); + error = GIT_EUSER; + goto on_error; + } + git_pkt_buffer_flush(&data); if (git_buf_oom(&data)) goto on_error; if (t->negotiation_step(t, data.ptr, data.size) < 0) @@ -219,11 +238,11 @@ if (git_buf_oom(&data)) goto on_error; } } - if (error < 0 && error != GIT_REVWALKOVER) + if (error < 0 && error != GIT_ITEROVER) goto on_error; /* Tell the other end that we're done negotiating */ if (t->rpc && t->common.length > 0) { git_pkt_ack *pkt; @@ -239,10 +258,15 @@ if (git_buf_oom(&data)) goto on_error; } git_pkt_buffer_done(&data); + if (t->cancel.val) { + giterr_set(GITERR_NET, "The fetch was cancelled by the user"); + error = GIT_EUSER; + goto on_error; + } if (t->negotiation_step(t, data.ptr, data.size) < 0) goto on_error; git_buf_free(&data); git_revwalk_free(walk); @@ -273,11 +297,11 @@ return 0; on_error: git_revwalk_free(walk); git_buf_free(&data); - return -1; + return error; } int git_fetch_download_pack(git_remote *remote, git_off_t *bytes, git_indexer_stats *stats) { git_transport *t = remote->transport; @@ -290,21 +314,48 @@ return git_fetch__download_pack(t, remote->repo, bytes, stats); } +static int no_sideband(git_transport *t, git_indexer_stream *idx, gitno_buffer *buf, git_off_t *bytes, git_indexer_stats *stats) +{ + int recvd; + + do { + if (t->cancel.val) { + giterr_set(GITERR_NET, "The fetch was cancelled by the user"); + return GIT_EUSER; + } + + if (git_indexer_stream_add(idx, buf->data, buf->offset, stats) < 0) + return -1; + + gitno_consume_n(buf, buf->offset); + + if ((recvd = gitno_recv(buf)) < 0) + return -1; + + *bytes += recvd; + } while(recvd > 0); + + if (git_indexer_stream_finalize(idx, stats)) + return -1; + + return 0; +} + /* Receiving data from a socket and storing it is pretty much the same for git and HTTP */ int git_fetch__download_pack( git_transport *t, git_repository *repo, git_off_t *bytes, git_indexer_stats *stats) { - int recvd; git_buf path = GIT_BUF_INIT; gitno_buffer *buf = &t->buffer; git_indexer_stream *idx = NULL; + int error = -1; if (git_buf_joinpath(&path, git_repository_path(repo), "objects/pack") < 0) return -1; if (git_indexer_stream_new(&idx, git_buf_cstr(&path)) < 0) @@ -312,31 +363,64 @@ git_buf_free(&path); memset(stats, 0, sizeof(git_indexer_stats)); *bytes = 0; - do { - if (git_indexer_stream_add(idx, buf->data, buf->offset, stats) < 0) + /* + * If the remote doesn't support the side-band, we can feed + * the data directly to the indexer. Otherwise, we need to + * check which one belongs there. + */ + if (!t->caps.side_band && !t->caps.side_band_64k) { + if (no_sideband(t, idx, buf, bytes, stats) < 0) goto on_error; - gitno_consume_n(buf, buf->offset); + git_indexer_stream_free(idx); + return 0; + } - if ((recvd = gitno_recv(buf)) < 0) + do { + git_pkt *pkt; + + if (t->cancel.val) { + giterr_set(GITERR_NET, "The fetch was cancelled by the user"); + error = GIT_EUSER; goto on_error; + } - *bytes += recvd; - } while(recvd > 0); + if (recv_pkt(&pkt, buf) < 0) + goto on_error; - if (git_indexer_stream_finalize(idx, stats)) + if (pkt->type == GIT_PKT_PROGRESS) { + if (t->progress_cb) { + git_pkt_progress *p = (git_pkt_progress *) pkt; + t->progress_cb(p->data, p->len, t->cb_data); + } + git__free(pkt); + } else if (pkt->type == GIT_PKT_DATA) { + git_pkt_data *p = (git_pkt_data *) pkt; + *bytes += p->len; + if (git_indexer_stream_add(idx, p->data, p->len, stats) < 0) + goto on_error; + + git__free(pkt); + } else if (pkt->type == GIT_PKT_FLUSH) { + /* A flush indicates the end of the packfile */ + git__free(pkt); + break; + } + } while (1); + + if (git_indexer_stream_finalize(idx, stats) < 0) goto on_error; git_indexer_stream_free(idx); return 0; on_error: git_buf_free(&path); git_indexer_stream_free(idx); - return -1; + return error; } int git_fetch_setup_walk(git_revwalk **out, git_repository *repo) { git_revwalk *walk;