diff options
Diffstat (limited to 'src/status.c')
| -rw-r--r-- | src/status.c | 99 |
1 files changed, 81 insertions, 18 deletions
diff --git a/src/status.c b/src/status.c index 64be6ce29..a92693851 100644 --- a/src/status.c +++ b/src/status.c @@ -13,6 +13,7 @@ #include "tree.h" #include "git2/status.h" #include "repository.h" +#include "ignore.h" struct status_entry { git_index_time mtime; @@ -21,7 +22,7 @@ struct status_entry { git_oid index_oid; git_oid wt_oid; - unsigned int status_flags:6; + unsigned int status_flags; char path[GIT_FLEX_ARRAY]; /* more */ }; @@ -117,10 +118,30 @@ static int status_entry_update_flags(struct status_entry *e) return GIT_SUCCESS; } +static int status_entry_is_ignorable(struct status_entry *e) +{ + /* don't ignore files that exist in head or index already */ + return (e->status_flags == GIT_STATUS_WT_NEW); +} + +static int status_entry_update_ignore(struct status_entry *e, git_vector *ignores, const char *path) +{ + int error, ignored; + + if ((error = git_ignore__lookup(ignores, path, &ignored)) == GIT_SUCCESS && + ignored) + e->status_flags = + (e->status_flags & ~GIT_STATUS_WT_NEW) | GIT_STATUS_IGNORED; + + return error; +} + struct status_st { + git_repository *repo; git_vector *vector; git_index *index; git_tree *tree; + git_vector *ignores; int workdir_path_len; git_buf head_tree_relative_path; @@ -210,9 +231,22 @@ static int process_folder( } } - if (full_path != NULL && path_type == GIT_STATUS_PATH_FOLDER) - error = alphasorted_futils_direach(full_path, dirent_cb, st); - else + + if (full_path != NULL && path_type == GIT_STATUS_PATH_FOLDER) { + git_vector ignores = GIT_VECTOR_INIT, *old_ignores; + + if ((error = git_ignore__for_path(st->repo, + full_path->ptr + st->workdir_path_len, &ignores)) == GIT_SUCCESS) + { + old_ignores = st->ignores; + st->ignores = &ignores; + + error = alphasorted_futils_direach(full_path, dirent_cb, st); + + git_ignore__free(st->ignores); + st->ignores = old_ignores; + } + } else error = dirent_cb(st, NULL); if (tree_entry_type == GIT_OBJ_TREE) { @@ -232,6 +266,10 @@ static int store_if_changed(struct status_st *st, struct status_entry *e) if ((error = status_entry_update_flags(e)) < GIT_SUCCESS) return git__throw(error, "Failed to process the file '%s'. It doesn't exist in the workdir, in the HEAD nor in the index", e->path); + if (status_entry_is_ignorable(e) && + (error = status_entry_update_ignore(e, st->ignores, e->path)) < GIT_SUCCESS) + return error; + if (e->status_flags == GIT_STATUS_CURRENT) { git__free(e); return GIT_SUCCESS; @@ -240,7 +278,8 @@ static int store_if_changed(struct status_st *st, struct status_entry *e) return git_vector_insert(st->vector, e); } -static int determine_status(struct status_st *st, +static int determine_status( + struct status_st *st, int in_head, int in_index, int in_workdir, const git_tree_entry *tree_entry, const git_index_entry *index_entry, @@ -274,8 +313,8 @@ static int determine_status(struct status_st *st, } if (in_workdir) - if ((error = status_entry_update_from_workdir(e, full_path->ptr -)) < GIT_SUCCESS) + if ((error = status_entry_update_from_workdir( + e, full_path->ptr)) < GIT_SUCCESS) return error; /* The callee has already set the error message */ return store_if_changed(st, e); @@ -340,7 +379,6 @@ static int dirent_cb(void *state, git_buf *a) int cmpma, cmpmi, cmpai, error; const char *pm, *pa, *pi; const char *m_name, *i_name, *a_name; - struct status_st *st = (struct status_st *)state; path_type = path_type_from(a, st->is_dir); @@ -372,7 +410,8 @@ static int dirent_cb(void *state, git_buf *a) error = git_buf_lasterror(&st->head_tree_relative_path); if (error < GIT_SUCCESS) - return git__rethrow(error, "An error occured while determining the status of '%s'", a->ptr); + return git__rethrow(error, "An error occured while " + "determining the status of '%s'", a->ptr); m_name = st->head_tree_relative_path.ptr; } else @@ -388,7 +427,8 @@ static int dirent_cb(void *state, git_buf *a) pa = ((cmpma >= 0) && (cmpai <= 0)) ? a_name : NULL; pi = ((cmpmi >= 0) && (cmpai >= 0)) ? i_name : NULL; - if((error = determine_status(st, pm != NULL, pi != NULL, pa != NULL, m, entry, a, status_path(pm, pi, pa), path_type)) < GIT_SUCCESS) + if ((error = determine_status(st, pm != NULL, pi != NULL, pa != NULL, + m, entry, a, status_path(pm, pi, pa), path_type)) < GIT_SUCCESS) return git__rethrow(error, "An error occured while determining the status of '%s'", a->ptr); if ((pa != NULL) || (path_type == GIT_STATUS_PATH_FOLDER)) @@ -406,9 +446,12 @@ static int status_cmp(const void *a, const void *b) #define DEFAULT_SIZE 16 -int git_status_foreach(git_repository *repo, int (*callback)(const char *, unsigned int, void *), void *payload) +int git_status_foreach( + git_repository *repo, + int (*callback)(const char *, unsigned int, void *), + void *payload) { - git_vector entries; + git_vector entries, ignores = GIT_VECTOR_INIT; git_index *index = NULL; git_buf temp_path = GIT_BUF_INIT; struct status_st dirent_st = {0}; @@ -434,14 +477,16 @@ int git_status_foreach(git_repository *repo, int (*callback)(const char *, unsig git_vector_init(&entries, DEFAULT_SIZE, status_cmp); - dirent_st.workdir_path_len = strlen(workdir); - dirent_st.tree_position = 0; - dirent_st.index_position = 0; - dirent_st.tree = tree; - dirent_st.index = index; + dirent_st.repo = repo; dirent_st.vector = &entries; + dirent_st.index = index; + dirent_st.tree = tree; + dirent_st.ignores = &ignores; + dirent_st.workdir_path_len = strlen(workdir); git_buf_init(&dirent_st.head_tree_relative_path, 0); dirent_st.head_tree_relative_path_len = 0; + dirent_st.tree_position = 0; + dirent_st.index_position = 0; dirent_st.is_dir = 1; if (git_futils_isdir(workdir)) { @@ -453,6 +498,10 @@ int git_status_foreach(git_repository *repo, int (*callback)(const char *, unsig git_buf_sets(&temp_path, workdir); + error = git_ignore__for_path(repo, "", dirent_st.ignores); + if (error < GIT_SUCCESS) + goto exit; + error = alphasorted_futils_direach( &temp_path, dirent_cb, &dirent_st); @@ -461,7 +510,8 @@ int git_status_foreach(git_repository *repo, int (*callback)(const char *, unsig "Failed to determine statuses. " "An error occured while processing the working directory"); - if ((error == GIT_SUCCESS) && ((error = dirent_cb(&dirent_st, NULL)) < GIT_SUCCESS)) + if ((error == GIT_SUCCESS) && + ((error = dirent_cb(&dirent_st, NULL)) < GIT_SUCCESS)) error = git__rethrow(error, "Failed to determine statuses. " "An error occured while post-processing the HEAD tree and the index"); @@ -483,6 +533,7 @@ exit: git_buf_free(&dirent_st.head_tree_relative_path); git_buf_free(&temp_path); git_vector_free(&entries); + git_vector_free(&ignores); git_tree_free(tree); return error; } @@ -599,6 +650,18 @@ int git_status_file(unsigned int *status_flags, git_repository *repo, const char goto cleanup; } + if (status_entry_is_ignorable(e)) { + git_vector ignores = GIT_VECTOR_INIT; + + if ((error = git_ignore__for_path(repo, path, &ignores)) == GIT_SUCCESS) + error = status_entry_update_ignore(e, &ignores, path); + + git_ignore__free(&ignores); + + if (error < GIT_SUCCESS) + goto cleanup; + } + *status_flags = e->status_flags; cleanup: |
