Commit afa79ca0 by yuangli

Merge branch 'pr/tiennou/4747' into transportPR

parent 70a332a5
......@@ -738,11 +738,16 @@ typedef struct {
* Extra headers for this fetch operation
*/
git_strarray custom_headers;
/**
* Depth of the fetch to perform
*/
int depth;
} git_fetch_options;
#define GIT_FETCH_OPTIONS_VERSION 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
......
......@@ -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);
/**
* 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
*
* The memory is owned by the repository and must not be freed by the
......
......@@ -33,6 +33,15 @@ typedef enum {
GIT_TRANSPORTFLAGS_NONE = 0,
} 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 {
unsigned int version; /**< The struct version */
......@@ -87,8 +96,7 @@ struct git_transport {
int GIT_CALLBACK(negotiate_fetch)(
git_transport *transport,
git_repository *repo,
const git_remote_head * const *refs,
size_t count);
const git_fetch_negotiation *fetch_data);
/**
* Start downloading the packfile from the remote repository.
......@@ -435,6 +443,11 @@ GIT_EXTERN(int) git_smart_subtransport_ssh(
git_transport *owner,
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
#endif
......@@ -85,12 +85,14 @@ on_oom:
#define git_array_foreach(a, i, element) \
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(
size_t *out,
void *array_ptr,
size_t item_size,
size_t array_len,
int (*compare)(const void *, const void *),
git_array_compare_cb compare,
const void *key)
{
size_t lim;
......
......@@ -18,6 +18,7 @@
#include "netops.h"
#include "repository.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)
{
......@@ -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
* 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,
remote->repo,
(const git_remote_head * const *)remote->refs.contents,
remote->refs.length);
&remote->nego);
}
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
git_transport *t = remote->transport;
git_indexer_progress_cb progress = NULL;
void *payload = NULL;
int error;
if (!remote->need_pack)
return 0;
......@@ -148,7 +158,13 @@ int git_fetch_download_pack(git_remote *remote, const git_remote_callbacks *call
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)
......
......@@ -104,15 +104,13 @@ int git_object__from_raw(
return 0;
}
int git_object__from_odb_object(
int git_object__init_from_odb_object(
git_object **object_out,
git_repository *repo,
git_odb_object *odb_obj,
git_object_t type)
{
int error;
size_t object_size;
git_object_def *def;
git_object *object = NULL;
GIT_ASSERT_ARG(object_out);
......@@ -139,6 +137,23 @@ int git_object__from_odb_object(
object->cached.size = odb_obj->cached.size;
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 */
def = &git_objects_table[odb_obj->cached.type];
GIT_ASSERT(def->free && def->parse);
......
......@@ -35,6 +35,12 @@ int git_object__from_raw(
size_t size,
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(
git_object **object_out,
git_repository *repo,
......
......@@ -35,6 +35,7 @@ struct git_remote {
git_remote_autotag_option_t download_tags;
int prune_refs;
int passed_refspecs;
git_fetch_negotiation nego;
};
typedef struct git_remote_connection_opts {
......
......@@ -3192,6 +3192,95 @@ int git_repository_state_cleanup(git_repository *repo)
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)
{
git_buf path = GIT_BUF_INIT;
......
......@@ -242,6 +242,9 @@ extern size_t git_repository__reserved_names_posix_len;
bool git_repository__reserved_names(
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`
* 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
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) {
......
......@@ -558,3 +558,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;
}
......@@ -14,6 +14,7 @@
#include "netops.h"
#include "buffer.h"
#include "push.h"
#include "oidarray.h"
#include "git2/sys/transport.h"
#define GIT_SIDE_BAND_DATA 1
......@@ -30,6 +31,7 @@
#define GIT_CAP_REPORT_STATUS "report-status"
#define GIT_CAP_THIN_PACK "thin-pack"
#define GIT_CAP_SYMREF "symref"
#define GIT_CAP_SHALLOW "shallow"
extern bool git_smart__ofs_delta_enabled;
......@@ -47,6 +49,8 @@ typedef enum {
GIT_PKT_OK,
GIT_PKT_NG,
GIT_PKT_UNPACK,
GIT_PKT_SHALLOW,
GIT_PKT_UNSHALLOW,
} git_pkt_type;
/* Used for multi_ack and multi_ack_detailed */
......@@ -118,6 +122,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 {
int common:1,
ofs_delta:1,
......@@ -128,7 +137,8 @@ typedef struct transport_smart_caps {
include_tag:1,
delete_refs:1,
report_status:1,
thin_pack:1;
thin_pack:1,
shallow:1;
} transport_smart_caps;
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
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,
......@@ -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_send_flush(GIT_SOCKET s);
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);
void git_pkt_free(git_pkt *pkt);
struct git_shallowarray {
git_array_oid_t array;
};
#endif
......@@ -363,6 +363,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];
......@@ -489,6 +533,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);
......@@ -554,6 +602,9 @@ static int buffer_want_with_caps(const git_remote_head *head, transport_smart_ca
if (caps->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))
return -1;
......@@ -583,8 +634,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_buf *buf)
{
......@@ -592,22 +642,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_HEXSZ];
head = refs[i];
head = wants->refs[i];
if (head->local)
continue;
......@@ -619,6 +669,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);
}
......
......@@ -205,6 +205,12 @@ int git_smart__detect_caps(git_pkt_ref *pkt, transport_smart_caps *caps, git_vec
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 */
ptr = strchr(ptr, ' ');
}
......@@ -305,7 +311,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;
......@@ -317,7 +342,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)
......@@ -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)
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
......@@ -389,7 +444,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) {
......@@ -409,7 +464,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) {
......
#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