Commit 0534641d by Russell Belfer

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.
parent da337c80
...@@ -147,7 +147,7 @@ int git_ignore__pop_dir(git_ignores *ign) ...@@ -147,7 +147,7 @@ int git_ignore__pop_dir(git_ignores *ign)
if (ign->ign_path.length > 0) { if (ign->ign_path.length > 0) {
git_attr_file *file = git_vector_last(&ign->ign_path); git_attr_file *file = git_vector_last(&ign->ign_path);
if (git__suffixcmp(ign->dir.ptr, file->path) == 0) 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, '/'); git_buf_rtruncate_at_char(&ign->dir, '/');
} }
return GIT_SUCCESS; return GIT_SUCCESS;
......
...@@ -10,36 +10,33 @@ ...@@ -10,36 +10,33 @@
#include "ignore.h" #include "ignore.h"
#include "buffer.h" #include "buffer.h"
#define IDX_AS_PTR(I) (void *)((uint64_t)(I)) typedef struct tree_iterator_frame tree_iterator_frame;
#define PTR_AS_IDX(P) (unsigned int)((uint64_t)(P)) struct tree_iterator_frame {
tree_iterator_frame *next;
git_tree *tree;
unsigned int index;
};
typedef struct { typedef struct {
git_iterator cb; git_iterator base;
git_repository *repo; git_repository *repo;
git_vector tree_stack; tree_iterator_frame *stack;
git_vector idx_stack;
git_index_entry entry; git_index_entry entry;
git_buf path; 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; return (ti->stack == NULL) ? NULL :
unsigned int tree_idx; git_tree_entry_byindex(ti->stack->tree, ti->stack->index);
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);
} }
static int git_iterator__tree_current( static int tree_iterator__current(
git_iterator *self, const git_index_entry **entry) git_iterator *self, const git_index_entry **entry)
{ {
int error; int error;
git_iterator_tree *ti = (git_iterator_tree *)self; tree_iterator *ti = (tree_iterator *)self;
const git_tree_entry *te = git_iterator__tree_entry(ti); const git_tree_entry *te = tree_iterator__tree_entry(ti);
*entry = NULL; *entry = NULL;
...@@ -58,132 +55,111 @@ static int git_iterator__tree_current( ...@@ -58,132 +55,111 @@ static int git_iterator__tree_current(
return GIT_SUCCESS; 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; return (tree_iterator__tree_entry((tree_iterator *)self) == NULL);
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);
} }
static int expand_tree_if_needed(git_iterator_tree *ti) static tree_iterator_frame *tree_iterator__alloc_frame(git_tree *tree)
{ {
int error; tree_iterator_frame *tf = git__calloc(1, sizeof(tree_iterator_frame));
git_tree *tree, *subtree; tf->tree = tree;
unsigned int tree_idx; return tf;
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)) static int tree_iterator__expand_tree(tree_iterator *ti)
break; {
int error;
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); error = git_tree_lookup(&subtree, ti->repo, &te->oid);
if (error != GIT_SUCCESS) if (error != GIT_SUCCESS)
return error; return error;
if ((error = git_vector_insert(&ti->tree_stack, subtree)) < GIT_SUCCESS || if ((tf = tree_iterator__alloc_frame(subtree)) == NULL)
(error = git_vector_insert(&ti->idx_stack, IDX_AS_PTR(0))) < GIT_SUCCESS || return GIT_ENOMEM;
(error = git_buf_joinpath(&ti->path, ti->path.ptr, te->filename)) < GIT_SUCCESS)
{ tf->next = ti->stack;
git_tree_free(subtree); ti->stack = tf;
error = git_buf_joinpath(&ti->path, ti->path.ptr, te->filename);
if (error < GIT_SUCCESS)
return error; return error;
}
te = tree_iterator__tree_entry(ti);
} }
return GIT_SUCCESS; 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) git_iterator *self, const git_index_entry **entry)
{ {
int error = GIT_SUCCESS; int error = GIT_SUCCESS;
git_iterator_tree *ti = (git_iterator_tree *)self; tree_iterator *ti = (tree_iterator *)self;
git_tree *tree = git_vector_last(&ti->tree_stack); const git_tree_entry *te;
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);
if (entry != NULL) if (entry != NULL)
*entry = NULL; *entry = NULL;
if (te == NULL) while (ti->stack != 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);
/* remove old entry filename */ /* remove old entry filename */
git_buf_rtruncate_at_char(&ti->path, '/'); 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; break;
/* no entry - either we are done or we are done with this subtree */ tree_iterator__pop_frame(ti);
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);
git_buf_rtruncate_at_char(&ti->path, '/'); 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)) if (te && entry_is_tree(te))
error = expand_tree_if_needed(ti); error = tree_iterator__expand_tree(ti);
if (error == GIT_SUCCESS && entry != NULL) if (error == GIT_SUCCESS && entry != NULL)
error = git_iterator__tree_current(self, entry); error = tree_iterator__current(self, entry);
return error; 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; tree_iterator *ti = (tree_iterator *)self;
while (ti->stack != NULL)
while (ti->tree_stack.length > 1) { tree_iterator__pop_frame(ti);
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);
git_buf_free(&ti->path); 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; int error;
git_iterator_tree *ti = git__calloc(1, sizeof(git_iterator_tree)); tree_iterator *ti = git__calloc(1, sizeof(tree_iterator));
if (!ti) if (!ti)
return GIT_ENOMEM; return GIT_ENOMEM;
ti->cb.type = GIT_ITERATOR_TREE; ti->base.type = GIT_ITERATOR_TREE;
ti->cb.current = git_iterator__tree_current; ti->base.current = tree_iterator__current;
ti->cb.at_end = git_iterator__tree_at_end; ti->base.at_end = tree_iterator__at_end;
ti->cb.advance = git_iterator__tree_advance; ti->base.advance = tree_iterator__advance;
ti->cb.free = git_iterator__tree_free; ti->base.free = tree_iterator__free;
ti->repo = repo; 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) if ((error = tree_iterator__expand_tree(ti)) < GIT_SUCCESS)
error = expand_tree_if_needed(ti);
if (error != GIT_SUCCESS)
git_iterator_free((git_iterator *)ti); git_iterator_free((git_iterator *)ti);
else else
*iter = (git_iterator *)ti; *iter = (git_iterator *)ti;
...@@ -193,29 +169,29 @@ int git_iterator_for_tree(git_repository *repo, git_tree *tree, git_iterator **i ...@@ -193,29 +169,29 @@ int git_iterator_for_tree(git_repository *repo, git_tree *tree, git_iterator **i
typedef struct { typedef struct {
git_iterator cb; git_iterator base;
git_index *index; git_index *index;
unsigned int current; 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 *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); *entry = git_index_get(ii->index, ii->current);
return GIT_SUCCESS; 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)); 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 *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)) if (ii->current < git_index_entrycount(ii->index))
ii->current++; ii->current++;
if (entry) if (entry)
...@@ -223,9 +199,9 @@ static int git_iterator__index_advance( ...@@ -223,9 +199,9 @@ static int git_iterator__index_advance(
return GIT_SUCCESS; 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); git_index_free(ii->index);
ii->index = NULL; ii->index = NULL;
} }
...@@ -233,16 +209,16 @@ static void git_iterator__index_free(git_iterator *self) ...@@ -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 git_iterator_for_index(git_repository *repo, git_iterator **iter)
{ {
int error; int error;
git_iterator_index *ii = git__calloc(1, sizeof(git_iterator_index)); index_iterator *ii = git__calloc(1, sizeof(index_iterator));
if (!ii) if (!ii)
return GIT_ENOMEM; return GIT_ENOMEM;
ii->cb.type = GIT_ITERATOR_INDEX; ii->base.type = GIT_ITERATOR_INDEX;
ii->cb.current = git_iterator__index_current; ii->base.current = index_iterator__current;
ii->cb.at_end = git_iterator__index_at_end; ii->base.at_end = index_iterator__at_end;
ii->cb.advance = git_iterator__index_advance; ii->base.advance = index_iterator__advance;
ii->cb.free = git_iterator__index_free; ii->base.free = index_iterator__free;
ii->current = 0; ii->current = 0;
if ((error = git_repository_index(&ii->index, repo)) < GIT_SUCCESS) if ((error = git_repository_index(&ii->index, repo)) < GIT_SUCCESS)
git__free(ii); git__free(ii);
...@@ -252,101 +228,107 @@ int git_iterator_for_index(git_repository *repo, git_iterator **iter) ...@@ -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 { typedef struct {
git_iterator cb; git_iterator base;
git_repository *repo; git_repository *repo;
size_t root_len; size_t root_len;
git_vector dir_stack; /* vector of vectors of paths */ workdir_iterator_frame *stack;
git_vector idx_stack;
git_ignores ignores; git_ignores ignores;
git_index_entry entry; git_index_entry entry;
git_buf path; git_buf path;
int is_ignored; int is_ignored;
} git_iterator_workdir; } workdir_iterator;
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 free_directory(git_vector *dir) static void workdir_iterator__free_frame(workdir_iterator_frame *wf)
{ {
unsigned int i; unsigned int i;
char *path; char *path;
git_vector_foreach(dir, i, path) git_vector_foreach(&wf->entries, i, path)
git__free(path); git__free(path);
git_vector_free(dir); git_vector_free(&wf->entries);
git__free(dir); 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; int error;
git_vector *dir = NULL; workdir_iterator_frame *wf = workdir_iterator__alloc_frame();
if (wf == NULL)
error = git_vector_alloc(&dir, 0, git__strcmp_cb); return GIT_ENOMEM;
if (error < GIT_SUCCESS)
return error;
/* allocate dir entries with extra byte (the "1" param) so later on we /* allocate dir entries with extra byte (the "1" param) so we
* can suffix directories with a "/" as needed. * can suffix directory names with a "/".
*/ */
error = git_path_dirload(wi->path.ptr, wi->root_len, 1, dir); error = git_path_dirload(wi->path.ptr, wi->root_len, 1, &wf->entries);
if (error < GIT_SUCCESS || dir->length == 0) { if (error < GIT_SUCCESS || wf->entries.length == 0) {
free_directory(dir); workdir_iterator__free_frame(wf);
return GIT_ENOTFOUND; return GIT_ENOTFOUND;
} }
if ((error = git_vector_insert(&wi->dir_stack, dir)) || git_vector_sort(&wf->entries);
(error = git_vector_insert(&wi->idx_stack, IDX_AS_PTR(0)))) wf->next = wi->stack;
{ wi->stack = wf;
free_directory(dir);
return error;
}
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, '/'); int slash_pos = git_buf_rfind_next(&wi->path, '/');
(void)git_ignore__push_dir(&wi->ignores, &wi->path.ptr[slash_pos + 1]); (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 *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; *entry = (wi->entry.path == NULL) ? NULL : &wi->entry;
return GIT_SUCCESS; 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 (((workdir_iterator *)self)->entry.path == NULL);
return (wi->entry.path == NULL);
} }
static int git_iterator__workdir_advance( static int workdir_iterator__advance(
git_iterator *self, const git_index_entry **entry) git_iterator *self, const git_index_entry **entry)
{ {
int error; int error;
git_iterator_workdir *wi = (git_iterator_workdir *)self; workdir_iterator *wi = (workdir_iterator *)self;
git_vector *dir; workdir_iterator_frame *wf;
unsigned int pos;
const char *next; const char *next;
if (entry) if (entry != NULL)
*entry = NULL; *entry = NULL;
if (wi->entry.path == NULL) if (wi->entry.path == NULL)
return GIT_SUCCESS; return GIT_SUCCESS;
while (1) { while ((wf = wi->stack) != NULL) {
dir = git_vector_last(&wi->dir_stack); next = git_vector_get(&wf->entries, ++wf->index);
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);
if (next != NULL) { if (next != NULL) {
if (strcmp(next, DOT_GIT) == 0) if (strcmp(next, DOT_GIT) == 0)
continue; continue;
...@@ -354,69 +336,45 @@ static int git_iterator__workdir_advance( ...@@ -354,69 +336,45 @@ static int git_iterator__workdir_advance(
break; break;
} }
memset(&wi->entry, 0, sizeof(wi->entry)); /* pop workdir directory stack */
if (wi->dir_stack.length == 1) wi->stack = wf->next;
return GIT_SUCCESS; workdir_iterator__free_frame(wf);
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);
git_ignore__pop_dir(&wi->ignores); 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) if (error == GIT_SUCCESS && entry != NULL)
return git_iterator__workdir_current(self, entry); error = workdir_iterator__current(self, entry);
return error; return error;
} }
int git_iterator_advance_into_directory( static void workdir_iterator__free(git_iterator *self)
git_iterator *iter, const git_index_entry **entry)
{ {
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 while (wi->stack != NULL) {
* an ignored directory, but we want to descend to find an actual entry. workdir_iterator_frame *wf = wi->stack;
*/ wi->stack = wf->next;
if (wi->entry.path && S_ISDIR(wi->entry.mode)) { workdir_iterator__free_frame(wf);
if (push_directory(wi) < GIT_SUCCESS)
/* If error loading or if empty, skip the directory. */
return git_iterator__workdir_advance((git_iterator *)wi, entry);
} }
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_ignore__free(&wi->ignores);
git_buf_free(&wi->path); 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; 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; struct stat st;
char *relpath = git_vector_get(&wi->stack->entries, wi->stack->index);
relpath = git_vector_get(dir, pos);
error = git_buf_joinpath( error = git_buf_joinpath(
&wi->path, git_repository_workdir(wi->repo), relpath); &wi->path, git_repository_workdir(wi->repo), relpath);
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
...@@ -425,14 +383,12 @@ static int load_workdir_entry(git_iterator_workdir *wi) ...@@ -425,14 +383,12 @@ static int load_workdir_entry(git_iterator_workdir *wi)
memset(&wi->entry, 0, sizeof(wi->entry)); memset(&wi->entry, 0, sizeof(wi->entry));
wi->entry.path = relpath; wi->entry.path = relpath;
/* skip over .git directory */
if (strcmp(relpath, DOT_GIT) == 0) 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 */ /* if there is an error processing the entry, treat as ignored */
wi->is_ignored = 1; 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) if (p_lstat(wi->path.ptr, &st) < 0)
return GIT_SUCCESS; return GIT_SUCCESS;
...@@ -451,6 +407,11 @@ static int load_workdir_entry(git_iterator_workdir *wi) ...@@ -451,6 +407,11 @@ static int load_workdir_entry(git_iterator_workdir *wi)
if (st.st_mode == 0) if (st.st_mode == 0)
return GIT_SUCCESS; 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 (S_ISDIR(st.st_mode)) {
if (git_path_contains(&wi->path, DOT_GIT) == GIT_SUCCESS) { if (git_path_contains(&wi->path, DOT_GIT) == GIT_SUCCESS) {
/* create submodule entry */ /* create submodule entry */
...@@ -470,30 +431,28 @@ static int load_workdir_entry(git_iterator_workdir *wi) ...@@ -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 git_iterator_for_workdir(git_repository *repo, git_iterator **iter)
{ {
int error; int error;
git_iterator_workdir *wi = git__calloc(1, sizeof(git_iterator_workdir)); workdir_iterator *wi = git__calloc(1, sizeof(workdir_iterator));
if (!wi) if (!wi)
return GIT_ENOMEM; return GIT_ENOMEM;
wi->cb.type = GIT_ITERATOR_WORKDIR; wi->base.type = GIT_ITERATOR_WORKDIR;
wi->cb.current = git_iterator__workdir_current; wi->base.current = workdir_iterator__current;
wi->cb.at_end = git_iterator__workdir_at_end; wi->base.at_end = workdir_iterator__at_end;
wi->cb.advance = git_iterator__workdir_advance; wi->base.advance = workdir_iterator__advance;
wi->cb.free = git_iterator__workdir_free; wi->base.free = workdir_iterator__free;
wi->repo = repo; wi->repo = repo;
if ((error = git_buf_sets( error = git_buf_sets(&wi->path, git_repository_workdir(repo));
&wi->path, git_repository_workdir(repo))) < GIT_SUCCESS || if (error == GIT_SUCCESS)
(error = git_vector_init(&wi->dir_stack, 0, NULL)) < GIT_SUCCESS || error = git_ignore__for_path(repo, "", &wi->ignores);
(error = git_vector_init(&wi->idx_stack, 0, NULL)) < GIT_SUCCESS || if (error != GIT_SUCCESS) {
(error = git_ignore__for_path(repo, "", &wi->ignores)) < GIT_SUCCESS)
{
git__free(wi); git__free(wi);
return error; return error;
} }
wi->root_len = wi->path.size; 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); git_iterator_free((git_iterator *)wi);
else else
*iter = (git_iterator *)wi; *iter = (git_iterator *)wi;
...@@ -501,21 +460,33 @@ int git_iterator_for_workdir(git_repository *repo, git_iterator **iter) ...@@ -501,21 +460,33 @@ int git_iterator_for_workdir(git_repository *repo, git_iterator **iter)
return error; return error;
} }
int git_iterator_current_tree_entry( int git_iterator_current_tree_entry(
git_iterator *iter, const git_tree_entry **tree_entry) git_iterator *iter, const git_tree_entry **tree_entry)
{ {
if (iter->type != GIT_ITERATOR_TREE) *tree_entry = (iter->type != GIT_ITERATOR_TREE) ? NULL :
*tree_entry = NULL; tree_iterator__tree_entry((tree_iterator *)iter);
else
*tree_entry = git_iterator__tree_entry((git_iterator_tree *)iter);
return GIT_SUCCESS; return GIT_SUCCESS;
} }
int git_iterator_current_is_ignored(git_iterator *iter) int git_iterator_current_is_ignored(git_iterator *iter)
{ {
if (iter->type != GIT_ITERATOR_WORKDIR) return (iter->type != GIT_ITERATOR_WORKDIR) ? 0 :
return 0; ((workdir_iterator *)iter)->is_ignored;
else }
return ((git_iterator_workdir *)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;
} }
...@@ -398,42 +398,38 @@ int git_path_isfile(const char *path) ...@@ -398,42 +398,38 @@ int git_path_isfile(const char *path)
static int _check_dir_contents( static int _check_dir_contents(
git_buf *dir, git_buf *dir,
const char *sub, const char *sub,
int append_on_success,
int (*predicate)(const char *)) int (*predicate)(const char *))
{ {
int error = GIT_SUCCESS; int error = GIT_SUCCESS;
size_t dir_size = dir->size; size_t dir_size = dir->size;
size_t sub_size = strlen(sub); 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) if ((error = git_buf_try_grow(dir, dir_size + sub_size + 2)) < GIT_SUCCESS)
return error; return error;
/* save excursion */
git_buf_joinpath(dir, dir->ptr, sub); git_buf_joinpath(dir, dir->ptr, sub);
error = (*predicate)(dir->ptr); error = (*predicate)(dir->ptr);
/* restore excursion */ /* restore path */
if (!append_on_success || error != GIT_SUCCESS) git_buf_truncate(dir, dir_size);
git_buf_truncate(dir, dir_size);
return error; return error;
} }
int git_path_contains(git_buf *dir, const char *item) 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) 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); ...@@ -143,20 +143,18 @@ extern int git_path_contains(git_buf *dir, const char *item);
* *
* @param parent Directory path that might contain subdir * @param parent Directory path that might contain subdir
* @param subdir Subdirectory name to look for in parent * @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. * @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. * Check if the given path contains the given file.
* *
* @param dir Directory path that might contain file * @param dir Directory path that might contain file
* @param file File name to look for in parent * @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. * @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. * Clean up path, prepending base if it is not already rooted.
......
...@@ -81,14 +81,14 @@ void git_repository_free(git_repository *repo) ...@@ -81,14 +81,14 @@ void git_repository_free(git_repository *repo)
static int quickcheck_repository_dir(git_buf *repository_path) static int quickcheck_repository_dir(git_buf *repository_path)
{ {
/* Check OBJECTS_DIR first, since it will generate the longest path name */ /* 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; return GIT_ERROR;
/* Ensure HEAD file exists */ /* 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; 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_ERROR;
return GIT_SUCCESS; return GIT_SUCCESS;
...@@ -166,8 +166,8 @@ int git_repository_open(git_repository **repo_out, const char *path) ...@@ -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` * of the working dir, by testing if it contains a `.git`
* folder inside of it. * folder inside of it.
*/ */
git_path_contains_dir(&path_buf, GIT_DIR, 1); /* append on success */ if (git_path_contains_dir(&path_buf, GIT_DIR) == GIT_SUCCESS)
/* ignore error, since it just means `path/.git` doesn't exist */ git_buf_joinpath(&path_buf, path_buf.ptr, GIT_DIR);
if (quickcheck_repository_dir(&path_buf) < GIT_SUCCESS) { if (quickcheck_repository_dir(&path_buf) < GIT_SUCCESS) {
error = git__throw(GIT_ENOTAREPO, error = git__throw(GIT_ENOTAREPO,
......
...@@ -25,24 +25,6 @@ static int resize_vector(git_vector *v) ...@@ -25,24 +25,6 @@ static int resize_vector(git_vector *v)
return GIT_SUCCESS; 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) void git_vector_free(git_vector *v)
{ {
assert(v); assert(v);
...@@ -205,19 +187,10 @@ int git_vector_remove(git_vector *v, unsigned int idx) ...@@ -205,19 +187,10 @@ int git_vector_remove(git_vector *v, unsigned int idx)
return GIT_SUCCESS; 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)
v->length--;
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;
} }
void git_vector_uniq(git_vector *v) void git_vector_uniq(git_vector *v)
......
...@@ -22,7 +22,6 @@ typedef struct git_vector { ...@@ -22,7 +22,6 @@ typedef struct git_vector {
#define GIT_VECTOR_INIT {0} #define GIT_VECTOR_INIT {0}
int git_vector_init(git_vector *v, unsigned int initial_size, git_vector_cmp cmp); 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_free(git_vector *v);
void git_vector_clear(git_vector *v); void git_vector_clear(git_vector *v);
...@@ -54,7 +53,7 @@ int git_vector_insert(git_vector *v, void *element); ...@@ -54,7 +53,7 @@ int git_vector_insert(git_vector *v, void *element);
int git_vector_insert_sorted(git_vector *v, void *element, int git_vector_insert_sorted(git_vector *v, void *element,
int (*on_dup)(void **old, void *new)); int (*on_dup)(void **old, void *new));
int git_vector_remove(git_vector *v, unsigned int idx); 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); void git_vector_uniq(git_vector *v);
#endif #endif
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