Commit 91e7d263 by Russell Belfer

Fix iterator reset and add reset ranges

The `git_iterator_reset` command has not been working in all cases
particularly when there is a start and end range.  This fixes it
and adds tests for it, and also extends it with the ability to
update the start/end range strings when an iterator is reset.
parent 9950d27a
...@@ -37,7 +37,7 @@ struct git_iterator { ...@@ -37,7 +37,7 @@ struct git_iterator {
int (*at_end)(git_iterator *); int (*at_end)(git_iterator *);
int (*advance)(git_iterator *, const git_index_entry **); int (*advance)(git_iterator *, const git_index_entry **);
int (*seek)(git_iterator *, const char *prefix); int (*seek)(git_iterator *, const char *prefix);
int (*reset)(git_iterator *); int (*reset)(git_iterator *, const char *start, const char *end);
void (*free)(git_iterator *); void (*free)(git_iterator *);
}; };
...@@ -126,9 +126,10 @@ GIT_INLINE(int) git_iterator_seek( ...@@ -126,9 +126,10 @@ GIT_INLINE(int) git_iterator_seek(
return iter->seek(iter, prefix); return iter->seek(iter, prefix);
} }
GIT_INLINE(int) git_iterator_reset(git_iterator *iter) GIT_INLINE(int) git_iterator_reset(
git_iterator *iter, const char *start, const char *end)
{ {
return iter->reset(iter); return iter->reset(iter, start, end);
} }
GIT_INLINE(void) git_iterator_free(git_iterator *iter) GIT_INLINE(void) git_iterator_free(git_iterator *iter)
......
...@@ -770,18 +770,30 @@ int git_path_dirload( ...@@ -770,18 +770,30 @@ int git_path_dirload(
int git_path_with_stat_cmp(const void *a, const void *b) int git_path_with_stat_cmp(const void *a, const void *b)
{ {
const git_path_with_stat *psa = a, *psb = b; const git_path_with_stat *psa = a, *psb = b;
return git__strcmp_cb(psa->path, psb->path); return strcmp(psa->path, psb->path);
}
int git_path_with_stat_cmp_icase(const void *a, const void *b)
{
const git_path_with_stat *psa = a, *psb = b;
return strcasecmp(psa->path, psb->path);
} }
int git_path_dirload_with_stat( int git_path_dirload_with_stat(
const char *path, const char *path,
size_t prefix_len, size_t prefix_len,
bool ignore_case,
const char *start_stat,
const char *end_stat,
git_vector *contents) git_vector *contents)
{ {
int error; int error;
unsigned int i; unsigned int i;
git_path_with_stat *ps; git_path_with_stat *ps;
git_buf full = GIT_BUF_INIT; git_buf full = GIT_BUF_INIT;
int (*strncomp)(const char *a, const char *b, size_t sz);
size_t start_len = start_stat ? strlen(start_stat) : 0;
size_t end_len = end_stat ? strlen(end_stat) : 0, cmp_len;
if (git_buf_set(&full, path, prefix_len) < 0) if (git_buf_set(&full, path, prefix_len) < 0)
return -1; return -1;
...@@ -793,11 +805,23 @@ int git_path_dirload_with_stat( ...@@ -793,11 +805,23 @@ int git_path_dirload_with_stat(
return error; return error;
} }
strncomp = ignore_case ? git__strncasecmp : git__strncmp;
/* stat struct at start of git_path_with_stat, so shift path text */
git_vector_foreach(contents, i, ps) { git_vector_foreach(contents, i, ps) {
size_t path_len = strlen((char *)ps); size_t path_len = strlen((char *)ps);
memmove(ps->path, ps, path_len + 1); memmove(ps->path, ps, path_len + 1);
ps->path_len = path_len; ps->path_len = path_len;
}
git_vector_foreach(contents, i, ps) {
/* skip if before start_stat or after end_stat */
cmp_len = min(start_len, ps->path_len);
if (cmp_len && strncomp(ps->path, start_stat, cmp_len) < 0)
continue;
cmp_len = min(end_len, ps->path_len);
if (cmp_len && strncomp(ps->path, end_stat, cmp_len) > 0)
continue;
if ((error = git_buf_joinpath(&full, full.ptr, ps->path)) < 0 || if ((error = git_buf_joinpath(&full, full.ptr, ps->path)) < 0 ||
(error = git_path_lstat(full.ptr, &ps->st)) < 0) (error = git_path_lstat(full.ptr, &ps->st)) < 0)
...@@ -806,11 +830,14 @@ int git_path_dirload_with_stat( ...@@ -806,11 +830,14 @@ int git_path_dirload_with_stat(
git_buf_truncate(&full, prefix_len); git_buf_truncate(&full, prefix_len);
if (S_ISDIR(ps->st.st_mode)) { if (S_ISDIR(ps->st.st_mode)) {
ps->path[path_len] = '/'; ps->path[ps->path_len++] = '/';
ps->path[path_len + 1] = '\0'; ps->path[ps->path_len] = '\0';
} }
} }
/* sort now that directory suffix is added */
git_vector_sort(contents);
git_buf_free(&full); git_buf_free(&full);
return error; return error;
......
...@@ -321,18 +321,33 @@ typedef struct { ...@@ -321,18 +321,33 @@ typedef struct {
} git_path_with_stat; } git_path_with_stat;
extern int git_path_with_stat_cmp(const void *a, const void *b); extern int git_path_with_stat_cmp(const void *a, const void *b);
extern int git_path_with_stat_cmp_icase(const void *a, const void *b);
/** /**
* Load all directory entries along with stat info into a vector. * Load all directory entries along with stat info into a vector.
* *
* This is just like git_path_dirload except that each entry in the * This adds four things on top of plain `git_path_dirload`:
* vector is a git_path_with_stat structure that contains both the *
* path and the stat info, plus directories will have a / suffixed * 1. Each entry in the vector is a `git_path_with_stat` struct that
* to their path name. * contains both the path and the stat info
* 2. The entries will be sorted alphabetically
* 3. Entries that are directories will be suffixed with a '/'
* 4. Optionally, you can be a start and end prefix and only elements
* after the start and before the end (inclusively) will be stat'ed.
*
* @param path The directory to read from
* @param prefix_len The trailing part of path to prefix to entry paths
* @param ignore_case How to sort and compare paths with start/end limits
* @param start_stat As optimization, only stat values after this prefix
* @param end_stat As optimization, only stat values before this prefix
* @param contents Vector to fill with git_path_with_stat structures
*/ */
extern int git_path_dirload_with_stat( extern int git_path_dirload_with_stat(
const char *path, const char *path,
size_t prefix_len, size_t prefix_len,
bool ignore_case,
const char *start_stat,
const char *end_stat,
git_vector *contents); git_vector *contents);
#endif #endif
...@@ -301,6 +301,9 @@ int git_tree__prefix_position(git_tree *tree, const char *path) ...@@ -301,6 +301,9 @@ int git_tree__prefix_position(git_tree *tree, const char *path)
struct tree_key_search ksearch; struct tree_key_search ksearch;
size_t at_pos; size_t at_pos;
if (!path)
return 0;
ksearch.filename = path; ksearch.filename = path;
ksearch.filename_len = strlen(path); ksearch.filename_len = strlen(path);
......
...@@ -29,6 +29,10 @@ struct git_treebuilder { ...@@ -29,6 +29,10 @@ struct git_treebuilder {
git_vector entries; git_vector entries;
}; };
GIT_INLINE(int) git_tree__dup(git_tree **dest, git_tree *source)
{
return git_object__dup((git_object **)dest, (git_object *)source);
}
GIT_INLINE(bool) git_tree_entry__is_tree(const struct git_tree_entry *e) GIT_INLINE(bool) git_tree_entry__is_tree(const struct git_tree_entry *e)
{ {
......
...@@ -199,9 +199,17 @@ int git__strncmp(const char *a, const char *b, size_t sz) ...@@ -199,9 +199,17 @@ int git__strncmp(const char *a, const char *b, size_t sz)
int git__strncasecmp(const char *a, const char *b, size_t sz) int git__strncasecmp(const char *a, const char *b, size_t sz)
{ {
while (sz && *a && *b && tolower(*a) == tolower(*b)) int al, bl;
while (sz && *a && *b) {
al = (unsigned char)tolower(*a);
bl = (unsigned char)tolower(*b);
if (al != bl)
break;
--sz, ++a, ++b; --sz, ++a, ++b;
return !sz ? 0 : (tolower(*a) - tolower(*b)); }
return !sz ? 0 : al - bl;
} }
void git__strntolower(char *str, size_t len) void git__strntolower(char *str, size_t len)
......
...@@ -31,25 +31,35 @@ static void tree_iterator_test( ...@@ -31,25 +31,35 @@ static void tree_iterator_test(
git_tree *t; git_tree *t;
git_iterator *i; git_iterator *i;
const git_index_entry *entry; const git_index_entry *entry;
int count = 0; int count = 0, count_post_reset = 0;
git_repository *repo = cl_git_sandbox_init(sandbox); git_repository *repo = cl_git_sandbox_init(sandbox);
cl_assert(t = resolve_commit_oid_to_tree(repo, treeish)); cl_assert(t = resolve_commit_oid_to_tree(repo, treeish));
cl_git_pass(git_iterator_for_tree_range(&i, t, start, end)); cl_git_pass(git_iterator_for_tree_range(&i, t, start, end));
cl_git_pass(git_iterator_current(i, &entry));
/* test loop */
cl_git_pass(git_iterator_current(i, &entry));
while (entry != NULL) { while (entry != NULL) {
if (expected_values != NULL) if (expected_values != NULL)
cl_assert_equal_s(expected_values[count], entry->path); cl_assert_equal_s(expected_values[count], entry->path);
count++; count++;
cl_git_pass(git_iterator_advance(i, &entry));
}
/* test reset */
cl_git_pass(git_iterator_reset(i, NULL, NULL));
cl_git_pass(git_iterator_current(i, &entry));
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(i, &entry));
} }
git_iterator_free(i); git_iterator_free(i);
cl_assert(expected_count == count); cl_assert_equal_i(expected_count, count);
cl_assert_equal_i(count, count_post_reset);
git_tree_free(t); git_tree_free(t);
} }
...@@ -520,7 +530,7 @@ static void workdir_iterator_test( ...@@ -520,7 +530,7 @@ static void workdir_iterator_test(
{ {
git_iterator *i; git_iterator *i;
const git_index_entry *entry; const git_index_entry *entry;
int count = 0, count_all = 0; int count = 0, count_all = 0, count_all_post_reset = 0;
git_repository *repo = cl_git_sandbox_init(sandbox); git_repository *repo = cl_git_sandbox_init(sandbox);
cl_git_pass(git_iterator_for_workdir_range(&i, repo, start, end)); cl_git_pass(git_iterator_for_workdir_range(&i, repo, start, end));
...@@ -547,10 +557,26 @@ static void workdir_iterator_test( ...@@ -547,10 +557,26 @@ static void workdir_iterator_test(
cl_git_pass(git_iterator_advance(i, &entry)); cl_git_pass(git_iterator_advance(i, &entry));
} }
cl_git_pass(git_iterator_reset(i, NULL, NULL));
cl_git_pass(git_iterator_current(i, &entry));
while (entry != NULL) {
if (S_ISDIR(entry->mode)) {
cl_git_pass(git_iterator_advance_into_directory(i, &entry));
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));
}
git_iterator_free(i); git_iterator_free(i);
cl_assert_equal_i(expected_count,count); cl_assert_equal_i(expected_count, count);
cl_assert_equal_i(expected_count + expected_ignores, count_all); cl_assert_equal_i(expected_count + expected_ignores, count_all);
cl_assert_equal_i(count_all, count_all_post_reset);
} }
void test_diff_iterator__workdir_0(void) void test_diff_iterator__workdir_0(void)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment