Commit afa79ca0 by yuangli

Merge branch 'pr/tiennou/4747' into transportPR

parent 70a332a5
...@@ -738,11 +738,16 @@ typedef struct { ...@@ -738,11 +738,16 @@ typedef struct {
* Extra headers for this fetch operation * Extra headers for this fetch operation
*/ */
git_strarray custom_headers; git_strarray custom_headers;
/**
* Depth of the fetch to perform
*/
int depth;
} git_fetch_options; } git_fetch_options;
#define GIT_FETCH_OPTIONS_VERSION 1 #define GIT_FETCH_OPTIONS_VERSION 1
#define GIT_FETCH_OPTIONS_INIT { GIT_FETCH_OPTIONS_VERSION, GIT_REMOTE_CALLBACKS_INIT, GIT_FETCH_PRUNE_UNSPECIFIED, 1, \ #define GIT_FETCH_OPTIONS_INIT { GIT_FETCH_OPTIONS_VERSION, GIT_REMOTE_CALLBACKS_INIT, GIT_FETCH_PRUNE_UNSPECIFIED, 1, \
GIT_REMOTE_DOWNLOAD_TAGS_UNSPECIFIED, GIT_PROXY_OPTIONS_INIT } GIT_REMOTE_DOWNLOAD_TAGS_UNSPECIFIED, GIT_PROXY_OPTIONS_INIT, { NULL }, -1 }
/** /**
* Initialize git_fetch_options structure * Initialize git_fetch_options structure
......
...@@ -921,6 +921,17 @@ GIT_EXTERN(const char *) git_repository_get_namespace(git_repository *repo); ...@@ -921,6 +921,17 @@ GIT_EXTERN(const char *) git_repository_get_namespace(git_repository *repo);
GIT_EXTERN(int) git_repository_is_shallow(git_repository *repo); GIT_EXTERN(int) git_repository_is_shallow(git_repository *repo);
/** /**
* Determine the shallow roots of the repository
*
* This oidarray is owned by the library. Do not free it.
*
* @param out An array of shallow oids.
* @param repo The repository
* @return 0 on success, an error otherwise.
*/
GIT_EXTERN(int) git_repository_shallow_roots(git_oidarray *out, git_repository *repo);
/**
* Retrieve the configured identity to use for reflogs * Retrieve the configured identity to use for reflogs
* *
* The memory is owned by the repository and must not be freed by the * The memory is owned by the repository and must not be freed by the
......
...@@ -33,6 +33,15 @@ typedef enum { ...@@ -33,6 +33,15 @@ typedef enum {
GIT_TRANSPORTFLAGS_NONE = 0, GIT_TRANSPORTFLAGS_NONE = 0,
} git_transport_flags_t; } git_transport_flags_t;
typedef struct git_shallowarray git_shallowarray;
typedef struct {
const git_remote_head * const *refs;
size_t count;
git_shallowarray *shallow_roots;
int depth;
} git_fetch_negotiation;
struct git_transport { struct git_transport {
unsigned int version; /**< The struct version */ unsigned int version; /**< The struct version */
...@@ -87,8 +96,7 @@ struct git_transport { ...@@ -87,8 +96,7 @@ struct git_transport {
int GIT_CALLBACK(negotiate_fetch)( int GIT_CALLBACK(negotiate_fetch)(
git_transport *transport, git_transport *transport,
git_repository *repo, git_repository *repo,
const git_remote_head * const *refs, const git_fetch_negotiation *fetch_data);
size_t count);
/** /**
* Start downloading the packfile from the remote repository. * Start downloading the packfile from the remote repository.
...@@ -435,6 +443,11 @@ GIT_EXTERN(int) git_smart_subtransport_ssh( ...@@ -435,6 +443,11 @@ GIT_EXTERN(int) git_smart_subtransport_ssh(
git_transport *owner, git_transport *owner,
void *param); void *param);
GIT_EXTERN(size_t) git_shallowarray_count(git_shallowarray *array);
GIT_EXTERN(const git_oid *) git_shallowarray_get(git_shallowarray *array, size_t idx);
GIT_EXTERN(int) git_shallowarray_add(git_shallowarray *array, git_oid *oid);
GIT_EXTERN(int) git_shallowarray_remove(git_shallowarray *array, git_oid *oid);
/** @} */ /** @} */
GIT_END_DECL GIT_END_DECL
#endif #endif
...@@ -85,12 +85,14 @@ on_oom: ...@@ -85,12 +85,14 @@ on_oom:
#define git_array_foreach(a, i, element) \ #define git_array_foreach(a, i, element) \
for ((i) = 0; (i) < (a).size && ((element) = &(a).ptr[(i)]); (i)++) for ((i) = 0; (i) < (a).size && ((element) = &(a).ptr[(i)]); (i)++)
typedef int (*git_array_compare_cb)(const void *, const void *);
GIT_INLINE(int) git_array__search( GIT_INLINE(int) git_array__search(
size_t *out, size_t *out,
void *array_ptr, void *array_ptr,
size_t item_size, size_t item_size,
size_t array_len, size_t array_len,
int (*compare)(const void *, const void *), git_array_compare_cb compare,
const void *key) const void *key)
{ {
size_t lim; size_t lim;
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include "netops.h" #include "netops.h"
#include "repository.h" #include "repository.h"
#include "refs.h" #include "refs.h"
#include "transports/smart.h"
static int maybe_want(git_remote *remote, git_remote_head *head, git_odb *odb, git_refspec *tagspec, git_remote_autotag_option_t tagopt) static int maybe_want(git_remote *remote, git_remote_head *head, git_odb *odb, git_refspec *tagspec, git_remote_autotag_option_t tagopt)
{ {
...@@ -128,10 +129,18 @@ int git_fetch_negotiate(git_remote *remote, const git_fetch_options *opts) ...@@ -128,10 +129,18 @@ int git_fetch_negotiate(git_remote *remote, const git_fetch_options *opts)
* Now we have everything set up so we can start tell the * Now we have everything set up so we can start tell the
* server what we want and what we have. * server what we want and what we have.
*/ */
remote->nego.refs = (const git_remote_head * const *)remote->refs.contents;
remote->nego.count = remote->refs.length;
remote->nego.depth = opts->depth;
remote->nego.shallow_roots = git__malloc(sizeof(git_shallowarray));
git_array_init(remote->nego.shallow_roots->array);
git_repository__shallow_roots(&remote->nego.shallow_roots->array, remote->repo);
return t->negotiate_fetch(t, return t->negotiate_fetch(t,
remote->repo, remote->repo,
(const git_remote_head * const *)remote->refs.contents, &remote->nego);
remote->refs.length);
} }
int git_fetch_download_pack(git_remote *remote, const git_remote_callbacks *callbacks) int git_fetch_download_pack(git_remote *remote, const git_remote_callbacks *callbacks)
...@@ -139,6 +148,7 @@ int git_fetch_download_pack(git_remote *remote, const git_remote_callbacks *call ...@@ -139,6 +148,7 @@ int git_fetch_download_pack(git_remote *remote, const git_remote_callbacks *call
git_transport *t = remote->transport; git_transport *t = remote->transport;
git_indexer_progress_cb progress = NULL; git_indexer_progress_cb progress = NULL;
void *payload = NULL; void *payload = NULL;
int error;
if (!remote->need_pack) if (!remote->need_pack)
return 0; return 0;
...@@ -148,7 +158,13 @@ int git_fetch_download_pack(git_remote *remote, const git_remote_callbacks *call ...@@ -148,7 +158,13 @@ int git_fetch_download_pack(git_remote *remote, const git_remote_callbacks *call
payload = callbacks->payload; payload = callbacks->payload;
} }
return t->download_pack(t, remote->repo, &remote->stats, progress, payload); if ((error = t->download_pack(t, remote->repo, &remote->stats, progress, payload)) < 0)
return error;
if ((error = git_repository__shallow_roots_write(remote->repo, remote->nego.shallow_roots->array)) < 0)
return error;
return 0;
} }
int git_fetch_options_init(git_fetch_options *opts, unsigned int version) int git_fetch_options_init(git_fetch_options *opts, unsigned int version)
......
...@@ -104,15 +104,13 @@ int git_object__from_raw( ...@@ -104,15 +104,13 @@ int git_object__from_raw(
return 0; return 0;
} }
int git_object__from_odb_object( int git_object__init_from_odb_object(
git_object **object_out, git_object **object_out,
git_repository *repo, git_repository *repo,
git_odb_object *odb_obj, git_odb_object *odb_obj,
git_object_t type) git_object_t type)
{ {
int error;
size_t object_size; size_t object_size;
git_object_def *def;
git_object *object = NULL; git_object *object = NULL;
GIT_ASSERT_ARG(object_out); GIT_ASSERT_ARG(object_out);
...@@ -139,6 +137,23 @@ int git_object__from_odb_object( ...@@ -139,6 +137,23 @@ int git_object__from_odb_object(
object->cached.size = odb_obj->cached.size; object->cached.size = odb_obj->cached.size;
object->repo = repo; object->repo = repo;
*object_out = object;
return 0;
}
int git_object__from_odb_object(
git_object **object_out,
git_repository *repo,
git_odb_object *odb_obj,
git_object_t type)
{
int error;
git_object_def *def;
git_object *object = NULL;
if ((error = git_object__init_from_odb_object(&object, repo, odb_obj, type)) < 0)
return error;
/* Parse raw object data */ /* Parse raw object data */
def = &git_objects_table[odb_obj->cached.type]; def = &git_objects_table[odb_obj->cached.type];
GIT_ASSERT(def->free && def->parse); GIT_ASSERT(def->free && def->parse);
......
...@@ -35,6 +35,12 @@ int git_object__from_raw( ...@@ -35,6 +35,12 @@ int git_object__from_raw(
size_t size, size_t size,
git_object_t type); git_object_t type);
int git_object__init_from_odb_object(
git_object **object_out,
git_repository *repo,
git_odb_object *odb_obj,
git_object_t type);
int git_object__from_odb_object( int git_object__from_odb_object(
git_object **object_out, git_object **object_out,
git_repository *repo, git_repository *repo,
......
...@@ -35,6 +35,7 @@ struct git_remote { ...@@ -35,6 +35,7 @@ struct git_remote {
git_remote_autotag_option_t download_tags; git_remote_autotag_option_t download_tags;
int prune_refs; int prune_refs;
int passed_refspecs; int passed_refspecs;
git_fetch_negotiation nego;
}; };
typedef struct git_remote_connection_opts { typedef struct git_remote_connection_opts {
......
...@@ -3192,6 +3192,95 @@ int git_repository_state_cleanup(git_repository *repo) ...@@ -3192,6 +3192,95 @@ int git_repository_state_cleanup(git_repository *repo)
return git_repository__cleanup_files(repo, state_files, ARRAY_SIZE(state_files)); return git_repository__cleanup_files(repo, state_files, ARRAY_SIZE(state_files));
} }
int git_repository__shallow_roots(git_array_oid_t *out, git_repository *repo)
{
git_buf path = GIT_BUF_INIT;
git_buf contents = GIT_BUF_INIT;
int error, updated, line_num = 1;
char *line;
char *buffer;
assert(out && repo);
if ((error = git_buf_joinpath(&path, repo->gitdir, "shallow")) < 0)
return error;
error = git_futils_readbuffer_updated(&contents, git_buf_cstr(&path), &repo->shallow_checksum, &updated);
git_buf_dispose(&path);
if (error < 0 && error != GIT_ENOTFOUND)
return error;
/* cancel out GIT_ENOTFOUND */
git_error_clear();
error = 0;
if (!updated) {
*out = repo->shallow_oids;
goto cleanup;
}
git_array_clear(repo->shallow_oids);
buffer = contents.ptr;
while ((line = git__strsep(&buffer, "\n")) != NULL) {
git_oid *oid = git_array_alloc(repo->shallow_oids);
error = git_oid_fromstr(oid, line);
if (error < 0) {
git_error_set(GIT_ERROR_REPOSITORY, "Invalid OID at line %d", line_num);
git_array_clear(repo->shallow_oids);
error = -1;
goto cleanup;
}
++line_num;
}
if (*buffer) {
git_error_set(GIT_ERROR_REPOSITORY, "No EOL at line %d", line_num);
git_array_clear(repo->shallow_oids);
error = -1;
goto cleanup;
}
*out = repo->shallow_oids;
cleanup:
git_buf_dispose(&contents);
return error;
}
int git_repository__shallow_roots_write(git_repository *repo, git_array_oid_t roots)
{
git_filebuf file = GIT_FILEBUF_INIT;
git_buf path = GIT_BUF_INIT;
int error = 0;
size_t idx;
git_oid *oid;
assert(repo);
if ((error = git_buf_joinpath(&path, repo->gitdir, "shallow")) < 0)
return error;
if ((error = git_filebuf_open(&file, git_buf_cstr(&path), GIT_FILEBUF_HASH_CONTENTS, 0666)) < 0)
return error;
git_array_foreach(roots, idx, oid) {
git_filebuf_write(&file, git_oid_tostr_s(oid), GIT_OID_HEXSZ);
git_filebuf_write(&file, "\n", 1);
}
git_filebuf_commit(&file);
/* WIP: reload shallow */
if (load_shallow(repo) < 0)
return -1;
return 0;
}
int git_repository_is_shallow(git_repository *repo) int git_repository_is_shallow(git_repository *repo)
{ {
git_buf path = GIT_BUF_INIT; git_buf path = GIT_BUF_INIT;
......
...@@ -242,6 +242,9 @@ extern size_t git_repository__reserved_names_posix_len; ...@@ -242,6 +242,9 @@ extern size_t git_repository__reserved_names_posix_len;
bool git_repository__reserved_names( bool git_repository__reserved_names(
git_buf **out, size_t *outlen, git_repository *repo, bool include_ntfs); git_buf **out, size_t *outlen, git_repository *repo, bool include_ntfs);
int git_repository__shallow_roots(git_array_oid_t *out, git_repository *repo);
int git_repository__shallow_roots_write(git_repository *repo, git_array_oid_t roots);
/* /*
* The default branch for the repository; the `init.defaultBranch` * The default branch for the repository; the `init.defaultBranch`
* configuration option, if set, or `master` if it is not. * configuration option, if set, or `master` if it is not.
......
...@@ -268,15 +268,13 @@ static int local_ls(const git_remote_head ***out, size_t *size, git_transport *t ...@@ -268,15 +268,13 @@ static int local_ls(const git_remote_head ***out, size_t *size, git_transport *t
static int local_negotiate_fetch( static int local_negotiate_fetch(
git_transport *transport, git_transport *transport,
git_repository *repo, git_repository *repo,
const git_remote_head * const *refs, const git_fetch_negotiation *wants)
size_t count)
{ {
transport_local *t = (transport_local*)transport; transport_local *t = (transport_local*)transport;
git_remote_head *rhead; git_remote_head *rhead;
unsigned int i; unsigned int i;
GIT_UNUSED(refs); GIT_UNUSED(wants);
GIT_UNUSED(count);
/* Fill in the loids */ /* Fill in the loids */
git_vector_foreach(&t->refs, i, rhead) { git_vector_foreach(&t->refs, i, rhead) {
......
...@@ -558,3 +558,31 @@ int git_transport_smart(git_transport **out, git_remote *owner, void *param) ...@@ -558,3 +558,31 @@ int git_transport_smart(git_transport **out, git_remote *owner, void *param)
*out = (git_transport *) t; *out = (git_transport *) t;
return 0; 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;
}
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "netops.h" #include "netops.h"
#include "buffer.h" #include "buffer.h"
#include "push.h" #include "push.h"
#include "oidarray.h"
#include "git2/sys/transport.h" #include "git2/sys/transport.h"
#define GIT_SIDE_BAND_DATA 1 #define GIT_SIDE_BAND_DATA 1
...@@ -30,6 +31,7 @@ ...@@ -30,6 +31,7 @@
#define GIT_CAP_REPORT_STATUS "report-status" #define GIT_CAP_REPORT_STATUS "report-status"
#define GIT_CAP_THIN_PACK "thin-pack" #define GIT_CAP_THIN_PACK "thin-pack"
#define GIT_CAP_SYMREF "symref" #define GIT_CAP_SYMREF "symref"
#define GIT_CAP_SHALLOW "shallow"
extern bool git_smart__ofs_delta_enabled; extern bool git_smart__ofs_delta_enabled;
...@@ -47,6 +49,8 @@ typedef enum { ...@@ -47,6 +49,8 @@ typedef enum {
GIT_PKT_OK, GIT_PKT_OK,
GIT_PKT_NG, GIT_PKT_NG,
GIT_PKT_UNPACK, GIT_PKT_UNPACK,
GIT_PKT_SHALLOW,
GIT_PKT_UNSHALLOW,
} git_pkt_type; } git_pkt_type;
/* Used for multi_ack and multi_ack_detailed */ /* Used for multi_ack and multi_ack_detailed */
...@@ -118,6 +122,11 @@ typedef struct { ...@@ -118,6 +122,11 @@ typedef struct {
int unpack_ok; int unpack_ok;
} git_pkt_unpack; } git_pkt_unpack;
typedef struct {
git_pkt_type type;
git_oid oid;
} git_pkt_shallow;
typedef struct transport_smart_caps { typedef struct transport_smart_caps {
int common:1, int common:1,
ofs_delta:1, ofs_delta:1,
...@@ -128,7 +137,8 @@ typedef struct transport_smart_caps { ...@@ -128,7 +137,8 @@ typedef struct transport_smart_caps {
include_tag:1, include_tag:1,
delete_refs:1, delete_refs:1,
report_status:1, report_status:1,
thin_pack:1; thin_pack:1,
shallow:1;
} transport_smart_caps; } transport_smart_caps;
typedef int (*packetsize_cb)(size_t received, void *payload); typedef int (*packetsize_cb)(size_t received, void *payload);
...@@ -171,8 +181,7 @@ int git_smart__push(git_transport *transport, git_push *push, const git_remote_c ...@@ -171,8 +181,7 @@ int git_smart__push(git_transport *transport, git_push *push, const git_remote_c
int git_smart__negotiate_fetch( int git_smart__negotiate_fetch(
git_transport *transport, git_transport *transport,
git_repository *repo, git_repository *repo,
const git_remote_head * const *refs, const git_fetch_negotiation *wants);
size_t count);
int git_smart__download_pack( int git_smart__download_pack(
git_transport *transport, git_transport *transport,
...@@ -192,8 +201,12 @@ int git_pkt_parse_line(git_pkt **head, const char **endptr, const char *line, si ...@@ -192,8 +201,12 @@ int git_pkt_parse_line(git_pkt **head, const char **endptr, const char *line, si
int git_pkt_buffer_flush(git_buf *buf); int git_pkt_buffer_flush(git_buf *buf);
int git_pkt_send_flush(GIT_SOCKET s); int git_pkt_send_flush(GIT_SOCKET s);
int git_pkt_buffer_done(git_buf *buf); int git_pkt_buffer_done(git_buf *buf);
int git_pkt_buffer_wants(const git_remote_head * const *refs, size_t count, transport_smart_caps *caps, git_buf *buf); int git_pkt_buffer_wants(const git_fetch_negotiation *wants, transport_smart_caps *caps, git_buf *buf);
int git_pkt_buffer_have(git_oid *oid, git_buf *buf); int git_pkt_buffer_have(git_oid *oid, git_buf *buf);
void git_pkt_free(git_pkt *pkt); void git_pkt_free(git_pkt *pkt);
struct git_shallowarray {
git_array_oid_t array;
};
#endif #endif
...@@ -363,6 +363,50 @@ static int unpack_pkt(git_pkt **out, const char *line, size_t len) ...@@ -363,6 +363,50 @@ static int unpack_pkt(git_pkt **out, const char *line, size_t len)
return 0; 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) static int parse_len(size_t *out, const char *line, size_t linelen)
{ {
char num[PKT_LEN_SIZE + 1]; char num[PKT_LEN_SIZE + 1];
...@@ -489,6 +533,10 @@ int git_pkt_parse_line( ...@@ -489,6 +533,10 @@ int git_pkt_parse_line(
error = ng_pkt(pkt, line, len); error = ng_pkt(pkt, line, len);
else if (!git__prefixncmp(line, len, "unpack")) else if (!git__prefixncmp(line, len, "unpack"))
error = unpack_pkt(pkt, line, len); 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 else
error = ref_pkt(pkt, line, len); error = ref_pkt(pkt, line, len);
...@@ -554,6 +602,9 @@ static int buffer_want_with_caps(const git_remote_head *head, transport_smart_ca ...@@ -554,6 +602,9 @@ static int buffer_want_with_caps(const git_remote_head *head, transport_smart_ca
if (caps->ofs_delta) if (caps->ofs_delta)
git_buf_puts(&str, GIT_CAP_OFS_DELTA " "); git_buf_puts(&str, GIT_CAP_OFS_DELTA " ");
if (caps->shallow)
git_buf_puts(&str, GIT_CAP_SHALLOW " ");
if (git_buf_oom(&str)) if (git_buf_oom(&str))
return -1; return -1;
...@@ -583,8 +634,7 @@ static int buffer_want_with_caps(const git_remote_head *head, transport_smart_ca ...@@ -583,8 +634,7 @@ static int buffer_want_with_caps(const git_remote_head *head, transport_smart_ca
*/ */
int git_pkt_buffer_wants( int git_pkt_buffer_wants(
const git_remote_head * const *refs, const git_fetch_negotiation *wants,
size_t count,
transport_smart_caps *caps, transport_smart_caps *caps,
git_buf *buf) git_buf *buf)
{ {
...@@ -592,22 +642,22 @@ int git_pkt_buffer_wants( ...@@ -592,22 +642,22 @@ int git_pkt_buffer_wants(
const git_remote_head *head; const git_remote_head *head;
if (caps->common) { if (caps->common) {
for (; i < count; ++i) { for (; i < wants->count; ++i) {
head = refs[i]; head = wants->refs[i];
if (!head->local) if (!head->local)
break; break;
} }
if (buffer_want_with_caps(refs[i], caps, buf) < 0) if (buffer_want_with_caps(wants->refs[i], caps, buf) < 0)
return -1; return -1;
i++; i++;
} }
for (; i < count; ++i) { for (; i < wants->count; ++i) {
char oid[GIT_OID_HEXSZ]; char oid[GIT_OID_HEXSZ];
head = refs[i]; head = wants->refs[i];
if (head->local) if (head->local)
continue; continue;
...@@ -619,6 +669,32 @@ int git_pkt_buffer_wants( ...@@ -619,6 +669,32 @@ int git_pkt_buffer_wants(
return -1; 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); return git_pkt_buffer_flush(buf);
} }
......
...@@ -205,6 +205,12 @@ int git_smart__detect_caps(git_pkt_ref *pkt, transport_smart_caps *caps, git_vec ...@@ -205,6 +205,12 @@ int git_smart__detect_caps(git_pkt_ref *pkt, transport_smart_caps *caps, git_vec
continue; continue;
} }
if (!git__prefixcmp(ptr, GIT_CAP_SHALLOW)) {
caps->common = caps->shallow = 1;
ptr += strlen(GIT_CAP_SHALLOW);
continue;
}
/* We don't know this capability, so skip it */ /* We don't know this capability, so skip it */
ptr = strchr(ptr, ' '); ptr = strchr(ptr, ' ');
} }
...@@ -305,7 +311,26 @@ static int wait_while_ack(gitno_buffer *buf) ...@@ -305,7 +311,26 @@ static int wait_while_ack(gitno_buffer *buf)
return 0; 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; transport_smart *t = (transport_smart *)transport;
git_revwalk__push_options opts = GIT_REVWALK__PUSH_OPTIONS_INIT; git_revwalk__push_options opts = GIT_REVWALK__PUSH_OPTIONS_INIT;
...@@ -317,7 +342,10 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c ...@@ -317,7 +342,10 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c
unsigned int i; unsigned int i;
git_oid oid; 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; return error;
if ((error = git_revwalk_new(&walk, repo)) < 0) if ((error = git_revwalk_new(&walk, repo)) < 0)
...@@ -327,6 +355,33 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c ...@@ -327,6 +355,33 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c
if ((error = git_revwalk__push_glob(walk, "refs/*", &opts)) < 0) if ((error = git_revwalk__push_glob(walk, "refs/*", &opts)) < 0)
goto on_error; 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 * Our support for ACK extensions is simply to parse them. On
* the first ACK we will accept that as enough common * the first ACK we will accept that as enough common
...@@ -389,7 +444,7 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c ...@@ -389,7 +444,7 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c
git_pkt_ack *pkt; git_pkt_ack *pkt;
unsigned int j; 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; goto on_error;
git_vector_foreach(&t->common, j, pkt) { git_vector_foreach(&t->common, j, pkt) {
...@@ -409,7 +464,7 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c ...@@ -409,7 +464,7 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c
git_pkt_ack *pkt; git_pkt_ack *pkt;
unsigned int j; 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; goto on_error;
git_vector_foreach(&t->common, j, pkt) { git_vector_foreach(&t->common, j, pkt) {
......
#include "clar_libgit2.h"
#include "futils.h"
void test_clone_shallow__initialize(void)
{
}
void test_clone_shallow__cleanup(void)
{
cl_git_sandbox_cleanup();
}
#define CLONE_DEPTH 5
void test_clone_shallow__clone_depth(void)
{
git_buf path = GIT_BUF_INIT;
git_repository *repo;
git_revwalk *walk;
git_clone_options clone_opts = GIT_CLONE_OPTIONS_INIT;
git_oid oid;
git_oidarray roots;
size_t depth = 0;
int error = 0;
clone_opts.fetch_opts.depth = CLONE_DEPTH;
git_buf_joinpath(&path, clar_sandbox_path(), "shallowclone");
cl_git_pass(git_clone(&repo, "https://github.com/libgit2/TestGitRepository", git_buf_cstr(&path), &clone_opts));
cl_assert_equal_b(true, git_repository_is_shallow(repo));
cl_git_pass(git_repository_shallow_roots(&roots, repo));
cl_assert_equal_i(1, roots.count);
cl_assert_equal_s("83834a7afdaa1a1260568567f6ad90020389f664", git_oid_tostr_s(&roots.ids[0]));
git_revwalk_new(&walk, repo);
git_revwalk_push_head(walk);
while ((error = git_revwalk_next(&oid, walk)) == GIT_OK) {
if (depth + 1 > CLONE_DEPTH)
cl_fail("expected depth mismatch");
depth++;
}
cl_git_pass(error);
git_buf_dispose(&path);
git_revwalk_free(walk);
git_repository_free(repo);
}
#include "clar_libgit2.h"
#include "futils.h"
#include "grafts.h"
static git_repository *g_repo;
void test_repo_grafts__initialize(void)
{
g_repo = cl_git_sandbox_init("grafted.git");
}
void test_repo_grafts__cleanup(void)
{
cl_git_sandbox_cleanup();
}
void test_repo_grafts__graft_register(void)
{
git_oid oid_src;
git_commit_graft *graft;
git_graftmap *grafts = git_oidmap_alloc();
git_array_oid_t parents = GIT_ARRAY_INIT;
git_oid *oid1 = git_array_alloc(parents);
cl_git_pass(git_oid_fromstr(&oid_src, "2f3053cbff8a4ca2f0666de364ddb734a28a31a9"));
git_oid_cpy(oid1, &oid_src);
git_oid_fromstr(&oid_src, "f503807ffa920e407a600cfaee96b7152259acc7");
cl_git_pass(git__graft_register(grafts, &oid_src, parents));
git_array_clear(parents);
cl_assert_equal_i(1, git_oidmap_size(grafts));
cl_git_pass(git__graft_for_oid(&graft, grafts, &oid_src));
cl_assert_equal_s("f503807ffa920e407a600cfaee96b7152259acc7", git_oid_tostr_s(&graft->oid));
cl_assert_equal_i(1, git_array_size(graft->parents));
cl_assert_equal_s("2f3053cbff8a4ca2f0666de364ddb734a28a31a9", git_oid_tostr_s(git_array_get(graft->parents, 0)));
git__graft_clear(grafts);
git_oidmap_free(grafts);
}
void test_repo_grafts__grafted_revwalk(void)
{
git_revwalk *w;
git_oid oids[10];
size_t i = 0;
git_commit *commit;
cl_git_pass(git_revwalk_new(&w, g_repo));
cl_git_pass(git_revwalk_push_ref(w, "refs/heads/branch"));
cl_git_pass(git_revwalk_next(&oids[i++], w));
cl_assert_equal_s(git_oid_tostr_s(&oids[0]), "8a00e91619098618be97c0d2ceabb05a2c58edd9");
cl_git_pass(git_revwalk_next(&oids[i++], w));
cl_assert_equal_s(git_oid_tostr_s(&oids[1]), "f503807ffa920e407a600cfaee96b7152259acc7");
cl_git_pass(git_revwalk_next(&oids[i++], w));
cl_assert_equal_s(git_oid_tostr_s(&oids[2]), "2f3053cbff8a4ca2f0666de364ddb734a28a31a9");
cl_git_fail_with(GIT_ITEROVER, git_revwalk_next(&oids[i++], w));
cl_git_pass(git_commit_lookup(&commit, g_repo, &oids[0]));
cl_assert_equal_i(1, git_commit_parentcount(commit));
git_commit_free(commit);
git_revwalk_free(w);
}
void test_repo_grafts__grafted_objects(void)
{
git_oid oid;
git_commit *commit;
cl_git_pass(git_oid_fromstr(&oid, "f503807ffa920e407a600cfaee96b7152259acc7"));
cl_git_pass(git_commit_lookup(&commit, g_repo, &oid));
cl_assert_equal_i(1, git_commit_parentcount(commit));
git_commit_free(commit);
cl_git_pass(git_oid_fromstr(&oid, "0512adebd3782157f0d5c9b22b043f87b4aaff9e"));
cl_git_pass(git_commit_lookup(&commit, g_repo, &oid));
cl_assert_equal_i(1, git_commit_parentcount(commit));
git_commit_free(commit);
cl_git_pass(git_oid_fromstr(&oid, "66cc22a015f6ca75b34c82d28f78ba663876bade"));
cl_git_pass(git_commit_lookup(&commit, g_repo, &oid));
cl_assert_equal_i(4, git_commit_parentcount(commit));
git_commit_free(commit);
}
void test_repo_grafts__grafted_merge_revwalk(void)
{
git_revwalk *w;
git_oid oids[10];
size_t i = 0;
cl_git_pass(git_revwalk_new(&w, g_repo));
cl_git_pass(git_revwalk_push_ref(w, "refs/heads/bottom"));
cl_git_pass(git_revwalk_next(&oids[i++], w));
cl_assert_equal_s(git_oid_tostr_s(&oids[i - 1]), "66cc22a015f6ca75b34c82d28f78ba663876bade");
cl_git_pass(git_revwalk_next(&oids[i++], w));
cl_assert_equal_s(git_oid_tostr_s(&oids[i - 1]), "e414f42f4e6bc6934563a2349a8600f0ab68618e");
cl_git_pass(git_revwalk_next(&oids[i++], w));
cl_assert_equal_s(git_oid_tostr_s(&oids[i - 1]), "8a00e91619098618be97c0d2ceabb05a2c58edd9");
cl_git_pass(git_revwalk_next(&oids[i++], w));
cl_assert_equal_s(git_oid_tostr_s(&oids[i - 1]), "1c18e80a276611bb9b146590616bbc5aebdf2945");
cl_git_pass(git_revwalk_next(&oids[i++], w));
cl_assert_equal_s(git_oid_tostr_s(&oids[i - 1]), "d7224d49d6d5aff6ade596ed74f4bcd4f77b29e2");
cl_git_pass(git_revwalk_next(&oids[i++], w));
cl_assert_equal_s(git_oid_tostr_s(&oids[i - 1]), "0512adebd3782157f0d5c9b22b043f87b4aaff9e");
cl_git_pass(git_revwalk_next(&oids[i++], w));
cl_assert_equal_s(git_oid_tostr_s(&oids[i - 1]), "f503807ffa920e407a600cfaee96b7152259acc7");
cl_git_pass(git_revwalk_next(&oids[i++], w));
cl_assert_equal_s(git_oid_tostr_s(&oids[i - 1]), "2f3053cbff8a4ca2f0666de364ddb734a28a31a9");
cl_git_fail_with(GIT_ITEROVER, git_revwalk_next(&oids[i++], w));
git_revwalk_free(w);
}
#include "clar_libgit2.h"
#include "futils.h"
static git_repository *g_repo;
static git_oid g_shallow_oid;
void test_repo_shallow__initialize(void)
{
cl_git_pass(git_oid_fromstr(&g_shallow_oid, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"));
}
void test_repo_shallow__cleanup(void)
{
cl_git_sandbox_cleanup();
}
void test_repo_shallow__no_shallow_file(void)
{
g_repo = cl_git_sandbox_init("testrepo.git");
cl_assert_equal_i(0, git_repository_is_shallow(g_repo));
}
void test_repo_shallow__empty_shallow_file(void)
{
g_repo = cl_git_sandbox_init("testrepo.git");
cl_git_mkfile("testrepo.git/shallow", "");
cl_assert_equal_i(0, git_repository_is_shallow(g_repo));
}
void test_repo_shallow__shallow_repo(void)
{
g_repo = cl_git_sandbox_init("shallow.git");
cl_assert_equal_i(1, git_repository_is_shallow(g_repo));
}
void test_repo_shallow__clears_errors(void)
{
g_repo = cl_git_sandbox_init("testrepo.git");
cl_assert_equal_i(0, git_repository_is_shallow(g_repo));
cl_assert_equal_p(NULL, git_error_last());
}
void test_repo_shallow__shallow_oids(void)
{
git_oidarray oids, oids2;
g_repo = cl_git_sandbox_init("shallow.git");
cl_git_pass(git_repository_shallow_roots(&oids, g_repo));
cl_assert_equal_i(1, oids.count);
cl_assert_equal_oid(&g_shallow_oid, &oids.ids[0]);
cl_git_pass(git_repository_shallow_roots(&oids2, g_repo));
cl_assert_equal_p(oids.ids, oids2.ids);
}
void test_repo_shallow__cache_clearing(void)
{
git_oidarray oids, oids2;
git_oid tmp_oid;
git_oid_fromstr(&tmp_oid, "0000000000000000000000000000000000000000");
g_repo = cl_git_sandbox_init("shallow.git");
cl_git_pass(git_repository_shallow_roots(&oids, g_repo));
cl_assert_equal_i(1, oids.count);
cl_assert_equal_oid(&g_shallow_oid, &oids.ids[0]);
cl_git_mkfile("shallow.git/shallow",
"be3563ae3f795b2b4353bcce3a527ad0a4f7f644\n"
"0000000000000000000000000000000000000000\n"
);
cl_git_pass(git_repository_shallow_roots(&oids2, g_repo));
cl_assert_equal_i(2, oids2.count);
cl_assert_equal_oid(&g_shallow_oid, &oids2.ids[0]);
cl_assert_equal_oid(&tmp_oid, &oids2.ids[1]);
}
void test_repo_shallow__errors_on_borked(void)
{
git_oidarray oids;
g_repo = cl_git_sandbox_init("shallow.git");
cl_git_mkfile("shallow.git/shallow", "lolno");
cl_git_fail_with(-1, git_repository_shallow_roots(&oids, g_repo));
cl_git_mkfile("shallow.git/shallow", "lolno\n");
cl_git_fail_with(-1, git_repository_shallow_roots(&oids, g_repo));
}
void test_repo_shallow__revwalk_behavior(void)
{
git_revwalk *w;
git_oid oid_1, oid_2, oid_3;
g_repo = cl_git_sandbox_init("shallow.git");
cl_git_pass(git_revwalk_new(&w, g_repo));
cl_git_pass(git_revwalk_push_head(w));
cl_git_pass(git_revwalk_next(&oid_1, w)); // a65fedf39aefe402d3bb6e24df4d4f5fe4547750
cl_git_pass(git_revwalk_next(&oid_2, w)); // be3563ae3f795b2b4353bcce3a527ad0a4f7f644
cl_git_fail_with(GIT_ITEROVER, git_revwalk_next(&oid_3, w));
cl_assert_equal_s(git_oid_tostr_s(&oid_1), "a65fedf39aefe402d3bb6e24df4d4f5fe4547750");
cl_assert_equal_s(git_oid_tostr_s(&oid_2), "be3563ae3f795b2b4353bcce3a527ad0a4f7f644");
git_revwalk_free(w);
}
void test_repo_shallow__grafted_object(void)
{
git_commit *commit;
g_repo = cl_git_sandbox_init("shallow.git");
cl_git_pass(git_commit_lookup(&commit, g_repo, &g_shallow_oid));
cl_assert_equal_i(0, git_commit_parentcount(commit));
git_commit_free(commit);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment