Commit 3be933b1 by Vicent Marti

refs: Add `git_referene_target_peel`

parent f124ebd4
......@@ -35,7 +35,12 @@ GIT_EXTERN(git_reference *) git_reference__alloc(
git_refdb *refdb,
const char *name,
const git_oid *oid,
const char *symbolic);
const git_oid *peel);
GIT_EXTERN(git_reference *) git_reference__alloc_symbolic(
git_refdb *refdb,
const char *name,
const char *target);
/**
* Create a new reference database with no backends.
......
......@@ -133,6 +133,17 @@ GIT_EXTERN(int) git_reference_create(git_reference **out, git_repository *repo,
GIT_EXTERN(const git_oid *) git_reference_target(const git_reference *ref);
/**
* Return the peeled OID target of this reference.
*
* This peeled OID only applies to direct references that point to
* a hard Tag object: it is the result of peeling such Tag.
*
* @param ref The reference
* @return a pointer to the oid if available, NULL otherwise
*/
GIT_EXTERN(const git_oid *) git_reference_target_peel(const git_reference *ref);
/**
* Get full name to the reference pointed to by a symbolic reference.
*
* Only available if the reference is symbolic.
......
......@@ -430,7 +430,7 @@ static int loose_lookup(
goto done;
}
*out = git_reference__alloc(backend->refdb, ref_name, NULL, target);
*out = git_reference__alloc_symbolic(backend->refdb, ref_name, target);
} else {
if ((error = loose_parse_oid(&oid, &ref_file)) < 0)
goto done;
......@@ -484,7 +484,8 @@ static int packed_lookup(
if ((error = packed_map_entry(&entry, &pos, backend, ref_name)) < 0)
return error;
if ((*out = git_reference__alloc(backend->refdb, ref_name, &entry->oid, NULL)) == NULL)
if ((*out = git_reference__alloc(backend->refdb, ref_name,
&entry->oid, &entry->peel)) == NULL)
return -1;
return 0;
......@@ -644,7 +645,7 @@ static int loose_write(refdb_fs_backend *backend, const git_reference *ref)
if (ref->type == GIT_REF_OID) {
char oid[GIT_OID_HEXSZ + 1];
git_oid_fmt(oid, &ref->target.oid);
git_oid_fmt(oid, &ref->target.direct.oid);
oid[GIT_OID_HEXSZ] = '\0';
git_filebuf_printf(&file, "%s\n", oid);
......
......@@ -31,37 +31,62 @@ enum {
GIT_PACKREF_WAS_LOOSE = 2
};
static git_reference *alloc_ref(git_refdb *refdb, const char *name)
{
git_reference *ref;
size_t namelen = strlen(name);
git_reference *git_reference__alloc(
if ((ref = git__calloc(1, sizeof(git_reference) + namelen + 1)) == NULL)
return NULL;
ref->db = refdb;
memcpy(ref->name, name, namelen + 1);
return ref;
}
git_reference *git_reference__alloc_symbolic(
git_refdb *refdb,
const char *name,
const git_oid *oid,
const char *symbolic)
const char *target)
{
git_reference *ref;
size_t namelen;
assert(refdb && name && ((oid && !symbolic) || (!oid && symbolic)));
assert(refdb && name && target);
namelen = strlen(name);
if ((ref = git__calloc(1, sizeof(git_reference) + namelen + 1)) == NULL)
ref = alloc_ref(refdb, name);
if (!ref)
return NULL;
if (oid) {
ref->type = GIT_REF_OID;
git_oid_cpy(&ref->target.oid, oid);
} else {
ref->type = GIT_REF_SYMBOLIC;
ref->type = GIT_REF_SYMBOLIC;
if ((ref->target.symbolic = git__strdup(symbolic)) == NULL) {
git__free(ref);
return NULL;
}
if ((ref->target.symbolic = git__strdup(target)) == NULL) {
git__free(ref);
return NULL;
}
ref->db = refdb;
memcpy(ref->name, name, namelen + 1);
return ref;
}
git_reference *git_reference__alloc(
git_refdb *refdb,
const char *name,
const git_oid *oid,
const git_oid *peel)
{
git_reference *ref;
assert(refdb && name && oid);
ref = alloc_ref(refdb, name);
if (!ref)
return NULL;
ref->type = GIT_REF_OID;
git_oid_cpy(&ref->target.direct.oid, oid);
if (peel != NULL)
git_oid_cpy(&ref->target.direct.peel, peel);
return ref;
}
......@@ -71,13 +96,8 @@ void git_reference_free(git_reference *reference)
if (reference == NULL)
return;
if (reference->type == GIT_REF_SYMBOLIC) {
if (reference->type == GIT_REF_SYMBOLIC)
git__free(reference->target.symbolic);
reference->target.symbolic = NULL;
}
reference->db = NULL;
reference->type = GIT_REF_INVALID;
git__free(reference);
}
......@@ -302,7 +322,17 @@ const git_oid *git_reference_target(const git_reference *ref)
if (ref->type != GIT_REF_OID)
return NULL;
return &ref->target.oid;
return &ref->target.direct.oid;
}
const git_oid *git_reference_target_peel(const git_reference *ref)
{
assert(ref);
if (ref->type != GIT_REF_OID || git_oid_iszero(&ref->target.direct.peel))
return NULL;
return &ref->target.direct.peel;
}
const char *git_reference_symbolic_target(const git_reference *ref)
......@@ -335,8 +365,15 @@ static int reference__create(
(error = reference_can_write(repo, normalized, NULL, force)) < 0 ||
(error = git_repository_refdb__weakptr(&refdb, repo)) < 0)
return error;
if (oid != NULL) {
assert(symbolic == NULL);
ref = git_reference__alloc(refdb, name, oid, NULL);
} else {
ref = git_reference__alloc_symbolic(refdb, name, symbolic);
}
if ((ref = git_reference__alloc(refdb, name, oid, symbolic)) == NULL)
if (ref == NULL)
return -1;
if ((error = git_refdb_write(refdb, ref)) < 0) {
......@@ -437,8 +474,6 @@ int git_reference_rename(
char normalized[GIT_REFNAME_MAX];
bool should_head_be_updated = false;
git_reference *result = NULL;
git_oid *oid;
const char *symbolic;
int error = 0;
int reference_has_log;
......@@ -447,7 +482,8 @@ int git_reference_rename(
normalization_flags = ref->type == GIT_REF_SYMBOLIC ?
GIT_REF_FORMAT_ALLOW_ONELEVEL : GIT_REF_FORMAT_NORMAL;
if ((error = git_reference_normalize_name(normalized, sizeof(normalized), new_name, normalization_flags)) < 0 ||
if ((error = git_reference_normalize_name(
normalized, sizeof(normalized), new_name, normalization_flags)) < 0 ||
(error = reference_can_write(ref->db->repo, normalized, ref->name, force)) < 0)
return error;
......@@ -455,14 +491,15 @@ int git_reference_rename(
* Create the new reference.
*/
if (ref->type == GIT_REF_OID) {
oid = &ref->target.oid;
symbolic = NULL;
result = git_reference__alloc(ref->db, new_name,
&ref->target.direct.oid, &ref->target.direct.peel);
} else if (ref->type == GIT_REF_SYMBOLIC) {
result = git_reference__alloc_symbolic(ref->db, new_name, ref->target.symbolic);
} else {
oid = NULL;
symbolic = ref->target.symbolic;
assert(0);
}
if ((result = git_reference__alloc(ref->db, new_name, oid, symbolic)) == NULL)
if (result == NULL)
return -1;
/* Check if we have to update HEAD. */
......@@ -509,11 +546,17 @@ on_error:
int git_reference_resolve(git_reference **ref_out, const git_reference *ref)
{
if (ref->type == GIT_REF_OID)
switch (git_reference_type(ref)) {
case GIT_REF_OID:
return git_reference_lookup(ref_out, ref->db->repo, ref->name);
else
return git_reference_lookup_resolved(ref_out, ref->db->repo,
ref->target.symbolic, -1);
case GIT_REF_SYMBOLIC:
return git_reference_lookup_resolved(ref_out, ref->db->repo, ref->target.symbolic, -1);
default:
giterr_set(GITERR_REFERENCE, "Invalid reference");
return -1;
}
}
int git_reference_foreach(
......@@ -778,16 +821,20 @@ int git_reference__normalize_name_lax(
int git_reference_cmp(git_reference *ref1, git_reference *ref2)
{
git_ref_t type1, type2;
assert(ref1 && ref2);
type1 = git_reference_type(ref1);
type2 = git_reference_type(ref2);
/* let's put symbolic refs before OIDs */
if (ref1->type != ref2->type)
return (ref1->type == GIT_REF_SYMBOLIC) ? -1 : 1;
if (type1 != type2)
return (type1 == GIT_REF_SYMBOLIC) ? -1 : 1;
if (ref1->type == GIT_REF_SYMBOLIC)
if (type1 == GIT_REF_SYMBOLIC)
return strcmp(ref1->target.symbolic, ref2->target.symbolic);
return git_oid_cmp(&ref1->target.oid, &ref2->target.oid);
return git_oid_cmp(&ref1->target.direct.oid, &ref2->target.direct.oid);
}
static int reference__update_terminal(
......@@ -905,15 +952,6 @@ static int peel_error(int error, git_reference *ref, const char* msg)
return error;
}
static int reference_target(git_object **object, git_reference *ref)
{
const git_oid *oid;
oid = git_reference_target(ref);
return git_object_lookup(object, git_reference_owner(ref), oid, GIT_OBJ_ANY);
}
int git_reference_peel(
git_object **peeled,
git_reference *ref,
......@@ -925,10 +963,22 @@ int git_reference_peel(
assert(ref);
if ((error = git_reference_resolve(&resolved, ref)) < 0)
return peel_error(error, ref, "Cannot resolve reference");
if (ref->type == GIT_REF_OID) {
resolved = ref;
} else {
if ((error = git_reference_resolve(&resolved, ref)) < 0)
return peel_error(error, ref, "Cannot resolve reference");
}
if (!git_oid_iszero(&resolved->target.direct.peel)) {
error = git_object_lookup(&target,
git_reference_owner(ref), &resolved->target.direct.peel, GIT_OBJ_ANY);
} else {
error = git_object_lookup(&target,
git_reference_owner(ref), &resolved->target.direct.oid, GIT_OBJ_ANY);
}
if ((error = reference_target(&target, resolved)) < 0) {
if (error < 0) {
peel_error(error, ref, "Cannot retrieve reference target");
goto cleanup;
}
......@@ -940,7 +990,10 @@ int git_reference_peel(
cleanup:
git_object_free(target);
git_reference_free(resolved);
if (resolved != ref)
git_reference_free(resolved);
return error;
}
......
......@@ -49,11 +49,14 @@
struct git_reference {
git_refdb *db;
git_ref_t type;
union {
git_oid oid;
struct {
git_oid oid;
git_oid peel;
} direct;
char *symbolic;
} target;
......
......@@ -135,7 +135,7 @@ int foreach_test(const char *ref_name, void *payload)
else if (*i == 2)
cl_git_pass(git_oid_fromstr(&expected, "763d71aadf09a7951596c9746c024e7eece7c7af"));
cl_assert(git_oid_cmp(&expected, &ref->target.oid) == 0);
cl_assert(git_oid_cmp(&expected, git_reference_target(ref)) == 0);
++(*i);
......@@ -176,7 +176,7 @@ int delete_test(const char *ref_name, void *payload)
cl_git_pass(git_reference_lookup(&ref, repo, ref_name));
cl_git_pass(git_oid_fromstr(&expected, "e90810b8df3e80c413d903f631643c716887138d"));
cl_assert(git_oid_cmp(&expected, &ref->target.oid) == 0);
cl_assert(git_oid_cmp(&expected, git_reference_target(ref)) == 0);
++(*i);
......
......@@ -98,12 +98,16 @@ static int refdb_test_backend__lookup(
git_vector_foreach(&backend->refs, i, entry) {
if (strcmp(entry->name, ref_name) == 0) {
const git_oid *oid =
entry->type == GIT_REF_OID ? &entry->target.oid : NULL;
const char *symbolic =
entry->type == GIT_REF_SYMBOLIC ? entry->target.symbolic : NULL;
if ((*out = git_reference__alloc(backend->refdb, ref_name, oid, symbolic)) == NULL)
if (entry->type == GIT_REF_OID) {
*out = git_reference__alloc(backend->refdb, ref_name,
&entry->target.oid, NULL);
} else if (entry->type == GIT_REF_SYMBOLIC) {
*out = git_reference__alloc_symbolic(backend->refdb, ref_name,
entry->target.symbolic);
}
if (*out == NULL)
return -1;
return 0;
......
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