diff --git a/src/revparse.c b/src/revparse.c index 3a1cd0598..da274f860 100644 --- a/src/revparse.c +++ b/src/revparse.c @@ -143,6 +143,9 @@ static git_object* dereference_object(git_object *obj) case GIT_OBJ_BLOB: break; case GIT_OBJ_TAG: + if (0 == git_tag_target(&newobj, (git_tag*)obj)) { + return newobj; + } break; case GIT_OBJ_OFS_DELTA: break; @@ -159,28 +162,36 @@ static git_object* dereference_object(git_object *obj) static int dereference_to_type(git_object **out, git_object *obj, git_otype target_type) { - git_otype this_type = git_object_type(obj); + git_object *obj1 = obj, *obj2 = obj; while (1) { + git_otype this_type = git_object_type(obj1); + if (this_type == target_type) { *out = obj; return 0; } - if (this_type == GIT_OBJ_TAG) { - git_tag_peel(&obj, (git_tag*)obj); - continue; - } - /* Dereference once, if possible. */ - obj = dereference_object(obj); - + obj2 = dereference_object(obj1); + if (obj2 != obj) { + git_object_free(obj2); + } + obj1 = obj2; } } -static int handle_caret_syntax(git_object **out, git_object *start, const char *movement) +static git_otype parse_obj_type(const char *str) +{ + if (!strcmp(str, "{commit}")) return GIT_OBJ_COMMIT; + if (!strcmp(str, "{tree}")) return GIT_OBJ_TREE; + if (!strcmp(str, "{blob}")) return GIT_OBJ_BLOB; + if (!strcmp(str, "{tag}")) return GIT_OBJ_TAG; + return GIT_OBJ_BAD; +} + +static int handle_caret_syntax(git_object **out, git_object *obj, const char *movement) { - git_object *obj; git_commit *commit; int n; @@ -189,15 +200,40 @@ static int handle_caret_syntax(git_object **out, git_object *start, const char * set_invalid_syntax_err(movement); return GIT_ERROR; } - - // TODO - /* {/...} -> Walk all commits until we see a commit msg that matches the phrase. */ + /* {} -> Dereference until we reach an object that isn't a tag. */ + if (strlen(movement) == 2) { + git_object *newobj = obj; + git_object *newobj2 = newobj; + while (git_object_type(newobj2) == GIT_OBJ_TAG) { + newobj2 = dereference_object(newobj); + if (newobj != obj) git_object_free(newobj); + if (!newobj2) { + giterr_set(GITERR_REFERENCE, "Couldn't find object of target type."); + return GIT_ERROR; + } + newobj = newobj; + } + *out = newobj2; + return 0; + } + + /* {/...} -> Walk all commits until we see a commit msg that matches the phrase. */ + if (movement[1] == '/') { + // TODO + return GIT_ERROR; + } + /* {...} -> Dereference until we reach an object of a certain type. */ + if (dereference_to_type(out, obj, parse_obj_type(movement)) < 0) { + giterr_set(GITERR_REFERENCE, "Can't dereference to type"); + return GIT_ERROR; + } + return 0; } /* Dereference until we reach a commit. */ - if (dereference_to_type(&obj, start, GIT_OBJ_COMMIT) < 0) { + if (dereference_to_type(&obj, obj, GIT_OBJ_COMMIT) < 0) { /* Can't dereference to a commit; fail */ return GIT_ERROR; } @@ -212,7 +248,7 @@ static int handle_caret_syntax(git_object **out, git_object *start, const char * /* "^0" just returns the input */ if (n == 0) { - *out = (git_object*)commit; + *out = obj; return 0; } @@ -259,7 +295,10 @@ int git_revparse_single(git_object **out, git_repository *repo, const char *spec if (current_state != next_state) { /* Leaving INIT state, find the object specified, in case that state needs it */ - assert(!revparse_lookup_object(&next_obj, repo, git_buf_cstr(&specbuffer))); + retcode = revparse_lookup_object(&next_obj, repo, git_buf_cstr(&specbuffer)); + if (retcode < 0) { + goto cleanup; + } } break; @@ -292,6 +331,13 @@ int git_revparse_single(git_object **out, git_repository *repo, const char *spec break; case REVPARSE_STATE_LINEAR: + if (!*spec_cur) { + } else if (*spec_cur == '~') { + } else if (*spec_cur == '^') { + } else { + git_buf_putc(&stepbuffer, *spec_cur); + } + spec_cur++; break; } diff --git a/tests-clar/refs/revparse.c b/tests-clar/refs/revparse.c index 9ff3bd1da..64aca4a70 100644 --- a/tests-clar/refs/revparse.c +++ b/tests-clar/refs/revparse.c @@ -8,11 +8,11 @@ static git_object *g_obj; // Hepers -static void oid_str_cmp(const git_oid *oid, const char *str) +static void oid_str_cmp(const git_object *obj, const char *expected) { - git_oid oid2; - cl_git_pass(git_oid_fromstr(&oid2, str)); - cl_assert(0 == git_oid_cmp(oid, &oid2)); + char objstr[64] = {0}; + git_oid_to_string(objstr, 64, git_object_id(obj)); + cl_assert_equal_s(objstr, expected); } @@ -28,64 +28,81 @@ void test_refs_revparse__cleanup(void) } +void test_refs_revparse__nonexistant_object(void) +{ + cl_git_fail(git_revparse_single(&g_obj, g_repo, "this doesn't exist")); +} + void test_refs_revparse__shas(void) { // Full SHA should return a valid object cl_git_pass(git_revparse_single(&g_obj, g_repo, "c47800c7266a2be04c571c04d5a6614691ea99bd")); - oid_str_cmp(git_object_id(g_obj), "c47800c7266a2be04c571c04d5a6614691ea99bd"); + oid_str_cmp(g_obj, "c47800c7266a2be04c571c04d5a6614691ea99bd"); cl_git_pass(git_revparse_single(&g_obj, g_repo, "c47800c")); - oid_str_cmp(git_object_id(g_obj), "c47800c7266a2be04c571c04d5a6614691ea99bd"); + oid_str_cmp(g_obj, "c47800c7266a2be04c571c04d5a6614691ea99bd"); } void test_refs_revparse__head(void) { // Named head should return a valid object cl_git_pass(git_revparse_single(&g_obj, g_repo, "HEAD")); - oid_str_cmp(git_object_id(g_obj), "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); + oid_str_cmp(g_obj, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); } void test_refs_revparse__full_refs(void) { // Fully-qualified refs should return valid objects cl_git_pass(git_revparse_single(&g_obj, g_repo, "refs/heads/master")); - oid_str_cmp(git_object_id(g_obj), "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); + oid_str_cmp(g_obj, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); cl_git_pass(git_revparse_single(&g_obj, g_repo, "refs/heads/test")); - oid_str_cmp(git_object_id(g_obj), "e90810b8df3e80c413d903f631643c716887138d"); + oid_str_cmp(g_obj, "e90810b8df3e80c413d903f631643c716887138d"); cl_git_pass(git_revparse_single(&g_obj, g_repo, "refs/tags/test")); - oid_str_cmp(git_object_id(g_obj), "b25fa35b38051e4ae45d4222e795f9df2e43f1d1"); + oid_str_cmp(g_obj, "b25fa35b38051e4ae45d4222e795f9df2e43f1d1"); } void test_refs_revparse__partial_refs(void) { // Partially-qualified refs should return valid objects cl_git_pass(git_revparse_single(&g_obj, g_repo, "point_to_blob")); - oid_str_cmp(git_object_id(g_obj), "1385f264afb75a56a5bec74243be9b367ba4ca08"); + oid_str_cmp(g_obj, "1385f264afb75a56a5bec74243be9b367ba4ca08"); cl_git_pass(git_revparse_single(&g_obj, g_repo, "packed-test")); - oid_str_cmp(git_object_id(g_obj), "4a202b346bb0fb0db7eff3cffeb3c70babbd2045"); + oid_str_cmp(g_obj, "4a202b346bb0fb0db7eff3cffeb3c70babbd2045"); cl_git_pass(git_revparse_single(&g_obj, g_repo, "br2")); - oid_str_cmp(git_object_id(g_obj), "a4a7dce85cf63874e984719f4fdd239f5145052f"); + oid_str_cmp(g_obj, "a4a7dce85cf63874e984719f4fdd239f5145052f"); } void test_refs_revparse__describe_output(void) { cl_git_pass(git_revparse_single(&g_obj, g_repo, "blah-7-gc47800c")); - oid_str_cmp(git_object_id(g_obj), "c47800c7266a2be04c571c04d5a6614691ea99bd"); + oid_str_cmp(g_obj, "c47800c7266a2be04c571c04d5a6614691ea99bd"); } void test_refs_revparse__nth_parent(void) { cl_git_pass(git_revparse_single(&g_obj, g_repo, "be3563a^1")); - oid_str_cmp(git_object_id(g_obj), "9fd738e8f7967c078dceed8190330fc8648ee56a"); + oid_str_cmp(g_obj, "9fd738e8f7967c078dceed8190330fc8648ee56a"); cl_git_pass(git_revparse_single(&g_obj, g_repo, "be3563a^")); - oid_str_cmp(git_object_id(g_obj), "9fd738e8f7967c078dceed8190330fc8648ee56a"); + oid_str_cmp(g_obj, "9fd738e8f7967c078dceed8190330fc8648ee56a"); cl_git_pass(git_revparse_single(&g_obj, g_repo, "be3563a^2")); - oid_str_cmp(git_object_id(g_obj), "c47800c7266a2be04c571c04d5a6614691ea99bd"); + oid_str_cmp(g_obj, "c47800c7266a2be04c571c04d5a6614691ea99bd"); cl_git_pass(git_revparse_single(&g_obj, g_repo, "be3563a^1^1")); - oid_str_cmp(git_object_id(g_obj), "4a202b346bb0fb0db7eff3cffeb3c70babbd2045"); + oid_str_cmp(g_obj, "4a202b346bb0fb0db7eff3cffeb3c70babbd2045"); cl_git_pass(git_revparse_single(&g_obj, g_repo, "be3563a^2^1")); - oid_str_cmp(git_object_id(g_obj), "5b5b025afb0b4c913b4c338a42934a3863bf3644"); + oid_str_cmp(g_obj, "5b5b025afb0b4c913b4c338a42934a3863bf3644"); cl_git_pass(git_revparse_single(&g_obj, g_repo, "be3563a^0")); - oid_str_cmp(git_object_id(g_obj), "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); + oid_str_cmp(g_obj, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); +} + +void test_refs_revparse__not_tag(void) +{ + cl_git_pass(git_revparse_single(&g_obj, g_repo, "point_to_blob^{}")); + oid_str_cmp(g_obj, "1385f264afb75a56a5bec74243be9b367ba4ca08"); + cl_git_pass(git_revparse_single(&g_obj, g_repo, "wrapped_tag^{}")); + oid_str_cmp(g_obj, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); +} + +void test_refs_revparse__to_type(void) +{ } void test_refs_revparse__reflog(void) diff --git a/tests/resources/testrepo.git/objects/d7/eddec7b3610726791785bf839065953f10341b b/tests/resources/testrepo.git/objects/d7/eddec7b3610726791785bf839065953f10341b new file mode 100644 index 000000000..32fc53202 Binary files /dev/null and b/tests/resources/testrepo.git/objects/d7/eddec7b3610726791785bf839065953f10341b differ diff --git a/tests/resources/testrepo.git/refs/tags/hard_tag b/tests/resources/testrepo.git/refs/tags/hard_tag new file mode 100644 index 000000000..1621c20d6 Binary files /dev/null and b/tests/resources/testrepo.git/refs/tags/hard_tag differ diff --git a/tests/resources/testrepo.git/refs/tags/wrapped_tag b/tests/resources/testrepo.git/refs/tags/wrapped_tag new file mode 100644 index 000000000..1621c20d6 Binary files /dev/null and b/tests/resources/testrepo.git/refs/tags/wrapped_tag differ