diff options
Diffstat (limited to 'src/libgit2/transports')
| -rw-r--r-- | src/libgit2/transports/local.c | 6 | ||||
| -rw-r--r-- | src/libgit2/transports/smart.c | 28 | ||||
| -rw-r--r-- | src/libgit2/transports/smart.h | 23 | ||||
| -rw-r--r-- | src/libgit2/transports/smart_pkt.c | 90 | ||||
| -rw-r--r-- | src/libgit2/transports/smart_protocol.c | 62 |
5 files changed, 189 insertions, 20 deletions
diff --git a/src/libgit2/transports/local.c b/src/libgit2/transports/local.c index 6c754a034..24f49cc65 100644 --- a/src/libgit2/transports/local.c +++ b/src/libgit2/transports/local.c @@ -284,15 +284,13 @@ static int local_ls(const git_remote_head ***out, size_t *size, git_transport *t static int local_negotiate_fetch( git_transport *transport, git_repository *repo, - const git_remote_head * const *refs, - size_t count) + const git_fetch_negotiation *wants) { transport_local *t = (transport_local*)transport; git_remote_head *rhead; unsigned int i; - GIT_UNUSED(refs); - GIT_UNUSED(count); + GIT_UNUSED(wants); /* Fill in the loids */ git_vector_foreach(&t->refs, i, rhead) { diff --git a/src/libgit2/transports/smart.c b/src/libgit2/transports/smart.c index 7f57dba2a..9d1afeb05 100644 --- a/src/libgit2/transports/smart.c +++ b/src/libgit2/transports/smart.c @@ -482,3 +482,31 @@ int git_transport_smart(git_transport **out, git_remote *owner, void *param) *out = (git_transport *) t; return 0; } + +size_t git_shallowarray_count(git_shallowarray *array) +{ + return git_array_size(array->array); +} + +const git_oid * git_shallowarray_get(git_shallowarray *array, size_t idx) +{ + return git_array_get(array->array, idx); +} + +int git_shallowarray_add(git_shallowarray *array, git_oid *oid) +{ + size_t oid_index; + if (git_array_search(&oid_index, array->array, (git_array_compare_cb)git_oid_cmp, &oid) < 0) { + git_oid *tmp = git_array_alloc(array->array); + git_oid_cpy(tmp, oid); + } + return 0; +} + +int git_shallowarray_remove(git_shallowarray *array, git_oid *oid) +{ + GIT_UNUSED(array); + GIT_UNUSED(oid); + /* no git_array_remove⦠meh */ + return -1; +} diff --git a/src/libgit2/transports/smart.h b/src/libgit2/transports/smart.h index 9323d6c44..bc072d2fe 100644 --- a/src/libgit2/transports/smart.h +++ b/src/libgit2/transports/smart.h @@ -14,6 +14,7 @@ #include "netops.h" #include "push.h" #include "str.h" +#include "oidarray.h" #include "git2/sys/transport.h" #define GIT_SIDE_BAND_DATA 1 @@ -32,6 +33,7 @@ #define GIT_CAP_SYMREF "symref" #define GIT_CAP_WANT_TIP_SHA1 "allow-tip-sha1-in-want" #define GIT_CAP_WANT_REACHABLE_SHA1 "allow-reachable-sha1-in-want" +#define GIT_CAP_SHALLOW "shallow" extern bool git_smart__ofs_delta_enabled; @@ -48,7 +50,9 @@ typedef enum { GIT_PKT_PROGRESS, GIT_PKT_OK, GIT_PKT_NG, - GIT_PKT_UNPACK + GIT_PKT_UNPACK, + GIT_PKT_SHALLOW, + GIT_PKT_UNSHALLOW, } git_pkt_type; /* Used for multi_ack and multi_ack_detailed */ @@ -120,6 +124,11 @@ typedef struct { int unpack_ok; } git_pkt_unpack; +typedef struct { + git_pkt_type type; + git_oid oid; +} git_pkt_shallow; + typedef struct transport_smart_caps { unsigned int common:1, ofs_delta:1, @@ -132,7 +141,8 @@ typedef struct transport_smart_caps { report_status:1, thin_pack:1, want_tip_sha1:1, - want_reachable_sha1:1; + want_reachable_sha1:1, + shallow:1; } transport_smart_caps; typedef int (*packetsize_cb)(size_t received, void *payload); @@ -167,8 +177,7 @@ int git_smart__push(git_transport *transport, git_push *push); int git_smart__negotiate_fetch( git_transport *transport, git_repository *repo, - const git_remote_head * const *refs, - size_t count); + const git_fetch_negotiation *wants); int git_smart__download_pack( git_transport *transport, @@ -186,8 +195,12 @@ int git_pkt_parse_line(git_pkt **head, const char **endptr, const char *line, si int git_pkt_buffer_flush(git_str *buf); int git_pkt_send_flush(GIT_SOCKET s); int git_pkt_buffer_done(git_str *buf); -int git_pkt_buffer_wants(const git_remote_head * const *refs, size_t count, transport_smart_caps *caps, git_str *buf); +int git_pkt_buffer_wants(const git_fetch_negotiation *wants, transport_smart_caps *caps, git_str *buf); int git_pkt_buffer_have(git_oid *oid, git_str *buf); void git_pkt_free(git_pkt *pkt); +struct git_shallowarray { + git_array_oid_t array; +}; + #endif diff --git a/src/libgit2/transports/smart_pkt.c b/src/libgit2/transports/smart_pkt.c index e679819fa..e368cb7e2 100644 --- a/src/libgit2/transports/smart_pkt.c +++ b/src/libgit2/transports/smart_pkt.c @@ -366,6 +366,50 @@ static int unpack_pkt(git_pkt **out, const char *line, size_t len) return 0; } +static int shallow_pkt(git_pkt **out, const char *line, size_t len) +{ + git_pkt_shallow *pkt; + + pkt = git__calloc(1, sizeof(git_pkt_shallow)); + GIT_ERROR_CHECK_ALLOC(pkt); + + pkt->type = GIT_PKT_SHALLOW; + line += 7; + len -= 7; + + if (len >= GIT_OID_HEXSZ) { + git_oid_fromstr(&pkt->oid, line + 1); + line += GIT_OID_HEXSZ + 1; + len -= GIT_OID_HEXSZ + 1; + } + + *out = (git_pkt *) pkt; + + return 0; +} + +static int unshallow_pkt(git_pkt **out, const char *line, size_t len) +{ + git_pkt_shallow *pkt; + + pkt = git__calloc(1, sizeof(git_pkt_shallow)); + GIT_ERROR_CHECK_ALLOC(pkt); + + pkt->type = GIT_PKT_UNSHALLOW; + line += 9; + len -= 9; + + if (len >= GIT_OID_HEXSZ) { + git_oid_fromstr(&pkt->oid, line + 1); + line += GIT_OID_HEXSZ + 1; + len -= GIT_OID_HEXSZ + 1; + } + + *out = (git_pkt *) pkt; + + return 0; +} + static int parse_len(size_t *out, const char *line, size_t linelen) { char num[PKT_LEN_SIZE + 1]; @@ -492,6 +536,10 @@ int git_pkt_parse_line( error = ng_pkt(pkt, line, len); else if (!git__prefixncmp(line, len, "unpack")) error = unpack_pkt(pkt, line, len); + else if (!git__prefixcmp(line, "shallow")) + error = shallow_pkt(pkt, line, len); + else if (!git__prefixcmp(line, "unshallow")) + error = unshallow_pkt(pkt, line, len); else error = ref_pkt(pkt, line, len); @@ -557,6 +605,9 @@ static int buffer_want_with_caps(const git_remote_head *head, transport_smart_ca if (caps->ofs_delta) git_str_puts(&str, GIT_CAP_OFS_DELTA " "); + if (caps->shallow) + git_str_puts(&str, GIT_CAP_SHALLOW " "); + if (git_str_oom(&str)) return -1; @@ -586,8 +637,7 @@ static int buffer_want_with_caps(const git_remote_head *head, transport_smart_ca */ int git_pkt_buffer_wants( - const git_remote_head * const *refs, - size_t count, + const git_fetch_negotiation *wants, transport_smart_caps *caps, git_str *buf) { @@ -595,22 +645,22 @@ int git_pkt_buffer_wants( const git_remote_head *head; if (caps->common) { - for (; i < count; ++i) { - head = refs[i]; + for (; i < wants->count; ++i) { + head = wants->refs[i]; if (!head->local) break; } - if (buffer_want_with_caps(refs[i], caps, buf) < 0) + if (buffer_want_with_caps(wants->refs[i], caps, buf) < 0) return -1; i++; } - for (; i < count; ++i) { + for (; i < wants->count; ++i) { char oid[GIT_OID_SHA1_HEXSIZE]; - head = refs[i]; + head = wants->refs[i]; if (head->local) continue; @@ -622,6 +672,32 @@ int git_pkt_buffer_wants( return -1; } + /* Tell the server about our shallow objects */ + for (i = 0; i < git_shallowarray_count(wants->shallow_roots); i++) { + char oid[GIT_OID_HEXSZ]; + git_buf shallow_buf = GIT_BUF_INIT; + + git_oid_fmt(oid, git_shallowarray_get(wants->shallow_roots, i)); + git_buf_puts(&shallow_buf, "shallow "); + git_buf_put(&shallow_buf, oid, GIT_OID_HEXSZ); + git_buf_putc(&shallow_buf, '\n'); + + git_buf_printf(buf, "%04x%s", (unsigned int)git_buf_len(&shallow_buf) + 4, git_buf_cstr(&shallow_buf)); + + if (git_buf_oom(buf)) + return -1; + } + + if (wants->depth > 0) { + git_buf deepen_buf = GIT_BUF_INIT; + + git_buf_printf(&deepen_buf, "deepen %d\n", wants->depth); + git_buf_printf(buf,"%04x%s", (unsigned int)git_buf_len(&deepen_buf) + 4, git_buf_cstr(&deepen_buf)); + + if (git_buf_oom(buf)) + return -1; + } + return git_pkt_buffer_flush(buf); } diff --git a/src/libgit2/transports/smart_protocol.c b/src/libgit2/transports/smart_protocol.c index 09778b335..cd90db43f 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,33 @@ 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) { + printf("shallow %s\n", git_oid_tostr_s(&pkt->oid)); + git_shallowarray_add(wants->shallow_roots, &pkt->oid); + } else if (pkt->type == GIT_PKT_UNSHALLOW) { + printf("unshallow %s\n", git_oid_tostr_s(&pkt->oid)); + 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; + } + } + + 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 +455,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 +475,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) { |
