]> git.proxmox.com Git - libgit2.git/commitdiff
Implement unified git_revparse
authorBen Straub <bs@github.com>
Tue, 12 Mar 2013 03:27:16 +0000 (20:27 -0700)
committerBen Straub <bs@github.com>
Mon, 8 Apr 2013 12:36:11 +0000 (16:36 +0400)
include/git2/revparse.h
src/revparse.c
tests-clar/refs/revparse.c

index 71ff6d6966e3c55cd508a736d131595552ca19a0..9315b66eb563719619e4da9ab246849ebc35dbaf 100644 (file)
@@ -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);
 
 
 /** @} */
index 2ba29383e4dbf2007e62ed43e7549cfaaef603d8..2ba42d8e3ac15174f6b3cf199a5357eee2386c6b 100644 (file)
@@ -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(&regex, ".+-[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;
+}
+
index 66ee391a760d8067f486e6f7788ae085795354ea..ab8839fda4d0bd8b566a23ea30948c6eeb19e79a 100644 (file)
@@ -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);
+}
+