Commit 0e0589fc by Edward Thomson

iterator: combine fs+workdir iterators more completely

Drop some of the layers of indirection between the workdir and the
filesystem iterators.  This makes the code a little bit easier to
follow, and reduces the number of unnecessary allocations a bit as
well.  (Prior to this, when we filter entries, we would allocate them,
filter them and then free them; now we do the filtering before
allocation.)

Also, rename `git_iterator_advance_over_with_status` to just
`git_iterator_advance_over`.  Mostly because it's a fucking long-ass
function name otherwise.
parent d051de24
......@@ -394,7 +394,7 @@ static int checkout_action_wd_only(
git_buf_sets(&data->tmp, wd->path);
saved_wd.path = data->tmp.ptr;
error = git_iterator_advance_over_with_status(
error = git_iterator_advance_over(
wditem, &untracked_state, workdir);
if (error == GIT_ITEROVER)
over = true;
......@@ -930,7 +930,7 @@ static int checkout_conflicts_load(checkout_data *data, git_iterator *workdir, g
git_index *index;
/* Only write conficts from sources that have them: indexes. */
if ((index = git_iterator_get_index(data->target)) == NULL)
if ((index = git_iterator_index(data->target)) == NULL)
return 0;
data->update_conflicts._cmp = checkout_conflictdata_cmp;
......@@ -1080,7 +1080,7 @@ static int checkout_conflicts_coalesce_renames(
size_t i, names;
int error = 0;
if ((index = git_iterator_get_index(data->target)) == NULL)
if ((index = git_iterator_index(data->target)) == NULL)
return 0;
/* Juggle entries based on renames */
......@@ -1138,7 +1138,7 @@ static int checkout_conflicts_mark_directoryfile(
const char *path;
int prefixed, error = 0;
if ((index = git_iterator_get_index(data->target)) == NULL)
if ((index = git_iterator_index(data->target)) == NULL)
return 0;
len = git_index_entrycount(index);
......@@ -2378,7 +2378,7 @@ static int checkout_data_init(
if ((error = git_repository_index(&data->index, data->repo)) < 0)
goto cleanup;
if (data->index != git_iterator_get_index(target)) {
if (data->index != git_iterator_index(target)) {
if ((error = git_index_read(data->index, true)) < 0)
goto cleanup;
......@@ -2600,7 +2600,7 @@ int git_checkout_iterator(
(error = checkout_create_conflicts(&data)) < 0)
goto cleanup;
if (data.index != git_iterator_get_index(target) &&
if (data.index != git_iterator_index(target) &&
(error = checkout_extensions_update_index(&data)) < 0)
goto cleanup;
......
......@@ -826,8 +826,7 @@ static int maybe_modified(
*/
} else if (git_oid_iszero(&nitem->id) && new_is_workdir) {
bool use_ctime = ((diff->diffcaps & GIT_DIFFCAPS_TRUST_CTIME) != 0);
git_index *index;
git_iterator_index(&index, info->new_iter);
git_index *index = git_iterator_index(info->new_iter);
status = GIT_DELTA_UNMODIFIED;
......@@ -980,15 +979,14 @@ static int iterator_advance_into(
return error;
}
static int iterator_advance_over_with_status(
static int iterator_advance_over(
const git_index_entry **entry,
git_iterator_status_t *status,
git_iterator *iterator)
{
int error;
int error = git_iterator_advance_over(entry, status, iterator);
if ((error = git_iterator_advance_over_with_status(
entry, status, iterator)) == GIT_ITEROVER) {
if (error == GIT_ITEROVER) {
*entry = NULL;
error = 0;
}
......@@ -1056,7 +1054,7 @@ static int handle_unmatched_new_item(
return iterator_advance(&info->nitem, info->new_iter);
/* iterate into dir looking for an actual untracked file */
if ((error = iterator_advance_over_with_status(
if ((error = iterator_advance_over(
&info->nitem, &untracked_state, info->new_iter)) < 0)
return error;
......
......@@ -34,10 +34,19 @@ typedef enum {
GIT_ITERATOR_DONT_AUTOEXPAND = (1u << 3),
/** convert precomposed unicode to decomposed unicode */
GIT_ITERATOR_PRECOMPOSE_UNICODE = (1u << 4),
/** never convert precomposed unicode to decomposed unicode */
GIT_ITERATOR_DONT_PRECOMPOSE_UNICODE = (1u << 5),
/** include conflicts */
GIT_ITERATOR_INCLUDE_CONFLICTS = (1u << 5),
GIT_ITERATOR_INCLUDE_CONFLICTS = (1u << 6),
} git_iterator_flag_t;
typedef enum {
GIT_ITERATOR_STATUS_NORMAL = 0,
GIT_ITERATOR_STATUS_IGNORED = 1,
GIT_ITERATOR_STATUS_EMPTY = 2,
GIT_ITERATOR_STATUS_FILTERED = 3
} git_iterator_status_t;
typedef struct {
const char *start;
const char *end;
......@@ -57,6 +66,8 @@ typedef struct {
int (*current)(const git_index_entry **, git_iterator *);
int (*advance)(const git_index_entry **, git_iterator *);
int (*advance_into)(const git_index_entry **, git_iterator *);
int (*advance_over)(
const git_index_entry **, git_iterator_status_t *, git_iterator *);
int (*reset)(git_iterator *);
int (*reset_range)(git_iterator *, const char *start, const char *end);
int (*at_end)(git_iterator *);
......@@ -67,8 +78,13 @@ struct git_iterator {
git_iterator_type_t type;
git_iterator_callbacks *cb;
git_repository *repo;
char *start;
size_t start_len;
char *end;
size_t end_len;
bool started;
bool ended;
git_vector pathlist;
......@@ -76,6 +92,7 @@ struct git_iterator {
int (*strcomp)(const char *a, const char *b);
int (*strncomp)(const char *a, const char *b, size_t n);
int (*prefixcomp)(const char *str, const char *prefix);
int (*entry_srch)(const void *key, const void *array_member);
size_t stat_calls;
unsigned int flags;
};
......@@ -183,6 +200,28 @@ GIT_INLINE(int) git_iterator_advance_into(
return iter->cb->advance_into(entry, iter);
}
/* Advance over a directory and check if it contains no files or just
* ignored files.
*
* In a tree or the index, all directories will contain files, but in the
* working directory it is possible to have an empty directory tree or a
* tree that only contains ignored files. Many Git operations treat these
* cases specially. This advances over a directory (presumably an
* untracked directory) but checks during the scan if there are any files
* and any non-ignored files.
*/
GIT_INLINE(int) git_iterator_advance_over(
const git_index_entry **entry,
git_iterator_status_t *status,
git_iterator *iter)
{
if (iter->cb->advance_over)
return iter->cb->advance_over(entry, status, iter);
*status = GIT_ITERATOR_STATUS_NORMAL;
return git_iterator_advance(entry, iter);
}
/**
* Advance into a tree or skip over it if it is empty.
*
......@@ -273,35 +312,12 @@ extern int git_iterator_cmp(
extern int git_iterator_current_workdir_path(
git_buf **path, git_iterator *iter);
/* Return index pointer if index iterator, else NULL */
extern git_index *git_iterator_get_index(git_iterator *iter);
typedef enum {
GIT_ITERATOR_STATUS_NORMAL = 0,
GIT_ITERATOR_STATUS_IGNORED = 1,
GIT_ITERATOR_STATUS_EMPTY = 2,
GIT_ITERATOR_STATUS_FILTERED = 3
} git_iterator_status_t;
/* Advance over a directory and check if it contains no files or just
* ignored files.
*
* In a tree or the index, all directories will contain files, but in the
* working directory it is possible to have an empty directory tree or a
* tree that only contains ignored files. Many Git operations treat these
* cases specially. This advances over a directory (presumably an
* untracked directory) but checks during the scan if there are any files
* and any non-ignored files.
*/
extern int git_iterator_advance_over_with_status(
const git_index_entry **entry, git_iterator_status_t *status, git_iterator *iter);
/**
* Retrieve the index stored in the iterator.
*
* Only implemented for the workdir iterator
* Only implemented for the workdir and index iterators.
*/
extern int git_iterator_index(git_index **out, git_iterator *iter);
extern git_index *git_iterator_index(git_iterator *iter);
typedef int (*git_iterator_walk_cb)(
const git_index_entry **entries,
......
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