mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-07 10:31:01 +00:00
Fix iterators based on pull request feedback
This update addresses all of the feedback in pull request #570. The biggest change was to create actual linked list stacks for storing the tree and workdir iterator state. This cleaned up the code a ton. Additionally, all of the static functions had their 'git_' prefix removed, and a lot of other unnecessary changes were removed from the original patch.
This commit is contained in:
parent
da337c8064
commit
0534641dfe
@ -147,7 +147,7 @@ int git_ignore__pop_dir(git_ignores *ign)
|
||||
if (ign->ign_path.length > 0) {
|
||||
git_attr_file *file = git_vector_last(&ign->ign_path);
|
||||
if (git__suffixcmp(ign->dir.ptr, file->path) == 0)
|
||||
git_vector_pop(&ign->ign_path, NULL);
|
||||
git_vector_pop(&ign->ign_path);
|
||||
git_buf_rtruncate_at_char(&ign->dir, '/');
|
||||
}
|
||||
return GIT_SUCCESS;
|
||||
|
429
src/iterator.c
429
src/iterator.c
@ -10,36 +10,33 @@
|
||||
#include "ignore.h"
|
||||
#include "buffer.h"
|
||||
|
||||
#define IDX_AS_PTR(I) (void *)((uint64_t)(I))
|
||||
#define PTR_AS_IDX(P) (unsigned int)((uint64_t)(P))
|
||||
typedef struct tree_iterator_frame tree_iterator_frame;
|
||||
struct tree_iterator_frame {
|
||||
tree_iterator_frame *next;
|
||||
git_tree *tree;
|
||||
unsigned int index;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
git_iterator cb;
|
||||
git_iterator base;
|
||||
git_repository *repo;
|
||||
git_vector tree_stack;
|
||||
git_vector idx_stack;
|
||||
tree_iterator_frame *stack;
|
||||
git_index_entry entry;
|
||||
git_buf path;
|
||||
} git_iterator_tree;
|
||||
} tree_iterator;
|
||||
|
||||
static const git_tree_entry *git_iterator__tree_entry(git_iterator_tree *ti)
|
||||
static const git_tree_entry *tree_iterator__tree_entry(tree_iterator *ti)
|
||||
{
|
||||
git_tree *tree;
|
||||
unsigned int tree_idx;
|
||||
|
||||
if ((tree = git_vector_last(&ti->tree_stack)) == NULL)
|
||||
return NULL;
|
||||
|
||||
tree_idx = PTR_AS_IDX(git_vector_last(&ti->idx_stack));
|
||||
return git_tree_entry_byindex(tree, tree_idx);
|
||||
return (ti->stack == NULL) ? NULL :
|
||||
git_tree_entry_byindex(ti->stack->tree, ti->stack->index);
|
||||
}
|
||||
|
||||
static int git_iterator__tree_current(
|
||||
static int tree_iterator__current(
|
||||
git_iterator *self, const git_index_entry **entry)
|
||||
{
|
||||
int error;
|
||||
git_iterator_tree *ti = (git_iterator_tree *)self;
|
||||
const git_tree_entry *te = git_iterator__tree_entry(ti);
|
||||
tree_iterator *ti = (tree_iterator *)self;
|
||||
const git_tree_entry *te = tree_iterator__tree_entry(ti);
|
||||
|
||||
*entry = NULL;
|
||||
|
||||
@ -58,132 +55,111 @@ static int git_iterator__tree_current(
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
static int git_iterator__tree_at_end(git_iterator *self)
|
||||
static int tree_iterator__at_end(git_iterator *self)
|
||||
{
|
||||
git_iterator_tree *ti = (git_iterator_tree *)self;
|
||||
git_tree *tree;
|
||||
return ((tree = git_vector_last(&ti->tree_stack)) == NULL ||
|
||||
git_tree_entry_byindex(
|
||||
tree, PTR_AS_IDX(git_vector_last(&ti->idx_stack))) == NULL);
|
||||
return (tree_iterator__tree_entry((tree_iterator *)self) == NULL);
|
||||
}
|
||||
|
||||
static int expand_tree_if_needed(git_iterator_tree *ti)
|
||||
static tree_iterator_frame *tree_iterator__alloc_frame(git_tree *tree)
|
||||
{
|
||||
tree_iterator_frame *tf = git__calloc(1, sizeof(tree_iterator_frame));
|
||||
tf->tree = tree;
|
||||
return tf;
|
||||
}
|
||||
|
||||
static int tree_iterator__expand_tree(tree_iterator *ti)
|
||||
{
|
||||
int error;
|
||||
git_tree *tree, *subtree;
|
||||
unsigned int tree_idx;
|
||||
const git_tree_entry *te;
|
||||
|
||||
while (1) {
|
||||
tree = git_vector_last(&ti->tree_stack);
|
||||
tree_idx = PTR_AS_IDX(git_vector_last(&ti->idx_stack));
|
||||
te = git_tree_entry_byindex(tree, tree_idx);
|
||||
|
||||
if (!entry_is_tree(te))
|
||||
break;
|
||||
git_tree *subtree;
|
||||
const git_tree_entry *te = tree_iterator__tree_entry(ti);
|
||||
tree_iterator_frame *tf;
|
||||
|
||||
while (te != NULL && entry_is_tree(te)) {
|
||||
error = git_tree_lookup(&subtree, ti->repo, &te->oid);
|
||||
if (error != GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
if ((error = git_vector_insert(&ti->tree_stack, subtree)) < GIT_SUCCESS ||
|
||||
(error = git_vector_insert(&ti->idx_stack, IDX_AS_PTR(0))) < GIT_SUCCESS ||
|
||||
(error = git_buf_joinpath(&ti->path, ti->path.ptr, te->filename)) < GIT_SUCCESS)
|
||||
{
|
||||
git_tree_free(subtree);
|
||||
if ((tf = tree_iterator__alloc_frame(subtree)) == NULL)
|
||||
return GIT_ENOMEM;
|
||||
|
||||
tf->next = ti->stack;
|
||||
ti->stack = tf;
|
||||
|
||||
error = git_buf_joinpath(&ti->path, ti->path.ptr, te->filename);
|
||||
if (error < GIT_SUCCESS)
|
||||
return error;
|
||||
}
|
||||
|
||||
te = tree_iterator__tree_entry(ti);
|
||||
}
|
||||
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
static int git_iterator__tree_advance(
|
||||
static void tree_iterator__pop_frame(tree_iterator *ti)
|
||||
{
|
||||
tree_iterator_frame *tf = ti->stack;
|
||||
ti->stack = tf->next;
|
||||
if (ti->stack != NULL) /* don't free the initial tree */
|
||||
git_tree_free(tf->tree);
|
||||
git__free(tf);
|
||||
}
|
||||
|
||||
static int tree_iterator__advance(
|
||||
git_iterator *self, const git_index_entry **entry)
|
||||
{
|
||||
int error = GIT_SUCCESS;
|
||||
git_iterator_tree *ti = (git_iterator_tree *)self;
|
||||
git_tree *tree = git_vector_last(&ti->tree_stack);
|
||||
unsigned int tree_idx = PTR_AS_IDX(git_vector_last(&ti->idx_stack));
|
||||
const git_tree_entry *te = git_tree_entry_byindex(tree, tree_idx);
|
||||
tree_iterator *ti = (tree_iterator *)self;
|
||||
const git_tree_entry *te;
|
||||
|
||||
if (entry != NULL)
|
||||
*entry = NULL;
|
||||
|
||||
if (te == NULL)
|
||||
return GIT_SUCCESS;
|
||||
|
||||
while (1) {
|
||||
/* advance this tree */
|
||||
tree_idx++;
|
||||
ti->idx_stack.contents[ti->idx_stack.length - 1] = IDX_AS_PTR(tree_idx);
|
||||
|
||||
while (ti->stack != NULL) {
|
||||
/* remove old entry filename */
|
||||
git_buf_rtruncate_at_char(&ti->path, '/');
|
||||
|
||||
if ((te = git_tree_entry_byindex(tree, tree_idx)) != NULL)
|
||||
te = git_tree_entry_byindex(ti->stack->tree, ++ti->stack->index);
|
||||
if (te != NULL)
|
||||
break;
|
||||
|
||||
/* no entry - either we are done or we are done with this subtree */
|
||||
if (ti->tree_stack.length == 1)
|
||||
return GIT_SUCCESS;
|
||||
|
||||
git_tree_free(tree);
|
||||
git_vector_remove(&ti->tree_stack, ti->tree_stack.length - 1);
|
||||
git_vector_remove(&ti->idx_stack, ti->idx_stack.length - 1);
|
||||
tree_iterator__pop_frame(ti);
|
||||
git_buf_rtruncate_at_char(&ti->path, '/');
|
||||
|
||||
tree = git_vector_last(&ti->tree_stack);
|
||||
tree_idx = PTR_AS_IDX(git_vector_last(&ti->idx_stack));
|
||||
}
|
||||
|
||||
if (te && entry_is_tree(te))
|
||||
error = expand_tree_if_needed(ti);
|
||||
error = tree_iterator__expand_tree(ti);
|
||||
|
||||
if (error == GIT_SUCCESS && entry != NULL)
|
||||
error = git_iterator__tree_current(self, entry);
|
||||
error = tree_iterator__current(self, entry);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static void git_iterator__tree_free(git_iterator *self)
|
||||
static void tree_iterator__free(git_iterator *self)
|
||||
{
|
||||
git_iterator_tree *ti = (git_iterator_tree *)self;
|
||||
|
||||
while (ti->tree_stack.length > 1) {
|
||||
git_tree *tree = git_vector_last(&ti->tree_stack);
|
||||
git_tree_free(tree);
|
||||
git_vector_remove(&ti->tree_stack, ti->tree_stack.length - 1);
|
||||
}
|
||||
|
||||
git_vector_clear(&ti->tree_stack);
|
||||
git_vector_clear(&ti->idx_stack);
|
||||
tree_iterator *ti = (tree_iterator *)self;
|
||||
while (ti->stack != NULL)
|
||||
tree_iterator__pop_frame(ti);
|
||||
git_buf_free(&ti->path);
|
||||
}
|
||||
|
||||
int git_iterator_for_tree(git_repository *repo, git_tree *tree, git_iterator **iter)
|
||||
int git_iterator_for_tree(
|
||||
git_repository *repo, git_tree *tree, git_iterator **iter)
|
||||
{
|
||||
int error;
|
||||
git_iterator_tree *ti = git__calloc(1, sizeof(git_iterator_tree));
|
||||
tree_iterator *ti = git__calloc(1, sizeof(tree_iterator));
|
||||
if (!ti)
|
||||
return GIT_ENOMEM;
|
||||
|
||||
ti->cb.type = GIT_ITERATOR_TREE;
|
||||
ti->cb.current = git_iterator__tree_current;
|
||||
ti->cb.at_end = git_iterator__tree_at_end;
|
||||
ti->cb.advance = git_iterator__tree_advance;
|
||||
ti->cb.free = git_iterator__tree_free;
|
||||
ti->repo = repo;
|
||||
ti->base.type = GIT_ITERATOR_TREE;
|
||||
ti->base.current = tree_iterator__current;
|
||||
ti->base.at_end = tree_iterator__at_end;
|
||||
ti->base.advance = tree_iterator__advance;
|
||||
ti->base.free = tree_iterator__free;
|
||||
ti->repo = repo;
|
||||
ti->stack = tree_iterator__alloc_frame(tree);
|
||||
|
||||
if (!(error = git_vector_init(&ti->tree_stack, 0, NULL)) &&
|
||||
!(error = git_vector_insert(&ti->tree_stack, tree)) &&
|
||||
!(error = git_vector_init(&ti->idx_stack, 0, NULL)))
|
||||
error = git_vector_insert(&ti->idx_stack, IDX_AS_PTR(0));
|
||||
|
||||
if (error == GIT_SUCCESS)
|
||||
error = expand_tree_if_needed(ti);
|
||||
|
||||
if (error != GIT_SUCCESS)
|
||||
if ((error = tree_iterator__expand_tree(ti)) < GIT_SUCCESS)
|
||||
git_iterator_free((git_iterator *)ti);
|
||||
else
|
||||
*iter = (git_iterator *)ti;
|
||||
@ -193,29 +169,29 @@ int git_iterator_for_tree(git_repository *repo, git_tree *tree, git_iterator **i
|
||||
|
||||
|
||||
typedef struct {
|
||||
git_iterator cb;
|
||||
git_iterator base;
|
||||
git_index *index;
|
||||
unsigned int current;
|
||||
} git_iterator_index;
|
||||
} index_iterator;
|
||||
|
||||
static int git_iterator__index_current(
|
||||
static int index_iterator__current(
|
||||
git_iterator *self, const git_index_entry **entry)
|
||||
{
|
||||
git_iterator_index *ii = (git_iterator_index *)self;
|
||||
index_iterator *ii = (index_iterator *)self;
|
||||
*entry = git_index_get(ii->index, ii->current);
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
static int git_iterator__index_at_end(git_iterator *self)
|
||||
static int index_iterator__at_end(git_iterator *self)
|
||||
{
|
||||
git_iterator_index *ii = (git_iterator_index *)self;
|
||||
index_iterator *ii = (index_iterator *)self;
|
||||
return (ii->current >= git_index_entrycount(ii->index));
|
||||
}
|
||||
|
||||
static int git_iterator__index_advance(
|
||||
static int index_iterator__advance(
|
||||
git_iterator *self, const git_index_entry **entry)
|
||||
{
|
||||
git_iterator_index *ii = (git_iterator_index *)self;
|
||||
index_iterator *ii = (index_iterator *)self;
|
||||
if (ii->current < git_index_entrycount(ii->index))
|
||||
ii->current++;
|
||||
if (entry)
|
||||
@ -223,9 +199,9 @@ static int git_iterator__index_advance(
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
static void git_iterator__index_free(git_iterator *self)
|
||||
static void index_iterator__free(git_iterator *self)
|
||||
{
|
||||
git_iterator_index *ii = (git_iterator_index *)self;
|
||||
index_iterator *ii = (index_iterator *)self;
|
||||
git_index_free(ii->index);
|
||||
ii->index = NULL;
|
||||
}
|
||||
@ -233,16 +209,16 @@ static void git_iterator__index_free(git_iterator *self)
|
||||
int git_iterator_for_index(git_repository *repo, git_iterator **iter)
|
||||
{
|
||||
int error;
|
||||
git_iterator_index *ii = git__calloc(1, sizeof(git_iterator_index));
|
||||
index_iterator *ii = git__calloc(1, sizeof(index_iterator));
|
||||
if (!ii)
|
||||
return GIT_ENOMEM;
|
||||
|
||||
ii->cb.type = GIT_ITERATOR_INDEX;
|
||||
ii->cb.current = git_iterator__index_current;
|
||||
ii->cb.at_end = git_iterator__index_at_end;
|
||||
ii->cb.advance = git_iterator__index_advance;
|
||||
ii->cb.free = git_iterator__index_free;
|
||||
ii->current = 0;
|
||||
ii->base.type = GIT_ITERATOR_INDEX;
|
||||
ii->base.current = index_iterator__current;
|
||||
ii->base.at_end = index_iterator__at_end;
|
||||
ii->base.advance = index_iterator__advance;
|
||||
ii->base.free = index_iterator__free;
|
||||
ii->current = 0;
|
||||
|
||||
if ((error = git_repository_index(&ii->index, repo)) < GIT_SUCCESS)
|
||||
git__free(ii);
|
||||
@ -252,101 +228,107 @@ int git_iterator_for_index(git_repository *repo, git_iterator **iter)
|
||||
}
|
||||
|
||||
|
||||
typedef struct workdir_iterator_frame workdir_iterator_frame;
|
||||
struct workdir_iterator_frame {
|
||||
workdir_iterator_frame *next;
|
||||
git_vector entries;
|
||||
unsigned int index;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
git_iterator cb;
|
||||
git_iterator base;
|
||||
git_repository *repo;
|
||||
size_t root_len;
|
||||
git_vector dir_stack; /* vector of vectors of paths */
|
||||
git_vector idx_stack;
|
||||
workdir_iterator_frame *stack;
|
||||
git_ignores ignores;
|
||||
git_index_entry entry;
|
||||
git_buf path;
|
||||
int is_ignored;
|
||||
} git_iterator_workdir;
|
||||
} workdir_iterator;
|
||||
|
||||
static void free_directory(git_vector *dir)
|
||||
static workdir_iterator_frame *workdir_iterator__alloc_frame(void)
|
||||
{
|
||||
workdir_iterator_frame *wf = git__calloc(1, sizeof(workdir_iterator_frame));
|
||||
if (wf == NULL)
|
||||
return wf;
|
||||
if (git_vector_init(&wf->entries, 0, git__strcmp_cb) != GIT_SUCCESS) {
|
||||
git__free(wf);
|
||||
return NULL;
|
||||
}
|
||||
return wf;
|
||||
}
|
||||
|
||||
static void workdir_iterator__free_frame(workdir_iterator_frame *wf)
|
||||
{
|
||||
unsigned int i;
|
||||
char *path;
|
||||
|
||||
git_vector_foreach(dir, i, path)
|
||||
git_vector_foreach(&wf->entries, i, path)
|
||||
git__free(path);
|
||||
git_vector_free(dir);
|
||||
git__free(dir);
|
||||
git_vector_free(&wf->entries);
|
||||
git__free(wf);
|
||||
}
|
||||
|
||||
static int load_workdir_entry(git_iterator_workdir *wi);
|
||||
static int workdir_iterator__update_entry(workdir_iterator *wi);
|
||||
|
||||
static int push_directory(git_iterator_workdir *wi)
|
||||
static int workdir_iterator__expand_dir(workdir_iterator *wi)
|
||||
{
|
||||
int error;
|
||||
git_vector *dir = NULL;
|
||||
workdir_iterator_frame *wf = workdir_iterator__alloc_frame();
|
||||
if (wf == NULL)
|
||||
return GIT_ENOMEM;
|
||||
|
||||
error = git_vector_alloc(&dir, 0, git__strcmp_cb);
|
||||
if (error < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
/* allocate dir entries with extra byte (the "1" param) so later on we
|
||||
* can suffix directories with a "/" as needed.
|
||||
/* allocate dir entries with extra byte (the "1" param) so we
|
||||
* can suffix directory names with a "/".
|
||||
*/
|
||||
error = git_path_dirload(wi->path.ptr, wi->root_len, 1, dir);
|
||||
if (error < GIT_SUCCESS || dir->length == 0) {
|
||||
free_directory(dir);
|
||||
error = git_path_dirload(wi->path.ptr, wi->root_len, 1, &wf->entries);
|
||||
if (error < GIT_SUCCESS || wf->entries.length == 0) {
|
||||
workdir_iterator__free_frame(wf);
|
||||
return GIT_ENOTFOUND;
|
||||
}
|
||||
|
||||
if ((error = git_vector_insert(&wi->dir_stack, dir)) ||
|
||||
(error = git_vector_insert(&wi->idx_stack, IDX_AS_PTR(0))))
|
||||
{
|
||||
free_directory(dir);
|
||||
return error;
|
||||
}
|
||||
git_vector_sort(&wf->entries);
|
||||
wf->next = wi->stack;
|
||||
wi->stack = wf;
|
||||
|
||||
git_vector_sort(dir);
|
||||
|
||||
if (wi->dir_stack.length > 1) {
|
||||
/* only push new ignores if this is not top level directory */
|
||||
if (wi->stack->next != NULL) {
|
||||
int slash_pos = git_buf_rfind_next(&wi->path, '/');
|
||||
(void)git_ignore__push_dir(&wi->ignores, &wi->path.ptr[slash_pos + 1]);
|
||||
}
|
||||
|
||||
return load_workdir_entry(wi);
|
||||
return workdir_iterator__update_entry(wi);
|
||||
}
|
||||
|
||||
static int git_iterator__workdir_current(
|
||||
static int workdir_iterator__current(
|
||||
git_iterator *self, const git_index_entry **entry)
|
||||
{
|
||||
git_iterator_workdir *wi = (git_iterator_workdir *)self;
|
||||
workdir_iterator *wi = (workdir_iterator *)self;
|
||||
*entry = (wi->entry.path == NULL) ? NULL : &wi->entry;
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
static int git_iterator__workdir_at_end(git_iterator *self)
|
||||
static int workdir_iterator__at_end(git_iterator *self)
|
||||
{
|
||||
git_iterator_workdir *wi = (git_iterator_workdir *)self;
|
||||
return (wi->entry.path == NULL);
|
||||
return (((workdir_iterator *)self)->entry.path == NULL);
|
||||
}
|
||||
|
||||
static int git_iterator__workdir_advance(
|
||||
static int workdir_iterator__advance(
|
||||
git_iterator *self, const git_index_entry **entry)
|
||||
{
|
||||
int error;
|
||||
git_iterator_workdir *wi = (git_iterator_workdir *)self;
|
||||
git_vector *dir;
|
||||
unsigned int pos;
|
||||
workdir_iterator *wi = (workdir_iterator *)self;
|
||||
workdir_iterator_frame *wf;
|
||||
const char *next;
|
||||
|
||||
if (entry)
|
||||
if (entry != NULL)
|
||||
*entry = NULL;
|
||||
|
||||
if (wi->entry.path == NULL)
|
||||
return GIT_SUCCESS;
|
||||
|
||||
while (1) {
|
||||
dir = git_vector_last(&wi->dir_stack);
|
||||
pos = 1 + PTR_AS_IDX(git_vector_last(&wi->idx_stack));
|
||||
wi->idx_stack.contents[wi->idx_stack.length - 1] = IDX_AS_PTR(pos);
|
||||
|
||||
next = git_vector_get(dir, pos);
|
||||
while ((wf = wi->stack) != NULL) {
|
||||
next = git_vector_get(&wf->entries, ++wf->index);
|
||||
if (next != NULL) {
|
||||
if (strcmp(next, DOT_GIT) == 0)
|
||||
continue;
|
||||
@ -354,69 +336,45 @@ static int git_iterator__workdir_advance(
|
||||
break;
|
||||
}
|
||||
|
||||
memset(&wi->entry, 0, sizeof(wi->entry));
|
||||
if (wi->dir_stack.length == 1)
|
||||
return GIT_SUCCESS;
|
||||
|
||||
free_directory(dir);
|
||||
git_vector_remove(&wi->dir_stack, wi->dir_stack.length - 1);
|
||||
git_vector_remove(&wi->idx_stack, wi->idx_stack.length - 1);
|
||||
/* pop workdir directory stack */
|
||||
wi->stack = wf->next;
|
||||
workdir_iterator__free_frame(wf);
|
||||
git_ignore__pop_dir(&wi->ignores);
|
||||
|
||||
if (wi->stack == NULL) {
|
||||
memset(&wi->entry, 0, sizeof(wi->entry));
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
error = load_workdir_entry(wi);
|
||||
error = workdir_iterator__update_entry(wi);
|
||||
|
||||
if (error == GIT_SUCCESS && entry)
|
||||
return git_iterator__workdir_current(self, entry);
|
||||
if (error == GIT_SUCCESS && entry != NULL)
|
||||
error = workdir_iterator__current(self, entry);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
int git_iterator_advance_into_directory(
|
||||
git_iterator *iter, const git_index_entry **entry)
|
||||
static void workdir_iterator__free(git_iterator *self)
|
||||
{
|
||||
git_iterator_workdir *wi = (git_iterator_workdir *)iter;
|
||||
workdir_iterator *wi = (workdir_iterator *)self;
|
||||
|
||||
if (iter->type != GIT_ITERATOR_WORKDIR)
|
||||
return git_iterator_current(iter, entry);
|
||||
|
||||
/* Loop because the first entry in the ignored directory could itself be
|
||||
* an ignored directory, but we want to descend to find an actual entry.
|
||||
*/
|
||||
if (wi->entry.path && S_ISDIR(wi->entry.mode)) {
|
||||
if (push_directory(wi) < GIT_SUCCESS)
|
||||
/* If error loading or if empty, skip the directory. */
|
||||
return git_iterator__workdir_advance((git_iterator *)wi, entry);
|
||||
while (wi->stack != NULL) {
|
||||
workdir_iterator_frame *wf = wi->stack;
|
||||
wi->stack = wf->next;
|
||||
workdir_iterator__free_frame(wf);
|
||||
}
|
||||
|
||||
return git_iterator__workdir_current(iter, entry);
|
||||
}
|
||||
|
||||
static void git_iterator__workdir_free(git_iterator *self)
|
||||
{
|
||||
git_iterator_workdir *wi = (git_iterator_workdir *)self;
|
||||
|
||||
while (wi->dir_stack.length) {
|
||||
git_vector *dir = git_vector_last(&wi->dir_stack);
|
||||
free_directory(dir);
|
||||
git_vector_remove(&wi->dir_stack, wi->dir_stack.length - 1);
|
||||
}
|
||||
|
||||
git_vector_clear(&wi->dir_stack);
|
||||
git_vector_clear(&wi->idx_stack);
|
||||
git_ignore__free(&wi->ignores);
|
||||
git_buf_free(&wi->path);
|
||||
}
|
||||
|
||||
static int load_workdir_entry(git_iterator_workdir *wi)
|
||||
static int workdir_iterator__update_entry(workdir_iterator *wi)
|
||||
{
|
||||
int error;
|
||||
char *relpath;
|
||||
git_vector *dir = git_vector_last(&wi->dir_stack);
|
||||
unsigned int pos = PTR_AS_IDX(git_vector_last(&wi->idx_stack));
|
||||
struct stat st;
|
||||
char *relpath = git_vector_get(&wi->stack->entries, wi->stack->index);
|
||||
|
||||
relpath = git_vector_get(dir, pos);
|
||||
error = git_buf_joinpath(
|
||||
&wi->path, git_repository_workdir(wi->repo), relpath);
|
||||
if (error < GIT_SUCCESS)
|
||||
@ -425,14 +383,12 @@ static int load_workdir_entry(git_iterator_workdir *wi)
|
||||
memset(&wi->entry, 0, sizeof(wi->entry));
|
||||
wi->entry.path = relpath;
|
||||
|
||||
/* skip over .git directory */
|
||||
if (strcmp(relpath, DOT_GIT) == 0)
|
||||
return git_iterator__workdir_advance((git_iterator *)wi, NULL);
|
||||
return workdir_iterator__advance((git_iterator *)wi, NULL);
|
||||
|
||||
/* if there is an error processing the entry, treat as ignored */
|
||||
wi->is_ignored = 1;
|
||||
error = git_ignore__lookup(&wi->ignores, wi->entry.path, &wi->is_ignored);
|
||||
if (error != GIT_SUCCESS)
|
||||
return GIT_SUCCESS;
|
||||
|
||||
if (p_lstat(wi->path.ptr, &st) < 0)
|
||||
return GIT_SUCCESS;
|
||||
@ -451,6 +407,11 @@ static int load_workdir_entry(git_iterator_workdir *wi)
|
||||
if (st.st_mode == 0)
|
||||
return GIT_SUCCESS;
|
||||
|
||||
/* okay, we are far enough along to look up real ignore rule */
|
||||
error = git_ignore__lookup(&wi->ignores, wi->entry.path, &wi->is_ignored);
|
||||
if (error != GIT_SUCCESS)
|
||||
return GIT_SUCCESS;
|
||||
|
||||
if (S_ISDIR(st.st_mode)) {
|
||||
if (git_path_contains(&wi->path, DOT_GIT) == GIT_SUCCESS) {
|
||||
/* create submodule entry */
|
||||
@ -470,30 +431,28 @@ static int load_workdir_entry(git_iterator_workdir *wi)
|
||||
int git_iterator_for_workdir(git_repository *repo, git_iterator **iter)
|
||||
{
|
||||
int error;
|
||||
git_iterator_workdir *wi = git__calloc(1, sizeof(git_iterator_workdir));
|
||||
workdir_iterator *wi = git__calloc(1, sizeof(workdir_iterator));
|
||||
if (!wi)
|
||||
return GIT_ENOMEM;
|
||||
|
||||
wi->cb.type = GIT_ITERATOR_WORKDIR;
|
||||
wi->cb.current = git_iterator__workdir_current;
|
||||
wi->cb.at_end = git_iterator__workdir_at_end;
|
||||
wi->cb.advance = git_iterator__workdir_advance;
|
||||
wi->cb.free = git_iterator__workdir_free;
|
||||
wi->repo = repo;
|
||||
wi->base.type = GIT_ITERATOR_WORKDIR;
|
||||
wi->base.current = workdir_iterator__current;
|
||||
wi->base.at_end = workdir_iterator__at_end;
|
||||
wi->base.advance = workdir_iterator__advance;
|
||||
wi->base.free = workdir_iterator__free;
|
||||
wi->repo = repo;
|
||||
|
||||
if ((error = git_buf_sets(
|
||||
&wi->path, git_repository_workdir(repo))) < GIT_SUCCESS ||
|
||||
(error = git_vector_init(&wi->dir_stack, 0, NULL)) < GIT_SUCCESS ||
|
||||
(error = git_vector_init(&wi->idx_stack, 0, NULL)) < GIT_SUCCESS ||
|
||||
(error = git_ignore__for_path(repo, "", &wi->ignores)) < GIT_SUCCESS)
|
||||
{
|
||||
error = git_buf_sets(&wi->path, git_repository_workdir(repo));
|
||||
if (error == GIT_SUCCESS)
|
||||
error = git_ignore__for_path(repo, "", &wi->ignores);
|
||||
if (error != GIT_SUCCESS) {
|
||||
git__free(wi);
|
||||
return error;
|
||||
}
|
||||
|
||||
wi->root_len = wi->path.size;
|
||||
|
||||
if ((error = push_directory(wi)) < GIT_SUCCESS)
|
||||
if ((error = workdir_iterator__expand_dir(wi)) < GIT_SUCCESS)
|
||||
git_iterator_free((git_iterator *)wi);
|
||||
else
|
||||
*iter = (git_iterator *)wi;
|
||||
@ -501,21 +460,33 @@ int git_iterator_for_workdir(git_repository *repo, git_iterator **iter)
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
int git_iterator_current_tree_entry(
|
||||
git_iterator *iter, const git_tree_entry **tree_entry)
|
||||
{
|
||||
if (iter->type != GIT_ITERATOR_TREE)
|
||||
*tree_entry = NULL;
|
||||
else
|
||||
*tree_entry = git_iterator__tree_entry((git_iterator_tree *)iter);
|
||||
|
||||
*tree_entry = (iter->type != GIT_ITERATOR_TREE) ? NULL :
|
||||
tree_iterator__tree_entry((tree_iterator *)iter);
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
int git_iterator_current_is_ignored(git_iterator *iter)
|
||||
{
|
||||
if (iter->type != GIT_ITERATOR_WORKDIR)
|
||||
return 0;
|
||||
else
|
||||
return ((git_iterator_workdir *)iter)->is_ignored;
|
||||
return (iter->type != GIT_ITERATOR_WORKDIR) ? 0 :
|
||||
((workdir_iterator *)iter)->is_ignored;
|
||||
}
|
||||
|
||||
int git_iterator_advance_into_directory(
|
||||
git_iterator *iter, const git_index_entry **entry)
|
||||
{
|
||||
workdir_iterator *wi = (workdir_iterator *)iter;
|
||||
|
||||
if (iter->type == GIT_ITERATOR_WORKDIR &&
|
||||
wi->entry.path && S_ISDIR(wi->entry.mode))
|
||||
{
|
||||
if (workdir_iterator__expand_dir(wi) < GIT_SUCCESS)
|
||||
/* if error loading or if empty, skip the directory. */
|
||||
return workdir_iterator__advance(iter, entry);
|
||||
}
|
||||
|
||||
return entry ? git_iterator_current(iter, entry) : GIT_SUCCESS;
|
||||
}
|
||||
|
20
src/path.c
20
src/path.c
@ -398,42 +398,38 @@ int git_path_isfile(const char *path)
|
||||
static int _check_dir_contents(
|
||||
git_buf *dir,
|
||||
const char *sub,
|
||||
int append_on_success,
|
||||
int (*predicate)(const char *))
|
||||
{
|
||||
int error = GIT_SUCCESS;
|
||||
size_t dir_size = dir->size;
|
||||
size_t sub_size = strlen(sub);
|
||||
|
||||
/* leave base valid even if we could not make space for subdir */
|
||||
/* separate allocation and join, so we can always leave git_buf valid */
|
||||
if ((error = git_buf_try_grow(dir, dir_size + sub_size + 2)) < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
/* save excursion */
|
||||
git_buf_joinpath(dir, dir->ptr, sub);
|
||||
|
||||
error = (*predicate)(dir->ptr);
|
||||
|
||||
/* restore excursion */
|
||||
if (!append_on_success || error != GIT_SUCCESS)
|
||||
git_buf_truncate(dir, dir_size);
|
||||
/* restore path */
|
||||
git_buf_truncate(dir, dir_size);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
int git_path_contains(git_buf *dir, const char *item)
|
||||
{
|
||||
return _check_dir_contents(dir, item, 0, &git_path_exists);
|
||||
return _check_dir_contents(dir, item, &git_path_exists);
|
||||
}
|
||||
|
||||
int git_path_contains_dir(git_buf *base, const char *subdir, int append_if_exists)
|
||||
int git_path_contains_dir(git_buf *base, const char *subdir)
|
||||
{
|
||||
return _check_dir_contents(base, subdir, append_if_exists, &git_path_isdir);
|
||||
return _check_dir_contents(base, subdir, &git_path_isdir);
|
||||
}
|
||||
|
||||
int git_path_contains_file(git_buf *base, const char *file, int append_if_exists)
|
||||
int git_path_contains_file(git_buf *base, const char *file)
|
||||
{
|
||||
return _check_dir_contents(base, file, append_if_exists, &git_path_isfile);
|
||||
return _check_dir_contents(base, file, &git_path_isfile);
|
||||
}
|
||||
|
||||
int git_path_find_dir(git_buf *dir, const char *path, const char *base)
|
||||
|
@ -143,20 +143,18 @@ extern int git_path_contains(git_buf *dir, const char *item);
|
||||
*
|
||||
* @param parent Directory path that might contain subdir
|
||||
* @param subdir Subdirectory name to look for in parent
|
||||
* @param append_if_exists If true, then subdir will be appended to the parent path if it does exist
|
||||
* @return GIT_SUCCESS if subdirectory exists, < 0 otherwise.
|
||||
*/
|
||||
extern int git_path_contains_dir(git_buf *parent, const char *subdir, int append_if_exists);
|
||||
extern int git_path_contains_dir(git_buf *parent, const char *subdir);
|
||||
|
||||
/**
|
||||
* Check if the given path contains the given file.
|
||||
*
|
||||
* @param dir Directory path that might contain file
|
||||
* @param file File name to look for in parent
|
||||
* @param append_if_exists If true, then file will be appended to the path if it does exist
|
||||
* @return GIT_SUCCESS if file exists, < 0 otherwise.
|
||||
*/
|
||||
extern int git_path_contains_file(git_buf *dir, const char *file, int append_if_exists);
|
||||
extern int git_path_contains_file(git_buf *dir, const char *file);
|
||||
|
||||
/**
|
||||
* Clean up path, prepending base if it is not already rooted.
|
||||
|
@ -81,14 +81,14 @@ void git_repository_free(git_repository *repo)
|
||||
static int quickcheck_repository_dir(git_buf *repository_path)
|
||||
{
|
||||
/* Check OBJECTS_DIR first, since it will generate the longest path name */
|
||||
if (git_path_contains_dir(repository_path, GIT_OBJECTS_DIR, 0) < 0)
|
||||
if (git_path_contains_dir(repository_path, GIT_OBJECTS_DIR) < 0)
|
||||
return GIT_ERROR;
|
||||
|
||||
/* Ensure HEAD file exists */
|
||||
if (git_path_contains_file(repository_path, GIT_HEAD_FILE, 0) < 0)
|
||||
if (git_path_contains_file(repository_path, GIT_HEAD_FILE) < 0)
|
||||
return GIT_ERROR;
|
||||
|
||||
if (git_path_contains_dir(repository_path, GIT_REFS_DIR, 0) < 0)
|
||||
if (git_path_contains_dir(repository_path, GIT_REFS_DIR) < 0)
|
||||
return GIT_ERROR;
|
||||
|
||||
return GIT_SUCCESS;
|
||||
@ -166,8 +166,8 @@ int git_repository_open(git_repository **repo_out, const char *path)
|
||||
* of the working dir, by testing if it contains a `.git`
|
||||
* folder inside of it.
|
||||
*/
|
||||
git_path_contains_dir(&path_buf, GIT_DIR, 1); /* append on success */
|
||||
/* ignore error, since it just means `path/.git` doesn't exist */
|
||||
if (git_path_contains_dir(&path_buf, GIT_DIR) == GIT_SUCCESS)
|
||||
git_buf_joinpath(&path_buf, path_buf.ptr, GIT_DIR);
|
||||
|
||||
if (quickcheck_repository_dir(&path_buf) < GIT_SUCCESS) {
|
||||
error = git__throw(GIT_ENOTAREPO,
|
||||
|
33
src/vector.c
33
src/vector.c
@ -25,24 +25,6 @@ static int resize_vector(git_vector *v)
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
int git_vector_alloc(
|
||||
git_vector **vptr, unsigned int initial_size, git_vector_cmp cmp)
|
||||
{
|
||||
int error;
|
||||
git_vector *v = git__malloc(sizeof(git_vector));
|
||||
if (!v) {
|
||||
*vptr = NULL;
|
||||
return GIT_ENOMEM;
|
||||
}
|
||||
|
||||
if ((error = git_vector_init(v, initial_size, cmp)) < GIT_SUCCESS) {
|
||||
git__free(v);
|
||||
v = NULL;
|
||||
}
|
||||
*vptr = v;
|
||||
return error;
|
||||
}
|
||||
|
||||
void git_vector_free(git_vector *v)
|
||||
{
|
||||
assert(v);
|
||||
@ -205,19 +187,10 @@ int git_vector_remove(git_vector *v, unsigned int idx)
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
int git_vector_pop(git_vector *v, void **element)
|
||||
void git_vector_pop(git_vector *v)
|
||||
{
|
||||
assert(v);
|
||||
|
||||
if (v->length == 0)
|
||||
return git__throw(GIT_ENOTFOUND, "Can't remove element from empty list");
|
||||
|
||||
if (element != NULL)
|
||||
*element = v->contents[v->length - 1];
|
||||
|
||||
v->length--;
|
||||
|
||||
return GIT_SUCCESS;
|
||||
if (v->length > 0)
|
||||
v->length--;
|
||||
}
|
||||
|
||||
void git_vector_uniq(git_vector *v)
|
||||
|
@ -22,7 +22,6 @@ typedef struct git_vector {
|
||||
#define GIT_VECTOR_INIT {0}
|
||||
|
||||
int git_vector_init(git_vector *v, unsigned int initial_size, git_vector_cmp cmp);
|
||||
int git_vector_alloc(git_vector **v, unsigned int initial_size, git_vector_cmp cmp);
|
||||
void git_vector_free(git_vector *v);
|
||||
void git_vector_clear(git_vector *v);
|
||||
|
||||
@ -54,7 +53,7 @@ int git_vector_insert(git_vector *v, void *element);
|
||||
int git_vector_insert_sorted(git_vector *v, void *element,
|
||||
int (*on_dup)(void **old, void *new));
|
||||
int git_vector_remove(git_vector *v, unsigned int idx);
|
||||
int git_vector_pop(git_vector *v, void **element);
|
||||
void git_vector_pop(git_vector *v);
|
||||
void git_vector_uniq(git_vector *v);
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user