diff options
| author | Vicent Marti <tanoku@gmail.com> | 2010-09-21 17:17:10 +0300 |
|---|---|---|
| committer | Vicent Marti <tanoku@gmail.com> | 2010-09-21 17:17:10 +0300 |
| commit | 2a884588b405c4dee78494119a123fb1878f3490 (patch) | |
| tree | 04be673b6bd0ea4dd6ac00d8ccf8101e1a9baaec /src/tree.c | |
| parent | d45b4a9a1bcbb157a4f02cf5ed23fde5222db9c8 (diff) | |
| download | libgit2-2a884588b405c4dee78494119a123fb1878f3490.tar.gz | |
Add write-back support for git_tree
All the setter methods for git_tree have been added, including the
setters for attributes on each git_tree_entry and methods to add/remove
entries of the tree.
Modified trees and trees created in-memory from scratch can be written
back to the repository using git_object_write().
Signed-off-by: Vicent Marti <tanoku@gmail.com>
Diffstat (limited to 'src/tree.c')
| -rw-r--r-- | src/tree.c | 207 |
1 files changed, 169 insertions, 38 deletions
diff --git a/src/tree.c b/src/tree.c index 670f99838..43a50423d 100644 --- a/src/tree.c +++ b/src/tree.c @@ -29,12 +29,49 @@ #include "tree.h" #include "git/repository.h" +static void resize_tree_array(git_tree *tree) +{ + git_tree_entry **new_entries; + + tree->array_size = tree->array_size * 2; + + new_entries = git__malloc(tree->array_size * sizeof(git_tree_entry *)); + memcpy(new_entries, tree->entries, tree->entry_count * sizeof(git_tree_entry *)); + + free(tree->entries); + tree->entries = new_entries; +} + +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); +} + +int entry_sort_cmp(const void *a, const void *b) +{ + const git_tree_entry *entry_a = *(const git_tree_entry **)(a); + const git_tree_entry *entry_b = *(const git_tree_entry **)(b); + + return strcmp(entry_a->filename, entry_b->filename); +} + +static void entry_resort(git_tree *tree) +{ + qsort(tree->entries, tree->entry_count, sizeof(git_tree_entry *), entry_sort_cmp); +} + + + + 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[i]); free(tree->entries); free(tree); @@ -55,45 +92,62 @@ git_tree *git_tree_lookup(git_repository *repo, const git_oid *id) return (git_tree *)git_repository_lookup(repo, id, GIT_OBJ_TREE); } -unsigned int git_tree_entry_attributes(const git_tree_entry *entry) +void git_tree_entry_set_attributes(git_tree_entry *entry, int attr) { - return entry->attr; + assert(entry && entry->owner); + + entry->attr = attr; + entry->owner->object.modified = 1; } -const char *git_tree_entry_name(const git_tree_entry *entry) +void git_tree_entry_set_name(git_tree_entry *entry, const char *name) { - return entry->filename; + assert(entry && entry->owner); + + strncpy(entry->filename, name, GIT_TREE_MAX_FILENAME); + entry_resort(entry->owner); + entry->owner->object.modified = 1; } -const git_oid *git_tree_entry_id(const git_tree_entry *entry) +void git_tree_entry_set_id(git_tree_entry *entry, const git_oid *oid) { - return &entry->oid; + assert(entry && entry->owner); + + git_oid_cpy(&entry->oid, oid); + entry->owner->object.modified = 1; } -git_object *git_tree_entry_2object(const git_tree_entry *entry) +unsigned int git_tree_entry_attributes(git_tree_entry *entry) { - return git_repository_lookup(entry->owner->object.repo, &entry->oid, GIT_OBJ_ANY); + return entry->attr; } -int entry_cmp(const void *key, const void *array_member) +const char *git_tree_entry_name(git_tree_entry *entry) { - const char *filename = (const char *)key; - const git_tree_entry *entry = (const git_tree_entry *)array_member; + return entry->filename; +} - return strcmp(filename, entry->filename); +const git_oid *git_tree_entry_id(git_tree_entry *entry) +{ + return &entry->oid; } -const git_tree_entry *git_tree_entry_byname(git_tree *tree, const char *filename) +git_object *git_tree_entry_2object(git_tree_entry *entry) { - return bsearch(filename, tree->entries, tree->entry_count, sizeof(git_tree_entry), entry_cmp); + return git_repository_lookup(entry->owner->object.repo, &entry->oid, GIT_OBJ_ANY); } -const git_tree_entry *git_tree_entry_byindex(git_tree *tree, int idx) +git_tree_entry *git_tree_entry_byname(git_tree *tree, const char *filename) +{ + return *(git_tree_entry **)bsearch(filename, tree->entries, tree->entry_count, sizeof(git_tree_entry *), entry_cmp); +} + +git_tree_entry *git_tree_entry_byindex(git_tree *tree, int idx) { if (tree->entries == NULL) return NULL; - return (idx >= 0 && idx < (int)tree->entry_count) ? &tree->entries[idx] : NULL; + return (idx >= 0 && idx < (int)tree->entry_count) ? tree->entries[idx] : NULL; } size_t git_tree_entrycount(git_tree *tree) @@ -101,16 +155,97 @@ size_t git_tree_entrycount(git_tree *tree) return tree->entry_count; } +void git_tree_add_entry(git_tree *tree, const git_oid *id, const char *filename, int attributes) +{ + git_tree_entry *entry; + + if (tree->entry_count >= tree->array_size) + resize_tree_array(tree); + + if ((entry = git__malloc(sizeof(git_tree_entry))) == NULL) + return; + + memset(entry, 0x0, sizeof(git_tree_entry)); + + strncpy(entry->filename, filename, GIT_TREE_MAX_FILENAME); + git_oid_cpy(&entry->oid, id); + entry->attr = attributes; + entry->owner = tree; + + tree->entries[tree->entry_count++] = entry; + entry_resort(tree); + + tree->object.modified = 1; +} + +int git_tree_remove_entry_byindex(git_tree *tree, int idx) +{ + git_tree_entry *remove_ptr; + + if (idx < 0 || idx >= (int)tree->entry_count) + return GIT_ENOTFOUND; + + remove_ptr = tree->entries[idx]; + tree->entries[idx] = tree->entries[--tree->entry_count]; + + free(remove_ptr); + entry_resort(tree); + + tree->object.modified = 1; + return GIT_SUCCESS; +} + +int git_tree_remove_entry_byname(git_tree *tree, const char *filename) +{ + git_tree_entry **entry_ptr; + int idx; + + entry_ptr = bsearch(filename, tree->entries, tree->entry_count, sizeof(git_tree_entry *), entry_cmp); + if (entry_ptr == NULL) + return GIT_ENOTFOUND; + + idx = (int)(entry_ptr - tree->entries); + return git_tree_remove_entry_byindex(tree, idx); +} + +int git_tree__writeback(git_tree *tree, git_odb_source *src) +{ + size_t i; + + if (tree->entries == NULL) + return GIT_ERROR; + + entry_resort(tree); + + for (i = 0; i < tree->entry_count; ++i) { + git_tree_entry *entry; + entry = tree->entries[i]; + + git__source_printf(src, "%06o %s\0", entry->attr, entry->filename); + git__source_write(src, entry->oid.id, GIT_OID_RAWSZ); + } + + return GIT_SUCCESS; +} + + int git_tree__parse(git_tree *tree) { static const size_t avg_entry_size = 40; int error = 0; char *buffer, *buffer_end; - size_t entries_size; - if (tree->entries != NULL) - return GIT_SUCCESS; + assert(!tree->object.in_memory); + + if (tree->entries != NULL) { + size_t i; + + for (i = 0; i < tree->entry_count; ++i) + free(tree->entries[i]); + + free(tree->entries); + } error = git_object__source_open((git_object *)tree); if (error < 0) @@ -120,27 +255,24 @@ int git_tree__parse(git_tree *tree) buffer_end = buffer + tree->object.source.raw.len; tree->entry_count = 0; - entries_size = (tree->object.source.raw.len / avg_entry_size) + 1; - tree->entries = git__malloc(entries_size * sizeof(git_tree_entry)); + tree->array_size = (tree->object.source.raw.len / avg_entry_size) + 1; + tree->entries = git__malloc(tree->array_size * sizeof(git_tree_entry *)); while (buffer < buffer_end) { git_tree_entry *entry; - if (tree->entry_count >= entries_size) { - git_tree_entry *new_entries; - - 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)); + if (tree->entry_count >= tree->array_size) + resize_tree_array(tree); - free(tree->entries); - tree->entries = new_entries; + entry = git__malloc(sizeof(git_tree_entry)); + if (entry == NULL) { + error = GIT_ENOMEM; + break; } - entry = &tree->entries[tree->entry_count++]; - entry->owner = tree; + tree->entries[tree->entry_count++] = entry; + entry->owner = tree; entry->attr = strtol(buffer, &buffer, 8); if (*buffer++ != ' ') { @@ -148,13 +280,12 @@ int git_tree__parse(git_tree *tree) break; } - entry->filename = git__strdup(buffer); + strncpy(entry->filename, buffer, GIT_TREE_MAX_FILENAME); - if (entry->filename == NULL) { - error = GIT_EOBJCORRUPTED; - } + while (buffer < buffer_end && *buffer != 0) + buffer++; - buffer += strlen(entry->filename) + 1; + buffer++; git_oid_mkraw(&entry->oid, (const unsigned char *)buffer); buffer += GIT_OID_RAWSZ; |
