diff options
author | Edward Thomson <ethomson@edwardthomson.com> | 2012-10-29 20:04:21 -0500 |
---|---|---|
committer | Edward Thomson <ethomson@edwardthomson.com> | 2012-10-29 20:04:21 -0500 |
commit | f45ec1a076e2347ba5d63eeb2d158f87b612e5cb (patch) | |
tree | 2e2bebc12e64e6f48eabde6010bf775b3fc6cd6e /src | |
parent | 81eecc342b3580e9b05e501c8ee75c7e2e0dca1a (diff) | |
download | libgit2-f45ec1a076e2347ba5d63eeb2d158f87b612e5cb.tar.gz |
index refactoring
Diffstat (limited to 'src')
-rw-r--r-- | src/attr.c | 2 | ||||
-rw-r--r-- | src/index.c | 610 | ||||
-rw-r--r-- | src/index.h | 5 | ||||
-rw-r--r-- | src/iterator.c | 2 | ||||
-rw-r--r-- | src/stash.c | 8 | ||||
-rw-r--r-- | src/submodule.c | 6 | ||||
-rw-r--r-- | src/tree.c | 4 | ||||
-rw-r--r-- | src/vector.c | 14 | ||||
-rw-r--r-- | src/vector.h | 1 |
9 files changed, 562 insertions, 90 deletions
diff --git a/src/attr.c b/src/attr.c index 025ad3c87..f5e09cc08 100644 --- a/src/attr.c +++ b/src/attr.c @@ -307,7 +307,7 @@ static int load_attr_blob_from_index( (error = git_index_find(index, relfile)) < 0) return error; - entry = git_index_get(index, error); + entry = git_index_get_byindex(index, error); if (old_oid && git_oid_cmp(old_oid, &entry->oid) == 0) return GIT_ENOTFOUND; diff --git a/src/index.c b/src/index.c index 38e83d007..44dd93417 100644 --- a/src/index.c +++ b/src/index.c @@ -81,6 +81,11 @@ struct entry_long { char path[1]; /* arbitrary length */ }; +struct entry_srch_key { + const char *path; + int stage; +}; + /* local declarations */ static size_t read_extension(git_index *index, const char *buffer, size_t buffer_size); static size_t read_entry(git_index_entry *dest, const void *buffer, size_t buffer_size); @@ -90,53 +95,126 @@ static int parse_index(git_index *index, const char *buffer, size_t buffer_size) static int is_index_extended(git_index *index); static int write_index(git_index *index, git_filebuf *file); +static int index_find(git_index *index, const char *path, int stage); + static void index_entry_free(git_index_entry *entry); +static void index_entry_reuc_free(git_index_reuc_entry *reuc); + +GIT_INLINE(int) index_entry_stage(const git_index_entry *entry) +{ + return (entry->flags & GIT_IDXENTRY_STAGEMASK) >> GIT_IDXENTRY_STAGESHIFT; +} static int index_srch(const void *key, const void *array_member) { + const struct entry_srch_key *srch_key = key; const git_index_entry *entry = array_member; + int ret; - return strcmp(key, entry->path); + ret = strcmp(srch_key->path, entry->path); + + if (ret == 0) + ret = srch_key->stage - index_entry_stage(entry); + + return ret; } static int index_isrch(const void *key, const void *array_member) { + const struct entry_srch_key *srch_key = key; + const git_index_entry *entry = array_member; + int ret; + + ret = strcasecmp(srch_key->path, entry->path); + + if (ret == 0) + ret = srch_key->stage - index_entry_stage(entry); + + return ret; +} + +static int index_cmp_path(const void *a, const void *b) +{ + return strcmp((const char *)a, (const char *)b); +} + +static int index_icmp_path(const void *a, const void *b) +{ + return strcasecmp((const char *)a, (const char *)b); +} + +static int index_srch_path(const void *path, const void *array_member) +{ const git_index_entry *entry = array_member; - return strcasecmp(key, entry->path); + return strcmp((const char *)path, entry->path); +} + +static int index_isrch_path(const void *path, const void *array_member) +{ + const git_index_entry *entry = array_member; + + return strcasecmp((const char *)path, entry->path); } static int index_cmp(const void *a, const void *b) { + int diff; const git_index_entry *entry_a = a; const git_index_entry *entry_b = b; - return strcmp(entry_a->path, entry_b->path); + diff = strcmp(entry_a->path, entry_b->path); + + if (diff == 0) + diff = (index_entry_stage(entry_a) - index_entry_stage(entry_b)); + + return diff; } static int index_icmp(const void *a, const void *b) { + int diff; const git_index_entry *entry_a = a; const git_index_entry *entry_b = b; - return strcasecmp(entry_a->path, entry_b->path); + diff = strcasecmp(entry_a->path, entry_b->path); + + if (diff == 0) + diff = (index_entry_stage(entry_a) - index_entry_stage(entry_b)); + + return diff; +} + +static int reuc_srch(const void *key, const void *array_member) +{ + const git_index_reuc_entry *reuc = array_member; + + return strcmp(key, reuc->path); } -static int unmerged_srch(const void *key, const void *array_member) +static int reuc_isrch(const void *key, const void *array_member) { - const git_index_entry_unmerged *entry = array_member; + const git_index_reuc_entry *reuc = array_member; - return strcmp(key, entry->path); + return strcasecmp(key, reuc->path); } -static int unmerged_cmp(const void *a, const void *b) +static int reuc_cmp(const void *a, const void *b) { - const git_index_entry_unmerged *info_a = a; - const git_index_entry_unmerged *info_b = b; + const git_index_reuc_entry *info_a = a; + const git_index_reuc_entry *info_b = b; return strcmp(info_a->path, info_b->path); } +static int reuc_icmp(const void *a, const void *b) +{ + const git_index_reuc_entry *info_a = a; + const git_index_reuc_entry *info_b = b; + + return strcasecmp(info_a->path, info_b->path); +} + static unsigned int index_create_mode(unsigned int mode) { if (S_ISLNK(mode)) @@ -165,9 +243,16 @@ static unsigned int index_merge_mode( static void index_set_ignore_case(git_index *index, bool ignore_case) { index->entries._cmp = ignore_case ? index_icmp : index_cmp; + index->entries_cmp_path = ignore_case ? index_icmp_path : index_cmp_path; index->entries_search = ignore_case ? index_isrch : index_srch; + index->entries_search_path = ignore_case ? index_isrch_path : index_srch_path; index->entries.sorted = 0; git_vector_sort(&index->entries); + + index->reuc._cmp = ignore_case ? reuc_icmp : reuc_cmp; + index->reuc_search = ignore_case ? reuc_isrch : reuc_srch; + index->reuc.sorted = 0; + git_vector_sort(&index->reuc); } int git_index_open(git_index **index_out, const char *index_path) @@ -185,7 +270,10 @@ int git_index_open(git_index **index_out, const char *index_path) if (git_vector_init(&index->entries, 32, index_cmp) < 0) return -1; + index->entries_cmp_path = index_cmp_path; index->entries_search = index_srch; + index->entries_search_path = index_srch_path; + index->reuc_search = reuc_srch; /* Check if index file is stored on disk already */ if (git_path_exists(index->index_file_path) == true) @@ -199,6 +287,7 @@ int git_index_open(git_index **index_out, const char *index_path) static void index_free(git_index *index) { git_index_entry *e; + git_index_reuc_entry *reuc; unsigned int i; git_index_clear(index); @@ -206,10 +295,10 @@ static void index_free(git_index *index) index_entry_free(e); } git_vector_free(&index->entries); - git_vector_foreach(&index->unmerged, i, e) { - index_entry_free(e); + git_vector_foreach(&index->reuc, i, reuc) { + index_entry_reuc_free(reuc); } - git_vector_free(&index->unmerged); + git_vector_free(&index->reuc); git__free(index->index_file_path); git__free(index); @@ -236,15 +325,15 @@ void git_index_clear(git_index *index) git__free(e); } - for (i = 0; i < index->unmerged.length; ++i) { - git_index_entry_unmerged *e; - e = git_vector_get(&index->unmerged, i); + for (i = 0; i < index->reuc.length; ++i) { + git_index_reuc_entry *e; + e = git_vector_get(&index->reuc, i); git__free(e->path); git__free(e); } git_vector_clear(&index->entries); - git_vector_clear(&index->unmerged); + git_vector_clear(&index->reuc); index->last_modified = 0; git_tree_cache_free(index->tree); @@ -340,6 +429,7 @@ int git_index_write(git_index *index) int error; git_vector_sort(&index->entries); + git_vector_sort(&index->reuc); if ((error = git_filebuf_open( &file, index->index_file_path, GIT_FILEBUF_HASH_CONTENTS)) < 0) @@ -367,16 +457,25 @@ unsigned int git_index_entrycount(git_index *index) return (unsigned int)index->entries.length; } -unsigned int git_index_entrycount_unmerged(git_index *index) +git_index_entry *git_index_get_byindex(git_index *index, size_t n) { assert(index); - return (unsigned int)index->unmerged.length; + git_vector_sort(&index->entries); + return git_vector_get(&index->entries, n); } -git_index_entry *git_index_get(git_index *index, size_t n) +git_index_entry *git_index_get_bypath(git_index *index, const char *path, int stage) { + int pos; + + assert(index); + git_vector_sort(&index->entries); - return git_vector_get(&index->entries, n); + + if((pos = index_find(index, path, stage)) < 0) + return NULL; + + return git_index_get_byindex(index, pos); } void git_index__init_entry_from_stat(struct stat *st, git_index_entry *entry) @@ -393,7 +492,7 @@ void git_index__init_entry_from_stat(struct stat *st, git_index_entry *entry) entry->file_size = st->st_size; } -static int index_entry_init(git_index_entry **entry_out, git_index *index, const char *rel_path, int stage) +static int index_entry_init(git_index_entry **entry_out, git_index *index, const char *rel_path) { git_index_entry *entry = NULL; struct stat st; @@ -402,8 +501,6 @@ static int index_entry_init(git_index_entry **entry_out, git_index *index, const git_buf full_path = GIT_BUF_INIT; int error; - assert(stage >= 0 && stage <= 3); - if (INDEX_OWNER(index) == NULL || (workdir = git_repository_workdir(INDEX_OWNER(index))) == NULL) { @@ -436,7 +533,6 @@ static int index_entry_init(git_index_entry **entry_out, git_index *index, const git_index__init_entry_from_stat(&st, entry); entry->oid = oid; - entry->flags |= (stage << GIT_IDXENTRY_STAGESHIFT); entry->path = git__strdup(rel_path); GITERR_CHECK_ALLOC(entry->path); @@ -444,6 +540,46 @@ static int index_entry_init(git_index_entry **entry_out, git_index *index, const return 0; } +static int index_entry_reuc_init(git_index_reuc_entry **reuc_out, + const char *path, + int ancestor_mode, git_oid *ancestor_oid, + int our_mode, git_oid *our_oid, int their_mode, git_oid *their_oid) +{ + git_index_reuc_entry *reuc = NULL; + + assert(reuc_out && path); + + *reuc_out = NULL; + + reuc = git__calloc(1, sizeof(git_index_reuc_entry)); + GITERR_CHECK_ALLOC(reuc); + + reuc->path = git__strdup(path); + if (reuc->path == NULL) + return -1; + + reuc->mode[0] = ancestor_mode; + git_oid_cpy(&reuc->oid[0], ancestor_oid); + + reuc->mode[1] = our_mode; + git_oid_cpy(&reuc->oid[1], our_oid); + + reuc->mode[2] = their_mode; + git_oid_cpy(&reuc->oid[2], their_oid); + + *reuc_out = reuc; + return 0; +} + +static void index_entry_reuc_free(git_index_reuc_entry *reuc) +{ + if (!reuc) + return; + + git__free(reuc->path); + git__free(reuc); +} + static git_index_entry *index_entry_dup(const git_index_entry *source_entry) { git_index_entry *entry; @@ -486,10 +622,10 @@ static int index_insert(git_index *index, git_index_entry *entry, int replace) if (path_length < GIT_IDXENTRY_NAMEMASK) entry->flags |= path_length & GIT_IDXENTRY_NAMEMASK; else - entry->flags |= GIT_IDXENTRY_NAMEMASK;; + entry->flags |= GIT_IDXENTRY_NAMEMASK; /* look if an entry with this path already exists */ - if ((position = git_index_find(index, entry->path)) >= 0) { + if ((position = index_find(index, entry->path, index_entry_stage(entry))) >= 0) { existing = (git_index_entry **)&index->entries.contents[position]; /* update filemode to existing values if stat is not trusted */ @@ -510,34 +646,56 @@ static int index_insert(git_index *index, git_index_entry *entry, int replace) return 0; } -static int index_add(git_index *index, const char *path, int stage, int replace) +static int index_conflict_to_reuc(git_index *index, const char *path) { - git_index_entry *entry = NULL; + git_index_entry *conflict_entries[3]; + int ancestor_mode, our_mode, their_mode; + git_oid *ancestor_oid, *our_oid, *their_oid; int ret; - if ((ret = index_entry_init(&entry, index, path, stage)) < 0 || - (ret = index_insert(index, entry, replace)) < 0) - { - index_entry_free(entry); + if ((ret = git_index_conflict_get(&conflict_entries[0], + &conflict_entries[1], &conflict_entries[2], index, path)) < 0) return ret; - } - git_tree_cache_invalidate_path(index->tree, entry->path); - return 0; -} + ancestor_mode = conflict_entries[0] == NULL ? 0 : conflict_entries[0]->mode; + our_mode = conflict_entries[1] == NULL ? 0 : conflict_entries[1]->mode; + their_mode = conflict_entries[2] == NULL ? 0 : conflict_entries[2]->mode; -int git_index_add(git_index *index, const char *path, int stage) -{ - return index_add(index, path, stage, 1); + ancestor_oid = conflict_entries[0] == NULL ? NULL : &conflict_entries[0]->oid; + our_oid = conflict_entries[1] == NULL ? NULL : &conflict_entries[1]->oid; + their_oid = conflict_entries[2] == NULL ? NULL : &conflict_entries[2]->oid; + + if ((ret = git_index_reuc_add(index, path, ancestor_mode, ancestor_oid, + our_mode, our_oid, their_mode, their_oid)) >= 0) + ret = git_index_conflict_remove(index, path); + + return ret; } -int git_index_append(git_index *index, const char *path, int stage) +int git_index_add_from_workdir(git_index *index, const char *path) { - return index_add(index, path, stage, 0); + git_index_entry *entry = NULL; + int ret; + + assert(index && path); + + if ((ret = index_entry_init(&entry, index, path)) < 0 || + (ret = index_insert(index, entry, 1)) < 0) + goto on_error; + + /* Adding implies conflict was resolved, move conflict entries to REUC */ + if ((ret = index_conflict_to_reuc(index, path)) < 0 && ret != GIT_ENOTFOUND) + goto on_error; + + git_tree_cache_invalidate_path(index->tree, entry->path); + return 0; + +on_error: + index_entry_free(entry); + return ret; } -static int index_add2( - git_index *index, const git_index_entry *source_entry, int replace) +int git_index_add(git_index *index, const git_index_entry *source_entry) { git_index_entry *entry = NULL; int ret; @@ -546,7 +704,7 @@ static int index_add2( if (entry == NULL) return -1; - if ((ret = index_insert(index, entry, replace)) < 0) { + if ((ret = index_insert(index, entry, 1)) < 0) { index_entry_free(entry); return ret; } @@ -555,23 +713,17 @@ static int index_add2( return 0; } -int git_index_add2(git_index *index, const git_index_entry *source_entry) -{ - return index_add2(index, source_entry, 1); -} - -int git_index_append2(git_index *index, const git_index_entry *source_entry) -{ - return index_add2(index, source_entry, 0); -} - -int git_index_remove(git_index *index, int position) +int git_index_remove(git_index *index, const char *path, int stage) { + int position; int error; git_index_entry *entry; git_vector_sort(&index->entries); + if ((position = index_find(index, path, stage)) < 0) + return position; + entry = git_vector_get(&index->entries, position); if (entry != NULL) git_tree_cache_invalidate_path(index->tree, entry->path); @@ -584,45 +736,277 @@ int git_index_remove(git_index *index, int position) return error; } +static int index_find(git_index *index, const char *path, int stage) +{ + struct entry_srch_key srch_key; + + assert(path); + + srch_key.path = path; + srch_key.stage = stage; + + return git_vector_bsearch2(&index->entries, index->entries_search, &srch_key); +} + int git_index_find(git_index *index, const char *path) { - return git_vector_bsearch2(&index->entries, index->entries_search, path); + int pos; + + assert(index && path); + + if ((pos = git_vector_bsearch2(&index->entries, index->entries_search_path, path)) < 0) + return pos; + + /* Since our binary search only looked at path, we may be in the + * middle of a list of stages. */ + while (pos > 0) { + git_index_entry *prev = git_vector_get(&index->entries, pos-1); + + if (index->entries_cmp_path(prev->path, path) != 0) + break; + + --pos; + } + + return pos; } unsigned int git_index__prefix_position(git_index *index, const char *path) { + struct entry_srch_key srch_key; unsigned int pos; - git_vector_bsearch3(&pos, &index->entries, index->entries_search, path); + srch_key.path = path; + srch_key.stage = 0; + + git_vector_bsearch3(&pos, &index->entries, index->entries_search, &srch_key); return pos; } -void git_index_uniq(git_index *index) +int git_index_conflict_add(git_index *index, + const git_index_entry *ancestor_entry, + const git_index_entry *our_entry, + const git_index_entry *their_entry) +{ + git_index_entry *entries[3] = { 0 }; + size_t i; + int ret = 0; + + assert (index); + + if ((ancestor_entry != NULL && (entries[0] = index_entry_dup(ancestor_entry)) == NULL) || + (our_entry != NULL && (entries[1] = index_entry_dup(our_entry)) == NULL) || + (their_entry != NULL && (entries[2] = index_entry_dup(their_entry)) == NULL)) + return -1; + + for (i = 0; i < 3; i++) { + if (entries[i] == NULL) + continue; + + /* Make sure stage is correct */ + entries[i]->flags = (entries[i]->flags & ~GIT_IDXENTRY_STAGEMASK) | + ((i+1) << GIT_IDXENTRY_STAGESHIFT); + + if ((ret = index_insert(index, entries[i], 1)) < 0) + goto on_error; + } + + return 0; + +on_error: + for (i = 0; i < 3; i++) { + if (entries[i] != NULL) + index_entry_free(entries[i]); + } + + return ret; +} + +int git_index_conflict_get(git_index_entry **ancestor_out, + git_index_entry **our_out, + git_index_entry **their_out, + git_index *index, const char *path) +{ + int pos, stage; + git_index_entry *conflict_entry; + int error = GIT_ENOTFOUND; + + assert(ancestor_out && our_out && their_out && index && path); + + *ancestor_out = NULL; + *our_out = NULL; + *their_out = NULL; + + if ((pos = git_index_find(index, path)) < 0) + return pos; + + while ((unsigned int)pos < git_index_entrycount(index)) { + conflict_entry = git_vector_get(&index->entries, pos); + + if (index->entries_cmp_path(conflict_entry->path, path) != 0) + break; + + stage = index_entry_stage(conflict_entry); + + switch (stage) { + case 3: + *their_out = conflict_entry; + error = 0; + break; + case 2: + *our_out = conflict_entry; + error = 0; + break; + case 1: + *ancestor_out = conflict_entry; + error = 0; + break; + default: + break; + }; + + ++pos; + } + + return error; +} + +int git_index_conflict_remove(git_index *index, const char *path) +{ + int pos; + git_index_entry *conflict_entry; + + assert(index && path); + + if ((pos = git_index_find(index, path)) < 0) + return pos; + + while ((unsigned int)pos < git_index_entrycount(index)) { + conflict_entry = git_vector_get(&index->entries, pos); + + if (index->entries_cmp_path(conflict_entry->path, path) != 0) + break; + + if (index_entry_stage(conflict_entry) == 0) { + pos++; + continue; + } + + git_vector_remove(&index->entries, (unsigned int)pos); + } + + return 0; +} + +static int index_conflicts_match(git_vector *v, size_t idx) +{ + git_index_entry *entry = git_vector_get(v, idx); + + if (index_entry_stage(entry) > 0) + return 1; + + return 0; +} + +void git_index_conflict_cleanup(git_index *index) +{ + assert(index); + git_vector_remove_matching(&index->entries, index_conflicts_match); +} + +unsigned int git_index_reuc_entrycount(git_index *index) +{ + assert(index); + return (unsigned int)index->reuc.length; +} + +static int index_reuc_insert(git_index *index, git_index_reuc_entry *reuc, int replace) +{ + git_index_reuc_entry **existing = NULL; + int position; + + assert(index && reuc && reuc->path != NULL); + + if ((position = git_index_reuc_find(index, reuc->path)) >= 0) + existing = (git_index_reuc_entry **)&index->reuc.contents[position]; + + if (!replace || !existing) + return git_vector_insert(&index->reuc, reuc); + + /* exists, replace it */ + git__free((*existing)->path); + git__free(*existing); + *existing = reuc; + + return 0; +} + +int git_index_reuc_add(git_index *index, const char *path, + int ancestor_mode, git_oid *ancestor_oid, + int our_mode, git_oid *our_oid, + int their_mode, git_oid *their_oid) +{ + git_index_reuc_entry *reuc = NULL; + int error = 0; + + assert(index && path); + + if ((error = index_entry_reuc_init(&reuc, path, ancestor_mode, ancestor_oid, our_mode, our_oid, their_mode, their_oid)) < 0 || + (error = index_reuc_insert(index, reuc, 1)) < 0) + { + index_entry_reuc_free(reuc); + return error; + } + + return error; +} + +int git_index_reuc_find(git_index *index, const char *path) { - git_vector_uniq(&index->entries); + return git_vector_bsearch2(&index->reuc, index->reuc_search, path); } -const git_index_entry_unmerged *git_index_get_unmerged_bypath( +const git_index_reuc_entry *git_index_reuc_get_bypath( git_index *index, const char *path) { int pos; assert(index && path); - if (!index->unmerged.length) + if (!index->reuc.length) return NULL; - if ((pos = git_vector_bsearch2(&index->unmerged, unmerged_srch, path)) < 0) + git_vector_sort(&index->reuc); + + if ((pos = git_index_reuc_find(index, path)) < 0) return NULL; - return git_vector_get(&index->unmerged, pos); + return git_vector_get(&index->reuc, pos); } -const git_index_entry_unmerged *git_index_get_unmerged_byindex( +const git_index_reuc_entry *git_index_reuc_get_byindex( git_index *index, size_t n) { assert(index); - return git_vector_get(&index->unmerged, n); + + git_vector_sort(&index->reuc); + return git_vector_get(&index->reuc, n); +} + +int git_index_reuc_remove(git_index *index, int position) +{ + int error; + git_index_reuc_entry *reuc; + + git_vector_sort(&index->reuc); + + reuc = git_vector_get(&index->reuc, position); + error = git_vector_remove(&index->reuc, (unsigned int)position); + + if (!error) + index_entry_reuc_free(reuc); + + return error; } static int index_error_invalid(const char *message) @@ -631,26 +1015,26 @@ static int index_error_invalid(const char *message) return -1; } -static int read_unmerged(git_index *index, const char *buffer, size_t size) +static int read_reuc(git_index *index, const char *buffer, size_t size) { const char *endptr; size_t len; int i; - if (git_vector_init(&index->unmerged, 16, unmerged_cmp) < 0) + if (git_vector_init(&index->reuc, 16, reuc_cmp) < 0) return -1; while (size) { - git_index_entry_unmerged *lost; + git_index_reuc_entry *lost; len = strlen(buffer) + 1; if (size <= len) - return index_error_invalid("reading unmerged entries"); + return index_error_invalid("reading reuc entries"); - lost = git__malloc(sizeof(git_index_entry_unmerged)); + lost = git__malloc(sizeof(git_index_reuc_entry)); GITERR_CHECK_ALLOC(lost); - if (git_vector_insert(&index->unmerged, lost) < 0) + if (git_vector_insert(&index->reuc, lost) < 0) return -1; /* read NUL-terminated pathname for entry */ @@ -667,13 +1051,13 @@ static int read_unmerged(git_index *index, const char *buffer, size_t size) if (git__strtol32(&tmp, buffer, &endptr, 8) < 0 || !endptr || endptr == buffer || *endptr || (unsigned)tmp > UINT_MAX) - return index_error_invalid("reading unmerged entry stage"); + return index_error_invalid("reading reuc entry stage"); lost->mode[i] = tmp; len = (endptr + 1) - buffer; if (size <= len) - return index_error_invalid("reading unmerged entry stage"); + return index_error_invalid("reading reuc entry stage"); size -= len; buffer += len; @@ -684,7 +1068,7 @@ static int read_unmerged(git_index *index, const char *buffer, size_t size) if (!lost->mode[i]) continue; if (size < 20) - return index_error_invalid("reading unmerged entry oid"); + return index_error_invalid("reading reuc entry oid"); git_oid_fromraw(&lost->oid[i], (const unsigned char *) buffer); size -= 20; @@ -692,6 +1076,9 @@ static int read_unmerged(git_index *index, const char *buffer, size_t size) } } + /* entries are guaranteed to be sorted on-disk */ + index->reuc.sorted = 1; + return 0; } @@ -797,7 +1184,7 @@ static size_t read_extension(git_index *index, const char *buffer, size_t buffer if (git_tree_cache_read(&index->tree, buffer + 8, dest.extension_size) < 0) return 0; } else if (memcmp(dest.signature, INDEX_EXT_UNMERGED_SIG, 4) == 0) { - if (read_unmerged(index, buffer + 8, dest.extension_size) < 0) + if (read_reuc(index, buffer + 8, dest.extension_size) < 0) return 0; } /* else, unsupported extension. We cannot parse this, but we can skip @@ -996,6 +1383,69 @@ static int write_entries(git_index *index, git_filebuf *file) return error; } +static int write_extension(git_filebuf *file, struct index_extension *header, git_buf *data) +{ + struct index_extension ondisk; + int error = 0; + + memset(&ondisk, 0x0, sizeof(struct index_extension)); + memcpy(&ondisk, header, 4); + ondisk.extension_size = htonl(header->extension_size); + + if ((error = git_filebuf_write(file, &ondisk, sizeof(struct index_extension))) == 0) + error = git_filebuf_write(file, data->ptr, data->size); + + return error; +} + +static int create_reuc_extension_data(git_buf *reuc_buf, git_index_reuc_entry *reuc) +{ + int i; + int error = 0; + + if ((error = git_buf_put(reuc_buf, reuc->path, strlen(reuc->path) + 1)) < 0) + return error; + + for (i = 0; i < 3; i++) { + if ((error = git_buf_printf(reuc_buf, "%o", reuc->mode[i])) < 0 || + (error = git_buf_put(reuc_buf, "\0", 1)) < 0) + return error; + } + + for (i = 0; i < 3; i++) { + if (reuc->mode[i] && (error = git_buf_put(reuc_buf, (char *)&reuc->oid[i].id, GIT_OID_RAWSZ)) < 0) + return error; + } + + return 0; +} + +static int write_reuc_extension(git_index *index, git_filebuf *file) +{ + git_buf reuc_buf = GIT_BUF_INIT; + git_vector *out = &index->reuc; + git_index_reuc_entry *reuc; + struct index_extension extension; + unsigned int i; + int error = 0; + + git_vector_foreach(out, i, reuc) { + if ((error = create_reuc_extension_data(&reuc_buf, reuc)) < 0) + goto done; + } + + memset(&extension, 0x0, sizeof(struct index_extension)); + memcpy(&extension.signature, INDEX_EXT_UNMERGED_SIG, 4); + extension.extension_size = reuc_buf.size; + + error = write_extension(file, &extension, &reuc_buf); + + git_buf_free(&reuc_buf); + +done: + return error; +} + static int write_index(git_index *index, git_filebuf *file) { git_oid hash_final; @@ -1018,7 +1468,11 @@ static int write_index(git_index *index, git_filebuf *file) if (write_entries(index, file) < 0) return -1; - /* TODO: write extensions (tree cache) */ + /* TODO: write tree cache extension */ + + /* write the reuc extension */ + if (index->reuc.length > 0 && write_reuc_extension(index, file) < 0) + return -1; /* get out the hash for all the contents we've appended to the file */ git_filebuf_hash(&hash_final, file); @@ -1029,7 +1483,7 @@ static int write_index(git_index *index, git_filebuf *file) int git_index_entry_stage(const git_index_entry *entry) { - return (entry->flags & GIT_IDXENTRY_STAGEMASK) >> GIT_IDXENTRY_STAGESHIFT; + return index_entry_stage(entry); } typedef struct read_tree_data { diff --git a/src/index.h b/src/index.h index 7dd23ee60..0fd59dd45 100644 --- a/src/index.h +++ b/src/index.h @@ -33,9 +33,12 @@ struct git_index { git_tree_cache *tree; - git_vector unmerged; + git_vector reuc; + git_vector_cmp entries_cmp_path; git_vector_cmp entries_search; + git_vector_cmp entries_search_path; + git_vector_cmp reuc_search; }; extern void git_index__init_entry_from_stat(struct stat *st, git_index_entry *entry); diff --git a/src/iterator.c b/src/iterator.c index df6da9a87..5fac41046 100644 --- a/src/iterator.c +++ b/src/iterator.c @@ -336,7 +336,7 @@ static int index_iterator__current( git_iterator *self, const git_index_entry **entry) { index_iterator *ii = (index_iterator *)self; - git_index_entry *ie = git_index_get(ii->index, ii->current); + git_index_entry *ie = git_index_get_byindex(ii->index, ii->current); if (ie != NULL && ii->base.end != NULL && diff --git a/src/stash.c b/src/stash.c index 3011f00f0..9c9c5dce7 100644 --- a/src/stash.c +++ b/src/stash.c @@ -183,13 +183,13 @@ static int update_index_cb( if (!data->include_ignored) break; - return git_index_add(data->index, delta->new_file.path, 0); + return git_index_add_from_workdir(data->index, delta->new_file.path); case GIT_DELTA_UNTRACKED: if (!data->include_untracked) break; - return git_index_add(data->index, delta->new_file.path, 0); + return git_index_add_from_workdir(data->index, delta->new_file.path); case GIT_DELTA_ADDED: /* Fall through */ @@ -197,7 +197,7 @@ static int update_index_cb( if (!data->include_changed) break; - return git_index_add(data->index, delta->new_file.path, 0); + return git_index_add_from_workdir(data->index, delta->new_file.path); case GIT_DELTA_DELETED: if (!data->include_changed) @@ -206,7 +206,7 @@ static int update_index_cb( if ((pos = git_index_find(data->index, delta->new_file.path)) < 0) return -1; - if (git_index_remove(data->index, pos) < 0) + if (git_index_remove(data->index, delta->new_file.path, 0) < 0) return -1; default: diff --git a/src/submodule.c b/src/submodule.c index e3657f9ad..d69559dc2 100644 --- a/src/submodule.c +++ b/src/submodule.c @@ -332,7 +332,7 @@ int git_submodule_add_finalize(git_submodule *sm) assert(sm); if ((error = git_repository_index__weakptr(&index, sm->owner)) < 0 || - (error = git_index_add(index, GIT_MODULES_FILE, 0)) < 0) + (error = git_index_add_from_workdir(index, GIT_MODULES_FILE)) < 0) return error; return git_submodule_add_to_index(sm, true); @@ -393,7 +393,7 @@ int git_submodule_add_to_index(git_submodule *sm, int write_index) git_commit_free(head); /* add it */ - error = git_index_add2(index, &entry); + error = git_index_add(index, &entry); /* write it, if requested */ if (!error && write_index) { @@ -733,7 +733,7 @@ int git_submodule_reload(git_submodule *submodule) pos = git_index_find(index, submodule->path); if (pos >= 0) { - git_index_entry *entry = git_index_get(index, pos); + git_index_entry *entry = git_index_get_byindex(index, pos); if (S_ISGITLINK(entry->mode)) { if ((error = submodule_load_from_index(repo, entry)) < 0) diff --git a/src/tree.c b/src/tree.c index 8d3f2665c..9ecefbb61 100644 --- a/src/tree.c +++ b/src/tree.c @@ -353,7 +353,7 @@ static unsigned int find_next_dir(const char *dirname, git_index *index, unsigne dirlen = strlen(dirname); for (i = start; i < entries; ++i) { - git_index_entry *entry = git_index_get(index, i); + git_index_entry *entry = git_index_get_byindex(index, i); if (strlen(entry->path) < dirlen || memcmp(entry->path, dirname, dirlen) || (dirlen > 0 && entry->path[dirlen] != '/')) { @@ -415,7 +415,7 @@ static int write_tree( * need to keep track of the current position. */ for (i = start; i < entries; ++i) { - git_index_entry *entry = git_index_get(index, i); + git_index_entry *entry = git_index_get_byindex(index, i); char *filename, *next_slash; /* diff --git a/src/vector.c b/src/vector.c index c6a644cc3..d9c4c9900 100644 --- a/src/vector.c +++ b/src/vector.c @@ -223,6 +223,20 @@ void git_vector_uniq(git_vector *v) v->length -= j - i - 1; } +void git_vector_remove_matching(git_vector *v, int (*match)(git_vector *v, size_t idx)) +{ + unsigned int i, j; + + for (i = 0, j = 0; j < v->length; ++j) { + v->contents[i] = v->contents[j]; + + if (!match(v, i)) + i++; + } + + v->length = i; +} + void git_vector_clear(git_vector *v) { assert(v); diff --git a/src/vector.h b/src/vector.h index 49ba754f0..32f790c71 100644 --- a/src/vector.h +++ b/src/vector.h @@ -75,5 +75,6 @@ int git_vector_insert_sorted(git_vector *v, void *element, int git_vector_remove(git_vector *v, unsigned int idx); void git_vector_pop(git_vector *v); void git_vector_uniq(git_vector *v); +void git_vector_remove_matching(git_vector *v, int (*match)(git_vector *v, size_t idx)); #endif |