Commit e841c533 by nulltoken

revparse: Introduce git_revparse_ext()

Expose a way to retrieve, along with the target git_object, the reference
pointed at by some revparse expression (`@{<-n>}` or
`<branchname>@{upstream}` syntax).
parent dcaa898d
......@@ -32,6 +32,28 @@ GIT_BEGIN_DECL
*/
GIT_EXTERN(int) git_revparse_single(git_object **out, git_repository *repo, const char *spec);
/**
* Find a single object, 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.
*
* In some cases (`@{<-n>}` or `<branchname>@{upstream}`), the expression may
* point to an intermediate reference. When such expressions are being passed
* in, `reference_out` will be valued as well.
*
* @param object_out pointer to output object
* @param reference_out pointer to output reference or NULL
* @param repo the repository to search in
* @param spec the textual specification for an object
* @return 0 on success, GIT_ENOTFOUND, GIT_EAMBIGUOUS, GIT_EINVALIDSPEC
* or an error code
*/
GIT_EXTERN(int) git_revparse_ext(
git_object **object_out,
git_reference **reference_out,
git_repository *repo,
const char *spec);
/**
* Revparse flags. These indicate the intended behavior of the spec passed to
......
......@@ -662,7 +662,12 @@ static int ensure_left_hand_identifier_is_not_known_yet(git_object *object, git_
return GIT_EINVALIDSPEC;
}
int git_revparse_single(git_object **out, git_repository *repo, const char *spec)
int revparse__ext(
git_object **object_out,
git_reference **reference_out,
int *identifier_len_out,
git_repository *repo,
const char *spec)
{
size_t pos = 0, identifier_len = 0;
int error = -1, n;
......@@ -671,9 +676,10 @@ int git_revparse_single(git_object **out, git_repository *repo, const char *spec
git_reference *reference = NULL;
git_object *base_rev = NULL;
assert(out && repo && spec);
assert(object_out && reference_out && repo && spec);
*out = NULL;
*object_out = NULL;
*reference_out = NULL;
while (spec[pos]) {
switch (spec[pos]) {
......@@ -792,7 +798,9 @@ int git_revparse_single(git_object **out, git_repository *repo, const char *spec
if ((error = ensure_base_rev_loaded(&base_rev, reference, spec, identifier_len, repo, false)) < 0)
goto cleanup;
*out = base_rev;
*object_out = base_rev;
*reference_out = reference;
*identifier_len_out = identifier_len;
error = 0;
cleanup:
......@@ -802,12 +810,59 @@ cleanup:
"Failed to parse revision specifier - Invalid pattern '%s'", spec);
git_object_free(base_rev);
git_reference_free(reference);
}
git_reference_free(reference);
git_buf_free(&buf);
return error;
}
int git_revparse_ext(
git_object **object_out,
git_reference **reference_out,
git_repository *repo,
const char *spec)
{
int error, identifier_len;
git_object *obj = NULL;
git_reference *ref = NULL;
if ((error = revparse__ext(&obj, &ref, &identifier_len, repo, spec)) < 0)
goto cleanup;
*object_out = obj;
*reference_out = ref;
return 0;
cleanup:
git_object_free(obj);
git_reference_free(ref);
return error;
}
int git_revparse_single(git_object **out, git_repository *repo, const char *spec)
{
int error;
git_object *obj = NULL;
git_reference *ref = NULL;
*out = NULL;
if ((error = git_revparse_ext(&obj, &ref, repo, spec)) < 0)
goto cleanup;
git_reference_free(ref);
*out = obj;
return 0;
cleanup:
git_object_free(obj);
git_reference_free(ref);
return error;
}
int git_revparse(
git_revspec *revspec,
......
......@@ -9,13 +9,19 @@ static git_repository *g_repo;
static git_object *g_obj;
/* Helpers */
static void test_object_inrepo(const char *spec, const char *expected_oid, git_repository *repo)
static void test_object_and_ref_inrepo(
const char *spec,
const char *expected_oid,
const char *expected_refname,
git_repository *repo,
bool assert_reference_retrieval)
{
char objstr[64] = {0};
git_object *obj = NULL;
git_reference *ref = NULL;
int error;
error = git_revparse_single(&obj, repo, spec);
error = git_revparse_ext(&obj, &ref, repo, spec);
if (expected_oid != NULL) {
cl_assert_equal_i(0, error);
......@@ -24,7 +30,20 @@ static void test_object_inrepo(const char *spec, const char *expected_oid, git_r
} else
cl_assert_equal_i(GIT_ENOTFOUND, error);
if (assert_reference_retrieval) {
if (expected_refname == NULL)
cl_assert(NULL == ref);
else
cl_assert_equal_s(expected_refname, git_reference_name(ref));
}
git_object_free(obj);
git_reference_free(ref);
}
static void test_object_inrepo(const char *spec, const char *expected_oid, git_repository *repo)
{
test_object_and_ref_inrepo(spec, expected_oid, NULL, repo, false);
}
static void test_id_inrepo(
......@@ -63,6 +82,11 @@ static void test_object(const char *spec, const char *expected_oid)
test_object_inrepo(spec, expected_oid, g_repo);
}
static void test_object_and_ref(const char *spec, const char *expected_oid, const char *expected_refname)
{
test_object_and_ref_inrepo(spec, expected_oid, expected_refname, g_repo, true);
}
static void test_rangelike(const char *rangelike,
const char *expected_left,
const char *expected_right,
......@@ -694,3 +718,24 @@ void test_refs_revparse__parses_range_operator(void)
"a65fedf39aefe402d3bb6e24df4d4f5fe4547750",
GIT_REVPARSE_RANGE | GIT_REVPARSE_MERGE_BASE);
}
void test_refs_revparse__ext_retrieves_both_the_reference_and_its_target(void)
{
test_object_and_ref(
"master@{upstream}",
"be3563ae3f795b2b4353bcce3a527ad0a4f7f644",
"refs/remotes/test/master");
test_object_and_ref(
"@{-1}",
"a4a7dce85cf63874e984719f4fdd239f5145052f",
"refs/heads/br2");
}
void test_refs_revparse__ext_only_retrieve_the_object_target(void)
{
test_object_and_ref(
"master",
"a65fedf39aefe402d3bb6e24df4d4f5fe4547750",
NULL);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment