mirror of
https://git.proxmox.com/git/libgit2
synced 2025-06-20 05:38:36 +00:00
Add loading and parsing of tag objects
Tag objects are now properly loaded from the revision pool. New test t0801 checks for loading a parsing a series of tags, including the tag of a tag. Signed-off-by: Vicent Marti <tanoku@gmail.com>
This commit is contained in:
parent
364788e1d1
commit
f875804487
89
src/git/tag.h
Normal file
89
src/git/tag.h
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
#ifndef INCLUDE_git_tag_h__
|
||||||
|
#define INCLUDE_git_tag_h__
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "oid.h"
|
||||||
|
#include "tree.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file git/tag.h
|
||||||
|
* @brief Git tag parsing routines
|
||||||
|
* @defgroup git_tag Git tag management
|
||||||
|
* @ingroup Git
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
GIT_BEGIN_DECL
|
||||||
|
|
||||||
|
/** Parsed representation of a tag object. */
|
||||||
|
typedef struct git_tag git_tag;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Locate a reference to a tag without loading it.
|
||||||
|
* The generated tag object is owned by the revision
|
||||||
|
* pool and shall not be freed by the user.
|
||||||
|
*
|
||||||
|
* @param pool the pool to use when locating the tag.
|
||||||
|
* @param id identity of the tag to locate.
|
||||||
|
* @return the tag; NULL if the tag could not be created
|
||||||
|
*/
|
||||||
|
GIT_EXTERN(git_tag *) git_tag_lookup(git_revpool *pool, const git_oid *id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Locate a reference to a tag, and try to load and parse it it from
|
||||||
|
* the object cache or the object database.
|
||||||
|
* The generated tag object is owned by the revision
|
||||||
|
* pool and shall not be freed by the user.
|
||||||
|
*
|
||||||
|
* @param pool the pool to use when parsing/caching the tag.
|
||||||
|
* @param id identity of the tag to locate.
|
||||||
|
* @return the tag; NULL if the tag does not exist in the
|
||||||
|
* pool's git_odb, or if the tag is present but is
|
||||||
|
* too malformed to be parsed successfully.
|
||||||
|
*/
|
||||||
|
GIT_EXTERN(git_tag *) git_tag_parse(git_revpool *pool, const git_oid *id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the id of a tag.
|
||||||
|
* @param tag a previously loaded tag.
|
||||||
|
* @return object identity for the tag.
|
||||||
|
*/
|
||||||
|
GIT_EXTERN(const git_oid *) git_tag_id(git_tag *tag);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the tagged object of a tag
|
||||||
|
* @param tag a previously loaded tag.
|
||||||
|
* @return reference to a repository object
|
||||||
|
*/
|
||||||
|
GIT_EXTERN(const git_repository_object *) git_tag_target(git_tag *t);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the type of a tag's tagged object
|
||||||
|
* @param tag a previously loaded tag.
|
||||||
|
* @return type of the tagged object
|
||||||
|
*/
|
||||||
|
GIT_EXTERN(git_otype) git_tag_type(git_tag *t);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the name of a tag
|
||||||
|
* @param tag a previously loaded tag.
|
||||||
|
* @return name of the tag
|
||||||
|
*/
|
||||||
|
GIT_EXTERN(const char *) git_tag_name(git_tag *t);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the tagger (author) of a tag
|
||||||
|
* @param tag a previously loaded tag.
|
||||||
|
* @return reference to the tag's author
|
||||||
|
*/
|
||||||
|
GIT_EXTERN(const git_person *) git_tag_tagger(git_tag *t);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the message of a tag
|
||||||
|
* @param tag a previously loaded tag.
|
||||||
|
* @return message of the tag
|
||||||
|
*/
|
||||||
|
GIT_EXTERN(const char *) git_tag_message(git_tag *t);
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
GIT_END_DECL
|
||||||
|
#endif
|
228
src/tag.c
Normal file
228
src/tag.c
Normal file
@ -0,0 +1,228 @@
|
|||||||
|
/*
|
||||||
|
* This file is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License, version 2,
|
||||||
|
* as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* In addition to the permissions in the GNU General Public License,
|
||||||
|
* the authors give you unlimited permission to link the compiled
|
||||||
|
* version of this file into combinations with other programs,
|
||||||
|
* and to distribute those combinations without any restriction
|
||||||
|
* coming from the use of this file. (The General Public License
|
||||||
|
* restrictions do apply in other respects; for example, they cover
|
||||||
|
* modification of the file, and distribution when not linked into
|
||||||
|
* a combined executable.)
|
||||||
|
*
|
||||||
|
* This file is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; see the file COPYING. If not, write to
|
||||||
|
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "commit.h"
|
||||||
|
#include "tag.h"
|
||||||
|
#include "revwalk.h"
|
||||||
|
#include "git/odb.h"
|
||||||
|
|
||||||
|
|
||||||
|
void git_tag__free(git_tag *tag)
|
||||||
|
{
|
||||||
|
free(tag->message);
|
||||||
|
free(tag->tag_name);
|
||||||
|
free(tag->tagger);
|
||||||
|
free(tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
const git_oid *git_tag_id(git_tag *t)
|
||||||
|
{
|
||||||
|
return &t->object.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
const git_revpool_object *git_tag_target(git_tag *t)
|
||||||
|
{
|
||||||
|
if (t->target)
|
||||||
|
return t->target;
|
||||||
|
|
||||||
|
git_tag__parse(t);
|
||||||
|
return t->target;
|
||||||
|
}
|
||||||
|
|
||||||
|
git_otype git_tag_type(git_tag *t)
|
||||||
|
{
|
||||||
|
if (t->type)
|
||||||
|
return t->type;
|
||||||
|
|
||||||
|
git_tag__parse(t);
|
||||||
|
return t->type;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const char *git_tag_name(git_tag *t)
|
||||||
|
{
|
||||||
|
if (t->tag_name)
|
||||||
|
return t->tag_name;
|
||||||
|
|
||||||
|
git_tag__parse(t);
|
||||||
|
return t->tag_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
const git_person *git_tag_tagger(git_tag *t)
|
||||||
|
{
|
||||||
|
if (t->tagger)
|
||||||
|
return t->tagger;
|
||||||
|
|
||||||
|
git_tag__parse(t);
|
||||||
|
return t->tagger;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *git_tag_message(git_tag *t)
|
||||||
|
{
|
||||||
|
if (t->message)
|
||||||
|
return t->message;
|
||||||
|
|
||||||
|
git_tag__parse(t);
|
||||||
|
return t->message;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parse_tag_buffer(git_tag *tag, char *buffer, const char *buffer_end)
|
||||||
|
{
|
||||||
|
static const char *tag_types[] = {
|
||||||
|
NULL, "commit\n", "tree\n", "blob\n", "tag\n"
|
||||||
|
};
|
||||||
|
|
||||||
|
git_oid target_oid;
|
||||||
|
unsigned int i, text_len;
|
||||||
|
char *search;
|
||||||
|
|
||||||
|
if (git__parse_oid(&target_oid, &buffer, buffer_end, "object ") < 0)
|
||||||
|
return GIT_EOBJCORRUPTED;
|
||||||
|
|
||||||
|
if (buffer + 5 >= buffer_end)
|
||||||
|
return GIT_EOBJCORRUPTED;
|
||||||
|
|
||||||
|
if (memcmp(buffer, "type ", 5) != 0)
|
||||||
|
return GIT_EOBJCORRUPTED;
|
||||||
|
buffer += 5;
|
||||||
|
|
||||||
|
tag->type = GIT_OBJ_BAD;
|
||||||
|
|
||||||
|
for (i = 1; i < ARRAY_SIZE(tag_types); ++i) {
|
||||||
|
size_t type_length = strlen(tag_types[i]);
|
||||||
|
|
||||||
|
if (buffer + type_length >= buffer_end)
|
||||||
|
return GIT_EOBJCORRUPTED;
|
||||||
|
|
||||||
|
if (memcmp(buffer, tag_types[i], type_length) == 0) {
|
||||||
|
tag->type = i;
|
||||||
|
buffer += type_length;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tag->type == GIT_OBJ_BAD)
|
||||||
|
return GIT_EOBJCORRUPTED;
|
||||||
|
|
||||||
|
/* Lookup the tagged object once we know its type */
|
||||||
|
tag->target =
|
||||||
|
git_repository_lookup(tag->object.repo, &target_oid, tag->type);
|
||||||
|
|
||||||
|
/* FIXME: is the tag file really corrupted if the tagged object
|
||||||
|
* cannot be found on the database? */
|
||||||
|
/* if (tag->target == NULL)
|
||||||
|
return GIT_EOBJCORRUPTED; */
|
||||||
|
|
||||||
|
if (buffer + 4 >= buffer_end)
|
||||||
|
return GIT_EOBJCORRUPTED;
|
||||||
|
|
||||||
|
if (memcmp(buffer, "tag ", 4) != 0)
|
||||||
|
return GIT_EOBJCORRUPTED;
|
||||||
|
buffer += 4;
|
||||||
|
|
||||||
|
search = memchr(buffer, '\n', buffer_end - buffer);
|
||||||
|
if (search == NULL)
|
||||||
|
return GIT_EOBJCORRUPTED;
|
||||||
|
|
||||||
|
text_len = search - buffer;
|
||||||
|
|
||||||
|
if (tag->tag_name != NULL)
|
||||||
|
free(tag->tag_name);
|
||||||
|
|
||||||
|
tag->tag_name = git__malloc(text_len + 1);
|
||||||
|
memcpy(tag->tag_name, buffer, text_len);
|
||||||
|
tag->tag_name[text_len] = '\0';
|
||||||
|
|
||||||
|
buffer = search + 1;
|
||||||
|
|
||||||
|
if (tag->tagger != NULL)
|
||||||
|
free(tag->tagger);
|
||||||
|
|
||||||
|
tag->tagger = git__malloc(sizeof(git_person));
|
||||||
|
|
||||||
|
if (git__parse_person(tag->tagger, &buffer, buffer_end, "tagger ") != 0)
|
||||||
|
return GIT_EOBJCORRUPTED;
|
||||||
|
|
||||||
|
text_len = buffer_end - buffer;
|
||||||
|
|
||||||
|
if (tag->message != NULL)
|
||||||
|
free(tag->message);
|
||||||
|
|
||||||
|
tag->message = git__malloc(text_len + 1);
|
||||||
|
memcpy(tag->message, buffer, text_len);
|
||||||
|
tag->message[text_len] = '\0';
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int git_tag__parse(git_tag *tag)
|
||||||
|
{
|
||||||
|
int error = 0;
|
||||||
|
git_obj odb_object;
|
||||||
|
|
||||||
|
error = git_odb_read(&odb_object, tag->object.pool->db, &tag->object.id);
|
||||||
|
if (error < 0)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
if (odb_object.type != GIT_OBJ_TAG) {
|
||||||
|
error = GIT_EOBJTYPE;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = parse_tag_buffer(tag, odb_object.data, odb_object.data + odb_object.len);
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
git_obj_close(&odb_object);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
git_tag *git_tag_lookup(git_revpool *pool, const git_oid *id)
|
||||||
|
{
|
||||||
|
git_tag *tag = NULL;
|
||||||
|
|
||||||
|
if (pool == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
tag = (git_tag *)git_revpool_table_lookup(pool->objects, id);
|
||||||
|
if (tag != NULL)
|
||||||
|
return tag;
|
||||||
|
|
||||||
|
tag = git__malloc(sizeof(git_tag));
|
||||||
|
|
||||||
|
if (tag == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
memset(tag, 0x0, sizeof(git_tag));
|
||||||
|
|
||||||
|
/* Initialize parent object */
|
||||||
|
git_oid_cpy(&tag->object.id, id);
|
||||||
|
tag->object.pool = pool;
|
||||||
|
tag->object.type = GIT_OBJ_TAG;
|
||||||
|
|
||||||
|
git_revpool_table_insert(pool->objects, (git_revpool_object *)tag);
|
||||||
|
|
||||||
|
return tag;
|
||||||
|
}
|
20
src/tag.h
Normal file
20
src/tag.h
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#ifndef INCLUDE_tag_h__
|
||||||
|
#define INCLUDE_tag_h__
|
||||||
|
|
||||||
|
#include "git/tag.h"
|
||||||
|
#include "revobject.h"
|
||||||
|
|
||||||
|
struct git_tag {
|
||||||
|
git_revpool_object object;
|
||||||
|
|
||||||
|
git_revpool_object *target;
|
||||||
|
git_otype type;
|
||||||
|
char *tag_name;
|
||||||
|
git_person *tagger;
|
||||||
|
char *message;
|
||||||
|
};
|
||||||
|
|
||||||
|
void git_tag__free(git_tag *tag);
|
||||||
|
int git_tag__parse(git_tag *tag);
|
||||||
|
|
||||||
|
#endif
|
Binary file not shown.
Binary file not shown.
48
tests/t0801-readtag.c
Normal file
48
tests/t0801-readtag.c
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
#include "test_lib.h"
|
||||||
|
#include "test_helpers.h"
|
||||||
|
#include "commit.h"
|
||||||
|
|
||||||
|
#include <git/odb.h>
|
||||||
|
#include <git/commit.h>
|
||||||
|
#include <git/tag.h>
|
||||||
|
|
||||||
|
static const char *odb_dir = "../resources/pack-odb";
|
||||||
|
static const char *tag1_id = "b25fa35b38051e4ae45d4222e795f9df2e43f1d1";
|
||||||
|
static const char *tag2_id = "7b4384978d2493e851f9cca7858815fac9b10980";
|
||||||
|
static const char *tagged_commit = "e90810b8df3e80c413d903f631643c716887138d";
|
||||||
|
|
||||||
|
BEGIN_TEST(readtag)
|
||||||
|
git_odb *db;
|
||||||
|
git_repository *repo;
|
||||||
|
git_tag *tag1, *tag2;
|
||||||
|
git_commit *commit;
|
||||||
|
git_oid id1, id2, id_commit;
|
||||||
|
|
||||||
|
must_pass(git_odb_open(&db, odb_dir));
|
||||||
|
|
||||||
|
repo = git_repository_alloc(db);
|
||||||
|
must_be_true(repo != NULL);
|
||||||
|
|
||||||
|
git_oid_mkstr(&id1, tag1_id);
|
||||||
|
git_oid_mkstr(&id2, tag2_id);
|
||||||
|
git_oid_mkstr(&id_commit, tagged_commit);
|
||||||
|
|
||||||
|
tag1 = git_tag_lookup(repo, &id1);
|
||||||
|
must_be_true(tag1 != NULL);
|
||||||
|
|
||||||
|
must_be_true(strcmp(git_tag_name(tag1), "test") == 0);
|
||||||
|
must_be_true(git_tag_type(tag1) == GIT_OBJ_TAG);
|
||||||
|
|
||||||
|
tag2 = (git_tag *)git_tag_target(tag1);
|
||||||
|
must_be_true(tag2 != NULL);
|
||||||
|
|
||||||
|
must_be_true(git_oid_cmp(&id2, git_tag_id(tag2)) == 0);
|
||||||
|
|
||||||
|
commit = (git_commit *)git_tag_target(tag2);
|
||||||
|
must_be_true(commit != NULL);
|
||||||
|
|
||||||
|
must_be_true(git_oid_cmp(&id_commit, git_commit_id(commit)) == 0);
|
||||||
|
|
||||||
|
git_repository_free(repo);
|
||||||
|
git_odb_close(db);
|
||||||
|
END_TEST
|
Loading…
Reference in New Issue
Block a user