diff --git a/include/git2/sys/transport.h b/include/git2/sys/transport.h index 6a190242cdb..b372eeb4431 100644 --- a/include/git2/sys/transport.h +++ b/include/git2/sys/transport.h @@ -259,6 +259,19 @@ GIT_EXTERN(int) git_transport_local( git_remote *owner, /* NULL */ void *payload); +/** + * Create an instance of the bundle transport. + * + * @param out The newly created transport (out) + * @param owner The git_remote which will own this transport + * @param payload You must pass NULL for this parameter. + * @return 0 or an error code + */ +GIT_EXTERN(int) git_transport_bundle( + git_transport **out, + git_remote *owner, + /* NULL */ void *payload); + /** * Create an instance of the smart transport. * diff --git a/src/libgit2/bundle.c b/src/libgit2/bundle.c new file mode 100644 index 00000000000..c17bf8a2c42 --- /dev/null +++ b/src/libgit2/bundle.c @@ -0,0 +1,302 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "bundle.h" +#include "futils.h" +#include "parse.h" +#include "repository.h" +#include "git2/odb_backend.h" + +#define GIT_BUNDLE_V2_SIGNATURE "# v2 git bundle\n" +#define GIT_BUNDLE_V3_SIGNATURE "# v3 git bundle\n" + +/** + * A bundle file is made up of a header plus a packfile, separated by two + * newlines. + */ +static int read_until_packfile(git_str *str, git_file fd) +{ + ssize_t bytes_read = 0; + char buf[1]; + + while ((bytes_read = p_read(fd, buf, 1)) == 1) { + if (buf[0] == '\n' && git_str_len(str) > 0 && + git_str_cstr(str)[git_str_len(str) - 1] == '\n') { + return 0; + } + + if (git_str_putc(str, buf[0]) < 0) { + return -1; + } + } + + return 0; +} + +static int read_bundle_version(git_bundle_header *header, git_file fd) +{ + int error = 0; + git_str version = GIT_STR_INIT; + + if ((error = git_futils_readbuffer_fd(&version, fd, 16)) < 0) { + goto cleanup; + } + + if (git__strncmp(git_str_cstr(&version), GIT_BUNDLE_V2_SIGNATURE, 16) == + 0) { + header->version = 2; + } else { + if (git__strncmp( + git_str_cstr(&version), GIT_BUNDLE_V3_SIGNATURE, + 16) == 0) { + header->version = 3; + } else { + error = GIT_EINVALID; + } + } + +cleanup: + git_str_dispose(&version); + return error; +} + +static int +parse_bundle_capabilities(git_bundle_header *header, git_parse_ctx *parser) +{ + int error = 0; + + git_parse_advance_chars(parser, 1); + + if (git_parse_ctx_contains(parser, "object-format=", 14)) { + git_parse_advance_chars(parser, 14); + if (git_parse_ctx_contains(parser, "sha1", 4)) { + header->oid_type = GIT_OID_SHA1; + } + if (git_parse_ctx_contains(parser, "sha256", 6)) { +#ifdef GIT_EXPERIMENTAL_SHA256 + header->oid_type = GIT_OID_SHA256; +#else + error = GIT_ENOTSUPPORTED; +#endif + } + goto cleanup; + } + + if (git_parse_ctx_contains(parser, "filter=", 7)) { + error = GIT_ENOTSUPPORTED; + goto cleanup; + } + + error = GIT_EINVALID; + +cleanup: + return error; +} + +static int +parse_bundle_prerequisites(git_bundle_header *header, git_parse_ctx *parser) +{ + int error = 0; + git_str name = GIT_STR_INIT; + git_oid *oid; + + oid = git__calloc(1, sizeof(git_oid)); + GIT_ERROR_CHECK_ALLOC(oid); + + git_parse_advance_chars(parser, 1); + if ((error = git_parse_advance_oid(oid, parser, header->oid_type)) < + 0 || + (error = git_vector_insert(&header->prerequisites, oid)) < 0) { + git__free(oid); + goto cleanup; + }; + +cleanup: + git_str_dispose(&name); + return error; +} + +static int +parse_bundle_references(git_bundle_header *header, git_parse_ctx *parser) +{ + int error = 0; + git_str name = GIT_STR_INIT; + git_remote_head *head; + + head = git__calloc(1, sizeof(git_remote_head)); + GIT_ERROR_CHECK_ALLOC(head); + + if ((error = git_parse_advance_oid( + &head->oid, parser, header->oid_type)) < 0 || + (error = git_parse_advance_ws(parser)) < 0 || + (error = git_str_set(&name, parser->line, parser->line_len)) < 0) { + goto cleanup; + }; + + git_str_rtrim(&name); + head->name = git_str_detach(&name); + git_vector_insert(&header->refs, head); + +cleanup: + git_str_dispose(&name); + return error; +} + +static int parse_bundle_header(git_bundle_header *header, git_str *buf) +{ + int error = 0; + git_parse_ctx parser; + char c; + + if ((error = git_parse_ctx_init( + &parser, git_str_cstr(buf), git_str_len(buf))) < 0) + goto cleanup; + + for (; parser.remain_len; git_parse_advance_line(&parser)) { + if ((error = git_parse_peek( + &c, &parser, GIT_PARSE_PEEK_SKIP_WHITESPACE)) < + 0) { + goto cleanup; + } + + if (header->version == 3 && c == '@') { + if ((error = parse_bundle_capabilities( + header, &parser)) < 0) { + goto cleanup; + } + continue; + } + + if (c == '-') { + if ((error = parse_bundle_prerequisites( + header, &parser)) < 0) { + goto cleanup; + } + continue; + } + + if ((error = parse_bundle_references(header, &parser)) < 0) { + goto cleanup; + } + } + +cleanup: + return error; +} + +int git_bundle_header_open(git_bundle_header **out, const char *url) +{ + int error = 0; + int fd = 0; + git_bundle_header *header = NULL; + git_str buf = GIT_STR_INIT; + + if ((fd = git_futils_open_ro(url)) < 0) { + git_str_dispose(&buf); + return fd; + } + + header = git__calloc(1, sizeof(git_bundle_header)); + GIT_ERROR_CHECK_ALLOC(header); + header->version = 0; + header->oid_type = GIT_OID_SHA1; + if ((error = git_vector_init(&header->refs, 0, NULL)) < 0 || + (error = git_vector_init(&header->prerequisites, 0, NULL)) < 0 || + (error = read_bundle_version(header, fd)) < 0 || + (error = read_until_packfile(&buf, fd)) < 0 || + (error = parse_bundle_header(header, &buf)) < 0) { + git_bundle_header_free(header); + goto cleanup; + } + + *out = header; + +cleanup: + git_str_dispose(&buf); + p_close(fd); + return error; +} + +void git_bundle_header_free(git_bundle_header *bundle) +{ + size_t i; + git_remote_head *ref; + git_oid *prerequisites; + + if (!bundle) { + return; + } + + git_vector_foreach (&bundle->refs, i, ref) { + git__free(ref->name); + git__free(ref->symref_target); + git__free(ref); + } + git_vector_dispose(&bundle->refs); + + i = 0; + git_vector_foreach (&bundle->prerequisites, i, prerequisites) { + git__free(prerequisites); + } + git_vector_dispose(&bundle->prerequisites); + + git__free(bundle); +} + +int git_bundle__is_bundle(const char *url) +{ + int error = 0; + git_bundle_header *header = NULL; + + if ((error = git_bundle_header_open(&header, url)) < 0) { + return 0; + } + + git_bundle_header_free(header); + return 1; +} + +int git_bundle__read_pack( + git_repository *repo, + const char *url, + git_indexer_progress *stats) +{ + int error = 0; + int fd = 0; + git_str buf = GIT_STR_INIT; + git_odb *odb; + ssize_t bytes_read = 0; + char buffer[1024]; + struct git_odb_writepack *writepack = NULL; + + if ((fd = git_futils_open_ro(url)) < 0) { + git_str_dispose(&buf); + return fd; + } + + if ((error = read_until_packfile(&buf, fd)) < 0 || + (error = git_repository_odb__weakptr(&odb, repo)) < 0 || + (error = git_odb_write_pack(&writepack, odb, NULL, NULL)) != 0) { + goto cleanup; + } + + while ((bytes_read = p_read(fd, buffer, 1024)) > 0) { + if ((error = writepack->append( + writepack, buffer, bytes_read, stats)) < 0) + goto cleanup; + } + + if ((error = writepack->commit(writepack, stats)) < 0) + goto cleanup; + +cleanup: + if (writepack) + writepack->free(writepack); + git_str_dispose(&buf); + p_close(fd); + return error; +} diff --git a/src/libgit2/bundle.h b/src/libgit2/bundle.h new file mode 100644 index 00000000000..407451ef6ad --- /dev/null +++ b/src/libgit2/bundle.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_bundle_h__ +#define INCLUDE_bundle_h__ + +#include "common.h" +#include "vector.h" + +#include "git2/indexer.h" +#include "git2/oid.h" +#include "git2/types.h" + +typedef struct { + int version; + git_oid_t oid_type; + git_vector prerequisites; + git_vector refs; +} git_bundle_header; + +int git_bundle_header_open(git_bundle_header **out, const char *url); +void git_bundle_header_free(git_bundle_header *bundle); + +int git_bundle__is_bundle(const char *url); + +int git_bundle__read_pack( + git_repository *repo, + const char *url, + git_indexer_progress *stats); + +#endif diff --git a/src/libgit2/transport.c b/src/libgit2/transport.c index c31fca3a490..93672043174 100644 --- a/src/libgit2/transport.c +++ b/src/libgit2/transport.c @@ -12,6 +12,7 @@ #include "git2/net.h" #include "git2/transport.h" #include "git2/sys/transport.h" +#include "bundle.h" #include "fs_path.h" typedef struct transport_definition { @@ -28,6 +29,9 @@ static git_smart_subtransport_definition ssh_subtransport_definition = { git_sma #endif static transport_definition local_transport_definition = { "file://", git_transport_local, NULL }; +static transport_definition bundle_transport_definition = { + "", git_transport_bundle, NULL +}; static transport_definition transports[] = { { "git://", git_transport_smart, &git_subtransport_definition }, @@ -105,6 +109,11 @@ static int transport_find_fn( definition = &local_transport_definition; #endif + if (!definition && git_fs_path_isfile(url) && + git_bundle__is_bundle(url)) { + definition = &bundle_transport_definition; + } + if (!definition) return GIT_ENOTFOUND; diff --git a/src/libgit2/transports/bundle.c b/src/libgit2/transports/bundle.c new file mode 100644 index 00000000000..62fb3ad3838 --- /dev/null +++ b/src/libgit2/transports/bundle.c @@ -0,0 +1,286 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "common.h" + +#include "bundle.h" +#include "remote.h" + +#include "git2/types.h" +#include "git2/transport.h" + +typedef struct { + git_transport parent; + git_remote *owner; + char *url; + int direction; + git_atomic32 cancelled; + git_bundle_header *header; + git_remote_connect_options connect_opts; + unsigned connected : 1; +} transport_bundle; + +/* + * HEAD needs to be a the front of the ls_remote call. At least clone + * assumes it its. + */ +static int sort_head_to_front(git_vector *refs) +{ + size_t idx = 0; + git_remote_head *ref; + git_vector sortedRefs = GIT_VECTOR_INIT; + + git_vector_foreach (refs, idx, ref) { + if (git__strcmp(ref->name, "HEAD") == 0) { + if (git_vector_insert(&sortedRefs, ref) < 0) { + return -1; + } + break; + } + } + + idx = 0; + git_vector_foreach (refs, idx, ref) { + if (git__strcmp(ref->name, "HEAD") != 0) { + if (git_vector_insert(&sortedRefs, ref) < 0) { + return -1; + } + } + } + + git_vector_swap(&sortedRefs, refs); + git_vector_dispose(&sortedRefs); + + return 0; +} + +static int bundle_set_connect_opts( + git_transport *transport, + const git_remote_connect_options *connect_opts) +{ + transport_bundle *t = (transport_bundle *)transport; + + if (!t->connected) { + git_error_set( + GIT_ERROR_NET, + "cannot reconfigure a transport that is not connected"); + return -1; + } + + return git_remote_connect_options_normalize( + &t->connect_opts, t->owner->repo, connect_opts); +} + +static int bundle_connect( + git_transport *transport, + const char *url, + int direction, + const git_remote_connect_options *connect_opts) +{ + int error; + transport_bundle *t = (transport_bundle *)transport; + + if (t->connected) + return 0; + + if (direction == GIT_DIRECTION_PUSH) { + git_error_set( + GIT_ERROR_NET, + "push is not supported by bundle transport"); + return GIT_ENOTSUPPORTED; + } + + if (git_remote_connect_options_normalize( + &t->connect_opts, t->owner->repo, connect_opts) < 0) + return -1; + + /* + * Need to free here. We cannot free in "bundle_close" because + * "bundle_ls" gets called after disconnection. + */ + git_bundle_header_free(t->header); + + t->url = git__strdup(url); + GIT_ERROR_CHECK_ALLOC(t->url); + t->direction = direction; + + if ((error = git_bundle_header_open(&t->header, url)) < 0 || + (error = sort_head_to_front(&t->header->refs)) < 0) { + return error; + } + + t->connected = 1; + + return 0; +} + +static int bundle_negotiate_fetch( + git_transport *transport, + git_repository *repo, + const git_fetch_negotiation *wants) +{ + transport_bundle *t = (transport_bundle *)transport; + git_remote_head *rhead; + unsigned int i; + + if (wants->depth) { + git_error_set( + GIT_ERROR_NET, + "shallow fetch is not supported by bundle transport"); + return GIT_ENOTSUPPORTED; + } + + /* Fill in the loids */ + git_vector_foreach (&t->header->refs, i, rhead) { + git_object *obj; + + int error = git_revparse_single(&obj, repo, rhead->name); + if (!error) + git_oid_cpy(&rhead->loid, git_object_id(obj)); + else if (error != GIT_ENOTFOUND) + return error; + else + git_error_clear(); + git_object_free(obj); + } + + return 0; +} + +static int +bundle_capabilities(unsigned int *capabilities, git_transport *transport) +{ + GIT_UNUSED(transport); + + *capabilities = GIT_REMOTE_CAPABILITY_TIP_OID | + GIT_REMOTE_CAPABILITY_REACHABLE_OID; + return 0; +} + +static int bundle_download_pack( + git_transport *transport, + git_repository *repo, + git_indexer_progress *stats) +{ + transport_bundle *t = (transport_bundle *)transport; + + return git_bundle__read_pack(repo, t->url, stats); +} + +static int bundle_shallow_roots(git_oidarray *out, git_transport *transport) +{ + GIT_UNUSED(out); + GIT_UNUSED(transport); + + return 0; +} + +static int bundle_push(git_transport *transport, git_push *push) +{ + GIT_UNUSED(transport); + GIT_UNUSED(push); + + git_error_set( + GIT_ERROR_NET, "push is not supported by bundle transport"); + return GIT_ENOTSUPPORTED; +} + +static int +bundle_ls(const git_remote_head ***out, size_t *size, git_transport *transport) +{ + transport_bundle *t = (transport_bundle *)transport; + + *out = (const git_remote_head **)t->header->refs.contents; + *size = t->header->refs.length; + return 0; +} + +static int bundle_is_connected(git_transport *transport) +{ + transport_bundle *t = (transport_bundle *)transport; + + return t->connected; +} + +static void bundle_cancel(git_transport *transport) +{ + transport_bundle *t = (transport_bundle *)transport; + + git_atomic32_set(&t->cancelled, 1); +} + +static int bundle_close(git_transport *transport) +{ + transport_bundle *t = (transport_bundle *)transport; + + t->connected = 0; + + if (t->url) { + git__free(t->url); + t->url = NULL; + } + + return 0; +} + +static void bundle_free(git_transport *transport) +{ + transport_bundle *t = (transport_bundle *)transport; + + /* Close the transport, if it's still open. */ + bundle_close(transport); + + git_bundle_header_free(t->header); + + /* Free the transport */ + git__free(t); +} + +#ifdef GIT_EXPERIMENTAL_SHA256 +static int bundle_oid_type(git_oid_t *out, git_transport *transport) +{ + transport_bundle *t = (transport_bundle *)transport; + + *out = t->header->oid_type; + + return 0; +} +#endif + +int git_transport_bundle(git_transport **out, git_remote *owner, void *param) +{ + int error = 0; + transport_bundle *t; + + GIT_UNUSED(param); + + t = git__calloc(1, sizeof(transport_bundle)); + GIT_ERROR_CHECK_ALLOC(t); + + t->parent.version = GIT_TRANSPORT_VERSION; + t->parent.connect = bundle_connect; + t->parent.set_connect_opts = bundle_set_connect_opts; + t->parent.capabilities = bundle_capabilities; +#ifdef GIT_EXPERIMENTAL_SHA256 + t->parent.oid_type = bundle_oid_type; +#endif + t->parent.negotiate_fetch = bundle_negotiate_fetch; + t->parent.shallow_roots = bundle_shallow_roots; + t->parent.download_pack = bundle_download_pack; + t->parent.push = bundle_push; + t->parent.close = bundle_close; + t->parent.free = bundle_free; + t->parent.ls = bundle_ls; + t->parent.is_connected = bundle_is_connected; + t->parent.cancel = bundle_cancel; + + t->owner = owner; + + *out = (git_transport *)t; + + return error; +} diff --git a/tests/libgit2/bundle/parse.c b/tests/libgit2/bundle/parse.c new file mode 100644 index 00000000000..82d01ecbb98 --- /dev/null +++ b/tests/libgit2/bundle/parse.c @@ -0,0 +1,124 @@ +#include "clar_libgit2.h" +#include "posix.h" +#include "bundle.h" +#include "futils.h" + +void test_bundle_parse__initialize(void) +{ + cl_fixture_sandbox("bundle"); +} + +void test_bundle_parse__cleanup(void) +{ + cl_fixture_cleanup("bundle"); +} + +void test_bundle_parse__v2(void) +{ + git_bundle_header *header = NULL; + + cl_assert(git_bundle__is_bundle("bundle/v2.header") == 1); + cl_git_pass(git_bundle_header_open(&header, "bundle/v2.header")); + cl_assert(header->version == 2); + cl_assert(header->oid_type == GIT_OID_SHA1); + cl_assert(git_vector_length(&header->prerequisites) == 2); + cl_assert(git_vector_length(&header->refs) == 4); + + git_bundle_header_free(header); +} + +void test_bundle_parse__v3(void) +{ + git_bundle_header *header = NULL; + + cl_assert(git_bundle__is_bundle("bundle/v3.header") == 1); + cl_git_pass(git_bundle_header_open(&header, "bundle/v3.header")); + cl_assert(header->version == 3); + cl_assert(header->oid_type == GIT_OID_SHA1); + cl_assert(git_vector_length(&header->prerequisites) == 3); + cl_assert(git_vector_length(&header->refs) == 3); + + git_bundle_header_free(header); +} + +void test_bundle_parse__v3_sha256(void) +{ + git_bundle_header *header = NULL; + +#ifdef GIT_EXPERIMENTAL_SHA256 + cl_assert(git_bundle__is_bundle("bundle/v3_sha256.header") == 1); + cl_git_pass(git_bundle_header_open(&header, "bundle/v3_sha256.header")); + cl_assert(header->version == 3); + cl_assert(header->oid_type == GIT_OID_SHA256); + cl_assert(git_vector_length(&header->prerequisites) == 3); + cl_assert(git_vector_length(&header->refs) == 3); + git_bundle_header_free(header); +#else + cl_assert(git_bundle__is_bundle("bundle/v3_sha256.header") == 0); + cl_git_fail_with( + GIT_ENOTSUPPORTED, + git_bundle_header_open(&header, "bundle/v3_sha256.header")); +#endif +} + +void test_bundle_parse__invalid(void) +{ + git_bundle_header *header = NULL; + + cl_assert(git_bundle__is_bundle("bundle/invalid.header") == 0); + cl_git_fail_with( + GIT_EINVALID, + git_bundle_header_open(&header, "bundle/invalid.header")); +} + +void test_bundle_parse__bundle_does_not_exist(void) +{ + git_bundle_header *header = NULL; + + cl_assert(git_bundle__is_bundle("bundle/does_not_exist.header") == 0); + cl_git_fail_with( + GIT_ENOTFOUND, + git_bundle_header_open(&header, "bundle/does_not_exist.header")); + + git_bundle_header_free(header); +} + +void test_bundle_parse__filter_capability_unsupported(void) +{ + git_bundle_header *header = NULL; + + cl_assert( + git_bundle__is_bundle("bundle/filter_capability.header") == 0); + cl_git_fail_with( + GIT_ENOTSUPPORTED, + git_bundle_header_open( + &header, "bundle/filter_capability.header")); + + git_bundle_header_free(header); +} + +void test_bundle_parse__unknown_capability(void) +{ + git_bundle_header *header = NULL; + + cl_assert( + git_bundle__is_bundle("bundle/unknown_capability.header") == 0); + cl_git_fail_with( + GIT_EINVALID, + git_bundle_header_open( + &header, "bundle/unknown_capability.header")); + + git_bundle_header_free(header); +} + +void test_bundle_parse__bad_oid(void) +{ + git_bundle_header *header = NULL; + + cl_assert(git_bundle__is_bundle("bundle/bad_oid.header") == 0); + cl_git_fail_with( + GIT_ERROR, + git_bundle_header_open(&header, "bundle/bad_oid.header")); + + git_bundle_header_free(header); +} diff --git a/tests/libgit2/clone/bundle.c b/tests/libgit2/clone/bundle.c new file mode 100644 index 00000000000..0b9e1306ea0 --- /dev/null +++ b/tests/libgit2/clone/bundle.c @@ -0,0 +1,14 @@ +#include "clar_libgit2.h" + +#include "git2/clone.h" + +void test_clone_bundle__v2(void) +{ + git_repository *repo; + + cl_git_pass(git_clone( + &repo, cl_fixture("bundle/testrepo.bundle"), "./clone.git", + NULL)); + + git_repository_free(repo); +} diff --git a/tests/libgit2/fetch/bundle.c b/tests/libgit2/fetch/bundle.c new file mode 100644 index 00000000000..65104cb2c46 --- /dev/null +++ b/tests/libgit2/fetch/bundle.c @@ -0,0 +1,36 @@ +#include "clar_libgit2.h" + +#include "git2/remote.h" + +static git_repository *g_repo; + +void test_fetch_bundle__initialize(void) +{ + g_repo = cl_git_sandbox_init("testrepo"); +} + +void test_fetch_bundle__cleanup(void) +{ + cl_git_sandbox_cleanup(); +} + +void test_fetch_bundle__v2(void) +{ + git_remote *remote; + git_oid expected_id; + git_object *obj; + + cl_git_pass(git_remote_create( + &remote, g_repo, "bundle", + cl_fixture("bundle/testrepo_fetch.bundle"))); + cl_git_pass(git_remote_fetch(remote, NULL, NULL, NULL)); + git_oid_from_string( + &expected_id, "d70553b411e163b98a1b704d5bf33c5438decd9c", + GIT_OID_SHA1); + cl_git_pass( + git_revparse_single(&obj, g_repo, "refs/remotes/bundle/master")); + cl_assert_equal_oid(&expected_id, git_object_id(obj)); + + git_object_free(obj); + git_remote_free(remote); +} diff --git a/tests/resources/bundle/bad_oid.header b/tests/resources/bundle/bad_oid.header new file mode 100644 index 00000000000..c54f3624b7d --- /dev/null +++ b/tests/resources/bundle/bad_oid.header @@ -0,0 +1,9 @@ +# v2 git bundle +-d4a7dce85cf63874e989f4fdd239f5145052f +-c4a7dce85cf63874e989f4fdd239f5145052f user comment +a4a7dce85cf63874e984f4fdd239f5145052f refs/heads/br2 +144344043ba4d4a405dae3844aa829ae8be0e refs/heads/dir +f9ed4af42472941da45a44458455ed227a6be refs/heads/executable +6fd5c7dd2ab27b48c493f794be09861e9045f refs/heads/ident + +PACK diff --git a/tests/resources/bundle/filter_capability.header b/tests/resources/bundle/filter_capability.header new file mode 100644 index 00000000000..82370284b0b --- /dev/null +++ b/tests/resources/bundle/filter_capability.header @@ -0,0 +1,10 @@ +# v3 git bundle +@filter=blah +-d4a7dce85cf63874e984719f4fdd239f5145052f +-c4a7dce85cf63874e984719f4fdd239f5145052f user comment +-e4a7dce85cf63874e984719f4fdd239f5145052f user comment2 +a4a7dce85cf63874e984719f4fdd239f5145052f refs/heads/br2 +144344043ba4d4a405da03de3844aa829ae8be0e refs/heads/dir +f9ed4af42472941da45a3ce44458455ed227a6be refs/heads/executable + +PACK diff --git a/tests/resources/bundle/invalid.header b/tests/resources/bundle/invalid.header new file mode 100644 index 00000000000..aa748d000b9 --- /dev/null +++ b/tests/resources/bundle/invalid.header @@ -0,0 +1,8 @@ +# v2 git bundle +a4a7dce85cf63874e984719f4fdd239f5145052f refs/heads/br2 +144344043ba4d4a405da03de3844aa829ae8be0e refs/heads/dir +f9ed4af42472941da45a3ce44458455ed227a6be refs/heads/executable + +This bundle is invalid + +PACK diff --git a/tests/resources/bundle/not_a_bundle.header b/tests/resources/bundle/not_a_bundle.header new file mode 100644 index 00000000000..391518dae56 --- /dev/null +++ b/tests/resources/bundle/not_a_bundle.header @@ -0,0 +1 @@ +This is not a bundle diff --git a/tests/resources/bundle/testrepo.bundle b/tests/resources/bundle/testrepo.bundle new file mode 100644 index 00000000000..98210216187 Binary files /dev/null and b/tests/resources/bundle/testrepo.bundle differ diff --git a/tests/resources/bundle/testrepo_fetch.bundle b/tests/resources/bundle/testrepo_fetch.bundle new file mode 100644 index 00000000000..f0b5f2d8fe9 Binary files /dev/null and b/tests/resources/bundle/testrepo_fetch.bundle differ diff --git a/tests/resources/bundle/unknown_capability.header b/tests/resources/bundle/unknown_capability.header new file mode 100644 index 00000000000..04fa356c05d --- /dev/null +++ b/tests/resources/bundle/unknown_capability.header @@ -0,0 +1,10 @@ +# v3 git bundle +@unknown-capability=unknown +-d4a7dce85cf63874e984719f4fdd239f5145052f +-c4a7dce85cf63874e984719f4fdd239f5145052f user comment +-e4a7dce85cf63874e984719f4fdd239f5145052f user comment2 +a4a7dce85cf63874e984719f4fdd239f5145052f refs/heads/br2 +144344043ba4d4a405da03de3844aa829ae8be0e refs/heads/dir +f9ed4af42472941da45a3ce44458455ed227a6be refs/heads/executable + +PACK diff --git a/tests/resources/bundle/v2.header b/tests/resources/bundle/v2.header new file mode 100644 index 00000000000..cd12993f18b --- /dev/null +++ b/tests/resources/bundle/v2.header @@ -0,0 +1,9 @@ +# v2 git bundle +-d4a7dce85cf63874e984719f4fdd239f5145052f +-c4a7dce85cf63874e984719f4fdd239f5145052f user comment +a4a7dce85cf63874e984719f4fdd239f5145052f refs/heads/br2 +144344043ba4d4a405da03de3844aa829ae8be0e refs/heads/dir +f9ed4af42472941da45a3ce44458455ed227a6be refs/heads/executable +6fd5c7dd2ab27b48c493023f794be09861e9045f refs/heads/ident + +PACK diff --git a/tests/resources/bundle/v3.header b/tests/resources/bundle/v3.header new file mode 100644 index 00000000000..2651c2ffc64 --- /dev/null +++ b/tests/resources/bundle/v3.header @@ -0,0 +1,9 @@ +# v3 git bundle +-d4a7dce85cf63874e984719f4fdd239f5145052f +-c4a7dce85cf63874e984719f4fdd239f5145052f user comment +-e4a7dce85cf63874e984719f4fdd239f5145052f user comment2 +a4a7dce85cf63874e984719f4fdd239f5145052f refs/heads/br2 +144344043ba4d4a405da03de3844aa829ae8be0e refs/heads/dir +f9ed4af42472941da45a3ce44458455ed227a6be refs/heads/executable + +PACK diff --git a/tests/resources/bundle/v3_sha256.header b/tests/resources/bundle/v3_sha256.header new file mode 100644 index 00000000000..6e0c27a3ca1 --- /dev/null +++ b/tests/resources/bundle/v3_sha256.header @@ -0,0 +1,10 @@ +# v3 git bundle +@object-format=sha256 +-d4a7dce85cf63874e984719f4fdd239f5145052f000000000000000000000000 +-c4a7dce85cf63874e984719f4fdd239f5145052f000000000000000000000000 user comment +-e4a7dce85cf63874e984719f4fdd239f5145052f000000000000000000000000 user comment2 +a4a7dce85cf63874e984719f4fdd239f5145052f000000000000000000000000 refs/heads/br2 +144344043ba4d4a405da03de3844aa829ae8be0e000000000000000000000000 refs/heads/dir +f9ed4af42472941da45a3ce44458455ed227a6be000000000000000000000000 refs/heads/executable + +PACK