2 * Copyright (C) 2009-2012 the libgit2 contributors
4 * This file is part of libgit2, distributed under the GNU GPL v2 with
5 * a Linking Exception. For full terms see the included COPYING file.
10 #include "git2/revwalk.h"
11 #include "git2/indexer.h"
14 #include "transport.h"
22 struct filter_payload
{
24 const git_refspec
*spec
, *tagspec
;
29 static int filter_ref__cb(git_remote_head
*head
, void *payload
)
31 struct filter_payload
*p
= payload
;
34 if (!git_reference_is_valid_name(head
->name
))
37 if (!p
->found_head
&& strcmp(head
->name
, GIT_HEAD_FILE
) == 0)
39 else if (git_refspec_src_matches(p
->spec
, head
->name
))
41 else if (p
->remote
->download_tags
== GIT_REMOTE_DOWNLOAD_TAGS_ALL
&&
42 git_refspec_src_matches(p
->tagspec
, head
->name
))
48 /* If we have the object, mark it so we don't ask for it */
49 if (git_odb_exists(p
->odb
, &head
->oid
))
52 p
->remote
->need_pack
= 1;
54 return git_vector_insert(&p
->remote
->refs
, head
);
57 static int filter_wants(git_remote
*remote
)
59 struct filter_payload p
;
62 git_vector_clear(&remote
->refs
);
63 if (git_refspec__parse(&tagspec
, GIT_REFSPEC_TAGS
, true) < 0)
67 * The fetch refspec can be NULL, and what this means is that the
68 * user didn't specify one. This is fine, as it means that we're
69 * not interested in any particular branch but just the remote's
70 * HEAD, which will be stored in FETCH_HEAD after the fetch.
72 p
.spec
= git_remote_fetchspec(remote
);
77 if (git_repository_odb__weakptr(&p
.odb
, remote
->repo
) < 0)
80 return git_remote_ls(remote
, filter_ref__cb
, &p
);
83 /* Wait until we get an ack from the */
84 static int recv_pkt(git_pkt
**out
, gitno_buffer
*buf
)
86 const char *ptr
= buf
->data
, *line_end
= ptr
;
88 int pkt_type
, error
= 0, ret
;
92 error
= git_pkt_parse_line(&pkt
, ptr
, &line_end
, buf
->offset
);
97 break; /* return the pkt */
99 if (error
< 0 && error
!= GIT_EBUFS
)
102 if ((ret
= gitno_recv(buf
)) < 0)
106 gitno_consume(buf
, line_end
);
107 pkt_type
= pkt
->type
;
116 static int store_common(git_transport
*t
)
119 gitno_buffer
*buf
= &t
->buffer
;
122 if (recv_pkt(&pkt
, buf
) < 0)
125 if (pkt
->type
== GIT_PKT_ACK
) {
126 if (git_vector_insert(&t
->common
, pkt
) < 0)
139 * In this first version, we push all our refs in and start sending
140 * them out. When we get an ACK we hide that commit and continue
141 * traversing until we're done
143 int git_fetch_negotiate(git_remote
*remote
)
145 git_transport
*t
= remote
->transport
;
146 gitno_buffer
*buf
= &t
->buffer
;
147 git_buf data
= GIT_BUF_INIT
;
148 git_revwalk
*walk
= NULL
;
153 if (filter_wants(remote
) < 0) {
154 giterr_set(GITERR_NET
, "Failed to filter the reference list for wants");
158 /* Don't try to negotiate when we don't want anything */
159 if (remote
->refs
.length
== 0 || !remote
->need_pack
)
163 * Now we have everything set up so we can start tell the
164 * server what we want and what we have. Call the function if
165 * the transport has its own logic. This is transitional and
166 * will be removed once this function can support git and http.
169 return t
->negotiate_fetch(t
, remote
->repo
, &remote
->refs
);
171 /* No own logic, do our thing */
172 if (git_pkt_buffer_wants(&remote
->refs
, &t
->caps
, &data
) < 0)
175 if (git_fetch_setup_walk(&walk
, remote
->repo
) < 0)
178 * We don't support any kind of ACK extensions, so the negotiation
179 * boils down to sending what we have and listening for an ACK
180 * every once in a while.
183 while ((error
= git_revwalk_next(&oid
, walk
)) == 0) {
184 git_pkt_buffer_have(&oid
, &data
);
187 git_pkt_buffer_flush(&data
);
188 if (git_buf_oom(&data
))
191 if (t
->negotiation_step(t
, data
.ptr
, data
.size
) < 0)
194 git_buf_clear(&data
);
195 if (t
->caps
.multi_ack
) {
196 if (store_common(t
) < 0)
199 pkt_type
= recv_pkt(NULL
, buf
);
201 if (pkt_type
== GIT_PKT_ACK
) {
203 } else if (pkt_type
== GIT_PKT_NAK
) {
206 giterr_set(GITERR_NET
, "Unexpected pkt type");
212 if (t
->common
.length
> 0)
215 if (i
% 20 == 0 && t
->rpc
) {
219 if (git_pkt_buffer_wants(&remote
->refs
, &t
->caps
, &data
) < 0)
222 git_vector_foreach(&t
->common
, i
, pkt
) {
223 git_pkt_buffer_have(&pkt
->oid
, &data
);
226 if (git_buf_oom(&data
))
231 if (error
< 0 && error
!= GIT_ITEROVER
)
234 /* Tell the other end that we're done negotiating */
235 if (t
->rpc
&& t
->common
.length
> 0) {
239 if (git_pkt_buffer_wants(&remote
->refs
, &t
->caps
, &data
) < 0)
242 git_vector_foreach(&t
->common
, i
, pkt
) {
243 git_pkt_buffer_have(&pkt
->oid
, &data
);
246 if (git_buf_oom(&data
))
250 git_pkt_buffer_done(&data
);
251 if (t
->negotiation_step(t
, data
.ptr
, data
.size
) < 0)
255 git_revwalk_free(walk
);
257 /* Now let's eat up whatever the server gives us */
258 if (!t
->caps
.multi_ack
) {
259 pkt_type
= recv_pkt(NULL
, buf
);
260 if (pkt_type
!= GIT_PKT_ACK
&& pkt_type
!= GIT_PKT_NAK
) {
261 giterr_set(GITERR_NET
, "Unexpected pkt type");
267 if (recv_pkt((git_pkt
**)&pkt
, buf
) < 0)
270 if (pkt
->type
== GIT_PKT_NAK
||
271 (pkt
->type
== GIT_PKT_ACK
&& pkt
->status
!= GIT_ACK_CONTINUE
)) {
283 git_revwalk_free(walk
);
288 int git_fetch_download_pack(git_remote
*remote
, git_off_t
*bytes
, git_indexer_stats
*stats
)
290 git_transport
*t
= remote
->transport
;
292 if(!remote
->need_pack
)
296 return t
->download_pack(t
, remote
->repo
, bytes
, stats
);
298 return git_fetch__download_pack(t
, remote
->repo
, bytes
, stats
);
302 static int no_sideband(git_indexer_stream
*idx
, gitno_buffer
*buf
, git_off_t
*bytes
, git_indexer_stats
*stats
)
307 if (git_indexer_stream_add(idx
, buf
->data
, buf
->offset
, stats
) < 0)
310 gitno_consume_n(buf
, buf
->offset
);
312 if ((recvd
= gitno_recv(buf
)) < 0)
318 if (git_indexer_stream_finalize(idx
, stats
))
324 /* Receiving data from a socket and storing it is pretty much the same for git and HTTP */
325 int git_fetch__download_pack(
327 git_repository
*repo
,
329 git_indexer_stats
*stats
)
331 git_buf path
= GIT_BUF_INIT
;
332 gitno_buffer
*buf
= &t
->buffer
;
333 git_indexer_stream
*idx
= NULL
;
335 if (git_buf_joinpath(&path
, git_repository_path(repo
), "objects/pack") < 0)
338 if (git_indexer_stream_new(&idx
, git_buf_cstr(&path
)) < 0)
342 memset(stats
, 0, sizeof(git_indexer_stats
));
346 * If the remote doesn't support the side-band, we can feed
347 * the data directly to the indexer. Otherwise, we need to
348 * check which one belongs there.
350 if (!t
->caps
.side_band
&& !t
->caps
.side_band_64k
) {
351 if (no_sideband(idx
, buf
, bytes
, stats
) < 0)
354 git_indexer_stream_free(idx
);
360 if (recv_pkt(&pkt
, buf
) < 0)
363 if (pkt
->type
== GIT_PKT_PROGRESS
) {
364 if (t
->progress_cb
) {
365 git_pkt_progress
*p
= (git_pkt_progress
*) pkt
;
366 t
->progress_cb(p
->data
, p
->len
, t
->cb_data
);
369 } else if (pkt
->type
== GIT_PKT_DATA
) {
370 git_pkt_data
*p
= (git_pkt_data
*) pkt
;
372 if (git_indexer_stream_add(idx
, p
->data
, p
->len
, stats
) < 0)
376 } else if (pkt
->type
== GIT_PKT_FLUSH
) {
377 /* A flush indicates the end of the packfile */
383 if (git_indexer_stream_finalize(idx
, stats
) < 0)
386 git_indexer_stream_free(idx
);
391 git_indexer_stream_free(idx
);
395 int git_fetch_setup_walk(git_revwalk
**out
, git_repository
*repo
)
402 if (git_reference_list(&refs
, repo
, GIT_REF_LISTALL
) < 0)
405 if (git_revwalk_new(&walk
, repo
) < 0)
408 git_revwalk_sorting(walk
, GIT_SORT_TIME
);
410 for (i
= 0; i
< refs
.count
; ++i
) {
412 if (!git__prefixcmp(refs
.strings
[i
], GIT_REFS_TAGS_DIR
))
415 if (git_reference_lookup(&ref
, repo
, refs
.strings
[i
]) < 0)
418 if (git_reference_type(ref
) == GIT_REF_SYMBOLIC
)
420 if (git_revwalk_push(walk
, git_reference_oid(ref
)) < 0)
423 git_reference_free(ref
);
426 git_strarray_free(&refs
);
431 git_reference_free(ref
);
432 git_strarray_free(&refs
);