mirror of
https://git.proxmox.com/git/libgit2
synced 2025-06-22 22:23:05 +00:00
Finish the tree object API
The interface for loading and parsing tree objects from a repository has been completed with all the required accesor methods for attributes, support for manipulating individual tree entries and a new unit test t0901-readtree which tries to load and parse a tree object from a repository. Signed-off-by: Vicent Marti <tanoku@gmail.com>
This commit is contained in:
parent
ff17642dc2
commit
003c269094
@ -14,6 +14,10 @@
|
|||||||
*/
|
*/
|
||||||
GIT_BEGIN_DECL
|
GIT_BEGIN_DECL
|
||||||
|
|
||||||
|
|
||||||
|
/** Representation of each one of the entries in a tree object. */
|
||||||
|
typedef struct git_tree_entry git_tree_entry;
|
||||||
|
|
||||||
/** Representation of a tree object. */
|
/** Representation of a tree object. */
|
||||||
typedef struct git_tree git_tree;
|
typedef struct git_tree git_tree;
|
||||||
|
|
||||||
@ -35,6 +39,58 @@ GIT_EXTERN(git_tree *) git_tree_lookup(git_repository *repo, const git_oid *id);
|
|||||||
*/
|
*/
|
||||||
GIT_EXTERN(const git_oid *) git_tree_id(git_tree *tree);
|
GIT_EXTERN(const git_oid *) git_tree_id(git_tree *tree);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the number of entries listed in a tree
|
||||||
|
* @param tree a previously loaded tree.
|
||||||
|
* @return the number of entries in the tree
|
||||||
|
*/
|
||||||
|
GIT_EXTERN(size_t) git_tree_entrycount(git_tree *tree);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lookup a tree entry by its filename
|
||||||
|
* @param tree a previously loaded tree.
|
||||||
|
* @param filename the filename of the desired entry
|
||||||
|
* @return the tree entry; NULL if not found
|
||||||
|
*/
|
||||||
|
GIT_EXTERN(const git_tree_entry *) git_tree_entry_byname(git_tree *tree, const char *filename);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lookup a tree entry by its position in the tree
|
||||||
|
* @param tree a previously loaded tree.
|
||||||
|
* @param idx the position in the entry list
|
||||||
|
* @return the tree entry; NULL if not found
|
||||||
|
*/
|
||||||
|
GIT_EXTERN(const git_tree_entry *) git_tree_entry_byindex(git_tree *tree, int idx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the UNIX file attributes of a tree entry
|
||||||
|
* @param entry a tree entry
|
||||||
|
* @return attributes as an integer
|
||||||
|
*/
|
||||||
|
GIT_EXTERN(uint32_t) git_tree_entry_attributes(const git_tree_entry *entry);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the filename of a tree entry
|
||||||
|
* @param entry a tree entry
|
||||||
|
* @return the name of the file
|
||||||
|
*/
|
||||||
|
GIT_EXTERN(const char *) git_tree_entry_name(const git_tree_entry *entry);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the id of the object pointed by the entry
|
||||||
|
* @param entry a tree entry
|
||||||
|
* @return the oid of the object
|
||||||
|
*/
|
||||||
|
GIT_EXTERN(const git_oid *) git_tree_entry_id(const git_tree_entry *entry);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a tree entry to the git_repository_object it points too.
|
||||||
|
* @param entry a tree entry
|
||||||
|
* @return a reference to the pointed object in the repository
|
||||||
|
*/
|
||||||
|
GIT_EXTERN(git_repository_object *) git_tree_entry_2object(const git_tree_entry *entry);
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
GIT_END_DECL
|
GIT_END_DECL
|
||||||
#endif
|
#endif
|
||||||
|
99
src/tree.c
99
src/tree.c
@ -31,6 +31,12 @@
|
|||||||
|
|
||||||
void git_tree__free(git_tree *tree)
|
void git_tree__free(git_tree *tree)
|
||||||
{
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < tree->entry_count; ++i)
|
||||||
|
free(tree->entries[i].filename);
|
||||||
|
|
||||||
|
free(tree->entries);
|
||||||
free(tree);
|
free(tree);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,13 +50,67 @@ git_tree *git_tree_lookup(git_repository *repo, const git_oid *id)
|
|||||||
return (git_tree *)git_repository_lookup(repo, id, GIT_OBJ_TREE);
|
return (git_tree *)git_repository_lookup(repo, id, GIT_OBJ_TREE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t git_tree_entry_attributes(const git_tree_entry *entry)
|
||||||
|
{
|
||||||
|
return entry->attr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *git_tree_entry_name(const git_tree_entry *entry)
|
||||||
|
{
|
||||||
|
return entry->filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
const git_oid *git_tree_entry_id(const git_tree_entry *entry)
|
||||||
|
{
|
||||||
|
return &entry->oid;
|
||||||
|
}
|
||||||
|
|
||||||
|
git_repository_object *git_tree_entry_2object(const git_tree_entry *entry)
|
||||||
|
{
|
||||||
|
return git_repository_lookup(entry->owner->object.repo, &entry->oid, GIT_OBJ_ANY);
|
||||||
|
}
|
||||||
|
|
||||||
|
int entry_cmp(const void *key, const void *array_member)
|
||||||
|
{
|
||||||
|
const char *filename = (const char *)key;
|
||||||
|
const git_tree_entry *entry = (const git_tree_entry *)array_member;
|
||||||
|
|
||||||
|
return strcmp(filename, entry->filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
const git_tree_entry *git_tree_entry_byname(git_tree *tree, const char *filename)
|
||||||
|
{
|
||||||
|
if (tree->entries == NULL)
|
||||||
|
git_tree__parse(tree);
|
||||||
|
|
||||||
|
return bsearch(filename, tree->entries, tree->entry_count, sizeof(git_tree_entry), entry_cmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
const git_tree_entry *git_tree_entry_byindex(git_tree *tree, int idx)
|
||||||
|
{
|
||||||
|
if (tree->entries == NULL)
|
||||||
|
git_tree__parse(tree);
|
||||||
|
|
||||||
|
return (tree->entries && idx >= 0 && idx < (int)tree->entry_count) ?
|
||||||
|
&tree->entries[idx] : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t git_tree_entrycount(git_tree *tree)
|
||||||
|
{
|
||||||
|
return tree->entry_count;
|
||||||
|
}
|
||||||
|
|
||||||
int git_tree__parse(git_tree *tree)
|
int git_tree__parse(git_tree *tree)
|
||||||
{
|
{
|
||||||
static const char tree_header[] = {'t', 'r', 'e', 'e', ' '};
|
static const size_t avg_entry_size = 40;
|
||||||
|
|
||||||
int error = 0;
|
int error = 0;
|
||||||
git_obj odb_object;
|
git_obj odb_object;
|
||||||
char *buffer, *buffer_end;
|
char *buffer, *buffer_end;
|
||||||
|
size_t entries_size;
|
||||||
|
|
||||||
|
if (tree->entries != NULL)
|
||||||
|
return GIT_SUCCESS;
|
||||||
|
|
||||||
error = git_odb_read(&odb_object, tree->object.repo->db, &tree->object.id);
|
error = git_odb_read(&odb_object, tree->object.repo->db, &tree->object.id);
|
||||||
if (error < 0)
|
if (error < 0)
|
||||||
@ -59,23 +119,29 @@ int git_tree__parse(git_tree *tree)
|
|||||||
buffer = odb_object.data;
|
buffer = odb_object.data;
|
||||||
buffer_end = odb_object.data + odb_object.len;
|
buffer_end = odb_object.data + odb_object.len;
|
||||||
|
|
||||||
if (memcmp(buffer, tree_header, 5) != 0)
|
tree->entry_count = 0;
|
||||||
return GIT_EOBJCORRUPTED;
|
entries_size = (odb_object.len / avg_entry_size) + 1;
|
||||||
|
tree->entries = git__malloc(entries_size * sizeof(git_tree_entry));
|
||||||
buffer += 5;
|
|
||||||
|
|
||||||
tree->byte_size = strtol(buffer, &buffer, 10);
|
|
||||||
|
|
||||||
if (*buffer++ != 0)
|
|
||||||
return GIT_EOBJCORRUPTED;
|
|
||||||
|
|
||||||
while (buffer < buffer_end) {
|
while (buffer < buffer_end) {
|
||||||
git_tree_entry *entry;
|
git_tree_entry *entry;
|
||||||
|
|
||||||
entry = git__malloc(sizeof(git_tree_entry));
|
if (tree->entry_count >= entries_size) {
|
||||||
entry->next = tree->entries;
|
git_tree_entry *new_entries;
|
||||||
|
|
||||||
entry->attr = strtol(buffer, &buffer, 10);
|
entries_size = entries_size * 2;
|
||||||
|
|
||||||
|
new_entries = git__malloc(entries_size * sizeof(git_tree_entry));
|
||||||
|
memcpy(new_entries, tree->entries, tree->entry_count * sizeof(git_tree_entry));
|
||||||
|
|
||||||
|
free(tree->entries);
|
||||||
|
tree->entries = new_entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry = &tree->entries[tree->entry_count++];
|
||||||
|
entry->owner = tree;
|
||||||
|
|
||||||
|
entry->attr = strtol(buffer, &buffer, 8);
|
||||||
|
|
||||||
if (*buffer++ != ' ') {
|
if (*buffer++ != ' ') {
|
||||||
error = GIT_EOBJCORRUPTED;
|
error = GIT_EOBJCORRUPTED;
|
||||||
@ -86,15 +152,14 @@ int git_tree__parse(git_tree *tree)
|
|||||||
|
|
||||||
if (entry->filename == NULL) {
|
if (entry->filename == NULL) {
|
||||||
error = GIT_EOBJCORRUPTED;
|
error = GIT_EOBJCORRUPTED;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
buffer += strlen(entry->filename);
|
|
||||||
|
buffer += strlen(entry->filename) + 1;
|
||||||
|
|
||||||
git_oid_mkraw(&entry->oid, (const unsigned char *)buffer);
|
git_oid_mkraw(&entry->oid, (const unsigned char *)buffer);
|
||||||
buffer += GIT_OID_RAWSZ;
|
buffer += GIT_OID_RAWSZ;
|
||||||
|
|
||||||
tree->entries = entry;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
git_obj_close(&odb_object);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
10
src/tree.h
10
src/tree.h
@ -5,22 +5,18 @@
|
|||||||
#include "repository.h"
|
#include "repository.h"
|
||||||
|
|
||||||
struct git_tree_entry {
|
struct git_tree_entry {
|
||||||
|
uint32_t attr;
|
||||||
unsigned int attr;
|
|
||||||
char *filename;
|
char *filename;
|
||||||
git_oid oid;
|
git_oid oid;
|
||||||
|
|
||||||
struct git_tree_entry *next;
|
git_tree *owner;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct git_tree_entry git_tree_entry;
|
|
||||||
|
|
||||||
struct git_tree {
|
struct git_tree {
|
||||||
git_repository_object object;
|
git_repository_object object;
|
||||||
|
|
||||||
size_t byte_size;
|
|
||||||
git_tree_entry *entries;
|
git_tree_entry *entries;
|
||||||
unsigned int entry_count;
|
size_t entry_count;
|
||||||
};
|
};
|
||||||
|
|
||||||
void git_tree__free(git_tree *tree);
|
void git_tree__free(git_tree *tree);
|
||||||
|
42
tests/t0901-readtree.c
Normal file
42
tests/t0901-readtree.c
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
#include "test_lib.h"
|
||||||
|
#include "test_helpers.h"
|
||||||
|
#include "commit.h"
|
||||||
|
|
||||||
|
#include <git/odb.h>
|
||||||
|
#include <git/commit.h>
|
||||||
|
#include <git/revwalk.h>
|
||||||
|
|
||||||
|
static const char *odb_dir = "../resources/sample-odb";
|
||||||
|
static const char *tree_oid = "1810dff58d8a660512d4832e740f692884338ccd";
|
||||||
|
|
||||||
|
BEGIN_TEST(tree_read_test)
|
||||||
|
git_odb *db;
|
||||||
|
git_oid id;
|
||||||
|
git_repository *repo;
|
||||||
|
git_tree *tree;
|
||||||
|
const git_tree_entry *entry;
|
||||||
|
|
||||||
|
must_pass(git_odb_open(&db, odb_dir));
|
||||||
|
|
||||||
|
repo = git_repository_alloc(db);
|
||||||
|
must_be_true(repo != NULL);
|
||||||
|
|
||||||
|
git_oid_mkstr(&id, tree_oid);
|
||||||
|
|
||||||
|
tree = git_tree_lookup(repo, &id);
|
||||||
|
must_be_true(tree != NULL);
|
||||||
|
|
||||||
|
must_pass(git_tree__parse(tree));
|
||||||
|
|
||||||
|
must_be_true(git_tree_entrycount(tree) == 3);
|
||||||
|
|
||||||
|
entry = git_tree_entry_byname(tree, "README");
|
||||||
|
must_be_true(entry != NULL);
|
||||||
|
|
||||||
|
must_be_true(strcmp(git_tree_entry_name(entry), "README") == 0);
|
||||||
|
|
||||||
|
must_be_true(git_tree_entry_2object(entry) != NULL);
|
||||||
|
|
||||||
|
git_repository_free(repo);
|
||||||
|
git_odb_close(db);
|
||||||
|
END_TEST
|
Loading…
Reference in New Issue
Block a user