From 3f46f313cbfcf57e5cbf3d7dc55b747568a21bef Mon Sep 17 00:00:00 2001 From: nulltoken Date: Fri, 6 Apr 2012 14:34:26 +0200 Subject: [PATCH] tag: Add git_tag_peel() which recursively peel a tag until a non tag git_object is met --- include/git2/tag.h | 15 +++++ src/tag.c | 20 +++++++ tests-clar/network/remotelocal.c | 4 +- tests-clar/object/tag/peel.c | 56 ++++++++++++++++++ .../52/1d87c1ec3aef9824daf6d96cc0ae3710766d91 | Bin 0 -> 152 bytes .../refs/tags/annotated_tag_to_blob | Bin 0 -> 41 bytes tests/t08-tag.c | 8 +-- tests/t10-refs.c | 4 +- 8 files changed, 99 insertions(+), 8 deletions(-) create mode 100644 tests-clar/object/tag/peel.c create mode 100644 tests/resources/testrepo.git/objects/52/1d87c1ec3aef9824daf6d96cc0ae3710766d91 create mode 100644 tests/resources/testrepo.git/refs/tags/annotated_tag_to_blob diff --git a/include/git2/tag.h b/include/git2/tag.h index f7fce3a70..9ab4b7b9e 100644 --- a/include/git2/tag.h +++ b/include/git2/tag.h @@ -274,6 +274,21 @@ GIT_EXTERN(int) git_tag_list_match( const char *pattern, git_repository *repo); +/** + * Recursively peel a tag until a non tag git_object + * is met + * + * The retrieved `tag_target` object is owned by the repository + * and should be closed with the `git_object_free` method. + * + * @param tag_target Pointer to the peeled git_object + * @param tag The tag to be processed + * @return GIT_SUCCESS or an error code + */ +GIT_EXTERN(int) git_tag_peel( + git_object **tag_target, + git_tag *tag); + /** @} */ GIT_END_DECL #endif diff --git a/src/tag.c b/src/tag.c index a5089e71c..cfd2c7081 100644 --- a/src/tag.c +++ b/src/tag.c @@ -451,3 +451,23 @@ int git_tag_list(git_strarray *tag_names, git_repository *repo) { return git_tag_list_match(tag_names, "", repo); } + +int git_tag_peel(git_object **tag_target, git_tag *tag) +{ + int error; + git_object *target; + + assert(tag_target && tag); + + if (git_tag_target(&target, tag) < 0) + return -1; + + if (git_object_type(target) == GIT_OBJ_TAG) { + error = git_tag_peel(tag_target, (git_tag *)target); + git_object_free(target); + return error; + } + + *tag_target = target; + return 0; +} diff --git a/tests-clar/network/remotelocal.c b/tests-clar/network/remotelocal.c index 81af77756..74a0b57aa 100644 --- a/tests-clar/network/remotelocal.c +++ b/tests-clar/network/remotelocal.c @@ -88,7 +88,7 @@ void test_network_remotelocal__retrieve_advertised_references(void) cl_git_pass(git_remote_ls(remote, &count_ref__cb, &how_many_refs)); - cl_assert(how_many_refs == 12); /* 1 HEAD + 9 refs + 2 peeled tags */ + cl_assert(how_many_refs == 14); /* 1 HEAD + 6 heads + 1 lightweight tag + 3 annotated tags + 3 peeled target */ } void test_network_remotelocal__retrieve_advertised_references_from_spaced_repository(void) @@ -102,7 +102,7 @@ void test_network_remotelocal__retrieve_advertised_references_from_spaced_reposi cl_git_pass(git_remote_ls(remote, &count_ref__cb, &how_many_refs)); - cl_assert(how_many_refs == 12); /* 1 HEAD */ + cl_assert(how_many_refs == 14); /* 1 HEAD + 6 heads + 1 lightweight tag + 3 annotated tags + 3 peeled target */ cl_fixture_cleanup("spaced testrepo.git"); } diff --git a/tests-clar/object/tag/peel.c b/tests-clar/object/tag/peel.c new file mode 100644 index 000000000..97c5a7dd3 --- /dev/null +++ b/tests-clar/object/tag/peel.c @@ -0,0 +1,56 @@ +#include "clar_libgit2.h" +#include "tag.h" + +static git_repository *repo; +static git_tag *tag; +static git_object *target; + +void test_object_tag_peel__initialize(void) +{ + cl_fixture_sandbox("testrepo.git"); + cl_git_pass(git_repository_open(&repo, "testrepo.git")); +} + +void test_object_tag_peel__cleanup(void) +{ + git_tag_free(tag); + git_object_free(target); + git_repository_free(repo); + + cl_fixture_cleanup("testrepo.git"); +} + +static void retrieve_tag_from_oid(git_tag **tag_out, git_repository *repo, const char *sha) +{ + git_oid oid; + + cl_git_pass(git_oid_fromstr(&oid, sha)); + cl_git_pass(git_tag_lookup(tag_out, repo, &oid)); +} + +void test_object_tag_peel__can_peel_to_a_commit(void) +{ + retrieve_tag_from_oid(&tag, repo, "7b4384978d2493e851f9cca7858815fac9b10980"); + + cl_git_pass(git_tag_peel(&target, tag)); + cl_assert(git_object_type(target) == GIT_OBJ_COMMIT); + cl_git_pass(git_oid_streq(git_object_id(target), "e90810b8df3e80c413d903f631643c716887138d")); +} + +void test_object_tag_peel__can_peel_several_nested_tags_to_a_commit(void) +{ + retrieve_tag_from_oid(&tag, repo, "b25fa35b38051e4ae45d4222e795f9df2e43f1d1"); + + cl_git_pass(git_tag_peel(&target, tag)); + cl_assert(git_object_type(target) == GIT_OBJ_COMMIT); + cl_git_pass(git_oid_streq(git_object_id(target), "e90810b8df3e80c413d903f631643c716887138d")); +} + +void test_object_tag_peel__can_peel_to_a_non_commit(void) +{ + retrieve_tag_from_oid(&tag, repo, "521d87c1ec3aef9824daf6d96cc0ae3710766d91"); + + cl_git_pass(git_tag_peel(&target, tag)); + cl_assert(git_object_type(target) == GIT_OBJ_BLOB); + cl_git_pass(git_oid_streq(git_object_id(target), "1385f264afb75a56a5bec74243be9b367ba4ca08")); +} diff --git a/tests/resources/testrepo.git/objects/52/1d87c1ec3aef9824daf6d96cc0ae3710766d91 b/tests/resources/testrepo.git/objects/52/1d87c1ec3aef9824daf6d96cc0ae3710766d91 new file mode 100644 index 0000000000000000000000000000000000000000..351cff823065f92f8b4ef218194c1dfb06e86fd0 GIT binary patch literal 152 zcmV;J0B8Sr0X2<53c@fD06pgw+p|#8CTS{&2wv4Mlug{0+9WG=J@|Wj@i+|32u{#+ zZpYzCQJ^us8{5v}7`#K*p$infZLJA(2&VG^ZA9HG`MwB3;-F+JU@0sp^cXf8gonSG zXod1gNqC_GN6NI$u^ws7_&!e==Tt||r|oNu*WNk@d);cS)RlRG8&+^gH-U~DU literal 0 HcmV?d00001 diff --git a/tests/t08-tag.c b/tests/t08-tag.c index 4cbd48379..1586be1fa 100644 --- a/tests/t08-tag.c +++ b/tests/t08-tag.c @@ -73,7 +73,7 @@ BEGIN_TEST(read1, "list all tag names from the repository") must_pass(git_repository_open(&repo, REPOSITORY_FOLDER)); must_pass(git_tag_list(&tag_list, repo)); - must_be_true(tag_list.count == 3); + must_be_true(tag_list.count == 4); git_strarray_free(&tag_list); git_repository_free(repo); @@ -98,10 +98,10 @@ exit: BEGIN_TEST(read2, "list all tag names from the repository matching a specified pattern") git_repository *repo; must_pass(git_repository_open(&repo, REPOSITORY_FOLDER)); - must_pass(ensure_tag_pattern_match(repo, "", 3)); - must_pass(ensure_tag_pattern_match(repo, "*", 3)); + must_pass(ensure_tag_pattern_match(repo, "", 4)); + must_pass(ensure_tag_pattern_match(repo, "*", 4)); must_pass(ensure_tag_pattern_match(repo, "t*", 1)); - must_pass(ensure_tag_pattern_match(repo, "*b", 2)); + must_pass(ensure_tag_pattern_match(repo, "*b", 3)); must_pass(ensure_tag_pattern_match(repo, "e", 0)); must_pass(ensure_tag_pattern_match(repo, "e90810b", 1)); must_pass(ensure_tag_pattern_match(repo, "e90810[ab]", 1)); diff --git a/tests/t10-refs.c b/tests/t10-refs.c index ad881726e..7229ded9c 100644 --- a/tests/t10-refs.c +++ b/tests/t10-refs.c @@ -1164,10 +1164,10 @@ BEGIN_TEST(list0, "try to list all the references in our test repo") printf("# %s\n", ref_list.strings[i]); }*/ - /* We have exactly 9 refs in total if we include the packed ones: + /* We have exactly 10 refs in total if we include the packed ones: * there is a reference that exists both in the packfile and as * loose, but we only list it once */ - must_be_true(ref_list.count == 9); + must_be_true(ref_list.count == 10); git_strarray_free(&ref_list); git_repository_free(repo);