mirror of
https://git.proxmox.com/git/libgit2
synced 2025-06-18 13:04:58 +00:00
parent
b8748c1217
commit
db9be9457d
@ -167,6 +167,23 @@ GIT_EXTERN(int) git_object_typeisloose(git_otype type);
|
|||||||
*/
|
*/
|
||||||
GIT_EXTERN(size_t) git_object__size(git_otype type);
|
GIT_EXTERN(size_t) git_object__size(git_otype type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursively peel an object until an object of the specified
|
||||||
|
* type is met
|
||||||
|
*
|
||||||
|
* The retrieved `peeled` object is owned by the repository
|
||||||
|
* and should be closed with the `git_object_free` method.
|
||||||
|
*
|
||||||
|
* @param peeled Pointer to the peeled git_object
|
||||||
|
* @param object The object to be processed
|
||||||
|
* @param target_type The type of the requested object
|
||||||
|
* @return 0 or an error code
|
||||||
|
*/
|
||||||
|
GIT_EXTERN(int) git_object_peel(
|
||||||
|
git_object **peeled,
|
||||||
|
git_object *object,
|
||||||
|
git_otype target_type);
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
GIT_END_DECL
|
GIT_END_DECL
|
||||||
|
|
||||||
|
69
src/object.c
69
src/object.c
@ -333,3 +333,72 @@ int git_object__resolve_to_type(git_object **obj, git_otype type)
|
|||||||
*obj = scan;
|
*obj = scan;
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int dereference_object(git_object **dereferenced, git_object *obj)
|
||||||
|
{
|
||||||
|
git_otype type = git_object_type(obj);
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case GIT_OBJ_COMMIT:
|
||||||
|
return git_commit_tree((git_tree **)dereferenced, (git_commit*)obj);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GIT_OBJ_TAG:
|
||||||
|
return git_tag_target(dereferenced, (git_tag*)obj);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return GIT_ENOTFOUND;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int peel_error(int error, const char* msg)
|
||||||
|
{
|
||||||
|
giterr_set(GITERR_INVALID, "The given object cannot be peeled - %s", msg);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
int git_object_peel(
|
||||||
|
git_object **peeled,
|
||||||
|
git_object *object,
|
||||||
|
git_otype target_type)
|
||||||
|
{
|
||||||
|
git_object *source, *deref = NULL;
|
||||||
|
|
||||||
|
assert(object);
|
||||||
|
|
||||||
|
if (git_object_type(object) == target_type)
|
||||||
|
return git_object__dup(peeled, object);
|
||||||
|
|
||||||
|
if (target_type == GIT_OBJ_BLOB
|
||||||
|
|| target_type == GIT_OBJ_ANY)
|
||||||
|
return peel_error(GIT_EAMBIGUOUS, "Ambiguous target type");
|
||||||
|
|
||||||
|
if (git_object_type(object) == GIT_OBJ_BLOB)
|
||||||
|
return peel_error(GIT_ERROR, "A blob cannot be dereferenced");
|
||||||
|
|
||||||
|
source = object;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
if (dereference_object(&deref, source) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
if (source != object)
|
||||||
|
git_object_free(source);
|
||||||
|
|
||||||
|
if (git_object_type(deref) == target_type) {
|
||||||
|
*peeled = deref;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
source = deref;
|
||||||
|
deref = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
if (source != object)
|
||||||
|
git_object_free(source);
|
||||||
|
git_object_free(deref);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
79
tests-clar/object/peel.c
Normal file
79
tests-clar/object/peel.c
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
#include "clar_libgit2.h"
|
||||||
|
|
||||||
|
static git_repository *g_repo;
|
||||||
|
|
||||||
|
void test_object_peel__initialize(void)
|
||||||
|
{
|
||||||
|
cl_git_pass(git_repository_open(&g_repo, cl_fixture("testrepo.git")));
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_object_peel__cleanup(void)
|
||||||
|
{
|
||||||
|
git_repository_free(g_repo);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void assert_peel(const char* expected_sha, const char *sha, git_otype requested_type)
|
||||||
|
{
|
||||||
|
git_oid oid, expected_oid;
|
||||||
|
git_object *obj;
|
||||||
|
git_object *peeled;
|
||||||
|
|
||||||
|
cl_git_pass(git_oid_fromstr(&oid, sha));
|
||||||
|
cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJ_ANY));
|
||||||
|
|
||||||
|
cl_git_pass(git_object_peel(&peeled, obj, requested_type));
|
||||||
|
|
||||||
|
cl_git_pass(git_oid_fromstr(&expected_oid, expected_sha));
|
||||||
|
cl_assert_equal_i(0, git_oid_cmp(&expected_oid, git_object_id(peeled)));
|
||||||
|
|
||||||
|
git_object_free(peeled);
|
||||||
|
git_object_free(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void assert_peel_error(int error, const char *sha, git_otype requested_type)
|
||||||
|
{
|
||||||
|
git_oid oid;
|
||||||
|
git_object *obj;
|
||||||
|
git_object *peeled;
|
||||||
|
|
||||||
|
cl_git_pass(git_oid_fromstr(&oid, sha));
|
||||||
|
cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJ_ANY));
|
||||||
|
|
||||||
|
cl_assert_equal_i(error, git_object_peel(&peeled, obj, requested_type));
|
||||||
|
|
||||||
|
git_object_free(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_object_peel__peeling_an_object_into_its_own_type_returns_another_instance_of_it(void)
|
||||||
|
{
|
||||||
|
assert_peel("e90810b8df3e80c413d903f631643c716887138d", "e90810b8df3e80c413d903f631643c716887138d", GIT_OBJ_COMMIT);
|
||||||
|
assert_peel("7b4384978d2493e851f9cca7858815fac9b10980", "7b4384978d2493e851f9cca7858815fac9b10980", GIT_OBJ_TAG);
|
||||||
|
assert_peel("53fc32d17276939fc79ed05badaef2db09990016", "53fc32d17276939fc79ed05badaef2db09990016", GIT_OBJ_TREE);
|
||||||
|
assert_peel("0266163a49e280c4f5ed1e08facd36a2bd716bcf", "0266163a49e280c4f5ed1e08facd36a2bd716bcf", GIT_OBJ_BLOB);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_object_peel__can_peel_a_tag(void)
|
||||||
|
{
|
||||||
|
assert_peel("e90810b8df3e80c413d903f631643c716887138d", "7b4384978d2493e851f9cca7858815fac9b10980", GIT_OBJ_COMMIT);
|
||||||
|
assert_peel("53fc32d17276939fc79ed05badaef2db09990016", "7b4384978d2493e851f9cca7858815fac9b10980", GIT_OBJ_TREE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_object_peel__can_peel_a_commit(void)
|
||||||
|
{
|
||||||
|
assert_peel("53fc32d17276939fc79ed05badaef2db09990016", "e90810b8df3e80c413d903f631643c716887138d", GIT_OBJ_TREE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_object_peel__cannot_peel_a_tree(void)
|
||||||
|
{
|
||||||
|
assert_peel_error(GIT_EAMBIGUOUS, "53fc32d17276939fc79ed05badaef2db09990016", GIT_OBJ_BLOB);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_object_peel__cannot_peel_a_blob(void)
|
||||||
|
{
|
||||||
|
assert_peel_error(GIT_ERROR, "0266163a49e280c4f5ed1e08facd36a2bd716bcf", GIT_OBJ_COMMIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_object_peel__cannot_target_any_object(void)
|
||||||
|
{
|
||||||
|
assert_peel_error(GIT_EAMBIGUOUS, "e90810b8df3e80c413d903f631643c716887138d", GIT_OBJ_ANY);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user