summaryrefslogtreecommitdiff
path: root/src/object.c
diff options
context:
space:
mode:
authornulltoken <emeric.fermas@gmail.com>2012-07-15 11:06:15 +0200
committernulltoken <emeric.fermas@gmail.com>2012-07-17 20:32:40 +0200
commitdb9be9457d74a683916f107b39cad05a347b4c2c (patch)
treee315b7dd7b7c629c8a651a588ea8aec9543ed3bb /src/object.c
parentb8748c1217445a95d3b29b361b467eb66992f8a7 (diff)
downloadlibgit2-db9be9457d74a683916f107b39cad05a347b4c2c.tar.gz
object: introduce git_object_peel()
Partially fix #530
Diffstat (limited to 'src/object.c')
-rw-r--r--src/object.c69
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;
+}