mirror of
https://git.proxmox.com/git/libgit2
synced 2026-01-04 17:48:27 +00:00
Merge pull request #1075 from carlosmn/alternates-recurse
odb: recursively load alternates
This commit is contained in:
commit
e087973ec7
28
src/odb.c
28
src/odb.c
@ -23,6 +23,8 @@
|
||||
#define GIT_LOOSE_PRIORITY 2
|
||||
#define GIT_PACKED_PRIORITY 1
|
||||
|
||||
#define GIT_ALTERNATES_MAX_DEPTH 5
|
||||
|
||||
typedef struct
|
||||
{
|
||||
git_odb_backend *backend;
|
||||
@ -30,6 +32,8 @@ typedef struct
|
||||
int is_alternate;
|
||||
} backend_internal;
|
||||
|
||||
static int load_alternates(git_odb *odb, const char *objects_dir, int alternate_depth);
|
||||
|
||||
static int format_object_header(char *hdr, size_t n, size_t obj_len, git_otype obj_type)
|
||||
{
|
||||
const char *type_str = git_object_type2string(obj_type);
|
||||
@ -395,7 +399,7 @@ int git_odb_add_alternate(git_odb *odb, git_odb_backend *backend, int priority)
|
||||
return add_backend_internal(odb, backend, priority, 1);
|
||||
}
|
||||
|
||||
static int add_default_backends(git_odb *db, const char *objects_dir, int as_alternates)
|
||||
static int add_default_backends(git_odb *db, const char *objects_dir, int as_alternates, int alternate_depth)
|
||||
{
|
||||
git_odb_backend *loose, *packed;
|
||||
|
||||
@ -409,10 +413,10 @@ static int add_default_backends(git_odb *db, const char *objects_dir, int as_alt
|
||||
add_backend_internal(db, packed, GIT_PACKED_PRIORITY, as_alternates) < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
return load_alternates(db, objects_dir, alternate_depth);
|
||||
}
|
||||
|
||||
static int load_alternates(git_odb *odb, const char *objects_dir)
|
||||
static int load_alternates(git_odb *odb, const char *objects_dir, int alternate_depth)
|
||||
{
|
||||
git_buf alternates_path = GIT_BUF_INIT;
|
||||
git_buf alternates_buf = GIT_BUF_INIT;
|
||||
@ -420,6 +424,11 @@ static int load_alternates(git_odb *odb, const char *objects_dir)
|
||||
const char *alternate;
|
||||
int result = 0;
|
||||
|
||||
/* Git reports an error, we just ignore anything deeper */
|
||||
if (alternate_depth > GIT_ALTERNATES_MAX_DEPTH) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (git_buf_joinpath(&alternates_path, objects_dir, GIT_ALTERNATES_FILE) < 0)
|
||||
return -1;
|
||||
|
||||
@ -440,14 +449,18 @@ static int load_alternates(git_odb *odb, const char *objects_dir)
|
||||
if (*alternate == '\0' || *alternate == '#')
|
||||
continue;
|
||||
|
||||
/* relative path: build based on the current `objects` folder */
|
||||
if (*alternate == '.') {
|
||||
/*
|
||||
* Relative path: build based on the current `objects`
|
||||
* folder. However, relative paths are only allowed in
|
||||
* the current repository.
|
||||
*/
|
||||
if (*alternate == '.' && !alternate_depth) {
|
||||
if ((result = git_buf_joinpath(&alternates_path, objects_dir, alternate)) < 0)
|
||||
break;
|
||||
alternate = git_buf_cstr(&alternates_path);
|
||||
}
|
||||
|
||||
if ((result = add_default_backends(odb, alternate, 1)) < 0)
|
||||
if ((result = add_default_backends(odb, alternate, 1, alternate_depth + 1)) < 0)
|
||||
break;
|
||||
}
|
||||
|
||||
@ -468,8 +481,7 @@ int git_odb_open(git_odb **out, const char *objects_dir)
|
||||
if (git_odb_new(&db) < 0)
|
||||
return -1;
|
||||
|
||||
if (add_default_backends(db, objects_dir, 0) < 0 ||
|
||||
load_alternates(db, objects_dir) < 0)
|
||||
if (add_default_backends(db, objects_dir, 0, 0) < 0)
|
||||
{
|
||||
git_odb_free(db);
|
||||
return -1;
|
||||
|
||||
75
tests-clar/odb/alternates.c
Normal file
75
tests-clar/odb/alternates.c
Normal file
@ -0,0 +1,75 @@
|
||||
#include "clar_libgit2.h"
|
||||
#include "odb.h"
|
||||
#include "repository.h"
|
||||
|
||||
static git_buf destpath, filepath;
|
||||
static const char *paths[] = {
|
||||
"A.git", "B.git", "C.git", "D.git", "E.git", "F.git", "G.git"
|
||||
};
|
||||
static git_filebuf file;
|
||||
static git_repository *repo;
|
||||
|
||||
void test_odb_alternates__cleanup(void)
|
||||
{
|
||||
git_buf_free(&destpath);
|
||||
git_buf_free(&filepath);
|
||||
}
|
||||
|
||||
static void init_linked_repo(const char *path, const char *alternate)
|
||||
{
|
||||
git_buf_clear(&destpath);
|
||||
git_buf_clear(&filepath);
|
||||
|
||||
cl_git_pass(git_repository_init(&repo, path, 1));
|
||||
cl_git_pass(git_path_prettify(&destpath, alternate, NULL));
|
||||
cl_git_pass(git_buf_joinpath(&destpath, destpath.ptr, "objects"));
|
||||
cl_git_pass(git_buf_joinpath(&filepath, git_repository_path(repo), "objects/info"));
|
||||
cl_git_pass(git_futils_mkdir(filepath.ptr, NULL, 0755, GIT_MKDIR_PATH));
|
||||
cl_git_pass(git_buf_joinpath(&filepath, filepath.ptr , "alternates"));
|
||||
|
||||
cl_git_pass(git_filebuf_open(&file, git_buf_cstr(&filepath), 0));
|
||||
git_filebuf_printf(&file, "%s\n", git_buf_cstr(&destpath));
|
||||
cl_git_pass(git_filebuf_commit(&file, 0644));
|
||||
|
||||
git_repository_free(repo);
|
||||
}
|
||||
|
||||
void test_odb_alternates__chained(void)
|
||||
{
|
||||
git_commit *commit;
|
||||
git_oid oid;
|
||||
|
||||
/* Set the alternate A -> testrepo.git */
|
||||
init_linked_repo(paths[0], cl_fixture("testrepo.git"));
|
||||
|
||||
/* Set the alternate B -> A */
|
||||
init_linked_repo(paths[1], paths[0]);
|
||||
|
||||
/* Now load B and see if we can find an object from testrepo.git */
|
||||
cl_git_pass(git_repository_open(&repo, paths[1]));
|
||||
git_oid_fromstr(&oid, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750");
|
||||
cl_git_pass(git_commit_lookup(&commit, repo, &oid));
|
||||
git_commit_free(commit);
|
||||
git_repository_free(repo);
|
||||
}
|
||||
|
||||
void test_odb_alternates__long_chain(void)
|
||||
{
|
||||
git_commit *commit;
|
||||
git_oid oid;
|
||||
size_t i;
|
||||
|
||||
/* Set the alternate A -> testrepo.git */
|
||||
init_linked_repo(paths[0], cl_fixture("testrepo.git"));
|
||||
|
||||
/* Set up the five-element chain */
|
||||
for (i = 1; i < ARRAY_SIZE(paths); i++) {
|
||||
init_linked_repo(paths[i], paths[i-1]);
|
||||
}
|
||||
|
||||
/* Now load the last one and see if we can find an object from testrepo.git */
|
||||
cl_git_pass(git_repository_open(&repo, paths[ARRAY_SIZE(paths)-1]));
|
||||
git_oid_fromstr(&oid, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750");
|
||||
cl_git_fail(git_commit_lookup(&commit, repo, &oid));
|
||||
git_repository_free(repo);
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user