diff options
44 files changed, 524 insertions, 310 deletions
diff --git a/src/checkout.c b/src/checkout.c index 19ac913d3..0be87b4a3 100644 --- a/src/checkout.c +++ b/src/checkout.c @@ -456,7 +456,7 @@ static int checkout_action( while (1) { if (!wd) return checkout_action_no_wd(data, delta); - + cmp = strcomp(wd->path, delta->old_file.path); /* 1. wd before delta ("a/a" before "a/b") @@ -473,9 +473,9 @@ static int checkout_action( if (cmp == 0) { if (wd->mode == GIT_FILEMODE_TREE) { /* case 2 - entry prefixed by workdir tree */ - if (git_iterator_advance_into_directory(workdir, &wd) < 0) + if (git_iterator_advance_into(&wd, workdir) < 0) goto fail; - + *wditem_ptr = wd; continue; } @@ -484,14 +484,14 @@ static int checkout_action( if (delta->old_file.path[strlen(wd->path)] == '/') { act = checkout_action_with_wd_blocker(data, delta, wd); *wditem_ptr = - git_iterator_advance(workdir, &wd) ? NULL : wd; + git_iterator_advance(&wd, workdir) ? NULL : wd; return act; } } /* case 1 - handle wd item (if it matches pathspec) */ if (checkout_action_wd_only(data, workdir, wd, pathspec) < 0 || - git_iterator_advance(workdir, &wd) < 0) + git_iterator_advance(&wd, workdir) < 0) goto fail; *wditem_ptr = wd; @@ -501,7 +501,7 @@ static int checkout_action( if (cmp == 0) { /* case 4 */ act = checkout_action_with_wd(data, delta, wd); - *wditem_ptr = git_iterator_advance(workdir, &wd) ? NULL : wd; + *wditem_ptr = git_iterator_advance(&wd, workdir) ? NULL : wd; return act; } @@ -514,7 +514,7 @@ static int checkout_action( if (delta->status == GIT_DELTA_TYPECHANGE) { if (delta->old_file.mode == GIT_FILEMODE_TREE) { act = checkout_action_with_wd(data, delta, wd); - if (git_iterator_advance_into_directory(workdir, &wd) < 0) + if (git_iterator_advance_into(&wd, workdir) < 0) wd = NULL; *wditem_ptr = wd; return act; @@ -525,7 +525,7 @@ static int checkout_action( delta->old_file.mode == GIT_FILEMODE_COMMIT) { act = checkout_action_with_wd(data, delta, wd); - if (git_iterator_advance(workdir, &wd) < 0) + if (git_iterator_advance(&wd, workdir) < 0) wd = NULL; *wditem_ptr = wd; return act; @@ -554,7 +554,7 @@ static int checkout_remaining_wd_items( while (wd && !error) { if (!(error = checkout_action_wd_only(data, workdir, wd, spec))) - error = git_iterator_advance(workdir, &wd); + error = git_iterator_advance(&wd, workdir); } return error; @@ -578,7 +578,7 @@ static int checkout_get_actions( git_pathspec_init(&pathspec, &data->opts.paths, &pathpool) < 0) return -1; - if ((error = git_iterator_current(workdir, &wditem)) < 0) + if ((error = git_iterator_current(&wditem, workdir)) < 0) goto fail; deltas = &data->diff->deltas; @@ -1134,16 +1134,17 @@ static int checkout_data_init( if ((error = git_config_refresh(cfg)) < 0) goto cleanup; - if (git_iterator_inner_type(target) == GIT_ITERATOR_TYPE_INDEX) { - /* if we are iterating over the index, don't reload */ - data->index = git_iterator_index_get_index(target); + /* if we are checking out the index, don't reload, + * otherwise get index and force reload + */ + if ((data->index = git_iterator_get_index(target)) != NULL) { GIT_REFCOUNT_INC(data->index); } else { /* otherwise, grab and reload the index */ if ((error = git_repository_index(&data->index, data->repo)) < 0 || (error = git_index_read(data->index)) < 0) goto cleanup; - + /* clear the REUC when doing a tree or commit checkout */ git_index_reuc_clear(data->index); } @@ -1241,9 +1242,9 @@ int git_checkout_iterator( GIT_ITERATOR_IGNORE_CASE : GIT_ITERATOR_DONT_IGNORE_CASE; if ((error = git_iterator_reset(target, data.pfx, data.pfx)) < 0 || - (error = git_iterator_for_workdir_range( + (error = git_iterator_for_workdir( &workdir, data.repo, iterflags, data.pfx, data.pfx)) < 0 || - (error = git_iterator_for_tree_range( + (error = git_iterator_for_tree( &baseline, data.opts.baseline, iterflags, data.pfx, data.pfx)) < 0) goto cleanup; @@ -1321,7 +1322,7 @@ int git_checkout_index( return error; GIT_REFCOUNT_INC(index); - if (!(error = git_iterator_for_index(&index_i, index))) + if (!(error = git_iterator_for_index(&index_i, index, 0, NULL, NULL))) error = git_checkout_iterator(index_i, opts); git_iterator_free(index_i); @@ -1348,7 +1349,7 @@ int git_checkout_tree( return -1; } - if (!(error = git_iterator_for_tree(&tree_i, tree))) + if (!(error = git_iterator_for_tree(&tree_i, tree, 0, NULL, NULL))) error = git_checkout_iterator(tree_i, opts); git_iterator_free(tree_i); @@ -1369,7 +1370,7 @@ int git_checkout_head( return error; if (!(error = checkout_lookup_head_tree(&head, repo)) && - !(error = git_iterator_for_tree(&head_i, head))) + !(error = git_iterator_for_tree(&head_i, head, 0, NULL, NULL))) error = git_checkout_iterator(head_i, opts); git_iterator_free(head_i); diff --git a/src/diff.c b/src/diff.c index 0861b13eb..c0f8ee689 100644 --- a/src/diff.c +++ b/src/diff.c @@ -630,8 +630,8 @@ int git_diff__from_iterators( goto fail; } - if (git_iterator_current(old_iter, &oitem) < 0 || - git_iterator_current(new_iter, &nitem) < 0) + if (git_iterator_current(&oitem, old_iter) < 0 || + git_iterator_current(&nitem, new_iter) < 0) goto fail; /* run iterators building diffs */ @@ -663,12 +663,12 @@ int git_diff__from_iterators( if (S_ISDIR(nitem->mode) && !(diff->opts.flags & GIT_DIFF_RECURSE_UNTRACKED_DIRS)) { - if (git_iterator_advance(new_iter, &nitem) < 0) + if (git_iterator_advance(&nitem, new_iter) < 0) goto fail; } } - if (git_iterator_advance(old_iter, &oitem) < 0) + if (git_iterator_advance(&oitem, old_iter) < 0) goto fail; } @@ -696,7 +696,7 @@ int git_diff__from_iterators( /* do not advance into directories that contain a .git file */ if (!contains_oitem && recurse_untracked) { git_buf *full = NULL; - if (git_iterator_current_workdir_path(new_iter, &full) < 0) + if (git_iterator_current_workdir_path(&full, new_iter) < 0) goto fail; if (git_path_contains_dir(full, DOT_GIT)) recurse_untracked = false; @@ -710,7 +710,7 @@ int git_diff__from_iterators( git_iterator_current_is_ignored(new_iter)) git_buf_sets(&ignore_prefix, nitem->path); - if (git_iterator_advance_into_directory(new_iter, &nitem) < 0) + if (git_iterator_advance_into(&nitem, new_iter) < 0) goto fail; continue; @@ -733,7 +733,7 @@ int git_diff__from_iterators( * skip the file. */ else if (delta_type == GIT_DELTA_IGNORED) { - if (git_iterator_advance(new_iter, &nitem) < 0) + if (git_iterator_advance(&nitem, new_iter) < 0) goto fail; continue; /* ignored parent directory, so skip completely */ } @@ -762,7 +762,7 @@ int git_diff__from_iterators( } } - if (git_iterator_advance(new_iter, &nitem) < 0) + if (git_iterator_advance(&nitem, new_iter) < 0) goto fail; } @@ -772,11 +772,10 @@ int git_diff__from_iterators( else { assert(oitem && nitem && cmp == 0); - if (maybe_modified( - old_iter, oitem, new_iter, nitem, diff) < 0 || - git_iterator_advance(old_iter, &oitem) < 0 || - git_iterator_advance(new_iter, &nitem) < 0) - goto fail; + if (maybe_modified(old_iter, oitem, new_iter, nitem, diff) < 0 || + git_iterator_advance(&oitem, old_iter) < 0 || + git_iterator_advance(&nitem, new_iter) < 0) + goto fail; } } @@ -814,8 +813,8 @@ int git_diff_tree_to_tree( assert(diff && repo); DIFF_FROM_ITERATORS( - git_iterator_for_tree_range(&a, old_tree, 0, pfx, pfx), - git_iterator_for_tree_range(&b, new_tree, 0, pfx, pfx) + git_iterator_for_tree(&a, old_tree, 0, pfx, pfx), + git_iterator_for_tree(&b, new_tree, 0, pfx, pfx) ); return error; @@ -836,8 +835,8 @@ int git_diff_tree_to_index( return error; DIFF_FROM_ITERATORS( - git_iterator_for_tree_range(&a, old_tree, 0, pfx, pfx), - git_iterator_for_index_range(&b, index, 0, pfx, pfx) + git_iterator_for_tree(&a, old_tree, 0, pfx, pfx), + git_iterator_for_index(&b, index, 0, pfx, pfx) ); return error; @@ -857,8 +856,8 @@ int git_diff_index_to_workdir( return error; DIFF_FROM_ITERATORS( - git_iterator_for_index_range(&a, index, 0, pfx, pfx), - git_iterator_for_workdir_range(&b, repo, 0, pfx, pfx) + git_iterator_for_index(&a, index, 0, pfx, pfx), + git_iterator_for_workdir(&b, repo, 0, pfx, pfx) ); return error; @@ -876,8 +875,8 @@ int git_diff_tree_to_workdir( assert(diff && repo); DIFF_FROM_ITERATORS( - git_iterator_for_tree_range(&a, old_tree, 0, pfx, pfx), - git_iterator_for_workdir_range(&b, repo, 0, pfx, pfx) + git_iterator_for_tree(&a, old_tree, 0, pfx, pfx), + git_iterator_for_workdir(&b, repo, 0, pfx, pfx) ); return error; diff --git a/src/index.c b/src/index.c index 4deafd77f..1ca3b16b2 100644 --- a/src/index.c +++ b/src/index.c @@ -1679,54 +1679,3 @@ git_repository *git_index_owner(const git_index *index) { return INDEX_OWNER(index); } - -int git_index_read_tree_match( - git_index *index, git_tree *tree, git_strarray *strspec) -{ -#if 0 - git_iterator *iter = NULL; - const git_index_entry *entry; - char *pfx = NULL; - git_vector pathspec = GIT_VECTOR_INIT; - git_pool pathpool = GIT_POOL_INIT_STRINGPOOL; -#endif - - if (!git_pathspec_is_interesting(strspec)) - return git_index_read_tree(index, tree); - - return git_index_read_tree(index, tree); - -#if 0 - /* The following loads the matches into the index, but doesn't - * erase obsoleted entries (e.g. you load a blob at "a/b" which - * should obsolete a blob at "a/b/c/d" since b is no longer a tree) - */ - - if (git_pathspec_init(&pathspec, strspec, &pathpool) < 0) - return -1; - - pfx = git_pathspec_prefix(strspec); - - if ((error = git_iterator_for_tree_range(&iter, tree, pfx, pfx)) < 0 || - (error = git_iterator_current(iter, &entry)) < 0) - goto cleanup; - - while (entry != NULL) { - if (git_pathspec_match_path( - &pathspec, entry->path, false, false, NULL) && - (error = git_index_add(index, entry)) < 0) - goto cleanup; - - if ((error = git_iterator_advance(iter, &entry)) < 0) - goto cleanup; - } - -cleanup: - git_iterator_free(iter); - git_pathspec_free(&pathspec); - git_pool_clear(&pathpool); - git__free(pfx); - - return error; -#endif -} diff --git a/src/index.h b/src/index.h index 2beaa6375..9498907b6 100644 --- a/src/index.h +++ b/src/index.h @@ -50,7 +50,4 @@ extern int git_index_entry__cmp_icase(const void *a, const void *b); extern void git_index__set_ignore_case(git_index *index, bool ignore_case); -extern int git_index_read_tree_match( - git_index *index, git_tree *tree, git_strarray *strspec); - #endif diff --git a/src/iterator.c b/src/iterator.c index 8ad639d6b..2832e4ac2 100644 --- a/src/iterator.c +++ b/src/iterator.c @@ -14,13 +14,16 @@ #define ITERATOR_SET_CB(P,NAME_LC) do { \ (P)->cb.current = NAME_LC ## _iterator__current; \ - (P)->cb.at_end = NAME_LC ## _iterator__at_end; \ (P)->cb.advance = NAME_LC ## _iterator__advance; \ (P)->cb.seek = NAME_LC ## _iterator__seek; \ (P)->cb.reset = NAME_LC ## _iterator__reset; \ + (P)->cb.at_end = NAME_LC ## _iterator__at_end; \ (P)->cb.free = NAME_LC ## _iterator__free; \ } while (0) +#define ITERATOR_CASE_FLAGS \ + (GIT_ITERATOR_IGNORE_CASE | GIT_ITERATOR_DONT_IGNORE_CASE) + #define ITERATOR_BASE_INIT(P,NAME_LC,NAME_UC) do { \ (P) = git__calloc(1, sizeof(NAME_LC ## _iterator)); \ GITERR_CHECK_ALLOC(P); \ @@ -32,8 +35,17 @@ if ((start && !(P)->base.start) || (end && !(P)->base.end)) { \ git__free(P); return -1; } \ (P)->base.prefixcomp = git__prefixcmp; \ + (P)->base.flags = flags & ~ITERATOR_CASE_FLAGS; \ } while (0) +#define iterator__flag(I,F) ((((git_iterator *)(I))->flags & (F)) != 0) +#define iterator__ignore_case(I) iterator__flag(I,GIT_ITERATOR_IGNORE_CASE) + +#define iterator__end(I) ((git_iterator *)(I))->end +#define iterator__past_end(I,PATH) \ + (iterator__end(I) && ((git_iterator *)(I))->prefixcomp((PATH),iterator__end(I)) > 0) + + static int iterator__reset_range( git_iterator *iter, const char *start, const char *end) { @@ -82,18 +94,13 @@ static int iterator_update_ignore_case( return error; } -static int empty_iterator__no_item( - git_iterator *iter, const git_index_entry **entry) -{ - GIT_UNUSED(iter); - *entry = NULL; - return 0; -} -static int empty_iterator__at_end(git_iterator *iter) +static int empty_iterator__noop( + const git_index_entry **entry, git_iterator *iter) { GIT_UNUSED(iter); - return 1; + if (entry) *entry = NULL; + return 0; } static int empty_iterator__reset( @@ -109,6 +116,12 @@ static int empty_iterator__seek(git_iterator *iter, const char *prefix) return -1; } +static int empty_iterator__at_end(git_iterator *iter) +{ + GIT_UNUSED(iter); + return 1; +} + static void empty_iterator__free(git_iterator *iter) { GIT_UNUSED(iter); @@ -119,20 +132,22 @@ typedef struct { git_iterator_callbacks cb; } empty_iterator; -int git_iterator_for_nothing(git_iterator **iter, git_iterator_flag_t flags) +int git_iterator_for_nothing( + git_iterator **iter, + git_iterator_flag_t flags, + const char *start, + const char *end) { empty_iterator *i = git__calloc(1, sizeof(empty_iterator)); GITERR_CHECK_ALLOC(i); - i->base.type = GIT_ITERATOR_TYPE_EMPTY; - i->base.cb = &i->cb; - i->base.flags = flags; - i->cb.current = empty_iterator__no_item; - i->cb.at_end = empty_iterator__at_end; - i->cb.advance = empty_iterator__no_item; - i->cb.seek = empty_iterator__seek; - i->cb.reset = empty_iterator__reset; - i->cb.free = empty_iterator__free; +#define empty_iterator__current empty_iterator__noop +#define empty_iterator__advance empty_iterator__noop + + ITERATOR_BASE_INIT(i, empty, EMPTY); + + if ((flags & GIT_ITERATOR_IGNORE_CASE) != 0) + i->base.flags |= GIT_ITERATOR_IGNORE_CASE; *iter = (git_iterator *)i; @@ -144,9 +159,10 @@ typedef struct tree_iterator_frame tree_iterator_frame; struct tree_iterator_frame { tree_iterator_frame *next, *prev; git_tree *tree; - char *start; + const char *start; size_t startlen; size_t index; + /* secondary tree index for case-insensitive sort */ void **icase_map; void *icase_data[GIT_FLEX_ARRAY]; }; @@ -163,12 +179,15 @@ typedef struct { GIT_INLINE(const git_tree_entry *)tree_iterator__tree_entry(tree_iterator *ti) { tree_iterator_frame *tf = ti->stack; + size_t entries = git_tree_entrycount(tf->tree), idx = tf->index; - if (tf->index >= git_tree_entrycount(tf->tree)) + if (idx >= entries) return NULL; - return git_tree_entry_byindex( - tf->tree, tf->icase_map ? (size_t)tf->icase_map[tf->index] : tf->index); + if (tf->icase_map) + idx = (size_t)tf->icase_map[idx]; + + return git_tree_entry_byindex(tf->tree, idx); } static char *tree_iterator__current_filename( @@ -218,7 +237,7 @@ static int tree_iterator__to_end(tree_iterator *ti) } static int tree_iterator__current( - git_iterator *self, const git_index_entry **entry) + const git_index_entry **entry, git_iterator *self) { tree_iterator *ti = (tree_iterator *)self; const git_tree_entry *te = tree_iterator__tree_entry(ti); @@ -236,7 +255,7 @@ static int tree_iterator__current( if (ti->entry.path == NULL) return -1; - if (ti->base.end && ti->base.prefixcomp(ti->entry.path, ti->base.end) > 0) + if (iterator__past_end(ti, ti->entry.path)) return tree_iterator__to_end(ti); if (entry) @@ -290,26 +309,35 @@ static void tree_iterator__frame_seek_start(tree_iterator_frame *tf) } } -static tree_iterator_frame *tree_iterator__alloc_frame( - tree_iterator *ti, git_tree *tree, char *start) +static int tree_iterator__push_frame( + tree_iterator *ti, git_tree *tree, const char *start) { size_t i, max_i = git_tree_entrycount(tree); tree_iterator_frame *tf = git__calloc(1, sizeof(tree_iterator_frame) + max_i * sizeof(void *)); - if (!tf) - return NULL; + GITERR_CHECK_ALLOC(tf); - tf->tree = tree; + tf->tree = tree; + + tf->next = ti->stack; + ti->stack = tf; + if (tf->next) + tf->next->prev = tf; + else + ti->tail = tf; if (start && *start) { - tf->start = start; + tf->start = start; tf->startlen = strlen(start); } + ti->path_has_filename = false; + if (!max_i) - return tf; + return 0; - if ((ti->base.flags & GIT_ITERATOR_IGNORE_CASE) != 0) { + /* build secondary index if iterator is case-insensitive */ + if (iterator__ignore_case(ti)) { tf->icase_map = tf->icase_data; for (i = 0; i < max_i; ++i) @@ -321,7 +349,7 @@ static tree_iterator_frame *tree_iterator__alloc_frame( tree_iterator__frame_seek_start(tf); - return tf; + return 0; } static int tree_iterator__expand_tree(tree_iterator *ti) @@ -329,16 +357,13 @@ static int tree_iterator__expand_tree(tree_iterator *ti) int error; git_tree *subtree; const git_tree_entry *te = tree_iterator__tree_entry(ti); - tree_iterator_frame *tf; - char *relpath; + const char *relpath; while (te != NULL && git_tree_entry__is_tree(te)) { - if (git_buf_joinpath(&ti->path, ti->path.ptr, te->filename) < 0) - return -1; + relpath = tree_iterator__current_filename(ti, te); /* check that we have not passed the range end */ - if (ti->base.end != NULL && - ti->base.prefixcomp(ti->path.ptr, ti->base.end) > 0) + if (iterator__past_end(ti, relpath)) return tree_iterator__to_end(ti); if ((error = git_tree_lookup(&subtree, ti->base.repo, &te->oid)) < 0) @@ -354,12 +379,8 @@ static int tree_iterator__expand_tree(tree_iterator *ti) relpath = ti->stack->start + te->filename_len + 1; } - if ((tf = tree_iterator__alloc_frame(ti, subtree, relpath)) == NULL) - return -1; - - tf->next = ti->stack; - ti->stack = tf; - tf->next->prev = tf; + if ((error = tree_iterator__push_frame(ti, subtree, relpath)) < 0) + return error; te = tree_iterator__tree_entry(ti); } @@ -368,9 +389,8 @@ static int tree_iterator__expand_tree(tree_iterator *ti) } static int tree_iterator__advance( - git_iterator *self, const git_index_entry **entry) + const git_index_entry **entry, git_iterator *self) { - int error = 0; tree_iterator *ti = (tree_iterator *)self; const git_tree_entry *te = NULL; @@ -394,13 +414,13 @@ static int tree_iterator__advance( git_buf_rtruncate_at_char(&ti->path, '/'); } - if (te && git_tree_entry__is_tree(te)) - error = tree_iterator__expand_tree(ti); - - if (!error) - error = tree_iterator__current(self, entry); + if (te && git_tree_entry__is_tree(te)) { + int error = tree_iterator__expand_tree(ti); + if (error < 0) + return error; + } - return error; + return tree_iterator__current(entry, self); } static int tree_iterator__seek(git_iterator *self, const char *prefix) @@ -444,7 +464,7 @@ static int tree_iterator__reset( return tree_iterator__expand_tree(ti); } -int git_iterator_for_tree_range( +int git_iterator_for_tree( git_iterator **iter, git_tree *tree, git_iterator_flag_t flags, @@ -455,7 +475,7 @@ int git_iterator_for_tree_range( tree_iterator *ti; if (tree == NULL) - return git_iterator_for_nothing(iter, flags); + return git_iterator_for_nothing(iter, flags, start, end); if ((error = git_tree__dup(&tree, tree)) < 0) return error; @@ -464,11 +484,10 @@ int git_iterator_for_tree_range( ti->base.repo = git_tree_owner(tree); - if ((error = iterator_update_ignore_case((git_iterator *)ti, flags)) < 0) + if ((error = iterator_update_ignore_case((git_iterator *)ti, flags)) < 0 || + (error = tree_iterator__push_frame(ti, tree, ti->base.start)) < 0) goto fail; - ti->stack = ti->tail = tree_iterator__alloc_frame(ti, tree, ti->base.start); - if ((error = tree_iterator__expand_tree(ti)) < 0) goto fail; @@ -489,7 +508,7 @@ typedef struct { } index_iterator; static int index_iterator__current( - git_iterator *self, const git_index_entry **entry) + const git_index_entry **entry, git_iterator *self) { index_iterator *ii = (index_iterator *)self; const git_index_entry *ie = git_index_get_byindex(ii->index, ii->current); @@ -506,18 +525,15 @@ static int index_iterator__at_end(git_iterator *self) return (ii->current >= git_index_entrycount(ii->index)); } -static void index_iterator__skip_conflicts( - index_iterator *ii) +static void index_iterator__skip_conflicts(index_iterator *ii) { size_t entrycount = git_index_entrycount(ii->index); - const git_index_entry *ie; + const git_index_entry *ie = NULL; while (ii->current < entrycount) { ie = git_index_get_byindex(ii->index, ii->current); - if (ie == NULL || - (ii->base.end != NULL && - ii->base.prefixcomp(ie->path, ii->base.end) > 0)) { + if (ie != NULL && iterator__past_end(ii, ie->path)) { ii->current = entrycount; break; } @@ -530,7 +546,7 @@ static void index_iterator__skip_conflicts( } static int index_iterator__advance( - git_iterator *self, const git_index_entry **entry) + const git_index_entry **entry, git_iterator *self) { index_iterator *ii = (index_iterator *)self; @@ -539,7 +555,7 @@ static int index_iterator__advance( index_iterator__skip_conflicts(ii); - return index_iterator__current(self, entry); + return index_iterator__current(entry, self); } static int index_iterator__seek(git_iterator *self, const char *prefix) @@ -554,11 +570,15 @@ static int index_iterator__reset( git_iterator *self, const char *start, const char *end) { index_iterator *ii = (index_iterator *)self; + if (iterator__reset_range(self, start, end) < 0) return -1; + ii->current = ii->base.start ? git_index__prefix_position(ii->index, ii->base.start) : 0; + index_iterator__skip_conflicts(ii); + return 0; } @@ -569,7 +589,7 @@ static void index_iterator__free(git_iterator *self) ii->index = NULL; } -int git_iterator_for_index_range( +int git_iterator_for_index( git_iterator **iter, git_index *index, git_iterator_flag_t flags, @@ -583,10 +603,12 @@ int git_iterator_for_index_range( ITERATOR_BASE_INIT(ii, index, INDEX); ii->base.repo = git_index_owner(index); + if (index->ignore_case) { ii->base.flags |= GIT_ITERATOR_IGNORE_CASE; ii->base.prefixcomp = git__prefixcmp_icase; } + ii->index = index; GIT_REFCOUNT_INC(index); @@ -643,7 +665,7 @@ static workdir_iterator_frame *workdir_iterator__alloc_frame( { workdir_iterator_frame *wf = git__calloc(1, sizeof(workdir_iterator_frame)); git_vector_cmp entry_compare = CASESELECT( - (wi->base.flags & GIT_ITERATOR_IGNORE_CASE) != 0, + iterator__ignore_case(wi), git_path_with_stat_cmp_icase, git_path_with_stat_cmp); if (wf == NULL) @@ -706,7 +728,7 @@ static int workdir_iterator__expand_dir(workdir_iterator *wi) error = git_path_dirload_with_stat( wi->path.ptr, wi->root_len, - (wi->base.flags & GIT_ITERATOR_IGNORE_CASE) != 0, + iterator__ignore_case(wi), wi->base.start, wi->base.end, &wf->entries); if (error < 0 || wf->entries.length == 0) { @@ -729,10 +751,11 @@ static int workdir_iterator__expand_dir(workdir_iterator *wi) } static int workdir_iterator__current( - git_iterator *self, const git_index_entry **entry) + const git_index_entry **entry, git_iterator *self) { workdir_iterator *wi = (workdir_iterator *)self; - *entry = (wi->entry.path == NULL) ? NULL : &wi->entry; + if (entry) + *entry = (wi->entry.path == NULL) ? NULL : &wi->entry; return 0; } @@ -742,7 +765,7 @@ static int workdir_iterator__at_end(git_iterator *self) } static int workdir_iterator__advance( - git_iterator *self, const git_index_entry **entry) + const git_index_entry **entry, git_iterator *self) { int error; workdir_iterator *wi = (workdir_iterator *)self; @@ -781,7 +804,7 @@ static int workdir_iterator__advance( error = workdir_iterator__update_entry(wi); if (!error && entry != NULL) - error = workdir_iterator__current(self, entry); + error = workdir_iterator__current(entry, self); return error; } @@ -832,6 +855,7 @@ static void workdir_iterator__free(git_iterator *self) static int workdir_iterator__update_entry(workdir_iterator *wi) { + int error = 0; git_path_with_stat *ps = git_vector_get(&wi->stack->entries, wi->stack->index); @@ -841,19 +865,18 @@ static int workdir_iterator__update_entry(workdir_iterator *wi) if (!ps) return 0; + /* skip over .git entries */ + if (path_is_dotgit(ps)) + return workdir_iterator__advance(NULL, (git_iterator *)wi); + if (git_buf_put(&wi->path, ps->path, ps->path_len) < 0) return -1; - if (wi->base.end && - wi->base.prefixcomp(wi->path.ptr + wi->root_len, wi->base.end) > 0) + if (iterator__past_end(wi, wi->path.ptr + wi->root_len)) return 0; wi->entry.path = ps->path; - /* skip over .git entries */ - if (path_is_dotgit(ps)) - return workdir_iterator__advance((git_iterator *)wi, NULL); - wi->is_ignored = -1; git_index_entry__init_from_stat(&wi->entry, &ps->st); @@ -867,26 +890,28 @@ static int workdir_iterator__update_entry(workdir_iterator *wi) return 0; } + /* if this isn't a tree, then we're done */ + if (wi->entry.mode != GIT_FILEMODE_TREE) + return 0; + /* detect submodules */ - if (S_ISDIR(wi->entry.mode)) { - int res = git_submodule_lookup(NULL, wi->base.repo, wi->entry.path); - bool is_submodule = (res == 0); - if (res == GIT_ENOTFOUND) - giterr_clear(); - - /* if submodule, mark as GITLINK and remove trailing slash */ - if (is_submodule) { - size_t len = strlen(wi->entry.path); - assert(wi->entry.path[len - 1] == '/'); - wi->entry.path[len - 1] = '\0'; - wi->entry.mode = S_IFGITLINK; - } + + error = git_submodule_lookup(NULL, wi->base.repo, wi->entry.path); + if (error == GIT_ENOTFOUND) + giterr_clear(); + + /* if submodule, mark as GITLINK and remove trailing slash */ + if (!error) { + size_t len = strlen(wi->entry.path); + assert(wi->entry.path[len - 1] == '/'); + wi->entry.path[len - 1] = '\0'; + wi->entry.mode = S_IFGITLINK; } return 0; } -int git_iterator_for_workdir_range( +int git_iterator_for_workdir( git_iterator **iter, git_repository *repo, git_iterator_flag_t flags, @@ -917,7 +942,7 @@ int git_iterator_for_workdir_range( } wi->root_len = wi->path.size; - wi->entrycmp = (wi->base.flags & GIT_ITERATOR_IGNORE_CASE) != 0 ? + wi->entrycmp = iterator__ignore_case(wi) ? workdir_iterator__entry_cmp_icase : workdir_iterator__entry_cmp_case; if ((error = workdir_iterator__expand_dir(wi)) < 0) { @@ -949,7 +974,7 @@ typedef struct { } spoolandsort_callbacks; static int spoolandsort_iterator__current( - git_iterator *self, const git_index_entry **entry) + const git_index_entry **entry, git_iterator *self) { spoolandsort_callbacks *scb = (spoolandsort_callbacks *)self->cb; @@ -967,7 +992,7 @@ static int spoolandsort_iterator__at_end(git_iterator *self) } static int spoolandsort_iterator__advance( - git_iterator *self, const git_index_entry **entry) + const git_index_entry **entry, git_iterator *self) { spoolandsort_callbacks *scb = (spoolandsort_callbacks *)self->cb; @@ -1053,7 +1078,7 @@ int git_iterator_spoolandsort_push(git_iterator *iter, bool ignore_case) if (git_vector_init(&scb->entries, 16, entrycomp) < 0 || git_pool_init(&scb->entry_pool, sizeof(git_index_entry), 0) < 0 || git_pool_init(&scb->string_pool, 1, 0) < 0 || - git_iterator_current(iter, &item) < 0) + git_iterator_current(&item, iter) < 0) goto fail; while (item) { @@ -1072,7 +1097,7 @@ int git_iterator_spoolandsort_push(git_iterator *iter, bool ignore_case) if (git_vector_insert(&scb->entries, clone) < 0) goto fail; - if (git_iterator_advance(iter, &item) < 0) + if (git_iterator_advance(&item, iter) < 0) goto fail; } @@ -1105,7 +1130,7 @@ void git_iterator_free(git_iterator *iter) git__free(iter); } -git_index *git_iterator_index_get_index(git_iterator *iter) +git_index *git_iterator_get_index(git_iterator *iter) { if (iter->type == GIT_ITERATOR_TYPE_INDEX) return ((index_iterator *)iter)->index; @@ -1126,7 +1151,7 @@ git_iterator_type_t git_iterator_inner_type(git_iterator *iter) } int git_iterator_current_tree_entry( - git_iterator *iter, const git_tree_entry **tree_entry) + const git_tree_entry **tree_entry, git_iterator *iter) { *tree_entry = (iter->type != GIT_ITERATOR_TYPE_TREE) ? NULL : tree_iterator__tree_entry((tree_iterator *)iter); @@ -1134,9 +1159,9 @@ int git_iterator_current_tree_entry( } int git_iterator_current_parent_tree( + const git_tree **tree_ptr, git_iterator *iter, - const char *parent_path, - const git_tree **tree_ptr) + const char *parent_path) { tree_iterator *ti = (tree_iterator *)iter; tree_iterator_frame *tf; @@ -1177,24 +1202,24 @@ notfound: return 0; } -int git_iterator_current_is_ignored(git_iterator *iter) +bool git_iterator_current_is_ignored(git_iterator *iter) { workdir_iterator *wi = (workdir_iterator *)iter; if (iter->type != GIT_ITERATOR_TYPE_WORKDIR) - return 0; + return false; if (wi->is_ignored != -1) - return wi->is_ignored; + return (bool)(wi->is_ignored != 0); if (git_ignore__lookup(&wi->ignores, wi->entry.path, &wi->is_ignored) < 0) - wi->is_ignored = 1; + wi->is_ignored = true; - return wi->is_ignored; + return (bool)wi->is_ignored; } -int git_iterator_advance_into_directory( - git_iterator *iter, const git_index_entry **entry) +int git_iterator_advance_into( + const git_index_entry **entry, git_iterator *iter) { workdir_iterator *wi = (workdir_iterator *)iter; @@ -1205,10 +1230,10 @@ int git_iterator_advance_into_directory( { if (workdir_iterator__expand_dir(wi) < 0) /* if error loading or if empty, skip the directory. */ - return workdir_iterator__advance(iter, entry); + return workdir_iterator__advance(entry, iter); } - return entry ? git_iterator_current(iter, entry) : 0; + return entry ? git_iterator_current(entry, iter) : 0; } int git_iterator_cmp(git_iterator *iter, const char *path_prefix) @@ -1216,7 +1241,7 @@ int git_iterator_cmp(git_iterator *iter, const char *path_prefix) const git_index_entry *entry; /* a "done" iterator is after every prefix */ - if (git_iterator_current(iter, &entry) < 0 || + if (git_iterator_current(&entry, iter) < 0 || entry == NULL) return 1; @@ -1227,7 +1252,7 @@ int git_iterator_cmp(git_iterator *iter, const char *path_prefix) return iter->prefixcomp(entry->path, path_prefix); } -int git_iterator_current_workdir_path(git_iterator *iter, git_buf **path) +int git_iterator_current_workdir_path(git_buf **path, git_iterator *iter) { workdir_iterator *wi = (workdir_iterator *)iter; diff --git a/src/iterator.h b/src/iterator.h index a9bccfca8..feb0c2271 100644 --- a/src/iterator.h +++ b/src/iterator.h @@ -12,11 +12,6 @@ #include "vector.h" #include "buffer.h" -#define ITERATOR_PREFIXCMP(ITER, STR, PREFIX) \ - (((ITER).flags & GIT_ITERATOR_IGNORE_CASE) != 0 ? \ - git__prefixcmp_icase((STR), (PREFIX)) : \ - git__prefixcmp((STR), (PREFIX))) - typedef struct git_iterator git_iterator; typedef enum { @@ -28,16 +23,18 @@ typedef enum { } git_iterator_type_t; typedef enum { - GIT_ITERATOR_IGNORE_CASE = (1 << 0), /* ignore_case */ - GIT_ITERATOR_DONT_IGNORE_CASE = (1 << 1), /* force ignore_case off */ + /** ignore case for entry sort order */ + GIT_ITERATOR_IGNORE_CASE = (1 << 0), + /** force case sensitivity for entry sort order */ + GIT_ITERATOR_DONT_IGNORE_CASE = (1 << 1), } git_iterator_flag_t; typedef struct { - int (*current)(git_iterator *, const git_index_entry **); - int (*at_end)(git_iterator *); - int (*advance)(git_iterator *, const git_index_entry **); + int (*current)(const git_index_entry **, git_iterator *); + int (*advance)(const git_index_entry **, git_iterator *); int (*seek)(git_iterator *, const char *prefix); int (*reset)(git_iterator *, const char *start, const char *end); + int (*at_end)(git_iterator *); void (*free)(git_iterator *); } git_iterator_callbacks; @@ -52,53 +49,41 @@ struct git_iterator { }; extern int git_iterator_for_nothing( - git_iterator **out, git_iterator_flag_t flags); + git_iterator **out, + git_iterator_flag_t flags, + const char *start, + const char *end); /* tree iterators will match the ignore_case value from the index of the * repository, unless you override with a non-zero flag value */ -extern int git_iterator_for_tree_range( +extern int git_iterator_for_tree( git_iterator **out, git_tree *tree, git_iterator_flag_t flags, const char *start, const char *end); -GIT_INLINE(int) git_iterator_for_tree(git_iterator **out, git_tree *tree) -{ - return git_iterator_for_tree_range(out, tree, 0, NULL, NULL); -} - /* index iterators will take the ignore_case value from the index; the * ignore_case flags are not used */ -extern int git_iterator_for_index_range( +extern int git_iterator_for_index( git_iterator **out, git_index *index, git_iterator_flag_t flags, const char *start, const char *end); -GIT_INLINE(int) git_iterator_for_index(git_iterator **out, git_index *index) -{ - return git_iterator_for_index_range(out, index, 0, NULL, NULL); -} - /* workdir iterators will match the ignore_case value from the index of the * repository, unless you override with a non-zero flag value */ -extern int git_iterator_for_workdir_range( +extern int git_iterator_for_workdir( git_iterator **out, git_repository *repo, git_iterator_flag_t flags, const char *start, const char *end); -GIT_INLINE(int) git_iterator_for_workdir(git_iterator **out, git_repository *repo) -{ - return git_iterator_for_workdir_range(out, repo, 0, NULL, NULL); -} - extern void git_iterator_free(git_iterator *iter); /* Spool all iterator values, resort with alternative ignore_case value @@ -109,29 +94,27 @@ extern int git_iterator_spoolandsort_push(git_iterator *iter, bool ignore_case); /* Restore original callbacks - not required in most circumstances */ extern void git_iterator_spoolandsort_pop(git_iterator *iter); -/* Entry is not guaranteed to be fully populated. For a tree iterator, - * we will only populate the mode, oid and path, for example. For a workdir - * iterator, we will not populate the oid. +/* Return a git_index_entry structure for the current value the iterator + * is looking at or NULL if the iterator is at the end. + * + * The entry may noy be fully populated. Tree iterators will only have a + * value mode, OID, and path. Workdir iterators will not have an OID (but + * you can use `git_iterator_current_oid()` to calculate it on demand). * * You do not need to free the entry. It is still "owned" by the iterator. - * Once you call `git_iterator_advance`, then content of the old entry is - * no longer guaranteed to be valid. + * Once you call `git_iterator_advance()` then the old entry is no longer + * guaranteed to be valid - it may be freed or just overwritten in place. */ GIT_INLINE(int) git_iterator_current( - git_iterator *iter, const git_index_entry **entry) -{ - return iter->cb->current(iter, entry); -} - -GIT_INLINE(int) git_iterator_at_end(git_iterator *iter) + const git_index_entry **entry, git_iterator *iter) { - return iter->cb->at_end(iter); + return iter->cb->current(entry, iter); } GIT_INLINE(int) git_iterator_advance( - git_iterator *iter, const git_index_entry **entry) + const git_index_entry **entry, git_iterator *iter) { - return iter->cb->advance(iter, entry); + return iter->cb->advance(entry, iter); } GIT_INLINE(int) git_iterator_seek( @@ -146,6 +129,11 @@ GIT_INLINE(int) git_iterator_reset( return iter->cb->reset(iter, start, end); } +GIT_INLINE(int) git_iterator_at_end(git_iterator *iter) +{ + return iter->cb->at_end(iter); +} + GIT_INLINE(git_iterator_type_t) git_iterator_type(git_iterator *iter) { return iter->type; @@ -167,15 +155,15 @@ GIT_INLINE(bool) git_iterator_ignore_case(git_iterator *iter) } extern int git_iterator_current_tree_entry( - git_iterator *iter, const git_tree_entry **tree_entry); + const git_tree_entry **tree_entry, git_iterator *iter); extern int git_iterator_current_parent_tree( - git_iterator *iter, const char *parent_path, const git_tree **tree_ptr); + const git_tree **tree_ptr, git_iterator *iter, const char *parent_path); -extern int git_iterator_current_is_ignored(git_iterator *iter); +extern bool git_iterator_current_is_ignored(git_iterator *iter); /** - * Iterate into a workdir directory. + * Iterate into a directory. * * Workdir iterators do not automatically descend into directories (so that * when comparing two iterator entries you can detect a newly created @@ -191,21 +179,22 @@ extern int git_iterator_current_is_ignored(git_iterator *iter); * On non-workdir iterators or if not pointing at a directory, this is a * no-op and will not advance the iterator. */ -extern int git_iterator_advance_into_directory( - git_iterator *iter, const git_index_entry **entry); +extern int git_iterator_advance_into( + const git_index_entry **entry, git_iterator *iter); extern int git_iterator_cmp( git_iterator *iter, const char *path_prefix); /** - * Get the full path of the current item from a workdir iterator. - * This will return NULL for a non-workdir iterator. + * Get full path of the current item from a workdir iterator. This will + * return NULL for a non-workdir iterator. The git_buf is still owned by + * the iterator; this is exposed just for efficiency. */ extern int git_iterator_current_workdir_path( - git_iterator *iter, git_buf **path); - + git_buf **path, git_iterator *iter); -extern git_index *git_iterator_index_get_index(git_iterator *iter); +/* Return index pointer if index iterator, else NULL */ +extern git_index *git_iterator_get_index(git_iterator *iter); extern git_iterator_type_t git_iterator_inner_type(git_iterator *iter); diff --git a/src/notes.c b/src/notes.c index a1a47d989..ef48ac88e 100644 --- a/src/notes.c +++ b/src/notes.c @@ -625,7 +625,7 @@ int git_note_iterator_new( if (error < 0) goto cleanup; - if ((error = git_iterator_for_tree(it, tree)) < 0) + if ((error = git_iterator_for_tree(it, tree, 0, NULL, NULL)) < 0) git_iterator_free(*it); cleanup: @@ -643,7 +643,7 @@ int git_note_next( int error; const git_index_entry *item; - if ((error = git_iterator_current(it, &item)) < 0) + if ((error = git_iterator_current(&item, it)) < 0) goto exit; if (item != NULL) { @@ -651,7 +651,7 @@ int git_note_next( error = process_entry_path(item->path, annotated_id); if (error >= 0) - error = git_iterator_advance(it, NULL); + error = git_iterator_advance(NULL, it); } else { error = GIT_ITEROVER; } diff --git a/src/submodule.c b/src/submodule.c index 359306498..c02061376 100644 --- a/src/submodule.c +++ b/src/submodule.c @@ -1135,10 +1135,10 @@ static int load_submodule_config_from_index( const git_index_entry *entry; if ((error = git_repository_index__weakptr(&index, repo)) < 0 || - (error = git_iterator_for_index(&i, index)) < 0) + (error = git_iterator_for_index(&i, index, 0, NULL, NULL)) < 0) return error; - error = git_iterator_current(i, &entry); + error = git_iterator_current(&entry, i); while (!error && entry != NULL) { @@ -1154,7 +1154,7 @@ static int load_submodule_config_from_index( git_oid_cpy(gitmodules_oid, &entry->oid); } - error = git_iterator_advance(i, &entry); + error = git_iterator_advance(&entry, i); } git_iterator_free(i); @@ -1173,12 +1173,12 @@ static int load_submodule_config_from_head( if ((error = git_repository_head_tree(&head, repo)) < 0) return error; - if ((error = git_iterator_for_tree(&i, head)) < 0) { + if ((error = git_iterator_for_tree(&i, head, 0, NULL, NULL)) < 0) { git_tree_free(head); return error; } - error = git_iterator_current(i, &entry); + error = git_iterator_current(&entry, i); while (!error && entry != NULL) { @@ -1195,7 +1195,7 @@ static int load_submodule_config_from_head( git_oid_cpy(gitmodules_oid, &entry->oid); } - error = git_iterator_advance(i, &entry); + error = git_iterator_advance(&entry, i); } git_iterator_free(i); diff --git a/tests-clar/diff/iterator.c b/tests-clar/diff/iterator.c index efdadbf1f..546f68abe 100644 --- a/tests-clar/diff/iterator.c +++ b/tests-clar/diff/iterator.c @@ -35,26 +35,26 @@ static void tree_iterator_test( git_repository *repo = cl_git_sandbox_init(sandbox); cl_assert(t = resolve_commit_oid_to_tree(repo, treeish)); - cl_git_pass(git_iterator_for_tree_range( + cl_git_pass(git_iterator_for_tree( &i, t, GIT_ITERATOR_DONT_IGNORE_CASE, start, end)); /* test loop */ - cl_git_pass(git_iterator_current(i, &entry)); + cl_git_pass(git_iterator_current(&entry, i)); while (entry != NULL) { if (expected_values != NULL) cl_assert_equal_s(expected_values[count], entry->path); count++; - cl_git_pass(git_iterator_advance(i, &entry)); + cl_git_pass(git_iterator_advance(&entry, i)); } /* test reset */ cl_git_pass(git_iterator_reset(i, NULL, NULL)); - cl_git_pass(git_iterator_current(i, &entry)); + cl_git_pass(git_iterator_current(&entry, i)); while (entry != NULL) { if (expected_values != NULL) cl_assert_equal_s(expected_values[count_post_reset], entry->path); count_post_reset++; - cl_git_pass(git_iterator_advance(i, &entry)); + cl_git_pass(git_iterator_advance(&entry, i)); } git_iterator_free(i); @@ -261,30 +261,30 @@ static void check_tree_entry( const git_tree *tree; git_buf path = GIT_BUF_INIT; - cl_git_pass(git_iterator_current_tree_entry(i, &te)); + cl_git_pass(git_iterator_current_tree_entry(&te, i)); cl_assert(te); cl_assert(git_oid_streq(&te->oid, oid) == 0); - cl_git_pass(git_iterator_current(i, &ie)); + cl_git_pass(git_iterator_current(&ie, i)); cl_git_pass(git_buf_sets(&path, ie->path)); if (oid_p) { git_buf_rtruncate_at_char(&path, '/'); - cl_git_pass(git_iterator_current_parent_tree(i, path.ptr, &tree)); + cl_git_pass(git_iterator_current_parent_tree(&tree, i, path.ptr)); cl_assert(tree); cl_assert(git_oid_streq(git_tree_id(tree), oid_p) == 0); } if (oid_pp) { git_buf_rtruncate_at_char(&path, '/'); - cl_git_pass(git_iterator_current_parent_tree(i, path.ptr, &tree)); + cl_git_pass(git_iterator_current_parent_tree(&tree, i, path.ptr)); cl_assert(tree); cl_assert(git_oid_streq(git_tree_id(tree), oid_pp) == 0); } if (oid_ppp) { git_buf_rtruncate_at_char(&path, '/'); - cl_git_pass(git_iterator_current_parent_tree(i, path.ptr, &tree)); + cl_git_pass(git_iterator_current_parent_tree(&tree, i, path.ptr)); cl_assert(tree); cl_assert(git_oid_streq(git_tree_id(tree), oid_ppp) == 0); } @@ -305,9 +305,9 @@ void test_diff_iterator__tree_special_functions(void) repo, "24fa9a9fc4e202313e24b648087495441dab432b"); cl_assert(t != NULL); - cl_git_pass(git_iterator_for_tree_range( + cl_git_pass(git_iterator_for_tree( &i, t, GIT_ITERATOR_DONT_IGNORE_CASE, NULL, NULL)); - cl_git_pass(git_iterator_current(i, &entry)); + cl_git_pass(git_iterator_current(&entry, i)); while (entry != NULL) { if (strcmp(entry->path, "sub/file") == 0) { @@ -339,7 +339,7 @@ void test_diff_iterator__tree_special_functions(void) rootoid, NULL); } - cl_git_pass(git_iterator_advance(i, &entry)); + cl_git_pass(git_iterator_advance(&entry, i)); } cl_assert_equal_i(4, cases); @@ -364,8 +364,8 @@ static void index_iterator_test( git_repository *repo = cl_git_sandbox_init(sandbox); cl_git_pass(git_repository_index(&index, repo)); - cl_git_pass(git_iterator_for_index_range(&i, index, 0, start, end)); - cl_git_pass(git_iterator_current(i, &entry)); + cl_git_pass(git_iterator_for_index(&i, index, 0, start, end)); + cl_git_pass(git_iterator_current(&entry, i)); while (entry != NULL) { if (expected_names != NULL) @@ -378,7 +378,7 @@ static void index_iterator_test( } count++; - cl_git_pass(git_iterator_advance(i, &entry)); + cl_git_pass(git_iterator_advance(&entry, i)); } git_iterator_free(i); @@ -538,14 +538,14 @@ static void workdir_iterator_test( int count = 0, count_all = 0, count_all_post_reset = 0; git_repository *repo = cl_git_sandbox_init(sandbox); - cl_git_pass(git_iterator_for_workdir_range(&i, repo, 0, start, end)); - cl_git_pass(git_iterator_current(i, &entry)); + cl_git_pass(git_iterator_for_workdir(&i, repo, 0, start, end)); + cl_git_pass(git_iterator_current(&entry, i)); while (entry != NULL) { int ignored = git_iterator_current_is_ignored(i); if (S_ISDIR(entry->mode)) { - cl_git_pass(git_iterator_advance_into_directory(i, &entry)); + cl_git_pass(git_iterator_advance_into(&entry, i)); continue; } @@ -559,22 +559,22 @@ static void workdir_iterator_test( count++; count_all++; - cl_git_pass(git_iterator_advance(i, &entry)); + cl_git_pass(git_iterator_advance(&entry, i)); } cl_git_pass(git_iterator_reset(i, NULL, NULL)); - cl_git_pass(git_iterator_current(i, &entry)); + cl_git_pass(git_iterator_current(&entry, i)); while (entry != NULL) { if (S_ISDIR(entry->mode)) { - cl_git_pass(git_iterator_advance_into_directory(i, &entry)); + cl_git_pass(git_iterator_advance_into(&entry, i)); continue; } if (expected_names != NULL) cl_assert_equal_s( expected_names[count_all_post_reset], entry->path); count_all_post_reset++; - cl_git_pass(git_iterator_advance(i, &entry)); + cl_git_pass(git_iterator_advance(&entry, i)); } git_iterator_free(i); @@ -736,8 +736,8 @@ void test_diff_iterator__workdir_builtin_ignores(void) cl_git_mkfile("attr/sub/.git", "whatever"); cl_git_pass( - git_iterator_for_workdir_range(&i, repo, 0, "dir", "sub/sub/file")); - cl_git_pass(git_iterator_current(i, &entry)); + git_iterator_for_workdir(&i, repo, 0, "dir", "sub/sub/file")); + cl_git_pass(git_iterator_current(&entry, i)); for (idx = 0; entry != NULL; ++idx) { int ignored = git_iterator_current_is_ignored(i); @@ -746,9 +746,9 @@ void test_diff_iterator__workdir_builtin_ignores(void) cl_assert_(ignored == expected[idx].ignored, expected[idx].path); if (!ignored && S_ISDIR(entry->mode)) - cl_git_pass(git_iterator_advance_into_directory(i, &entry)); + cl_git_pass(git_iterator_advance_into(&entry, i)); else - cl_git_pass(git_iterator_advance(i, &entry)); + cl_git_pass(git_iterator_advance(&entry, i)); } cl_assert(expected[idx].path == NULL); @@ -764,17 +764,17 @@ static void check_wd_first_through_third_range( int idx; static const char *expected[] = { "FIRST", "second", "THIRD", NULL }; - cl_git_pass(git_iterator_for_workdir_range( + cl_git_pass(git_iterator_for_workdir( &i, repo, GIT_ITERATOR_IGNORE_CASE, start, end)); - cl_git_pass(git_iterator_current(i, &entry)); + cl_git_pass(git_iterator_current(&entry, i)); for (idx = 0; entry != NULL; ++idx) { cl_assert_equal_s(expected[idx], entry->path); if (S_ISDIR(entry->mode)) - cl_git_pass(git_iterator_advance_into_directory(i, &entry)); + cl_git_pass(git_iterator_advance_into(&entry, i)); else - cl_git_pass(git_iterator_advance(i, &entry)); + cl_git_pass(git_iterator_advance(&entry, i)); } cl_assert(expected[idx] == NULL); @@ -817,16 +817,16 @@ static void check_tree_range( cl_git_pass(git_repository_head_tree(&head, repo)); - cl_git_pass(git_iterator_for_tree_range( + cl_git_pass(git_iterator_for_tree( &i, head, ignore_case ? GIT_ITERATOR_IGNORE_CASE : GIT_ITERATOR_DONT_IGNORE_CASE, start, end)); - cl_git_pass(git_iterator_current(i, &entry)); + cl_git_pass(git_iterator_current(&entry, i)); for (count = 0; entry != NULL; ) { ++count; - cl_git_pass(git_iterator_advance(i, &entry)); + cl_git_pass(git_iterator_advance(&entry, i)); } cl_assert_equal_i(expected_count, count); @@ -882,15 +882,15 @@ static void check_index_range( if (ignore_case != is_ignoring_case) cl_git_pass(git_index_set_caps(index, caps ^ GIT_INDEXCAP_IGNORE_CASE)); - cl_git_pass(git_iterator_for_index_range(&i, index, 0, start, end)); + cl_git_pass(git_iterator_for_index(&i, index, 0, start, end)); cl_assert(git_iterator_ignore_case(i) == ignore_case); - cl_git_pass(git_iterator_current(i, &entry)); + cl_git_pass(git_iterator_current(&entry, i)); for (count = 0; entry != NULL; ) { ++count; - cl_git_pass(git_iterator_advance(i, &entry)); + cl_git_pass(git_iterator_advance(&entry, i)); } cl_assert_equal_i(expected_count, count); diff --git a/tests-clar/repo/iterator.c b/tests-clar/repo/iterator.c new file mode 100644 index 000000000..9a3815a03 --- /dev/null +++ b/tests-clar/repo/iterator.c @@ -0,0 +1,210 @@ +#include "clar_libgit2.h" +#include "iterator.h" +#include "repository.h" + +static git_repository *g_repo; + +void test_repo_iterator__initialize(void) +{ + g_repo = cl_git_sandbox_init("icase"); +} + +void test_repo_iterator__cleanup(void) +{ + cl_git_sandbox_cleanup(); + g_repo = NULL; +} + +static void expect_iterator_items( + git_iterator *i, int expected_flat, int expected_total) +{ + const git_index_entry *entry; + int count; + + count = 0; + cl_git_pass(git_iterator_current(&entry, i)); + + while (entry != NULL) { + count++; + + cl_git_pass(git_iterator_advance(&entry, i)); + + if (count > expected_flat) + break; + } + + cl_assert_equal_i(expected_flat, count); + + cl_git_pass(git_iterator_reset(i, NULL, NULL)); + + count = 0; + cl_git_pass(git_iterator_current(&entry, i)); + + while (entry != NULL) { + count++; + + if (entry->mode == GIT_FILEMODE_TREE) + cl_git_pass(git_iterator_advance_into(&entry, i)); + else + cl_git_pass(git_iterator_advance(&entry, i)); + + if (count > expected_total) + break; + } + + cl_assert_equal_i(expected_total, count); +} + +/* Index contents (including pseudotrees): + * + * 0: a 5: F 10: k/ 16: L/ + * 1: B 6: g 11: k/1 17: L/1 + * 2: c 7: H 12: k/a 18: L/a + * 3: D 8: i 13: k/B 19: L/B + * 4: e 9: J 14: k/c 20: L/c + * 15: k/D 21: L/D + * + * 0: B 5: L/ 11: a 16: k/ + * 1: D 6: L/1 12: c 17: k/1 + * 2: F 7: L/B 13: e 18: k/B + * 3: H 8: L/D 14: g 19: k/D + * 4: J 9: L/a 15: i 20: k/a + * 10: L/c 21: k/c + */ + +void test_repo_iterator__index(void) +{ + git_iterator *i; + git_index *index; + + cl_git_pass(git_repository_index(&index, g_repo)); + + /* normal index iteration */ + cl_git_pass(git_iterator_for_index(&i, index, 0, NULL, NULL)); + expect_iterator_items(i, 20, 20); + git_iterator_free(i); + + git_index_free(index); +} + +void test_repo_iterator__index_icase(void) +{ + git_iterator *i; + git_index *index; + unsigned int caps; + + cl_git_pass(git_repository_index(&index, g_repo)); + caps = git_index_caps(index); + + /* force case sensitivity */ + cl_git_pass(git_index_set_caps(index, caps & ~GIT_INDEXCAP_IGNORE_CASE)); + + /* normal index iteration with range */ + cl_git_pass(git_iterator_for_index(&i, index, 0, "c", "k/D")); + expect_iterator_items(i, 7, 7); + git_iterator_free(i); + + cl_git_pass(git_iterator_for_index(&i, index, 0, "k", "k/Z")); + expect_iterator_items(i, 3, 3); + git_iterator_free(i); + + /* force case insensitivity */ + cl_git_pass(git_index_set_caps(index, caps | GIT_INDEXCAP_IGNORE_CASE)); + + /* normal index iteration with range */ + cl_git_pass(git_iterator_for_index(&i, index, 0, "c", "k/D")); + expect_iterator_items(i, 13, 13); + git_iterator_free(i); + + cl_git_pass(git_iterator_for_index(&i, index, 0, "k", "k/Z")); + expect_iterator_items(i, 5, 5); + git_iterator_free(i); + + cl_git_pass(git_index_set_caps(index, caps)); + git_index_free(index); +} + +void test_repo_iterator__tree(void) +{ + git_iterator *i; + git_tree *head; + + cl_git_pass(git_repository_head_tree(&head, g_repo)); + + /* normal tree iteration */ + cl_git_pass(git_iterator_for_tree(&i, head, 0, NULL, NULL)); + expect_iterator_items(i, 20, 20); + git_iterator_free(i); + + git_tree_free(head); +} + +void test_repo_iterator__tree_icase(void) +{ + git_iterator *i; + git_tree *head; + git_iterator_flag_t flag; + + cl_git_pass(git_repository_head_tree(&head, g_repo)); + + flag = GIT_ITERATOR_DONT_IGNORE_CASE; + + /* normal tree iteration with range */ + cl_git_pass(git_iterator_for_tree(&i, head, flag, "c", "k/D")); + expect_iterator_items(i, 7, 7); + git_iterator_free(i); + + cl_git_pass(git_iterator_for_tree(&i, head, flag, "k", "k/Z")); + expect_iterator_items(i, 3, 3); + git_iterator_free(i); + + flag = GIT_ITERATOR_IGNORE_CASE; + + /* normal tree iteration with range */ + cl_git_pass(git_iterator_for_tree(&i, head, flag, "c", "k/D")); + expect_iterator_items(i, 13, 13); + git_iterator_free(i); + + cl_git_pass(git_iterator_for_tree(&i, head, flag, "k", "k/Z")); + expect_iterator_items(i, 5, 5); + git_iterator_free(i); +} + +void test_repo_iterator__workdir(void) +{ + git_iterator *i; + + /* normal workdir iteration uses explicit tree expansion */ + cl_git_pass(git_iterator_for_workdir( + &i, g_repo, 0, NULL, NULL)); + expect_iterator_items(i, 12, 22); + git_iterator_free(i); +} + +void test_repo_iterator__workdir_icase(void) +{ + git_iterator *i; + git_iterator_flag_t flag; + + flag = GIT_ITERATOR_DONT_IGNORE_CASE; + + /* normal workdir iteration with range */ + cl_git_pass(git_iterator_for_workdir(&i, g_repo, flag, "c", "k/D")); + expect_iterator_items(i, 5, 8); + git_iterator_free(i); + + cl_git_pass(git_iterator_for_workdir(&i, g_repo, flag, "k", "k/Z")); + expect_iterator_items(i, 1, 4); + git_iterator_free(i); + + flag = GIT_ITERATOR_IGNORE_CASE; + + /* normal workdir iteration with range */ + cl_git_pass(git_iterator_for_workdir(&i, g_repo, flag, "c", "k/D")); + expect_iterator_items(i, 9, 14); + git_iterator_free(i); + + cl_git_pass(git_iterator_for_workdir(&i, g_repo, flag, "k", "k/Z")); + expect_iterator_items(i, 1, 6); + git_iterator_free(i); +} diff --git a/tests-clar/resources/icase/.gitted/HEAD b/tests-clar/resources/icase/.gitted/HEAD new file mode 100644 index 000000000..cb089cd89 --- /dev/null +++ b/tests-clar/resources/icase/.gitted/HEAD @@ -0,0 +1 @@ +ref: refs/heads/master diff --git a/tests-clar/resources/icase/.gitted/config b/tests-clar/resources/icase/.gitted/config new file mode 100644 index 000000000..bb4d11c1f --- /dev/null +++ b/tests-clar/resources/icase/.gitted/config @@ -0,0 +1,7 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = false + logallrefupdates = true + ignorecase = true + precomposeunicode = false diff --git a/tests-clar/resources/icase/.gitted/description b/tests-clar/resources/icase/.gitted/description new file mode 100644 index 000000000..498b267a8 --- /dev/null +++ b/tests-clar/resources/icase/.gitted/description @@ -0,0 +1 @@ +Unnamed repository; edit this file 'description' to name the repository. diff --git a/tests-clar/resources/icase/.gitted/index b/tests-clar/resources/icase/.gitted/index Binary files differnew file mode 100644 index 000000000..f8288ec13 --- /dev/null +++ b/tests-clar/resources/icase/.gitted/index diff --git a/tests-clar/resources/icase/.gitted/info/exclude b/tests-clar/resources/icase/.gitted/info/exclude new file mode 100644 index 000000000..a5196d1be --- /dev/null +++ b/tests-clar/resources/icase/.gitted/info/exclude @@ -0,0 +1,6 @@ +# git ls-files --others --exclude-from=.git/info/exclude +# Lines that start with '#' are comments. +# For a project mostly in C, the following would be a good set of +# exclude patterns (uncomment them if you want to use them): +# *.[oa] +# *~ diff --git a/tests-clar/resources/icase/.gitted/logs/HEAD b/tests-clar/resources/icase/.gitted/logs/HEAD new file mode 100644 index 000000000..3b16bd163 --- /dev/null +++ b/tests-clar/resources/icase/.gitted/logs/HEAD @@ -0,0 +1 @@ +0000000000000000000000000000000000000000 76d6e1d231b1085fcce151427e9899335de74be6 Russell Belfer <rb@github.com> 1359157123 -0800 commit (initial): initial commit diff --git a/tests-clar/resources/icase/.gitted/logs/refs/heads/master b/tests-clar/resources/icase/.gitted/logs/refs/heads/master new file mode 100644 index 000000000..3b16bd163 --- /dev/null +++ b/tests-clar/resources/icase/.gitted/logs/refs/heads/master @@ -0,0 +1 @@ +0000000000000000000000000000000000000000 76d6e1d231b1085fcce151427e9899335de74be6 Russell Belfer <rb@github.com> 1359157123 -0800 commit (initial): initial commit diff --git a/tests-clar/resources/icase/.gitted/objects/3e/257c57f136a1cb8f2b8e9a2e5bc8ec0258bdce b/tests-clar/resources/icase/.gitted/objects/3e/257c57f136a1cb8f2b8e9a2e5bc8ec0258bdce Binary files differnew file mode 100644 index 000000000..10691c788 --- /dev/null +++ b/tests-clar/resources/icase/.gitted/objects/3e/257c57f136a1cb8f2b8e9a2e5bc8ec0258bdce diff --git a/tests-clar/resources/icase/.gitted/objects/4d/d6027d083575c7431396dc2a3174afeb393c93 b/tests-clar/resources/icase/.gitted/objects/4d/d6027d083575c7431396dc2a3174afeb393c93 Binary files differnew file mode 100644 index 000000000..8ca70df17 --- /dev/null +++ b/tests-clar/resources/icase/.gitted/objects/4d/d6027d083575c7431396dc2a3174afeb393c93 diff --git a/tests-clar/resources/icase/.gitted/objects/62/e0af52c199ec731fe4ad230041cd3286192d49 b/tests-clar/resources/icase/.gitted/objects/62/e0af52c199ec731fe4ad230041cd3286192d49 Binary files differnew file mode 100644 index 000000000..e264aeab3 --- /dev/null +++ b/tests-clar/resources/icase/.gitted/objects/62/e0af52c199ec731fe4ad230041cd3286192d49 diff --git a/tests-clar/resources/icase/.gitted/objects/76/d6e1d231b1085fcce151427e9899335de74be6 b/tests-clar/resources/icase/.gitted/objects/76/d6e1d231b1085fcce151427e9899335de74be6 new file mode 100644 index 000000000..24a4b3ee3 --- /dev/null +++ b/tests-clar/resources/icase/.gitted/objects/76/d6e1d231b1085fcce151427e9899335de74be6 @@ -0,0 +1,3 @@ +x 1ENӀc XdƉ&/usԛ8}2
SH, +am1ЋEѷ9CJ$
nܷA +bଃjO_SO9%)9
\ No newline at end of file diff --git a/tests-clar/resources/icase/.gitted/objects/d4/4e18fb93b7107b5cd1b95d601591d77869a1b6 b/tests-clar/resources/icase/.gitted/objects/d4/4e18fb93b7107b5cd1b95d601591d77869a1b6 Binary files differnew file mode 100644 index 000000000..32d8c499f --- /dev/null +++ b/tests-clar/resources/icase/.gitted/objects/d4/4e18fb93b7107b5cd1b95d601591d77869a1b6 diff --git a/tests-clar/resources/icase/.gitted/refs/heads/master b/tests-clar/resources/icase/.gitted/refs/heads/master new file mode 100644 index 000000000..37410ec2a --- /dev/null +++ b/tests-clar/resources/icase/.gitted/refs/heads/master @@ -0,0 +1 @@ +76d6e1d231b1085fcce151427e9899335de74be6 diff --git a/tests-clar/resources/icase/B b/tests-clar/resources/icase/B new file mode 100644 index 000000000..d44e18fb9 --- /dev/null +++ b/tests-clar/resources/icase/B @@ -0,0 +1 @@ +start diff --git a/tests-clar/resources/icase/D b/tests-clar/resources/icase/D new file mode 100644 index 000000000..d44e18fb9 --- /dev/null +++ b/tests-clar/resources/icase/D @@ -0,0 +1 @@ +start diff --git a/tests-clar/resources/icase/F b/tests-clar/resources/icase/F new file mode 100644 index 000000000..d44e18fb9 --- /dev/null +++ b/tests-clar/resources/icase/F @@ -0,0 +1 @@ +start diff --git a/tests-clar/resources/icase/H b/tests-clar/resources/icase/H new file mode 100644 index 000000000..d44e18fb9 --- /dev/null +++ b/tests-clar/resources/icase/H @@ -0,0 +1 @@ +start diff --git a/tests-clar/resources/icase/J b/tests-clar/resources/icase/J new file mode 100644 index 000000000..d44e18fb9 --- /dev/null +++ b/tests-clar/resources/icase/J @@ -0,0 +1 @@ +start diff --git a/tests-clar/resources/icase/L/1 b/tests-clar/resources/icase/L/1 new file mode 100644 index 000000000..62e0af52c --- /dev/null +++ b/tests-clar/resources/icase/L/1 @@ -0,0 +1 @@ +sub diff --git a/tests-clar/resources/icase/L/B b/tests-clar/resources/icase/L/B new file mode 100644 index 000000000..62e0af52c --- /dev/null +++ b/tests-clar/resources/icase/L/B @@ -0,0 +1 @@ +sub diff --git a/tests-clar/resources/icase/L/D b/tests-clar/resources/icase/L/D new file mode 100644 index 000000000..62e0af52c --- /dev/null +++ b/tests-clar/resources/icase/L/D @@ -0,0 +1 @@ +sub diff --git a/tests-clar/resources/icase/L/a b/tests-clar/resources/icase/L/a new file mode 100644 index 000000000..62e0af52c --- /dev/null +++ b/tests-clar/resources/icase/L/a @@ -0,0 +1 @@ +sub diff --git a/tests-clar/resources/icase/L/c b/tests-clar/resources/icase/L/c new file mode 100644 index 000000000..62e0af52c --- /dev/null +++ b/tests-clar/resources/icase/L/c @@ -0,0 +1 @@ +sub diff --git a/tests-clar/resources/icase/a b/tests-clar/resources/icase/a new file mode 100644 index 000000000..d44e18fb9 --- /dev/null +++ b/tests-clar/resources/icase/a @@ -0,0 +1 @@ +start diff --git a/tests-clar/resources/icase/c b/tests-clar/resources/icase/c new file mode 100644 index 000000000..d44e18fb9 --- /dev/null +++ b/tests-clar/resources/icase/c @@ -0,0 +1 @@ +start diff --git a/tests-clar/resources/icase/e b/tests-clar/resources/icase/e new file mode 100644 index 000000000..d44e18fb9 --- /dev/null +++ b/tests-clar/resources/icase/e @@ -0,0 +1 @@ +start diff --git a/tests-clar/resources/icase/g b/tests-clar/resources/icase/g new file mode 100644 index 000000000..d44e18fb9 --- /dev/null +++ b/tests-clar/resources/icase/g @@ -0,0 +1 @@ +start diff --git a/tests-clar/resources/icase/i b/tests-clar/resources/icase/i new file mode 100644 index 000000000..d44e18fb9 --- /dev/null +++ b/tests-clar/resources/icase/i @@ -0,0 +1 @@ +start diff --git a/tests-clar/resources/icase/k/1 b/tests-clar/resources/icase/k/1 new file mode 100644 index 000000000..62e0af52c --- /dev/null +++ b/tests-clar/resources/icase/k/1 @@ -0,0 +1 @@ +sub diff --git a/tests-clar/resources/icase/k/B b/tests-clar/resources/icase/k/B new file mode 100644 index 000000000..62e0af52c --- /dev/null +++ b/tests-clar/resources/icase/k/B @@ -0,0 +1 @@ +sub diff --git a/tests-clar/resources/icase/k/D b/tests-clar/resources/icase/k/D new file mode 100644 index 000000000..62e0af52c --- /dev/null +++ b/tests-clar/resources/icase/k/D @@ -0,0 +1 @@ +sub diff --git a/tests-clar/resources/icase/k/a b/tests-clar/resources/icase/k/a new file mode 100644 index 000000000..62e0af52c --- /dev/null +++ b/tests-clar/resources/icase/k/a @@ -0,0 +1 @@ +sub diff --git a/tests-clar/resources/icase/k/c b/tests-clar/resources/icase/k/c new file mode 100644 index 000000000..62e0af52c --- /dev/null +++ b/tests-clar/resources/icase/k/c @@ -0,0 +1 @@ +sub diff --git a/tests-clar/status/worktree.c b/tests-clar/status/worktree.c index e1fc8dff8..b5449f6f1 100644 --- a/tests-clar/status/worktree.c +++ b/tests-clar/status/worktree.c @@ -274,6 +274,7 @@ void test_status_worktree__issue_592(void) repo = cl_git_sandbox_init("issue_592"); cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(repo), "l.txt")); cl_git_pass(p_unlink(git_buf_cstr(&path))); + cl_assert(!git_path_exists("issue_592/l.txt")); cl_git_pass(git_status_foreach(repo, cb_status__check_592, "l.txt")); @@ -288,6 +289,7 @@ void test_status_worktree__issue_592_2(void) repo = cl_git_sandbox_init("issue_592"); cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(repo), "c/a.txt")); cl_git_pass(p_unlink(git_buf_cstr(&path))); + cl_assert(!git_path_exists("issue_592/c/a.txt")); cl_git_pass(git_status_foreach(repo, cb_status__check_592, "c/a.txt")); @@ -303,6 +305,7 @@ void test_status_worktree__issue_592_3(void) cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(repo), "c")); cl_git_pass(git_futils_rmdir_r(git_buf_cstr(&path), NULL, GIT_RMDIR_REMOVE_FILES)); + cl_assert(!git_path_exists("issue_592/c/a.txt")); cl_git_pass(git_status_foreach(repo, cb_status__check_592, "c/a.txt")); |