From ff0ddfa4bbec2e27491c822cf6b882c54d8675c8 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Wed, 17 Apr 2013 15:56:31 -0700 Subject: [PATCH 1/8] Add filesystem iterator variant This adds a new variant iterator that is a raw filesystem iterator for scanning directories from a root. There is still more work to do to blend this with the working directory iterator. --- src/iterator.c | 301 +++++++++++++++++++++++++++++++++++++ src/iterator.h | 11 ++ tests-clar/repo/iterator.c | 44 ++++++ 3 files changed, 356 insertions(+) diff --git a/src/iterator.c b/src/iterator.c index 5b5ed9525..dd8a6133d 100644 --- a/src/iterator.c +++ b/src/iterator.c @@ -833,6 +833,307 @@ int git_iterator_for_index( } +typedef struct fs_iterator_frame fs_iterator_frame; +struct fs_iterator_frame { + fs_iterator_frame *next; + git_vector entries; + size_t index; +}; + +typedef struct { + git_iterator base; + git_iterator_callbacks cb; + fs_iterator_frame *stack; + git_index_entry entry; + git_buf path; + size_t root_len; + int depth; +} fs_iterator; + +#define FS_MAX_DEPTH 100 + +static fs_iterator_frame *fs_iterator__alloc_frame(fs_iterator *fi) +{ + fs_iterator_frame *ff = git__calloc(1, sizeof(fs_iterator_frame)); + git_vector_cmp entry_compare = CASESELECT( + iterator__ignore_case(fi), + git_path_with_stat_cmp_icase, git_path_with_stat_cmp); + + if (ff && git_vector_init(&ff->entries, 0, entry_compare) < 0) { + git__free(ff); + ff = NULL; + } + + return ff; +} + +static void fs_iterator__free_frame(fs_iterator_frame *ff) +{ + size_t i; + git_path_with_stat *path; + + git_vector_foreach(&ff->entries, i, path) + git__free(path); + git_vector_free(&ff->entries); + git__free(ff); +} + +static int fs_iterator__update_entry(fs_iterator *fi); + +static int fs_iterator__entry_cmp(const void *i, const void *item) +{ + const fs_iterator *fi = (const fs_iterator *)i; + const git_path_with_stat *ps = item; + return fi->base.prefixcomp(fi->base.start, ps->path); +} + +static void fs_iterator__seek_frame_start( + fs_iterator *fi, fs_iterator_frame *ff) +{ + if (!ff) + return; + + if (fi->base.start) + git_vector_bsearch2( + &ff->index, &ff->entries, fs_iterator__entry_cmp, fi); + else + ff->index = 0; +} + +static int fs_iterator__expand_dir(fs_iterator *fi) +{ + int error; + fs_iterator_frame *ff; + + ff = fs_iterator__alloc_frame(fi); + GITERR_CHECK_ALLOC(ff); + + error = git_path_dirload_with_stat( + fi->path.ptr, fi->root_len, iterator__ignore_case(fi), + fi->base.start, fi->base.end, &ff->entries); + + if (error < 0 || ff->entries.length == 0) { + fs_iterator__free_frame(ff); + return GIT_ENOTFOUND; + } + + if (++(fi->depth) > FS_MAX_DEPTH) { + giterr_set(GITERR_REPOSITORY, + "Directory nesting is too deep (%d)", fi->depth); + fs_iterator__free_frame(ff); + return -1; + } + + fs_iterator__seek_frame_start(fi, ff); + + ff->next = fi->stack; + fi->stack = ff; + + return fs_iterator__update_entry(fi); +} + +static int fs_iterator__current( + const git_index_entry **entry, git_iterator *self) +{ + fs_iterator *fi = (fs_iterator *)self; + if (entry) + *entry = (fi->entry.path == NULL) ? NULL : &fi->entry; + return 0; +} + +static int fs_iterator__at_end(git_iterator *self) +{ + return (((fs_iterator *)self)->entry.path == NULL); +} + +static int fs_iterator__advance_into( + const git_index_entry **entry, git_iterator *iter) +{ + int error = 0; + fs_iterator *fi = (fs_iterator *)iter; + + iterator__clear_entry(entry); + + /* Allow you to explicitly advance into a commit/submodule (as well as a + * tree) to avoid cases where an entry is mislabeled as a submodule in + * the working directory. The fs iterator will never have COMMMIT + * entries on it's own, but a wrapper might add them. + */ + if (fi->entry.path != NULL && + (fi->entry.mode == GIT_FILEMODE_TREE || + fi->entry.mode == GIT_FILEMODE_COMMIT)) + /* returns GIT_ENOTFOUND if the directory is empty */ + error = fs_iterator__expand_dir(fi); + + if (!error && entry) + error = fs_iterator__current(entry, iter); + + return error; +} + +static int fs_iterator__advance( + const git_index_entry **entry, git_iterator *self) +{ + int error = 0; + fs_iterator *fi = (fs_iterator *)self; + fs_iterator_frame *ff; + git_path_with_stat *next; + + /* given include_trees & autoexpand, we might have to go into a tree */ + if (iterator__do_autoexpand(fi) && + fi->entry.path != NULL && + fi->entry.mode == GIT_FILEMODE_TREE) + { + error = fs_iterator__advance_into(entry, self); + + /* continue silently past empty directories if autoexpanding */ + if (error != GIT_ENOTFOUND) + return error; + giterr_clear(); + error = 0; + } + + if (entry != NULL) + *entry = NULL; + + while (fi->entry.path != NULL) { + ff = fi->stack; + next = git_vector_get(&ff->entries, ++ff->index); + + if (next != NULL) + break; + + /* pop stack if anything is left to pop */ + if (!ff->next) { + memset(&fi->entry, 0, sizeof(fi->entry)); + return 0; + } + + fi->stack = ff->next; + fi->depth--; + fs_iterator__free_frame(ff); + } + + error = fs_iterator__update_entry(fi); + + if (!error && entry != NULL) + error = fs_iterator__current(entry, self); + + return error; +} + +static int fs_iterator__seek(git_iterator *self, const char *prefix) +{ + GIT_UNUSED(self); + GIT_UNUSED(prefix); + /* pop stack until matching prefix */ + /* find prefix item in current frame */ + /* push subdirectories as deep as possible while matching */ + return 0; +} + +static int fs_iterator__reset( + git_iterator *self, const char *start, const char *end) +{ + fs_iterator *fi = (fs_iterator *)self; + + while (fi->stack != NULL && fi->stack->next != NULL) { + fs_iterator_frame *ff = fi->stack; + fi->stack = ff->next; + fs_iterator__free_frame(ff); + } + fi->depth = 0; + + if (iterator__reset_range(self, start, end) < 0) + return -1; + + fs_iterator__seek_frame_start(fi, fi->stack); + + return fs_iterator__update_entry(fi); +} + +static void fs_iterator__free(git_iterator *self) +{ + fs_iterator *fi = (fs_iterator *)self; + + while (fi->stack != NULL) { + fs_iterator_frame *ff = fi->stack; + fi->stack = ff->next; + fs_iterator__free_frame(ff); + } + + git_buf_free(&fi->path); +} + +static int fs_iterator__update_entry(fs_iterator *fi) +{ + git_path_with_stat *ps = + git_vector_get(&fi->stack->entries, fi->stack->index); + + git_buf_truncate(&fi->path, fi->root_len); + memset(&fi->entry, 0, sizeof(fi->entry)); + + if (!ps) + return 0; + + if (git_buf_put(&fi->path, ps->path, ps->path_len) < 0) + return -1; + + if (iterator__past_end(fi, fi->path.ptr + fi->root_len)) + return 0; + + fi->entry.path = ps->path; + git_index_entry__init_from_stat(&fi->entry, &ps->st); + + /* need different mode here to keep directories during iteration */ + fi->entry.mode = git_futils_canonical_mode(ps->st.st_mode); + + /* if this isn't a tree, then we're done */ + if (fi->entry.mode != GIT_FILEMODE_TREE) + return 0; + + if (iterator__include_trees(fi)) + return 0; + + return fs_iterator__advance(NULL, (git_iterator *)fi); +} + +int git_iterator_for_filesystem( + git_iterator **out, + const char *root, + git_iterator_flag_t flags, + const char *start, + const char *end) +{ + int error; + fs_iterator *fi; + + ITERATOR_BASE_INIT(fi, fs, FS, NULL); + + if ((flags & GIT_ITERATOR_IGNORE_CASE) != 0) + fi->base.flags |= GIT_ITERATOR_IGNORE_CASE; + + if (git_buf_sets(&fi->path, root) < 0 || git_path_to_dir(&fi->path) < 0) { + git__free(fi); + return -1; + } + fi->root_len = fi->path.size; + + if ((error = fs_iterator__expand_dir(fi)) < 0) { + if (error != GIT_ENOTFOUND) + goto fail; + giterr_clear(); + } + + *out = (git_iterator *)fi; + return 0; + +fail: + git_iterator_free((git_iterator *)fi); + return error; +} + + #define WORKDIR_MAX_DEPTH 100 typedef struct workdir_iterator_frame workdir_iterator_frame; diff --git a/src/iterator.h b/src/iterator.h index 4a4e6a9d8..7998f7c6b 100644 --- a/src/iterator.h +++ b/src/iterator.h @@ -19,6 +19,7 @@ typedef enum { GIT_ITERATOR_TYPE_TREE = 1, GIT_ITERATOR_TYPE_INDEX = 2, GIT_ITERATOR_TYPE_WORKDIR = 3, + GIT_ITERATOR_TYPE_FS = 4, } git_iterator_type_t; typedef enum { @@ -88,6 +89,16 @@ extern int git_iterator_for_workdir( const char *start, const char *end); +/* for filesystem iterators, you have to explicitly pass in the ignore_case + * behavior that you desire + */ +extern int git_iterator_for_filesystem( + git_iterator **out, + const char *root, + git_iterator_flag_t flags, + const char *start, + const char *end); + extern void git_iterator_free(git_iterator *iter); /* Return a git_index_entry structure for the current value the iterator diff --git a/tests-clar/repo/iterator.c b/tests-clar/repo/iterator.c index 00c46d6b1..ef9bfc33d 100644 --- a/tests-clar/repo/iterator.c +++ b/tests-clar/repo/iterator.c @@ -808,3 +808,47 @@ void test_repo_iterator__workdir_depth(void) expect_iterator_items(iter, 337, NULL, 337, NULL); git_iterator_free(iter); } + +void test_repo_iterator__fs(void) +{ + git_iterator *i; + static const char *expect_subdir[] = { + "current_file", + "modified_file", + "new_file", + NULL, + }; + + g_repo = cl_git_sandbox_init("status"); + + cl_git_pass(git_iterator_for_filesystem( + &i, "status/subdir", 0, NULL, NULL)); + expect_iterator_items(i, 3, expect_subdir, 3, expect_subdir); + git_iterator_free(i); +} + +void test_repo_iterator__fs2(void) +{ + git_iterator *i; + static const char *expect_subdir[] = { + "heads/br2", + "heads/dir", + "heads/master", + "heads/packed-test", + "heads/subtrees", + "heads/test", + "tags/e90810b", + "tags/foo/bar", + "tags/foo/foo/bar", + "tags/point_to_blob", + "tags/test", + NULL, + }; + + g_repo = cl_git_sandbox_init("testrepo"); + + cl_git_pass(git_iterator_for_filesystem( + &i, "testrepo/.git/refs", 0, NULL, NULL)); + expect_iterator_items(i, 11, expect_subdir, 11, expect_subdir); + git_iterator_free(i); +} From 71f85226eb5c2ef9e8c8ddb1943fc7fc1e6615ff Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Thu, 18 Apr 2013 11:11:38 -0700 Subject: [PATCH 2/8] Make workdir iterator use filesystem iterator This adds some hooks into the filesystem iterator so that the workdir iterator can just become a wrapper around it. Then we remove most of the workdir iterator code and just have it augment the filesystem iterator with skipping .git entries, updating the ignore stack, and checking for submodules. --- src/iterator.c | 557 ++++++++++++++----------------------------------- 1 file changed, 160 insertions(+), 397 deletions(-) diff --git a/src/iterator.c b/src/iterator.c index dd8a6133d..6eee5a805 100644 --- a/src/iterator.c +++ b/src/iterator.c @@ -26,8 +26,6 @@ (GIT_ITERATOR_IGNORE_CASE | GIT_ITERATOR_DONT_IGNORE_CASE) #define ITERATOR_BASE_INIT(P,NAME_LC,NAME_UC,REPO) do { \ - (P) = git__calloc(1, sizeof(NAME_LC ## _iterator)); \ - GITERR_CHECK_ALLOC(P); \ (P)->base.type = GIT_ITERATOR_TYPE_ ## NAME_UC; \ (P)->base.cb = &(P)->cb; \ ITERATOR_SET_CB(P,NAME_LC); \ @@ -148,7 +146,8 @@ int git_iterator_for_nothing( const char *start, const char *end) { - empty_iterator *i; + empty_iterator *i = git__calloc(1, sizeof(empty_iterator)); + GITERR_CHECK_ALLOC(i); #define empty_iterator__current empty_iterator__noop #define empty_iterator__advance empty_iterator__noop @@ -581,6 +580,9 @@ int git_iterator_for_tree( if ((error = git_object_dup((git_object **)&tree, (git_object *)tree)) < 0) return error; + ti = git__calloc(1, sizeof(tree_iterator)); + GITERR_CHECK_ALLOC(ti); + ITERATOR_BASE_INIT(ti, tree, TREE, git_tree_owner(tree)); if ((error = iterator__update_ignore_case((git_iterator *)ti, flags)) < 0) @@ -810,7 +812,8 @@ int git_iterator_for_index( const char *start, const char *end) { - index_iterator *ii; + index_iterator *ii = git__calloc(1, sizeof(index_iterator)); + GITERR_CHECK_ALLOC(ii); ITERATOR_BASE_INIT(ii, index, INDEX, git_index_owner(index)); @@ -840,7 +843,8 @@ struct fs_iterator_frame { size_t index; }; -typedef struct { +typedef struct fs_iterator fs_iterator; +struct fs_iterator { git_iterator base; git_iterator_callbacks cb; fs_iterator_frame *stack; @@ -848,7 +852,11 @@ typedef struct { git_buf path; size_t root_len; int depth; -} fs_iterator; + + int (*frame_added)(fs_iterator *self); + int (*frame_removed)(fs_iterator *self); + int (*entry_updated)(fs_iterator *self); +}; #define FS_MAX_DEPTH 100 @@ -867,15 +875,31 @@ static fs_iterator_frame *fs_iterator__alloc_frame(fs_iterator *fi) return ff; } -static void fs_iterator__free_frame(fs_iterator_frame *ff) +static void fs_iterator__pop_frame( + fs_iterator *fi, fs_iterator_frame *ff, bool pop_last) { size_t i; git_path_with_stat *path; + fs_iterator_frame *ff_next = ff->next; + + if (fi && !ff_next && !pop_last) { + memset(&fi->entry, 0, sizeof(fi->entry)); + return; + } git_vector_foreach(&ff->entries, i, path) git__free(path); git_vector_free(&ff->entries); git__free(ff); + + if (!fi || fi->stack != ff) + return; + + fi->stack = ff_next; + fi->depth--; + + if (fi->frame_removed) + fi->frame_removed(fi); } static int fs_iterator__update_entry(fs_iterator *fi); @@ -913,14 +937,14 @@ static int fs_iterator__expand_dir(fs_iterator *fi) fi->base.start, fi->base.end, &ff->entries); if (error < 0 || ff->entries.length == 0) { - fs_iterator__free_frame(ff); + fs_iterator__pop_frame(NULL, ff, true); return GIT_ENOTFOUND; } if (++(fi->depth) > FS_MAX_DEPTH) { giterr_set(GITERR_REPOSITORY, "Directory nesting is too deep (%d)", fi->depth); - fs_iterator__free_frame(ff); + fs_iterator__pop_frame(NULL, ff, true); return -1; } @@ -929,6 +953,9 @@ static int fs_iterator__expand_dir(fs_iterator *fi) ff->next = fi->stack; fi->stack = ff; + if (fi->frame_added && (error = fi->frame_added(fi)) < 0) + return error; + return fs_iterator__update_entry(fi); } @@ -971,7 +998,7 @@ static int fs_iterator__advance_into( return error; } -static int fs_iterator__advance( +static int fs_iterator__advance_over( const git_index_entry **entry, git_iterator *self) { int error = 0; @@ -979,20 +1006,6 @@ static int fs_iterator__advance( fs_iterator_frame *ff; git_path_with_stat *next; - /* given include_trees & autoexpand, we might have to go into a tree */ - if (iterator__do_autoexpand(fi) && - fi->entry.path != NULL && - fi->entry.mode == GIT_FILEMODE_TREE) - { - error = fs_iterator__advance_into(entry, self); - - /* continue silently past empty directories if autoexpanding */ - if (error != GIT_ENOTFOUND) - return error; - giterr_clear(); - error = 0; - } - if (entry != NULL) *entry = NULL; @@ -1003,15 +1016,7 @@ static int fs_iterator__advance( if (next != NULL) break; - /* pop stack if anything is left to pop */ - if (!ff->next) { - memset(&fi->entry, 0, sizeof(fi->entry)); - return 0; - } - - fi->stack = ff->next; - fi->depth--; - fs_iterator__free_frame(ff); + fs_iterator__pop_frame(fi, ff, false); } error = fs_iterator__update_entry(fi); @@ -1022,6 +1027,26 @@ static int fs_iterator__advance( return error; } +static int fs_iterator__advance( + const git_index_entry **entry, git_iterator *self) +{ + fs_iterator *fi = (fs_iterator *)self; + + /* given include_trees & autoexpand, we might have to go into a tree */ + if (iterator__do_autoexpand(fi) && + fi->entry.path != NULL && + fi->entry.mode == GIT_FILEMODE_TREE) + { + int error = fs_iterator__advance_into(entry, self); + if (error != GIT_ENOTFOUND) + return error; + /* continue silently past empty directories if autoexpanding */ + giterr_clear(); + } + + return fs_iterator__advance_over(entry, self); +} + static int fs_iterator__seek(git_iterator *self, const char *prefix) { GIT_UNUSED(self); @@ -1037,11 +1062,8 @@ static int fs_iterator__reset( { fs_iterator *fi = (fs_iterator *)self; - while (fi->stack != NULL && fi->stack->next != NULL) { - fs_iterator_frame *ff = fi->stack; - fi->stack = ff->next; - fs_iterator__free_frame(ff); - } + while (fi->stack != NULL && fi->stack->next != NULL) + fs_iterator__pop_frame(fi, fi->stack, false); fi->depth = 0; if (iterator__reset_range(self, start, end) < 0) @@ -1056,11 +1078,8 @@ static void fs_iterator__free(git_iterator *self) { fs_iterator *fi = (fs_iterator *)self; - while (fi->stack != NULL) { - fs_iterator_frame *ff = fi->stack; - fi->stack = ff->next; - fs_iterator__free_frame(ff); - } + while (fi->stack != NULL) + fs_iterator__pop_frame(fi, fi->stack, true); git_buf_free(&fi->path); } @@ -1075,10 +1094,8 @@ static int fs_iterator__update_entry(fs_iterator *fi) if (!ps) return 0; - if (git_buf_put(&fi->path, ps->path, ps->path_len) < 0) return -1; - if (iterator__past_end(fi, fi->path.ptr + fi->root_len)) return 0; @@ -1088,14 +1105,41 @@ static int fs_iterator__update_entry(fs_iterator *fi) /* need different mode here to keep directories during iteration */ fi->entry.mode = git_futils_canonical_mode(ps->st.st_mode); - /* if this isn't a tree, then we're done */ - if (fi->entry.mode != GIT_FILEMODE_TREE) - return 0; + /* allow wrapper to check/update the entry (can force skip) */ + if (fi->entry_updated && + fi->entry_updated(fi) == GIT_ENOTFOUND) + return fs_iterator__advance_over(NULL, (git_iterator *)fi); - if (iterator__include_trees(fi)) - return 0; + /* if this is a tree and trees aren't included, then skip */ + if (fi->entry.mode == GIT_FILEMODE_TREE && !iterator__include_trees(fi)) + return git_iterator_advance(NULL, (git_iterator *)fi); - return fs_iterator__advance(NULL, (git_iterator *)fi); + return 0; +} + +static int fs_iterator__initialize( + git_iterator **out, fs_iterator *fi, const char *root) +{ + int error; + + if (git_buf_sets(&fi->path, root) < 0 || git_path_to_dir(&fi->path) < 0) { + git__free(fi); + return -1; + } + + fi->root_len = fi->path.size; + + if ((error = fs_iterator__expand_dir(fi)) == GIT_ENOTFOUND) { + giterr_clear(); + error = 0; + } + if (error) { + git_iterator_free((git_iterator *)fi); + fi = NULL; + } + + *out = (git_iterator *)fi; + return error; } int git_iterator_for_filesystem( @@ -1105,372 +1149,97 @@ int git_iterator_for_filesystem( const char *start, const char *end) { - int error; - fs_iterator *fi; + fs_iterator *fi = git__calloc(1, sizeof(fs_iterator)); + GITERR_CHECK_ALLOC(fi); ITERATOR_BASE_INIT(fi, fs, FS, NULL); if ((flags & GIT_ITERATOR_IGNORE_CASE) != 0) fi->base.flags |= GIT_ITERATOR_IGNORE_CASE; - if (git_buf_sets(&fi->path, root) < 0 || git_path_to_dir(&fi->path) < 0) { - git__free(fi); - return -1; - } - fi->root_len = fi->path.size; - - if ((error = fs_iterator__expand_dir(fi)) < 0) { - if (error != GIT_ENOTFOUND) - goto fail; - giterr_clear(); - } - - *out = (git_iterator *)fi; - return 0; - -fail: - git_iterator_free((git_iterator *)fi); - return error; + return fs_iterator__initialize(out, fi, root); } -#define WORKDIR_MAX_DEPTH 100 - -typedef struct workdir_iterator_frame workdir_iterator_frame; -struct workdir_iterator_frame { - workdir_iterator_frame *next; - git_vector entries; - size_t index; -}; - typedef struct { - git_iterator base; - git_iterator_callbacks cb; - workdir_iterator_frame *stack; + fs_iterator fi; git_ignores ignores; - git_index_entry entry; - git_buf path; - size_t root_len; int is_ignored; - int depth; } workdir_iterator; -GIT_INLINE(bool) path_is_dotgit(const git_path_with_stat *ps) +GIT_INLINE(bool) workdir_path_is_dotgit(const git_buf *path) { - if (!ps) + size_t len; + + if (!path || (len = path->size) < 4) return false; - else { - const char *path = ps->path; - size_t len = ps->path_len; - if (len < 4) - return false; - if (path[len - 1] == '/') - len--; - if (tolower(path[len - 1]) != 't' || - tolower(path[len - 2]) != 'i' || - tolower(path[len - 3]) != 'g' || - tolower(path[len - 4]) != '.') - return false; - return (len == 4 || path[len - 5] == '/'); - } + if (path->ptr[len - 1] == '/') + len--; + + if (tolower(path->ptr[len - 1]) != 't' || + tolower(path->ptr[len - 2]) != 'i' || + tolower(path->ptr[len - 3]) != 'g' || + tolower(path->ptr[len - 4]) != '.') + return false; + + return (len == 4 || path->ptr[len - 5] == '/'); } -static workdir_iterator_frame *workdir_iterator__alloc_frame( - workdir_iterator *wi) +static int workdir_iterator__frame_added(fs_iterator *fi) { - workdir_iterator_frame *wf = git__calloc(1, sizeof(workdir_iterator_frame)); - git_vector_cmp entry_compare = CASESELECT( - iterator__ignore_case(wi), - git_path_with_stat_cmp_icase, git_path_with_stat_cmp); - - if (wf == NULL) - return NULL; - - if (git_vector_init(&wf->entries, 0, entry_compare) != 0) { - git__free(wf); - return NULL; - } - - return wf; -} - -static void workdir_iterator__free_frame(workdir_iterator_frame *wf) -{ - unsigned int i; - git_path_with_stat *path; - - git_vector_foreach(&wf->entries, i, path) - git__free(path); - git_vector_free(&wf->entries); - git__free(wf); -} - -static int workdir_iterator__update_entry(workdir_iterator *wi); - -static int workdir_iterator__entry_cmp(const void *i, const void *item) -{ - const workdir_iterator *wi = (const workdir_iterator *)i; - const git_path_with_stat *ps = item; - return wi->base.prefixcomp(wi->base.start, ps->path); -} - -static void workdir_iterator__seek_frame_start( - workdir_iterator *wi, workdir_iterator_frame *wf) -{ - if (!wf) - return; - - if (wi->base.start) - git_vector_bsearch2( - &wf->index, &wf->entries, workdir_iterator__entry_cmp, wi); - else - wf->index = 0; - - if (path_is_dotgit(git_vector_get(&wf->entries, wf->index))) - wf->index++; -} - -static int workdir_iterator__expand_dir(workdir_iterator *wi) -{ - int error; - workdir_iterator_frame *wf; - - wf = workdir_iterator__alloc_frame(wi); - GITERR_CHECK_ALLOC(wf); - - error = git_path_dirload_with_stat( - wi->path.ptr, wi->root_len, iterator__ignore_case(wi), - wi->base.start, wi->base.end, &wf->entries); - - if (error < 0 || wf->entries.length == 0) { - workdir_iterator__free_frame(wf); - return GIT_ENOTFOUND; - } - - if (++(wi->depth) > WORKDIR_MAX_DEPTH) { - giterr_set(GITERR_REPOSITORY, - "Working directory is too deep (%d)", wi->depth); - workdir_iterator__free_frame(wf); - return -1; - } - - workdir_iterator__seek_frame_start(wi, wf); - /* only push new ignores if this is not top level directory */ - if (wi->stack != NULL) { - ssize_t slash_pos = git_buf_rfind_next(&wi->path, '/'); - (void)git_ignore__push_dir(&wi->ignores, &wi->path.ptr[slash_pos + 1]); + if (fi->stack->next != NULL) { + workdir_iterator *wi = (workdir_iterator *)fi; + ssize_t slash_pos = git_buf_rfind_next(&fi->path, '/'); + + (void)git_ignore__push_dir(&wi->ignores, &fi->path.ptr[slash_pos + 1]); } - wf->next = wi->stack; - wi->stack = wf; - - return workdir_iterator__update_entry(wi); -} - -static int workdir_iterator__current( - const git_index_entry **entry, git_iterator *self) -{ - workdir_iterator *wi = (workdir_iterator *)self; - if (entry) - *entry = (wi->entry.path == NULL) ? NULL : &wi->entry; return 0; } -static int workdir_iterator__at_end(git_iterator *self) +static int workdir_iterator__frame_removed(fs_iterator *fi) { - return (((workdir_iterator *)self)->entry.path == NULL); + workdir_iterator *wi = (workdir_iterator *)fi; + git_ignore__pop_dir(&wi->ignores); + return 0; } -static int workdir_iterator__advance_into( - const git_index_entry **entry, git_iterator *iter) +static int workdir_iterator__entry_updated(fs_iterator *fi) { int error = 0; - workdir_iterator *wi = (workdir_iterator *)iter; + workdir_iterator *wi = (workdir_iterator *)fi; - iterator__clear_entry(entry); + /* skip over .git entries */ + if (workdir_path_is_dotgit(&fi->path)) + return GIT_ENOTFOUND; - /* workdir iterator will allow you to explicitly advance into a - * commit/submodule (as well as a tree) to avoid some cases where an - * entry is mislabeled as a submodule in the working directory - */ - if (wi->entry.path != NULL && - (wi->entry.mode == GIT_FILEMODE_TREE || - wi->entry.mode == GIT_FILEMODE_COMMIT)) - /* returns GIT_ENOTFOUND if the directory is empty */ - error = workdir_iterator__expand_dir(wi); + /* reset is_ignored since we haven't checked yet */ + wi->is_ignored = -1; - if (!error && entry) - error = workdir_iterator__current(entry, iter); + /* check if apparent tree entries are actually submodules */ + if (fi->entry.mode != GIT_FILEMODE_TREE) + return 0; - return error; -} - -static int workdir_iterator__advance( - const git_index_entry **entry, git_iterator *self) -{ - int error = 0; - workdir_iterator *wi = (workdir_iterator *)self; - workdir_iterator_frame *wf; - git_path_with_stat *next; - - /* given include_trees & autoexpand, we might have to go into a tree */ - if (iterator__do_autoexpand(wi) && - wi->entry.path != NULL && - wi->entry.mode == GIT_FILEMODE_TREE) - { - error = workdir_iterator__advance_into(entry, self); - - /* continue silently past empty directories if autoexpanding */ - if (error != GIT_ENOTFOUND) - return error; + error = git_submodule_lookup(NULL, fi->base.repo, fi->entry.path); + if (error < 0) giterr_clear(); - error = 0; + + /* mark submodule (or any dir with .git) as GITLINK and remove slash */ + if (!error || error == GIT_EEXISTS) { + fi->entry.mode = S_IFGITLINK; + fi->entry.path[strlen(fi->entry.path) - 1] = '\0'; } - if (entry != NULL) - *entry = NULL; - - while (wi->entry.path != NULL) { - wf = wi->stack; - next = git_vector_get(&wf->entries, ++wf->index); - - if (next != NULL) { - /* match git's behavior of ignoring anything named ".git" */ - if (path_is_dotgit(next)) - continue; - /* else found a good entry */ - break; - } - - /* pop stack if anything is left to pop */ - if (!wf->next) { - memset(&wi->entry, 0, sizeof(wi->entry)); - return 0; - } - - wi->stack = wf->next; - wi->depth--; - workdir_iterator__free_frame(wf); - git_ignore__pop_dir(&wi->ignores); - } - - error = workdir_iterator__update_entry(wi); - - if (!error && entry != NULL) - error = workdir_iterator__current(entry, self); - - return error; -} - -static int workdir_iterator__seek(git_iterator *self, const char *prefix) -{ - GIT_UNUSED(self); - GIT_UNUSED(prefix); - /* pop stack until matching prefix */ - /* find prefix item in current frame */ - /* push subdirectories as deep as possible while matching */ return 0; } -static int workdir_iterator__reset( - git_iterator *self, const char *start, const char *end) -{ - workdir_iterator *wi = (workdir_iterator *)self; - - while (wi->stack != NULL && wi->stack->next != NULL) { - workdir_iterator_frame *wf = wi->stack; - wi->stack = wf->next; - workdir_iterator__free_frame(wf); - git_ignore__pop_dir(&wi->ignores); - } - wi->depth = 0; - - if (iterator__reset_range(self, start, end) < 0) - return -1; - - workdir_iterator__seek_frame_start(wi, wi->stack); - - return workdir_iterator__update_entry(wi); -} - static void workdir_iterator__free(git_iterator *self) { workdir_iterator *wi = (workdir_iterator *)self; - - while (wi->stack != NULL) { - workdir_iterator_frame *wf = wi->stack; - wi->stack = wf->next; - workdir_iterator__free_frame(wf); - } - + fs_iterator__free(self); git_ignore__free(&wi->ignores); - git_buf_free(&wi->path); -} - -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); - - git_buf_truncate(&wi->path, wi->root_len); - memset(&wi->entry, 0, sizeof(wi->entry)); - - 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 (iterator__past_end(wi, wi->path.ptr + wi->root_len)) - return 0; - - wi->entry.path = ps->path; - - wi->is_ignored = -1; - - git_index_entry__init_from_stat(&wi->entry, &ps->st); - - /* need different mode here to keep directories during iteration */ - wi->entry.mode = git_futils_canonical_mode(ps->st.st_mode); - - /* if this is a file type we don't handle, treat as ignored */ - if (wi->entry.mode == 0) { - wi->is_ignored = 1; - return 0; - } - - /* if this isn't a tree, then we're done */ - if (wi->entry.mode != GIT_FILEMODE_TREE) - return 0; - - /* detect submodules */ - error = git_submodule_lookup(NULL, wi->base.repo, wi->entry.path); - if (error == GIT_ENOTFOUND) - giterr_clear(); - - if (error == GIT_EEXISTS) /* if contains .git, treat as untracked submod */ - error = 0; - - /* 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; - } - - if (iterator__include_trees(wi)) - return 0; - - return workdir_iterator__advance(NULL, (git_iterator *)wi); } int git_iterator_for_workdir( @@ -1481,7 +1250,8 @@ int git_iterator_for_workdir( const char *end) { int error; - workdir_iterator *wi; + workdir_iterator *wi = git__calloc(1, sizeof(workdir_iterator)); + GITERR_CHECK_ALLOC(wi); assert(iter && repo); @@ -1489,32 +1259,24 @@ int git_iterator_for_workdir( repo, "scan working directory")) < 0) return error; - ITERATOR_BASE_INIT(wi, workdir, WORKDIR, repo); + /* initialize as an fs iterator then do overrides */ + ITERATOR_BASE_INIT((&wi->fi), fs, FS, repo); - if ((error = iterator__update_ignore_case((git_iterator *)wi, flags)) < 0) - goto fail; + wi->fi.base.type = GIT_ITERATOR_TYPE_WORKDIR; + wi->fi.cb.free = workdir_iterator__free; + wi->fi.frame_added = workdir_iterator__frame_added; + wi->fi.frame_removed = workdir_iterator__frame_removed; + wi->fi.entry_updated = workdir_iterator__entry_updated; - if (git_buf_sets(&wi->path, git_repository_workdir(repo)) < 0 || - git_path_to_dir(&wi->path) < 0 || - git_ignore__for_path(repo, "", &wi->ignores) < 0) + if ((error = iterator__update_ignore_case((git_iterator *)wi, flags)) < 0 || + (error = git_ignore__for_path(repo, "", &wi->ignores)) < 0) { - git__free(wi); - return -1; - } - wi->root_len = wi->path.size; - - if ((error = workdir_iterator__expand_dir(wi)) < 0) { - if (error != GIT_ENOTFOUND) - goto fail; - giterr_clear(); + git_iterator_free((git_iterator *)wi); + return error; } - *iter = (git_iterator *)wi; - return 0; - -fail: - git_iterator_free((git_iterator *)wi); - return error; + return fs_iterator__initialize( + iter, (fs_iterator *)wi, git_repository_workdir(repo)); } @@ -1616,7 +1378,8 @@ bool git_iterator_current_is_ignored(git_iterator *iter) if (wi->is_ignored != -1) return (bool)(wi->is_ignored != 0); - if (git_ignore__lookup(&wi->ignores, wi->entry.path, &wi->is_ignored) < 0) + if (git_ignore__lookup( + &wi->ignores, wi->fi.entry.path, &wi->is_ignored) < 0) wi->is_ignored = true; return (bool)wi->is_ignored; @@ -1641,10 +1404,10 @@ int git_iterator_current_workdir_path(git_buf **path, git_iterator *iter) { workdir_iterator *wi = (workdir_iterator *)iter; - if (iter->type != GIT_ITERATOR_TYPE_WORKDIR || !wi->entry.path) + if (iter->type != GIT_ITERATOR_TYPE_WORKDIR || !wi->fi.entry.path) *path = NULL; else - *path = &wi->path; + *path = &wi->fi.path; return 0; } From fc57471a0c1834143ae6b18e65c1484c5c04e7e3 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Thu, 18 Apr 2013 14:13:53 -0700 Subject: [PATCH 3/8] More filesystem iterator cleanup Renamed the callback functions and made some minor rearrangements to clean up the flow of some code. --- src/iterator.c | 83 +++++++++++++++++++++++++------------------------- 1 file changed, 42 insertions(+), 41 deletions(-) diff --git a/src/iterator.c b/src/iterator.c index 6eee5a805..a72f97eca 100644 --- a/src/iterator.c +++ b/src/iterator.c @@ -853,9 +853,9 @@ struct fs_iterator { size_t root_len; int depth; - int (*frame_added)(fs_iterator *self); - int (*frame_removed)(fs_iterator *self); - int (*entry_updated)(fs_iterator *self); + int (*enter_dir_cb)(fs_iterator *self); + int (*leave_dir_cb)(fs_iterator *self); + int (*update_entry_cb)(fs_iterator *self); }; #define FS_MAX_DEPTH 100 @@ -875,31 +875,34 @@ static fs_iterator_frame *fs_iterator__alloc_frame(fs_iterator *fi) return ff; } -static void fs_iterator__pop_frame( - fs_iterator *fi, fs_iterator_frame *ff, bool pop_last) +static void fs_iterator__free_frame(fs_iterator_frame *ff) { size_t i; git_path_with_stat *path; - fs_iterator_frame *ff_next = ff->next; - - if (fi && !ff_next && !pop_last) { - memset(&fi->entry, 0, sizeof(fi->entry)); - return; - } git_vector_foreach(&ff->entries, i, path) git__free(path); git_vector_free(&ff->entries); git__free(ff); +} - if (!fi || fi->stack != ff) - return; +static void fs_iterator__pop_frame( + fs_iterator *fi, fs_iterator_frame *ff, bool pop_last) +{ + if (fi && fi->stack == ff) { + if (!ff->next && !pop_last) { + memset(&fi->entry, 0, sizeof(fi->entry)); + return; + } - fi->stack = ff_next; - fi->depth--; + if (fi->leave_dir_cb) + (void)fi->leave_dir_cb(fi); - if (fi->frame_removed) - fi->frame_removed(fi); + fi->stack = ff->next; + fi->depth--; + } + + fs_iterator__free_frame(ff); } static int fs_iterator__update_entry(fs_iterator *fi); @@ -929,6 +932,12 @@ static int fs_iterator__expand_dir(fs_iterator *fi) int error; fs_iterator_frame *ff; + if (fi->depth > FS_MAX_DEPTH) { + giterr_set(GITERR_REPOSITORY, + "Directory nesting is too deep (%d)", fi->depth); + return -1; + } + ff = fs_iterator__alloc_frame(fi); GITERR_CHECK_ALLOC(ff); @@ -937,23 +946,17 @@ static int fs_iterator__expand_dir(fs_iterator *fi) fi->base.start, fi->base.end, &ff->entries); if (error < 0 || ff->entries.length == 0) { - fs_iterator__pop_frame(NULL, ff, true); + fs_iterator__free_frame(ff); return GIT_ENOTFOUND; } - if (++(fi->depth) > FS_MAX_DEPTH) { - giterr_set(GITERR_REPOSITORY, - "Directory nesting is too deep (%d)", fi->depth); - fs_iterator__pop_frame(NULL, ff, true); - return -1; - } - fs_iterator__seek_frame_start(fi, ff); ff->next = fi->stack; fi->stack = ff; + fi->depth++; - if (fi->frame_added && (error = fi->frame_added(fi)) < 0) + if (fi->enter_dir_cb && (error = fi->enter_dir_cb(fi)) < 0) return error; return fs_iterator__update_entry(fi); @@ -1106,8 +1109,8 @@ static int fs_iterator__update_entry(fs_iterator *fi) fi->entry.mode = git_futils_canonical_mode(ps->st.st_mode); /* allow wrapper to check/update the entry (can force skip) */ - if (fi->entry_updated && - fi->entry_updated(fi) == GIT_ENOTFOUND) + if (fi->update_entry_cb && + fi->update_entry_cb(fi) == GIT_ENOTFOUND) return fs_iterator__advance_over(NULL, (git_iterator *)fi); /* if this is a tree and trees aren't included, then skip */ @@ -1126,7 +1129,6 @@ static int fs_iterator__initialize( git__free(fi); return -1; } - fi->root_len = fi->path.size; if ((error = fs_iterator__expand_dir(fi)) == GIT_ENOTFOUND) { @@ -1186,7 +1188,7 @@ GIT_INLINE(bool) workdir_path_is_dotgit(const git_buf *path) return (len == 4 || path->ptr[len - 5] == '/'); } -static int workdir_iterator__frame_added(fs_iterator *fi) +static int workdir_iterator__enter_dir(fs_iterator *fi) { /* only push new ignores if this is not top level directory */ if (fi->stack->next != NULL) { @@ -1199,14 +1201,14 @@ static int workdir_iterator__frame_added(fs_iterator *fi) return 0; } -static int workdir_iterator__frame_removed(fs_iterator *fi) +static int workdir_iterator__leave_dir(fs_iterator *fi) { workdir_iterator *wi = (workdir_iterator *)fi; git_ignore__pop_dir(&wi->ignores); return 0; } -static int workdir_iterator__entry_updated(fs_iterator *fi) +static int workdir_iterator__update_entry(fs_iterator *fi) { int error = 0; workdir_iterator *wi = (workdir_iterator *)fi; @@ -1243,7 +1245,7 @@ static void workdir_iterator__free(git_iterator *self) } int git_iterator_for_workdir( - git_iterator **iter, + git_iterator **out, git_repository *repo, git_iterator_flag_t flags, const char *start, @@ -1253,7 +1255,7 @@ int git_iterator_for_workdir( workdir_iterator *wi = git__calloc(1, sizeof(workdir_iterator)); GITERR_CHECK_ALLOC(wi); - assert(iter && repo); + assert(out && repo); if ((error = git_repository__ensure_not_bare( repo, "scan working directory")) < 0) @@ -1262,11 +1264,11 @@ int git_iterator_for_workdir( /* initialize as an fs iterator then do overrides */ ITERATOR_BASE_INIT((&wi->fi), fs, FS, repo); - wi->fi.base.type = GIT_ITERATOR_TYPE_WORKDIR; - wi->fi.cb.free = workdir_iterator__free; - wi->fi.frame_added = workdir_iterator__frame_added; - wi->fi.frame_removed = workdir_iterator__frame_removed; - wi->fi.entry_updated = workdir_iterator__entry_updated; + wi->fi.base.type = GIT_ITERATOR_TYPE_WORKDIR; + wi->fi.cb.free = workdir_iterator__free; + wi->fi.enter_dir_cb = workdir_iterator__enter_dir; + wi->fi.leave_dir_cb = workdir_iterator__leave_dir; + wi->fi.update_entry_cb = workdir_iterator__update_entry; if ((error = iterator__update_ignore_case((git_iterator *)wi, flags)) < 0 || (error = git_ignore__for_path(repo, "", &wi->ignores)) < 0) @@ -1275,8 +1277,7 @@ int git_iterator_for_workdir( return error; } - return fs_iterator__initialize( - iter, (fs_iterator *)wi, git_repository_workdir(repo)); + return fs_iterator__initialize(out, &wi->fi, git_repository_workdir(repo)); } From 627d590819efa7f43b605ce1a22278c0c6b42516 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Thu, 18 Apr 2013 14:14:22 -0700 Subject: [PATCH 4/8] More filesystem iterator tests Refactors the helper function that builds a directory hierarchy and then made use of it to try more variations on filesystem iterator tests. --- tests-clar/repo/iterator.c | 150 +++++++++++++++++++++++++++---------- 1 file changed, 111 insertions(+), 39 deletions(-) diff --git a/tests-clar/repo/iterator.c b/tests-clar/repo/iterator.c index ef9bfc33d..2e53c48d7 100644 --- a/tests-clar/repo/iterator.c +++ b/tests-clar/repo/iterator.c @@ -755,47 +755,52 @@ void test_repo_iterator__workdir_icase(void) git_iterator_free(i); } -void test_repo_iterator__workdir_depth(void) +static void build_workdir_tree(const char *root, int dirs, int subs) { int i, j; + char buf[64], sub[64]; + + for (i = 0; i < dirs; ++i) { + if (i % 2 == 0) { + p_snprintf(buf, sizeof(buf), "%s/dir%02d", root, i); + cl_git_pass(git_futils_mkdir(buf, NULL, 0775, GIT_MKDIR_PATH)); + + p_snprintf(buf, sizeof(buf), "%s/dir%02d/file", root, i); + cl_git_mkfile(buf, buf); + buf[strlen(buf) - 5] = '\0'; + } else { + p_snprintf(buf, sizeof(buf), "%s/DIR%02d", root, i); + cl_git_pass(git_futils_mkdir(buf, NULL, 0775, GIT_MKDIR_PATH)); + } + + for (j = 0; j < subs; ++j) { + switch (j % 4) { + case 0: p_snprintf(sub, sizeof(sub), "%s/sub%02d", buf, j); break; + case 1: p_snprintf(sub, sizeof(sub), "%s/sUB%02d", buf, j); break; + case 2: p_snprintf(sub, sizeof(sub), "%s/Sub%02d", buf, j); break; + case 3: p_snprintf(sub, sizeof(sub), "%s/SUB%02d", buf, j); break; + } + cl_git_pass(git_futils_mkdir(sub, NULL, 0775, GIT_MKDIR_PATH)); + + if (j % 2 == 0) { + size_t sublen = strlen(sub); + memcpy(&sub[sublen], "/file", sizeof("/file")); + cl_git_mkfile(sub, sub); + sub[sublen] = '\0'; + } + } + } +} + +void test_repo_iterator__workdir_depth(void) +{ git_iterator *iter; - char buf[64]; g_repo = cl_git_sandbox_init("icase"); - for (i = 0; i < 10; ++i) { - p_snprintf(buf, sizeof(buf), "icase/dir%02d", i); - cl_git_pass(git_futils_mkdir(buf, NULL, 0775, GIT_MKDIR_PATH)); - - if (i % 2 == 0) { - p_snprintf(buf, sizeof(buf), "icase/dir%02d/file", i); - cl_git_mkfile(buf, buf); - } - - for (j = 0; j < 10; ++j) { - p_snprintf(buf, sizeof(buf), "icase/dir%02d/sub%02d", i, j); - cl_git_pass(git_futils_mkdir(buf, NULL, 0775, GIT_MKDIR_PATH)); - - if (j % 2 == 0) { - p_snprintf( - buf, sizeof(buf), "icase/dir%02d/sub%02d/file", i, j); - cl_git_mkfile(buf, buf); - } - } - } - - for (i = 1; i < 3; ++i) { - for (j = 0; j < 50; ++j) { - p_snprintf(buf, sizeof(buf), "icase/dir%02d/sub01/moar%02d", i, j); - cl_git_pass(git_futils_mkdir(buf, NULL, 0775, GIT_MKDIR_PATH)); - - if (j % 2 == 0) { - p_snprintf(buf, sizeof(buf), - "icase/dir%02d/sub01/moar%02d/file", i, j); - cl_git_mkfile(buf, buf); - } - } - } + build_workdir_tree("icase", 10, 10); + build_workdir_tree("icase/dir01/Sub01", 50, 0); + build_workdir_tree("icase/DIR02/Sub01", 50, 0); /* auto expand with no tree entries */ cl_git_pass(git_iterator_for_workdir(&iter, g_repo, 0, NULL, NULL)); @@ -812,8 +817,42 @@ void test_repo_iterator__workdir_depth(void) void test_repo_iterator__fs(void) { git_iterator *i; - static const char *expect_subdir[] = { + static const char *expect_base[] = { + "DIR01/Sub02/file", + "DIR01/sub00/file", "current_file", + "dir00/Sub02/file", + "dir00/file", + "dir00/sub00/file", + "modified_file", + "new_file", + NULL, + }; + static const char *expect_trees[] = { + "DIR01/", + "DIR01/SUB03/", + "DIR01/Sub02/", + "DIR01/Sub02/file", + "DIR01/sUB01/", + "DIR01/sub00/", + "DIR01/sub00/file", + "current_file", + "dir00/", + "dir00/SUB03/", + "dir00/Sub02/", + "dir00/Sub02/file", + "dir00/file", + "dir00/sUB01/", + "dir00/sub00/", + "dir00/sub00/file", + "modified_file", + "new_file", + NULL, + }; + static const char *expect_noauto[] = { + "DIR01/", + "current_file", + "dir00/", "modified_file", "new_file", NULL, @@ -821,16 +860,49 @@ void test_repo_iterator__fs(void) g_repo = cl_git_sandbox_init("status"); + build_workdir_tree("status/subdir", 2, 4); + cl_git_pass(git_iterator_for_filesystem( &i, "status/subdir", 0, NULL, NULL)); - expect_iterator_items(i, 3, expect_subdir, 3, expect_subdir); + expect_iterator_items(i, 8, expect_base, 8, expect_base); + git_iterator_free(i); + + cl_git_pass(git_iterator_for_filesystem( + &i, "status/subdir", GIT_ITERATOR_INCLUDE_TREES, NULL, NULL)); + expect_iterator_items(i, 18, expect_trees, 18, expect_trees); + git_iterator_free(i); + + cl_git_pass(git_iterator_for_filesystem( + &i, "status/subdir", GIT_ITERATOR_DONT_AUTOEXPAND, NULL, NULL)); + expect_iterator_items(i, 5, expect_noauto, 18, expect_trees); + git_iterator_free(i); + + git__tsort((void **)expect_base, 8, (git__tsort_cmp)git__strcasecmp); + git__tsort((void **)expect_trees, 18, (git__tsort_cmp)git__strcasecmp); + git__tsort((void **)expect_noauto, 5, (git__tsort_cmp)git__strcasecmp); + + cl_git_pass(git_iterator_for_filesystem( + &i, "status/subdir", GIT_ITERATOR_IGNORE_CASE, NULL, NULL)); + expect_iterator_items(i, 8, expect_base, 8, expect_base); + git_iterator_free(i); + + cl_git_pass(git_iterator_for_filesystem( + &i, "status/subdir", GIT_ITERATOR_IGNORE_CASE | + GIT_ITERATOR_INCLUDE_TREES, NULL, NULL)); + expect_iterator_items(i, 18, expect_trees, 18, expect_trees); + git_iterator_free(i); + + cl_git_pass(git_iterator_for_filesystem( + &i, "status/subdir", GIT_ITERATOR_IGNORE_CASE | + GIT_ITERATOR_DONT_AUTOEXPAND, NULL, NULL)); + expect_iterator_items(i, 5, expect_noauto, 18, expect_trees); git_iterator_free(i); } void test_repo_iterator__fs2(void) { git_iterator *i; - static const char *expect_subdir[] = { + static const char *expect_base[] = { "heads/br2", "heads/dir", "heads/master", @@ -849,6 +921,6 @@ void test_repo_iterator__fs2(void) cl_git_pass(git_iterator_for_filesystem( &i, "testrepo/.git/refs", 0, NULL, NULL)); - expect_iterator_items(i, 11, expect_subdir, 11, expect_subdir); + expect_iterator_items(i, 11, expect_base, 11, expect_base); git_iterator_free(i); } From 2aee1aa4165583cf77815df404d87818d53b72dc Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Thu, 18 Apr 2013 14:35:13 -0700 Subject: [PATCH 5/8] Fix uninitialized var warnings --- src/index.c | 2 +- src/revparse.c | 2 +- tests-clar/repo/iterator.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/index.c b/src/index.c index 6290ec4e8..2afd28158 100644 --- a/src/index.c +++ b/src/index.c @@ -1345,7 +1345,7 @@ static size_t read_extension(git_index *index, const char *buffer, size_t buffer static int parse_index(git_index *index, const char *buffer, size_t buffer_size) { unsigned int i; - struct index_header header; + struct index_header header = { 0 }; git_oid checksum_calculated, checksum_expected; #define seek_forward(_increase) { \ diff --git a/src/revparse.c b/src/revparse.c index 74635ed04..8a22a04f3 100644 --- a/src/revparse.c +++ b/src/revparse.c @@ -16,7 +16,7 @@ static int disambiguate_refname(git_reference **out, git_repository *repo, const char *refname) { - int error, i; + int error = 0, i; bool fallbackmode = true; git_reference *ref; git_buf refnamebuf = GIT_BUF_INIT, name = GIT_BUF_INIT; diff --git a/tests-clar/repo/iterator.c b/tests-clar/repo/iterator.c index 2e53c48d7..9118dd17e 100644 --- a/tests-clar/repo/iterator.c +++ b/tests-clar/repo/iterator.c @@ -422,7 +422,7 @@ static void build_test_tree( git_treebuilder *builder; const char *scan = fmt, *next; char type, delimiter; - git_filemode_t mode; + git_filemode_t mode = GIT_FILEMODE_BLOB; git_buf name = GIT_BUF_INIT; va_list arglist; From 9ea29c8f1dd155cf62fc6c87edaeb9984da72f72 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Thu, 18 Apr 2013 14:41:16 -0700 Subject: [PATCH 6/8] Fix fs iterator test on case sensitive fs --- tests-clar/repo/iterator.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests-clar/repo/iterator.c b/tests-clar/repo/iterator.c index 9118dd17e..ab460735c 100644 --- a/tests-clar/repo/iterator.c +++ b/tests-clar/repo/iterator.c @@ -799,8 +799,8 @@ void test_repo_iterator__workdir_depth(void) g_repo = cl_git_sandbox_init("icase"); build_workdir_tree("icase", 10, 10); - build_workdir_tree("icase/dir01/Sub01", 50, 0); - build_workdir_tree("icase/DIR02/Sub01", 50, 0); + build_workdir_tree("icase/DIR01/sUB01", 50, 0); + build_workdir_tree("icase/dir02/sUB01", 50, 0); /* auto expand with no tree entries */ cl_git_pass(git_iterator_for_workdir(&iter, g_repo, 0, NULL, NULL)); From 38fd8121a2a87cc0da405b50f4439ca6578dcff5 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Thu, 18 Apr 2013 14:48:20 -0700 Subject: [PATCH 7/8] Fix win64 warnings --- src/branch.c | 2 +- tests-clar/refdb/inmemory.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/branch.c b/src/branch.c index e7088790e..956286b74 100644 --- a/src/branch.c +++ b/src/branch.c @@ -377,7 +377,7 @@ int git_branch_remote_name(char *buffer, size_t buffer_len, git_repository *repo if (buffer) git_buf_copy_cstr(buffer, buffer_len, &buf); - ret = git_buf_len(&buf) + 1; + ret = (int)git_buf_len(&buf) + 1; git_buf_free(&buf); return ret; diff --git a/tests-clar/refdb/inmemory.c b/tests-clar/refdb/inmemory.c index 2cccd8eb2..ca721e977 100644 --- a/tests-clar/refdb/inmemory.c +++ b/tests-clar/refdb/inmemory.c @@ -160,7 +160,7 @@ void test_refdb_inmemory__foreach(void) cl_git_pass(git_reference_create(&write3, repo, GIT_REFS_HEADS_DIR "test3", &oid3, 0)); cl_git_pass(git_reference_foreach(repo, GIT_REF_LISTALL, foreach_test, &i)); - cl_assert_equal_i(i, 3); + cl_assert_equal_i(3, (int)i); git_reference_free(write1); git_reference_free(write2); @@ -207,7 +207,7 @@ void test_refdb_inmemory__delete(void) git_reference_free(write3); cl_git_pass(git_reference_foreach(repo, GIT_REF_LISTALL, delete_test, &i)); - cl_assert_equal_i(i, 1); + cl_assert_equal_i(1, (int)i); git_reference_free(write2); } From 1af80a676613882b3e04e82874c6e7c8c14b5f49 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Thu, 18 Apr 2013 16:13:52 -0700 Subject: [PATCH 8/8] Fix workdir iterator leak When attempting to create a workdir iterator for a bare repo, don't leak the iterator structure. --- src/iterator.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/iterator.c b/src/iterator.c index a72f97eca..ff08c1ce0 100644 --- a/src/iterator.c +++ b/src/iterator.c @@ -1252,16 +1252,14 @@ int git_iterator_for_workdir( const char *end) { int error; - workdir_iterator *wi = git__calloc(1, sizeof(workdir_iterator)); - GITERR_CHECK_ALLOC(wi); + workdir_iterator *wi; - assert(out && repo); - - if ((error = git_repository__ensure_not_bare( - repo, "scan working directory")) < 0) - return error; + if (git_repository__ensure_not_bare(repo, "scan working directory") < 0) + return GIT_EBAREREPO; /* initialize as an fs iterator then do overrides */ + wi = git__calloc(1, sizeof(workdir_iterator)); + GITERR_CHECK_ALLOC(wi); ITERATOR_BASE_INIT((&wi->fi), fs, FS, repo); wi->fi.base.type = GIT_ITERATOR_TYPE_WORKDIR;