diff options
author | Vicent Marti <tanoku@gmail.com> | 2010-08-07 01:02:20 +0200 |
---|---|---|
committer | Vicent Marti <tanoku@gmail.com> | 2010-08-12 04:40:43 +0200 |
commit | f8758044876b30b0f6482d1fe8c3b1de743f4186 (patch) | |
tree | 95dd9fd8cb6b7c2acf97acdbbc436d7dbb7a3fbc /src | |
parent | 364788e1d114a174dd3c6fdfd3aa16d9627551b2 (diff) | |
download | libgit2-f8758044876b30b0f6482d1fe8c3b1de743f4186.tar.gz |
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>
Diffstat (limited to 'src')
-rw-r--r-- | src/git/tag.h | 89 | ||||
-rw-r--r-- | src/tag.c | 228 | ||||
-rw-r--r-- | src/tag.h | 20 |
3 files changed, 337 insertions, 0 deletions
diff --git a/src/git/tag.h b/src/git/tag.h new file mode 100644 index 000000000..509d2f047 --- /dev/null +++ b/src/git/tag.h @@ -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 diff --git a/src/tag.c b/src/tag.c new file mode 100644 index 000000000..803cfa13c --- /dev/null +++ b/src/tag.c @@ -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; +} diff --git a/src/tag.h b/src/tag.h new file mode 100644 index 000000000..5b1f5e2b9 --- /dev/null +++ b/src/tag.h @@ -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 |