diff options
| -rw-r--r-- | include/git2/revparse.h | 34 | ||||
| -rw-r--r-- | src/revparse.c | 64 | ||||
| -rw-r--r-- | tests-clar/refs/revparse.c | 59 |
3 files changed, 135 insertions, 22 deletions
diff --git a/include/git2/revparse.h b/include/git2/revparse.h index 71ff6d696..9315b66eb 100644 --- a/include/git2/revparse.h +++ b/include/git2/revparse.h @@ -51,35 +51,37 @@ GIT_EXTERN(int) git_revparse_rangelike(git_object **left, git_object **right, in * git_revparse. */ typedef enum { - /** The spec targeted a single object. */ - GIT_REVPARSE_SINGLE = 1 << 0, - /** The spec targeted a range of commits. */ - GIT_REVPARSE_RANGE = 1 << 1, - /** The spec used the '...' operator, which invokes special semantics. */ - GIT_REVPARSE_MERGE_BASE = 1 << 2, + /** The spec targeted a single object. */ + GIT_REVPARSE_SINGLE = 1 << 0, + /** The spec targeted a range of commits. */ + GIT_REVPARSE_RANGE = 1 << 1, + /** The spec used the '...' operator, which invokes special semantics. */ + GIT_REVPARSE_MERGE_BASE = 1 << 2, } git_revparse_flag_t; /** - * Find an object or range of commits as specified by a revision string. - * See `man gitrevisions` or http://git-scm.com/docs/git-rev-parse.html#_specifying_revisions - * for information on the syntax accepted. + * Parse a revision string for left, right, and intent. See `man gitrevisions` or + * http://git-scm.com/docs/git-rev-parse.html#_specifying_revisions for information + * on the syntax accepted. * * @param left buffer that receives the target of the left side of a range operator. If * there is no range operator, this buffer receives the single target. * @param right buffer that receives the target of the right side of a range operator. - * This is only filled in if `spec` specifies a range of commits - * @param flags buffer that receives a bitwise combination of `git_revparse_flag_t` values + * This is only filled in if `spec` specifies a range of commits. May + * be NULL. + * @param flags buffer that receives a bitwise combination of `git_revparse_flag_t` values. + * May be NULL. * @param repo the repository to search in * @param spec the rev-parse spec to parse * @return 0 on success, GIT_INVALIDSPEC, GIT_ENOTFOUND, GIT_EAMBIGUOUS or an error code */ GIT_EXTERN(int) git_revparse( - git_oid *left, - git_oid *right, - unsigned int *flags, - git_repository *repo, - const char *spec); + git_oid *left, + git_oid *right, + unsigned int *flags, + git_repository *repo, + const char *spec); /** @} */ diff --git a/src/revparse.c b/src/revparse.c index 2ba29383e..2ba42d8e3 100644 --- a/src/revparse.c +++ b/src/revparse.c @@ -107,7 +107,7 @@ static int build_regex(regex_t *regex, const char *pattern) error = regcomp(regex, pattern, REG_EXTENDED); if (!error) return 0; - + error = giterr_set_regex(regex, error); regfree(regex); @@ -125,7 +125,7 @@ static int maybe_describe(git_object**out, git_repository *repo, const char *spe if (substr == NULL) return GIT_ENOTFOUND; - + if (build_regex(®ex, ".+-[0-9]+-g[0-9a-fA-F]+") < 0) return -1; @@ -358,7 +358,7 @@ static int retrieve_remote_tracking_reference(git_reference **base_ref, const ch if ((error = git_branch_tracking(&tracking, ref)) < 0) goto cleanup; - + *base_ref = tracking; cleanup: @@ -508,7 +508,7 @@ static int walk_and_search(git_object **out, git_revwalk *walk, regex_t *regex) int error; git_oid oid; git_object *obj; - + while (!(error = git_revwalk_next(&oid, walk))) { error = git_object_lookup(&obj, git_revwalk_repository(walk), &oid, GIT_OBJ_COMMIT); @@ -537,7 +537,7 @@ static int handle_grep_syntax(git_object **out, git_repository *repo, const git_ if ((error = build_regex(&preg, pattern)) < 0) return error; - + if ((error = git_revwalk_new(&walk, repo)) < 0) goto cleanup; @@ -551,7 +551,7 @@ static int handle_grep_syntax(git_object **out, git_repository *repo, const git_ goto cleanup; error = walk_and_search(out, walk, &preg); - + cleanup: regfree(&preg); git_revwalk_free(walk); @@ -892,3 +892,55 @@ int git_revparse_rangelike(git_object **left, git_object **right, int *threedots git__free(revspec); return error; } + + +int git_revparse( + git_oid *left, + git_oid *right, + unsigned int *flags, + git_repository *repo, + const char *spec) +{ + unsigned int lflags = 0; + const char *dotdot; + int error = 0; + git_object *obj = NULL; + + assert(left && repo && spec); + + if ((dotdot = strstr(spec, "..")) != NULL) { + char *lstr; + const char *rstr; + lflags = GIT_REVPARSE_RANGE; + + lstr = git__substrdup(spec, dotdot-spec); + rstr = dotdot + 2; + if (dotdot[2] == '.') { + lflags |= GIT_REVPARSE_MERGE_BASE; + rstr++; + } + + if (!(error = git_revparse_single(&obj, repo, lstr))) { + git_oid_cpy(left, git_object_id(obj)); + git_object_free(obj); + } + if (right && !(error = git_revparse_single(&obj, repo, rstr))) { + git_oid_cpy(right, git_object_id(obj)); + git_object_free(obj); + } + + git__free((void*)lstr); + } else { + lflags = GIT_REVPARSE_SINGLE; + if (!(error = git_revparse_single(&obj, repo, spec))) { + git_oid_cpy(left, git_object_id(obj)); + git_object_free(obj); + } + } + + if (flags) + *flags = lflags; + + return error; +} + diff --git a/tests-clar/refs/revparse.c b/tests-clar/refs/revparse.c index 66ee391a7..ab8839fda 100644 --- a/tests-clar/refs/revparse.c +++ b/tests-clar/refs/revparse.c @@ -27,6 +27,37 @@ static void test_object_inrepo(const char *spec, const char *expected_oid, git_r git_object_free(obj); } +static void test_id_inrepo( + const char *spec, + const char *expected_left, + const char *expected_right, + git_revparse_flag_t expected_flags, + git_repository *repo) +{ + git_oid l = {{0}}, r = {{0}}; + git_revparse_flag_t flags = 0; + + int error = git_revparse(&l, &r, &flags, repo, spec); + + if (expected_left) { + char str[64] = {0}; + cl_assert_equal_i(0, error); + git_oid_fmt(str, &l); + cl_assert_equal_s(str, expected_left); + } else { + cl_assert_equal_i(GIT_ENOTFOUND, error); + } + + if (expected_right) { + char str[64] = {0}; + git_oid_fmt(str, &r); + cl_assert_equal_s(str, expected_right); + } + + if (expected_flags) + cl_assert_equal_i(expected_flags, flags); +} + static void test_object(const char *spec, const char *expected_oid) { test_object_inrepo(spec, expected_oid, g_repo); @@ -59,6 +90,15 @@ static void test_rangelike(const char *rangelike, } +static void test_id( + const char *spec, + const char *expected_left, + const char *expected_right, + git_revparse_flag_t expected_flags) +{ + test_id_inrepo(spec, expected_left, expected_right, expected_flags, g_repo); +} + void test_refs_revparse__initialize(void) { cl_git_pass(git_repository_open(&g_repo, cl_fixture("testrepo.git"))); @@ -639,3 +679,22 @@ void test_refs_revparse__range(void) test_rangelike("be3563a^1.be3563a", NULL, NULL, 0); } + +void test_refs_revparse__validates_args(void) +{ + git_oid l={{0}}, r={{0}}; + git_revparse_flag_t flags = 0; + + cl_git_pass(git_revparse(&l,&r,NULL, g_repo, "HEAD")); + cl_git_pass(git_revparse(&l,NULL,&flags, g_repo, "HEAD")); + cl_assert_equal_i(GIT_EINVALIDSPEC, git_revparse(&l,&r,&flags, g_repo, "^&*(")); +} + +void test_refs_revparse__parses_range_operator(void) +{ + test_id("HEAD", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", NULL, GIT_REVPARSE_SINGLE); + test_id("HEAD~3..HEAD", "4a202b346bb0fb0db7eff3cffeb3c70babbd2045", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", GIT_REVPARSE_RANGE); + test_id("HEAD~3...HEAD", "4a202b346bb0fb0db7eff3cffeb3c70babbd2045", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", + GIT_REVPARSE_RANGE | GIT_REVPARSE_MERGE_BASE); +} + |
