2 * Copyright (C) the libgit2 contributors. All rights reserved.
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.
11 #include "git2/odb_backend.h"
15 #include "repository.h"
17 #include "pack-objects.h"
22 #define NETWORK_XFER_THRESHOLD (100*1024)
23 /* The minimal interval between progress updates (in seconds). */
24 #define MIN_PROGRESS_UPDATE_INTERVAL 0.5
26 bool git_smart__ofs_delta_enabled
= true;
28 int git_smart__store_refs(transport_smart
*t
, int flushes
)
30 gitno_buffer
*buf
= &t
->buffer
;
31 git_vector
*refs
= &t
->refs
;
32 int error
, flush
= 0, recvd
;
33 const char *line_end
= NULL
;
37 /* Clear existing refs in case git_remote_connect() is called again
38 * after git_remote_disconnect().
40 git_vector_foreach(refs
, i
, pkt
) {
43 git_vector_clear(refs
);
48 error
= git_pkt_parse_line(&pkt
, &line_end
, buf
->data
, buf
->offset
);
52 if (error
< 0 && error
!= GIT_EBUFS
)
55 if (error
== GIT_EBUFS
) {
56 if ((recvd
= gitno_recv(buf
)) < 0)
60 git_error_set(GIT_ERROR_NET
, "early EOF");
67 if (gitno_consume(buf
, line_end
) < 0)
70 if (pkt
->type
== GIT_PKT_ERR
) {
71 git_error_set(GIT_ERROR_NET
, "remote error: %s", ((git_pkt_err
*)pkt
)->error
);
76 if (pkt
->type
!= GIT_PKT_FLUSH
&& git_vector_insert(refs
, pkt
) < 0)
79 if (pkt
->type
== GIT_PKT_FLUSH
) {
83 } while (flush
< flushes
);
88 static int append_symref(const char **out
, git_vector
*symrefs
, const char *ptr
)
92 git_buf buf
= GIT_BUF_INIT
;
93 git_refspec
*mapping
= NULL
;
95 ptr
+= strlen(GIT_CAP_SYMREF
);
100 if (!(end
= strchr(ptr
, ' ')) &&
101 !(end
= strchr(ptr
, '\0')))
104 if ((error
= git_buf_put(&buf
, ptr
, end
- ptr
)) < 0)
107 /* symref mapping has refspec format */
108 mapping
= git__calloc(1, sizeof(git_refspec
));
109 GIT_ERROR_CHECK_ALLOC(mapping
);
111 error
= git_refspec__parse(mapping
, git_buf_cstr(&buf
), true);
112 git_buf_dispose(&buf
);
114 /* if the error isn't OOM, then it's a parse error; let's use a nicer message */
116 if (git_error_last()->klass
!= GIT_ERROR_NOMEMORY
)
123 if ((error
= git_vector_insert(symrefs
, mapping
)) < 0)
130 git_error_set(GIT_ERROR_NET
, "remote sent invalid symref");
131 git_refspec__dispose(mapping
);
136 int git_smart__detect_caps(git_pkt_ref
*pkt
, transport_smart_caps
*caps
, git_vector
*symrefs
)
140 /* No refs or capabilites, odd but not a problem */
141 if (pkt
== NULL
|| pkt
->capabilities
== NULL
)
142 return GIT_ENOTFOUND
;
144 ptr
= pkt
->capabilities
;
145 while (ptr
!= NULL
&& *ptr
!= '\0') {
149 if (git_smart__ofs_delta_enabled
&& !git__prefixcmp(ptr
, GIT_CAP_OFS_DELTA
)) {
150 caps
->common
= caps
->ofs_delta
= 1;
151 ptr
+= strlen(GIT_CAP_OFS_DELTA
);
155 /* Keep multi_ack_detailed before multi_ack */
156 if (!git__prefixcmp(ptr
, GIT_CAP_MULTI_ACK_DETAILED
)) {
157 caps
->common
= caps
->multi_ack_detailed
= 1;
158 ptr
+= strlen(GIT_CAP_MULTI_ACK_DETAILED
);
162 if (!git__prefixcmp(ptr
, GIT_CAP_MULTI_ACK
)) {
163 caps
->common
= caps
->multi_ack
= 1;
164 ptr
+= strlen(GIT_CAP_MULTI_ACK
);
168 if (!git__prefixcmp(ptr
, GIT_CAP_INCLUDE_TAG
)) {
169 caps
->common
= caps
->include_tag
= 1;
170 ptr
+= strlen(GIT_CAP_INCLUDE_TAG
);
174 /* Keep side-band check after side-band-64k */
175 if (!git__prefixcmp(ptr
, GIT_CAP_SIDE_BAND_64K
)) {
176 caps
->common
= caps
->side_band_64k
= 1;
177 ptr
+= strlen(GIT_CAP_SIDE_BAND_64K
);
181 if (!git__prefixcmp(ptr
, GIT_CAP_SIDE_BAND
)) {
182 caps
->common
= caps
->side_band
= 1;
183 ptr
+= strlen(GIT_CAP_SIDE_BAND
);
187 if (!git__prefixcmp(ptr
, GIT_CAP_DELETE_REFS
)) {
188 caps
->common
= caps
->delete_refs
= 1;
189 ptr
+= strlen(GIT_CAP_DELETE_REFS
);
193 if (!git__prefixcmp(ptr
, GIT_CAP_THIN_PACK
)) {
194 caps
->common
= caps
->thin_pack
= 1;
195 ptr
+= strlen(GIT_CAP_THIN_PACK
);
199 if (!git__prefixcmp(ptr
, GIT_CAP_SYMREF
)) {
202 if ((error
= append_symref(&ptr
, symrefs
, ptr
)) < 0)
208 /* We don't know this capability, so skip it */
209 ptr
= strchr(ptr
, ' ');
215 static int recv_pkt(git_pkt
**out_pkt
, git_pkt_type
*out_type
, gitno_buffer
*buf
)
217 const char *ptr
= buf
->data
, *line_end
= ptr
;
223 error
= git_pkt_parse_line(&pkt
, &line_end
, ptr
, buf
->offset
);
228 break; /* return the pkt */
230 if (error
< 0 && error
!= GIT_EBUFS
)
233 if ((ret
= gitno_recv(buf
)) < 0) {
235 } else if (ret
== 0) {
236 git_error_set(GIT_ERROR_NET
, "early EOF");
241 if (gitno_consume(buf
, line_end
) < 0)
244 if (out_type
!= NULL
)
245 *out_type
= pkt
->type
;
254 static int store_common(transport_smart
*t
)
257 gitno_buffer
*buf
= &t
->buffer
;
261 if ((error
= recv_pkt(&pkt
, NULL
, buf
)) < 0)
264 if (pkt
->type
!= GIT_PKT_ACK
) {
269 if (git_vector_insert(&t
->common
, pkt
) < 0) {
278 static int wait_while_ack(gitno_buffer
*buf
)
282 git_pkt_ack
*ack
= NULL
;
287 if ((error
= recv_pkt(&pkt
, NULL
, buf
)) < 0)
290 if (pkt
->type
== GIT_PKT_NAK
)
292 if (pkt
->type
!= GIT_PKT_ACK
)
295 ack
= (git_pkt_ack
*)pkt
;
297 if (ack
->status
!= GIT_ACK_CONTINUE
&&
298 ack
->status
!= GIT_ACK_COMMON
&&
299 ack
->status
!= GIT_ACK_READY
) {
308 int git_smart__negotiate_fetch(git_transport
*transport
, git_repository
*repo
, const git_remote_head
* const *wants
, size_t count
)
310 transport_smart
*t
= (transport_smart
*)transport
;
311 git_revwalk__push_options opts
= GIT_REVWALK__PUSH_OPTIONS_INIT
;
312 gitno_buffer
*buf
= &t
->buffer
;
313 git_buf data
= GIT_BUF_INIT
;
314 git_revwalk
*walk
= NULL
;
316 git_pkt_type pkt_type
;
320 if ((error
= git_pkt_buffer_wants(wants
, count
, &t
->caps
, &data
)) < 0)
323 if ((error
= git_revwalk_new(&walk
, repo
)) < 0)
326 opts
.insert_by_date
= 1;
327 if ((error
= git_revwalk__push_glob(walk
, "refs/*", &opts
)) < 0)
331 * Our support for ACK extensions is simply to parse them. On
332 * the first ACK we will accept that as enough common
333 * objects. We give up if we haven't found an answer in the
338 error
= git_revwalk_next(&oid
, walk
);
341 if (GIT_ITEROVER
== error
)
347 git_pkt_buffer_have(&oid
, &data
);
350 if (t
->cancelled
.val
) {
351 git_error_set(GIT_ERROR_NET
, "The fetch was cancelled by the user");
356 git_pkt_buffer_flush(&data
);
357 if (git_buf_oom(&data
)) {
362 if ((error
= git_smart__negotiation_step(&t
->parent
, data
.ptr
, data
.size
)) < 0)
365 git_buf_clear(&data
);
366 if (t
->caps
.multi_ack
|| t
->caps
.multi_ack_detailed
) {
367 if ((error
= store_common(t
)) < 0)
370 if ((error
= recv_pkt(NULL
, &pkt_type
, buf
)) < 0)
373 if (pkt_type
== GIT_PKT_ACK
) {
375 } else if (pkt_type
== GIT_PKT_NAK
) {
378 git_error_set(GIT_ERROR_NET
, "unexpected pkt type");
385 if (t
->common
.length
> 0)
388 if (i
% 20 == 0 && t
->rpc
) {
392 if ((error
= git_pkt_buffer_wants(wants
, count
, &t
->caps
, &data
)) < 0)
395 git_vector_foreach(&t
->common
, j
, pkt
) {
396 if ((error
= git_pkt_buffer_have(&pkt
->oid
, &data
)) < 0)
400 if (git_buf_oom(&data
)) {
407 /* Tell the other end that we're done negotiating */
408 if (t
->rpc
&& t
->common
.length
> 0) {
412 if ((error
= git_pkt_buffer_wants(wants
, count
, &t
->caps
, &data
)) < 0)
415 git_vector_foreach(&t
->common
, j
, pkt
) {
416 if ((error
= git_pkt_buffer_have(&pkt
->oid
, &data
)) < 0)
420 if (git_buf_oom(&data
)) {
426 if ((error
= git_pkt_buffer_done(&data
)) < 0)
429 if (t
->cancelled
.val
) {
430 git_error_set(GIT_ERROR_NET
, "The fetch was cancelled by the user");
434 if ((error
= git_smart__negotiation_step(&t
->parent
, data
.ptr
, data
.size
)) < 0)
437 git_buf_dispose(&data
);
438 git_revwalk_free(walk
);
440 /* Now let's eat up whatever the server gives us */
441 if (!t
->caps
.multi_ack
&& !t
->caps
.multi_ack_detailed
) {
442 if ((error
= recv_pkt(NULL
, &pkt_type
, buf
)) < 0)
445 if (pkt_type
!= GIT_PKT_ACK
&& pkt_type
!= GIT_PKT_NAK
) {
446 git_error_set(GIT_ERROR_NET
, "unexpected pkt type");
450 error
= wait_while_ack(buf
);
456 git_revwalk_free(walk
);
457 git_buf_dispose(&data
);
461 static int no_sideband(transport_smart
*t
, struct git_odb_writepack
*writepack
, gitno_buffer
*buf
, git_indexer_progress
*stats
)
466 if (t
->cancelled
.val
) {
467 git_error_set(GIT_ERROR_NET
, "the fetch was cancelled by the user");
471 if (writepack
->append(writepack
, buf
->data
, buf
->offset
, stats
) < 0)
474 gitno_consume_n(buf
, buf
->offset
);
476 if ((recvd
= gitno_recv(buf
)) < 0)
480 if (writepack
->commit(writepack
, stats
) < 0)
486 struct network_packetsize_payload
488 git_indexer_progress_cb callback
;
490 git_indexer_progress
*stats
;
491 size_t last_fired_bytes
;
494 static int network_packetsize(size_t received
, void *payload
)
496 struct network_packetsize_payload
*npp
= (struct network_packetsize_payload
*)payload
;
498 /* Accumulate bytes */
499 npp
->stats
->received_bytes
+= received
;
501 /* Fire notification if the threshold is reached */
502 if ((npp
->stats
->received_bytes
- npp
->last_fired_bytes
) > NETWORK_XFER_THRESHOLD
) {
503 npp
->last_fired_bytes
= npp
->stats
->received_bytes
;
505 if (npp
->callback(npp
->stats
, npp
->payload
))
512 int git_smart__download_pack(
513 git_transport
*transport
,
514 git_repository
*repo
,
515 git_indexer_progress
*stats
,
516 git_indexer_progress_cb progress_cb
,
517 void *progress_payload
)
519 transport_smart
*t
= (transport_smart
*)transport
;
520 gitno_buffer
*buf
= &t
->buffer
;
522 struct git_odb_writepack
*writepack
= NULL
;
524 struct network_packetsize_payload npp
= {0};
526 memset(stats
, 0, sizeof(git_indexer_progress
));
529 npp
.callback
= progress_cb
;
530 npp
.payload
= progress_payload
;
532 t
->packetsize_cb
= &network_packetsize
;
533 t
->packetsize_payload
= &npp
;
535 /* We might have something in the buffer already from negotiate_fetch */
536 if (t
->buffer
.offset
> 0 && !t
->cancelled
.val
)
537 if (t
->packetsize_cb(t
->buffer
.offset
, t
->packetsize_payload
))
538 git_atomic32_set(&t
->cancelled
, 1);
541 if ((error
= git_repository_odb__weakptr(&odb
, repo
)) < 0 ||
542 ((error
= git_odb_write_pack(&writepack
, odb
, progress_cb
, progress_payload
)) != 0))
546 * If the remote doesn't support the side-band, we can feed
547 * the data directly to the pack writer. Otherwise, we need to
548 * check which one belongs there.
550 if (!t
->caps
.side_band
&& !t
->caps
.side_band_64k
) {
551 error
= no_sideband(t
, writepack
, buf
, stats
);
558 /* Check cancellation before network call */
559 if (t
->cancelled
.val
) {
565 if ((error
= recv_pkt(&pkt
, NULL
, buf
)) >= 0) {
566 /* Check cancellation after network call */
567 if (t
->cancelled
.val
) {
570 } else if (pkt
->type
== GIT_PKT_PROGRESS
) {
571 if (t
->progress_cb
) {
572 git_pkt_progress
*p
= (git_pkt_progress
*) pkt
;
574 if (p
->len
> INT_MAX
) {
575 git_error_set(GIT_ERROR_NET
, "oversized progress message");
580 error
= t
->progress_cb(p
->data
, (int)p
->len
, t
->message_cb_payload
);
582 } else if (pkt
->type
== GIT_PKT_DATA
) {
583 git_pkt_data
*p
= (git_pkt_data
*) pkt
;
586 error
= writepack
->append(writepack
, p
->data
, p
->len
, stats
);
587 } else if (pkt
->type
== GIT_PKT_FLUSH
) {
588 /* A flush indicates the end of the packfile */
602 * Trailing execution of progress_cb, if necessary...
603 * Only the callback through the npp datastructure currently
604 * updates the last_fired_bytes value. It is possible that
605 * progress has already been reported with the correct
606 * "received_bytes" value, but until (if?) this is unified
607 * then we will report progress again to be sure that the
608 * correct last received_bytes value is reported.
610 if (npp
.callback
&& npp
.stats
->received_bytes
> npp
.last_fired_bytes
) {
611 error
= npp
.callback(npp
.stats
, npp
.payload
);
616 error
= writepack
->commit(writepack
, stats
);
620 writepack
->free(writepack
);
622 t
->packetsize_cb
= NULL
;
623 t
->packetsize_payload
= NULL
;
629 static int gen_pktline(git_buf
*buf
, git_push
*push
)
633 char old_id
[GIT_OID_HEXSZ
+1], new_id
[GIT_OID_HEXSZ
+1];
635 old_id
[GIT_OID_HEXSZ
] = '\0'; new_id
[GIT_OID_HEXSZ
] = '\0';
637 git_vector_foreach(&push
->specs
, i
, spec
) {
638 len
= 2*GIT_OID_HEXSZ
+ 7 + strlen(spec
->refspec
.dst
);
642 if (push
->report_status
)
643 len
+= strlen(GIT_CAP_REPORT_STATUS
) + 1;
644 len
+= strlen(GIT_CAP_SIDE_BAND_64K
) + 1;
647 git_oid_fmt(old_id
, &spec
->roid
);
648 git_oid_fmt(new_id
, &spec
->loid
);
650 git_buf_printf(buf
, "%04"PRIxZ
"%s %s %s", len
, old_id
, new_id
, spec
->refspec
.dst
);
653 git_buf_putc(buf
, '\0');
654 /* Core git always starts their capabilities string with a space */
655 if (push
->report_status
) {
656 git_buf_putc(buf
, ' ');
657 git_buf_printf(buf
, GIT_CAP_REPORT_STATUS
);
659 git_buf_putc(buf
, ' ');
660 git_buf_printf(buf
, GIT_CAP_SIDE_BAND_64K
);
663 git_buf_putc(buf
, '\n');
666 git_buf_puts(buf
, "0000");
667 return git_buf_oom(buf
) ? -1 : 0;
670 static int add_push_report_pkt(git_push
*push
, git_pkt
*pkt
)
676 status
= git__calloc(1, sizeof(push_status
));
677 GIT_ERROR_CHECK_ALLOC(status
);
679 status
->ref
= git__strdup(((git_pkt_ok
*)pkt
)->ref
);
681 git_vector_insert(&push
->status
, status
) < 0) {
682 git_push_status_free(status
);
687 status
= git__calloc(1, sizeof(push_status
));
688 GIT_ERROR_CHECK_ALLOC(status
);
689 status
->ref
= git__strdup(((git_pkt_ng
*)pkt
)->ref
);
690 status
->msg
= git__strdup(((git_pkt_ng
*)pkt
)->msg
);
691 if (!status
->ref
|| !status
->msg
||
692 git_vector_insert(&push
->status
, status
) < 0) {
693 git_push_status_free(status
);
698 push
->unpack_ok
= ((git_pkt_unpack
*)pkt
)->unpack_ok
;
703 git_error_set(GIT_ERROR_NET
, "report-status: protocol error");
710 static int add_push_report_sideband_pkt(git_push
*push
, git_pkt_data
*data_pkt
, git_buf
*data_pkt_buf
)
713 const char *line
, *line_end
= NULL
;
716 int reading_from_buf
= data_pkt_buf
->size
> 0;
718 if (reading_from_buf
) {
719 /* We had an existing partial packet, so add the new
720 * packet to the buffer and parse the whole thing */
721 git_buf_put(data_pkt_buf
, data_pkt
->data
, data_pkt
->len
);
722 line
= data_pkt_buf
->ptr
;
723 line_len
= data_pkt_buf
->size
;
726 line
= data_pkt
->data
;
727 line_len
= data_pkt
->len
;
730 while (line_len
> 0) {
731 error
= git_pkt_parse_line(&pkt
, &line_end
, line
, line_len
);
733 if (error
== GIT_EBUFS
) {
734 /* Buffer the data when the inner packet is split
735 * across multiple sideband packets */
736 if (!reading_from_buf
)
737 git_buf_put(data_pkt_buf
, line
, line_len
);
744 /* Advance in the buffer */
745 line_len
-= (line_end
- line
);
748 error
= add_push_report_pkt(push
, pkt
);
752 if (error
< 0 && error
!= GIT_ITEROVER
)
759 if (reading_from_buf
)
760 git_buf_consume(data_pkt_buf
, line_end
);
764 static int parse_report(transport_smart
*transport
, git_push
*push
)
767 const char *line_end
= NULL
;
768 gitno_buffer
*buf
= &transport
->buffer
;
770 git_buf data_pkt_buf
= GIT_BUF_INIT
;
774 error
= git_pkt_parse_line(&pkt
, &line_end
,
775 buf
->data
, buf
->offset
);
779 if (error
< 0 && error
!= GIT_EBUFS
) {
784 if (error
== GIT_EBUFS
) {
785 if ((recvd
= gitno_recv(buf
)) < 0) {
791 git_error_set(GIT_ERROR_NET
, "early EOF");
798 if (gitno_consume(buf
, line_end
) < 0)
805 /* This is a sideband packet which contains other packets */
806 error
= add_push_report_sideband_pkt(push
, (git_pkt_data
*)pkt
, &data_pkt_buf
);
809 git_error_set(GIT_ERROR_NET
, "report-status: Error reported: %s",
810 ((git_pkt_err
*)pkt
)->error
);
813 case GIT_PKT_PROGRESS
:
814 if (transport
->progress_cb
) {
815 git_pkt_progress
*p
= (git_pkt_progress
*) pkt
;
817 if (p
->len
> INT_MAX
) {
818 git_error_set(GIT_ERROR_NET
, "oversized progress message");
823 error
= transport
->progress_cb(p
->data
, (int)p
->len
, transport
->message_cb_payload
);
827 error
= add_push_report_pkt(push
, pkt
);
833 /* add_push_report_pkt returns GIT_ITEROVER when it receives a flush */
834 if (error
== GIT_ITEROVER
) {
836 if (data_pkt_buf
.size
> 0) {
837 /* If there was data remaining in the pack data buffer,
838 * then the server sent a partial pkt-line */
839 git_error_set(GIT_ERROR_NET
, "incomplete pack data pkt-line");
850 git_buf_dispose(&data_pkt_buf
);
854 static int add_ref_from_push_spec(git_vector
*refs
, push_spec
*push_spec
)
856 git_pkt_ref
*added
= git__calloc(1, sizeof(git_pkt_ref
));
857 GIT_ERROR_CHECK_ALLOC(added
);
859 added
->type
= GIT_PKT_REF
;
860 git_oid_cpy(&added
->head
.oid
, &push_spec
->loid
);
861 added
->head
.name
= git__strdup(push_spec
->refspec
.dst
);
863 if (!added
->head
.name
||
864 git_vector_insert(refs
, added
) < 0) {
865 git_pkt_free((git_pkt
*)added
);
872 static int update_refs_from_report(
874 git_vector
*push_specs
,
875 git_vector
*push_report
)
878 push_spec
*push_spec
;
879 push_status
*push_status
;
880 size_t i
, j
, refs_len
;
883 /* For each push spec we sent to the server, we should have
884 * gotten back a status packet in the push report */
885 if (push_specs
->length
!= push_report
->length
) {
886 git_error_set(GIT_ERROR_NET
, "report-status: protocol error");
890 /* We require that push_specs be sorted with push_spec_rref_cmp,
891 * and that push_report be sorted with push_status_ref_cmp */
892 git_vector_sort(push_specs
);
893 git_vector_sort(push_report
);
895 git_vector_foreach(push_specs
, i
, push_spec
) {
896 push_status
= git_vector_get(push_report
, i
);
898 /* For each push spec we sent to the server, we should have
899 * gotten back a status packet in the push report which matches */
900 if (strcmp(push_spec
->refspec
.dst
, push_status
->ref
)) {
901 git_error_set(GIT_ERROR_NET
, "report-status: protocol error");
906 /* We require that refs be sorted with ref_name_cmp */
907 git_vector_sort(refs
);
909 refs_len
= refs
->length
;
911 /* Merge join push_specs with refs */
912 while (i
< push_specs
->length
&& j
< refs_len
) {
913 push_spec
= git_vector_get(push_specs
, i
);
914 push_status
= git_vector_get(push_report
, i
);
915 ref
= git_vector_get(refs
, j
);
917 cmp
= strcmp(push_spec
->refspec
.dst
, ref
->head
.name
);
919 /* Iterate appropriately */
926 add_ref_from_push_spec(refs
, push_spec
) < 0)
929 /* Update case, delete case */
932 git_oid_cpy(&ref
->head
.oid
, &push_spec
->loid
);
935 for (; i
< push_specs
->length
; i
++) {
936 push_spec
= git_vector_get(push_specs
, i
);
937 push_status
= git_vector_get(push_report
, i
);
940 if (!push_status
->msg
&&
941 add_ref_from_push_spec(refs
, push_spec
) < 0)
945 /* Remove any refs which we updated to have a zero OID. */
946 git_vector_rforeach(refs
, i
, ref
) {
947 if (git_oid_is_zero(&ref
->head
.oid
)) {
948 git_vector_remove(refs
, i
);
949 git_pkt_free((git_pkt
*)ref
);
953 git_vector_sort(refs
);
958 struct push_packbuilder_payload
960 git_smart_subtransport_stream
*stream
;
962 git_push_transfer_progress_cb cb
;
965 double last_progress_report_time
;
968 static int stream_thunk(void *buf
, size_t size
, void *data
)
971 struct push_packbuilder_payload
*payload
= data
;
973 if ((error
= payload
->stream
->write(payload
->stream
, (const char *)buf
, size
)) < 0)
977 double current_time
= git__timer();
978 double elapsed
= current_time
- payload
->last_progress_report_time
;
979 payload
->last_bytes
+= size
;
981 if (elapsed
< 0 || elapsed
>= MIN_PROGRESS_UPDATE_INTERVAL
) {
982 payload
->last_progress_report_time
= current_time
;
983 error
= payload
->cb(payload
->pb
->nr_written
, payload
->pb
->nr_objects
, payload
->last_bytes
, payload
->cb_payload
);
990 int git_smart__push(git_transport
*transport
, git_push
*push
, const git_remote_callbacks
*cbs
)
992 transport_smart
*t
= (transport_smart
*)transport
;
993 struct push_packbuilder_payload packbuilder_payload
= {0};
994 git_buf pktline
= GIT_BUF_INIT
;
995 int error
= 0, need_pack
= 0;
999 packbuilder_payload
.pb
= push
->pb
;
1001 if (cbs
&& cbs
->push_transfer_progress
) {
1002 packbuilder_payload
.cb
= cbs
->push_transfer_progress
;
1003 packbuilder_payload
.cb_payload
= cbs
->payload
;
1008 git_remote_head
*head
;
1009 char hex
[GIT_OID_HEXSZ
+1]; hex
[GIT_OID_HEXSZ
] = '\0';
1011 git_vector_foreach(&push
->remote
->refs
, i
, head
) {
1012 git_oid_fmt(hex
, &head
->oid
);
1013 fprintf(stderr
, "%s (%s)\n", hex
, head
->name
);
1016 git_vector_foreach(&push
->specs
, i
, spec
) {
1017 git_oid_fmt(hex
, &spec
->roid
);
1018 fprintf(stderr
, "%s (%s) -> ", hex
, spec
->lref
);
1019 git_oid_fmt(hex
, &spec
->loid
);
1020 fprintf(stderr
, "%s (%s)\n", hex
, spec
->rref
?
1021 spec
->rref
: spec
->lref
);
1027 * Figure out if we need to send a packfile; which is in all
1028 * cases except when we only send delete commands
1030 git_vector_foreach(&push
->specs
, i
, spec
) {
1031 if (spec
->refspec
.src
&& spec
->refspec
.src
[0] != '\0') {
1037 if ((error
= git_smart__get_push_stream(t
, &packbuilder_payload
.stream
)) < 0 ||
1038 (error
= gen_pktline(&pktline
, push
)) < 0 ||
1039 (error
= packbuilder_payload
.stream
->write(packbuilder_payload
.stream
, git_buf_cstr(&pktline
), git_buf_len(&pktline
))) < 0)
1043 (error
= git_packbuilder_foreach(push
->pb
, &stream_thunk
, &packbuilder_payload
)) < 0)
1046 /* If we sent nothing or the server doesn't support report-status, then
1047 * we consider the pack to have been unpacked successfully */
1048 if (!push
->specs
.length
|| !push
->report_status
)
1049 push
->unpack_ok
= 1;
1050 else if ((error
= parse_report(t
, push
)) < 0)
1053 /* If progress is being reported write the final report */
1054 if (cbs
&& cbs
->push_transfer_progress
) {
1055 error
= cbs
->push_transfer_progress(
1056 push
->pb
->nr_written
,
1057 push
->pb
->nr_objects
,
1058 packbuilder_payload
.last_bytes
,
1065 if (push
->status
.length
) {
1066 error
= update_refs_from_report(&t
->refs
, &push
->specs
, &push
->status
);
1070 error
= git_smart__update_heads(t
, NULL
);
1074 git_buf_dispose(&pktline
);