diff options
author | nulltoken <emeric.fermas@gmail.com> | 2012-07-15 11:06:15 +0200 |
---|---|---|
committer | nulltoken <emeric.fermas@gmail.com> | 2012-07-17 20:32:40 +0200 |
commit | db9be9457d74a683916f107b39cad05a347b4c2c (patch) | |
tree | e315b7dd7b7c629c8a651a588ea8aec9543ed3bb /src/object.c | |
parent | b8748c1217445a95d3b29b361b467eb66992f8a7 (diff) | |
download | libgit2-db9be9457d74a683916f107b39cad05a347b4c2c.tar.gz |
object: introduce git_object_peel()
Partially fix #530
Diffstat (limited to 'src/object.c')
-rw-r--r-- | src/object.c | 69 |
1 files changed, 69 insertions, 0 deletions
diff --git a/src/object.c b/src/object.c index 14d64befe..3ff894212 100644 --- a/src/object.c +++ b/src/object.c @@ -333,3 +333,72 @@ int git_object__resolve_to_type(git_object **obj, git_otype type) *obj = scan; 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; +} |