Commit bf0107d1 by Vicent Martí

Merge remote-tracking branch 'arrbee/status-bugs' into development

parents 771cde43 e4eb94a2
...@@ -21,7 +21,8 @@ int git_attr_get( ...@@ -21,7 +21,8 @@ int git_attr_get(
*value = NULL; *value = NULL;
if ((error = git_attr_path__init(&path, pathname)) < GIT_SUCCESS || if ((error = git_attr_path__init(
&path, pathname, git_repository_workdir(repo))) < GIT_SUCCESS ||
(error = collect_attr_files(repo, pathname, &files)) < GIT_SUCCESS) (error = collect_attr_files(repo, pathname, &files)) < GIT_SUCCESS)
return git__rethrow(error, "Could not get attribute for %s", pathname); return git__rethrow(error, "Could not get attribute for %s", pathname);
...@@ -69,7 +70,8 @@ int git_attr_get_many( ...@@ -69,7 +70,8 @@ int git_attr_get_many(
memset((void *)values, 0, sizeof(const char *) * num_attr); memset((void *)values, 0, sizeof(const char *) * num_attr);
if ((error = git_attr_path__init(&path, pathname)) < GIT_SUCCESS || if ((error = git_attr_path__init(
&path, pathname, git_repository_workdir(repo))) < GIT_SUCCESS ||
(error = collect_attr_files(repo, pathname, &files)) < GIT_SUCCESS) (error = collect_attr_files(repo, pathname, &files)) < GIT_SUCCESS)
return git__rethrow(error, "Could not get attributes for %s", pathname); return git__rethrow(error, "Could not get attributes for %s", pathname);
...@@ -130,7 +132,8 @@ int git_attr_foreach( ...@@ -130,7 +132,8 @@ int git_attr_foreach(
git_attr_assignment *assign; git_attr_assignment *assign;
git_hashtable *seen = NULL; git_hashtable *seen = NULL;
if ((error = git_attr_path__init(&path, pathname)) < GIT_SUCCESS || if ((error = git_attr_path__init(
&path, pathname, git_repository_workdir(repo))) < GIT_SUCCESS ||
(error = collect_attr_files(repo, pathname, &files)) < GIT_SUCCESS) (error = collect_attr_files(repo, pathname, &files)) < GIT_SUCCESS)
return git__rethrow(error, "Could not get attributes for %s", pathname); return git__rethrow(error, "Could not get attributes for %s", pathname);
......
...@@ -200,6 +200,8 @@ int git_attr_fnmatch__match( ...@@ -200,6 +200,8 @@ int git_attr_fnmatch__match(
if (match->flags & GIT_ATTR_FNMATCH_FULLPATH) if (match->flags & GIT_ATTR_FNMATCH_FULLPATH)
matched = p_fnmatch(match->pattern, path->path, FNM_PATHNAME); matched = p_fnmatch(match->pattern, path->path, FNM_PATHNAME);
else if (path->is_dir)
matched = p_fnmatch(match->pattern, path->basename, FNM_LEADING_DIR);
else else
matched = p_fnmatch(match->pattern, path->basename, 0); matched = p_fnmatch(match->pattern, path->basename, 0);
...@@ -234,7 +236,7 @@ git_attr_assignment *git_attr_rule__lookup_assignment( ...@@ -234,7 +236,7 @@ git_attr_assignment *git_attr_rule__lookup_assignment(
} }
int git_attr_path__init( int git_attr_path__init(
git_attr_path *info, const char *path) git_attr_path *info, const char *path, const char *base)
{ {
assert(info && path); assert(info && path);
info->path = path; info->path = path;
...@@ -243,7 +245,17 @@ int git_attr_path__init( ...@@ -243,7 +245,17 @@ int git_attr_path__init(
info->basename++; info->basename++;
if (!info->basename || !*info->basename) if (!info->basename || !*info->basename)
info->basename = path; info->basename = path;
if (base != NULL && git_path_root(path) < 0) {
git_buf full_path = GIT_BUF_INIT;
int error = git_buf_joinpath(&full_path, base, path);
if (error == GIT_SUCCESS)
info->is_dir = (git_path_isdir(full_path.ptr) == GIT_SUCCESS);
git_buf_free(&full_path);
return error;
}
info->is_dir = (git_path_isdir(path) == GIT_SUCCESS); info->is_dir = (git_path_isdir(path) == GIT_SUCCESS);
return GIT_SUCCESS; return GIT_SUCCESS;
} }
......
...@@ -110,7 +110,7 @@ extern git_attr_assignment *git_attr_rule__lookup_assignment( ...@@ -110,7 +110,7 @@ extern git_attr_assignment *git_attr_rule__lookup_assignment(
git_attr_rule *rule, const char *name); git_attr_rule *rule, const char *name);
extern int git_attr_path__init( extern int git_attr_path__init(
git_attr_path *info, const char *path); git_attr_path *info, const char *path, const char *base);
extern int git_attr_assignment__parse( extern int git_attr_assignment__parse(
git_repository *repo, /* needed to expand macros */ git_repository *repo, /* needed to expand macros */
......
...@@ -66,24 +66,20 @@ static int load_ignore_file( ...@@ -66,24 +66,20 @@ static int load_ignore_file(
#define push_ignore(R,S,B,F) \ #define push_ignore(R,S,B,F) \
git_attr_cache__push_file((R),(S),(B),(F),load_ignore_file) git_attr_cache__push_file((R),(S),(B),(F),load_ignore_file)
typedef struct {
git_repository *repo;
git_vector *stack;
} ignore_walk_up_info;
static int push_one_ignore(void *ref, git_buf *path) static int push_one_ignore(void *ref, git_buf *path)
{ {
ignore_walk_up_info *info = (ignore_walk_up_info *)ref; git_ignores *ign = (git_ignores *)ref;
return push_ignore(info->repo, info->stack, path->ptr, GIT_IGNORE_FILE); return push_ignore(ign->repo, &ign->stack, path->ptr, GIT_IGNORE_FILE);
} }
int git_ignore__for_path(git_repository *repo, const char *path, git_vector *stack) int git_ignore__for_path(git_repository *repo, const char *path, git_ignores *ignores)
{ {
int error = GIT_SUCCESS; int error = GIT_SUCCESS;
git_buf dir = GIT_BUF_INIT; git_buf dir = GIT_BUF_INIT;
git_config *cfg; git_config *cfg;
const char *workdir = git_repository_workdir(repo); const char *workdir = git_repository_workdir(repo);
ignore_walk_up_info info;
assert(ignores);
if ((error = git_attr_cache__init(repo)) < GIT_SUCCESS) if ((error = git_attr_cache__init(repo)) < GIT_SUCCESS)
goto cleanup; goto cleanup;
...@@ -91,18 +87,20 @@ int git_ignore__for_path(git_repository *repo, const char *path, git_vector *sta ...@@ -91,18 +87,20 @@ int git_ignore__for_path(git_repository *repo, const char *path, git_vector *sta
if ((error = git_path_find_dir(&dir, path, workdir)) < GIT_SUCCESS) if ((error = git_path_find_dir(&dir, path, workdir)) < GIT_SUCCESS)
goto cleanup; goto cleanup;
ignores->repo = repo;
ignores->dir = NULL;
git_vector_init(&ignores->stack, 2, NULL);
/* insert internals */ /* insert internals */
if ((error = push_ignore(repo, stack, NULL, GIT_IGNORE_INTERNAL)) < GIT_SUCCESS) if ((error = push_ignore(repo, &ignores->stack, NULL, GIT_IGNORE_INTERNAL)) < GIT_SUCCESS)
goto cleanup; goto cleanup;
/* load .gitignore up the path */ /* load .gitignore up the path */
info.repo = repo; if ((error = git_path_walk_up(&dir, workdir, push_one_ignore, ignores)) < GIT_SUCCESS)
info.stack = stack;
if ((error = git_path_walk_up(&dir, workdir, push_one_ignore, &info)) < GIT_SUCCESS)
goto cleanup; goto cleanup;
/* load .git/info/exclude */ /* load .git/info/exclude */
if ((error = push_ignore(repo, stack, repo->path_repository, GIT_IGNORE_FILE_INREPO)) < GIT_SUCCESS) if ((error = push_ignore(repo, &ignores->stack, repo->path_repository, GIT_IGNORE_FILE_INREPO)) < GIT_SUCCESS)
goto cleanup; goto cleanup;
/* load core.excludesfile */ /* load core.excludesfile */
...@@ -110,7 +108,7 @@ int git_ignore__for_path(git_repository *repo, const char *path, git_vector *sta ...@@ -110,7 +108,7 @@ int git_ignore__for_path(git_repository *repo, const char *path, git_vector *sta
const char *core_ignore; const char *core_ignore;
error = git_config_get_string(cfg, GIT_IGNORE_CONFIG, &core_ignore); error = git_config_get_string(cfg, GIT_IGNORE_CONFIG, &core_ignore);
if (error == GIT_SUCCESS && core_ignore != NULL) if (error == GIT_SUCCESS && core_ignore != NULL)
error = push_ignore(repo, stack, NULL, core_ignore); error = push_ignore(repo, &ignores->stack, NULL, core_ignore);
else { else {
error = GIT_SUCCESS; error = GIT_SUCCESS;
git_clearerror(); /* don't care if attributesfile is not set */ git_clearerror(); /* don't care if attributesfile is not set */
...@@ -121,18 +119,22 @@ int git_ignore__for_path(git_repository *repo, const char *path, git_vector *sta ...@@ -121,18 +119,22 @@ int git_ignore__for_path(git_repository *repo, const char *path, git_vector *sta
cleanup: cleanup:
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
git__rethrow(error, "Could not get ignore files for '%s'", path); git__rethrow(error, "Could not get ignore files for '%s'", path);
else
ignores->dir = git_buf_detach(&dir);
git_buf_free(&dir); git_buf_free(&dir);
return error; return error;
} }
void git_ignore__free(git_vector *stack) void git_ignore__free(git_ignores *ignores)
{ {
git_vector_free(stack); git__free(ignores->dir);
ignores->dir = NULL;
git_vector_free(&ignores->stack);
} }
int git_ignore__lookup(git_vector *stack, const char *pathname, int *ignored) int git_ignore__lookup(git_ignores *ignores, const char *pathname, int *ignored)
{ {
int error; int error;
unsigned int i, j; unsigned int i, j;
...@@ -140,12 +142,13 @@ int git_ignore__lookup(git_vector *stack, const char *pathname, int *ignored) ...@@ -140,12 +142,13 @@ int git_ignore__lookup(git_vector *stack, const char *pathname, int *ignored)
git_attr_path path; git_attr_path path;
git_attr_fnmatch *match; git_attr_fnmatch *match;
if ((error = git_attr_path__init(&path, pathname)) < GIT_SUCCESS) if ((error = git_attr_path__init(
&path, pathname, git_repository_workdir(ignores->repo))) < GIT_SUCCESS)
return git__rethrow(error, "Could not get attribute for '%s'", pathname); return git__rethrow(error, "Could not get attribute for '%s'", pathname);
*ignored = 0; *ignored = 0;
git_vector_foreach(stack, i, file) { git_vector_foreach(&ignores->stack, i, file) {
git_vector_rforeach(&file->rules, j, match) { git_vector_rforeach(&file->rules, j, match) {
if (git_attr_fnmatch__match(match, &path) == GIT_SUCCESS) { if (git_attr_fnmatch__match(match, &path) == GIT_SUCCESS) {
*ignored = ((match->flags & GIT_ATTR_FNMATCH_NEGATIVE) == 0); *ignored = ((match->flags & GIT_ATTR_FNMATCH_NEGATIVE) == 0);
......
...@@ -10,8 +10,14 @@ ...@@ -10,8 +10,14 @@
#include "repository.h" #include "repository.h"
#include "vector.h" #include "vector.h"
extern int git_ignore__for_path(git_repository *repo, const char *path, git_vector *stack); typedef struct {
extern void git_ignore__free(git_vector *stack); git_repository *repo;
extern int git_ignore__lookup(git_vector *stack, const char *path, int *ignored); char *dir;
git_vector stack;
} git_ignores;
extern int git_ignore__for_path(git_repository *repo, const char *path, git_ignores *stack);
extern void git_ignore__free(git_ignores *stack);
extern int git_ignore__lookup(git_ignores *stack, const char *path, int *ignored);
#endif #endif
...@@ -124,7 +124,7 @@ static int status_entry_is_ignorable(struct status_entry *e) ...@@ -124,7 +124,7 @@ static int status_entry_is_ignorable(struct status_entry *e)
return (e->status_flags == GIT_STATUS_WT_NEW); return (e->status_flags == GIT_STATUS_WT_NEW);
} }
static int status_entry_update_ignore(struct status_entry *e, git_vector *ignores, const char *path) static int status_entry_update_ignore(struct status_entry *e, git_ignores *ignores, const char *path)
{ {
int error, ignored; int error, ignored;
...@@ -141,7 +141,7 @@ struct status_st { ...@@ -141,7 +141,7 @@ struct status_st {
git_vector *vector; git_vector *vector;
git_index *index; git_index *index;
git_tree *tree; git_tree *tree;
git_vector *ignores; git_ignores *ignores;
int workdir_path_len; int workdir_path_len;
git_buf head_tree_relative_path; git_buf head_tree_relative_path;
...@@ -233,7 +233,7 @@ static int process_folder( ...@@ -233,7 +233,7 @@ static int process_folder(
if (full_path != NULL && path_type == GIT_STATUS_PATH_FOLDER) { if (full_path != NULL && path_type == GIT_STATUS_PATH_FOLDER) {
git_vector ignores = GIT_VECTOR_INIT, *old_ignores; git_ignores ignores, *old_ignores;
if ((error = git_ignore__for_path(st->repo, if ((error = git_ignore__for_path(st->repo,
full_path->ptr + st->workdir_path_len, &ignores)) == GIT_SUCCESS) full_path->ptr + st->workdir_path_len, &ignores)) == GIT_SUCCESS)
...@@ -321,8 +321,18 @@ static int determine_status( ...@@ -321,8 +321,18 @@ static int determine_status(
} }
/* Last option, we're dealing with a leftover folder tree entry */ /* Last option, we're dealing with a leftover folder tree entry */
assert(in_head && !in_index && !in_workdir && (tree_entry_type == GIT_OBJ_TREE)); if (tree_entry_type == GIT_OBJ_TREE) {
assert(in_head && !in_index && !in_workdir);
return process_folder(st, tree_entry, full_path, path_type); return process_folder(st, tree_entry, full_path, path_type);
}
else {
/* skip anything else we found (such as a submodule) */
if (in_head)
st->tree_position++;
if (in_index)
st->index_position++;
return GIT_SUCCESS;
}
} }
static int path_type_from(git_buf *full_path, int is_dir) static int path_type_from(git_buf *full_path, int is_dir)
...@@ -451,7 +461,8 @@ int git_status_foreach( ...@@ -451,7 +461,8 @@ int git_status_foreach(
int (*callback)(const char *, unsigned int, void *), int (*callback)(const char *, unsigned int, void *),
void *payload) void *payload)
{ {
git_vector entries, ignores = GIT_VECTOR_INIT; git_vector entries;
git_ignores ignores;
git_index *index = NULL; git_index *index = NULL;
git_buf temp_path = GIT_BUF_INIT; git_buf temp_path = GIT_BUF_INIT;
struct status_st dirent_st = {0}; struct status_st dirent_st = {0};
...@@ -533,7 +544,7 @@ exit: ...@@ -533,7 +544,7 @@ exit:
git_buf_free(&dirent_st.head_tree_relative_path); git_buf_free(&dirent_st.head_tree_relative_path);
git_buf_free(&temp_path); git_buf_free(&temp_path);
git_vector_free(&entries); git_vector_free(&entries);
git_vector_free(&ignores); git_ignore__free(&ignores);
git_tree_free(tree); git_tree_free(tree);
return error; return error;
} }
...@@ -651,7 +662,7 @@ int git_status_file(unsigned int *status_flags, git_repository *repo, const char ...@@ -651,7 +662,7 @@ int git_status_file(unsigned int *status_flags, git_repository *repo, const char
} }
if (status_entry_is_ignorable(e)) { if (status_entry_is_ignorable(e)) {
git_vector ignores = GIT_VECTOR_INIT; git_ignores ignores;
if ((error = git_ignore__for_path(repo, path, &ignores)) == GIT_SUCCESS) if ((error = git_ignore__for_path(repo, path, &ignores)) == GIT_SUCCESS)
error = status_entry_update_ignore(e, &ignores, path); error = status_entry_update_ignore(e, &ignores, path);
...@@ -766,7 +777,7 @@ static int alphasorted_futils_direach( ...@@ -766,7 +777,7 @@ static int alphasorted_futils_direach(
int git_status_should_ignore(git_repository *repo, const char *path, int *ignored) int git_status_should_ignore(git_repository *repo, const char *path, int *ignored)
{ {
int error; int error;
git_vector ignores = GIT_VECTOR_INIT; git_ignores ignores;
if ((error = git_ignore__for_path(repo, path, &ignores)) == GIT_SUCCESS) if ((error = git_ignore__for_path(repo, path, &ignores)) == GIT_SUCCESS)
error = git_ignore__lookup(&ignores, path, ignored); error = git_ignore__lookup(&ignores, path, ignored);
......
...@@ -12,7 +12,7 @@ void test_attr_lookup__simple(void) ...@@ -12,7 +12,7 @@ void test_attr_lookup__simple(void)
cl_assert_strequal(cl_fixture("attr/attr0"), file->path); cl_assert_strequal(cl_fixture("attr/attr0"), file->path);
cl_assert(file->rules.length == 1); cl_assert(file->rules.length == 1);
cl_git_pass(git_attr_path__init(&path, "test")); cl_git_pass(git_attr_path__init(&path, "test", NULL));
cl_assert_strequal("test", path.path); cl_assert_strequal("test", path.path);
cl_assert_strequal("test", path.basename); cl_assert_strequal("test", path.basename);
cl_assert(!path.is_dir); cl_assert(!path.is_dir);
...@@ -42,7 +42,7 @@ static void run_test_cases(git_attr_file *file, test_case *cases) ...@@ -42,7 +42,7 @@ static void run_test_cases(git_attr_file *file, test_case *cases)
int error; int error;
for (c = cases; c->path != NULL; c++) { for (c = cases; c->path != NULL; c++) {
cl_git_pass(git_attr_path__init(&path, c->path)); cl_git_pass(git_attr_path__init(&path, c->path, NULL));
if (c->force_dir) if (c->force_dir)
path.is_dir = 1; path.is_dir = 1;
...@@ -138,7 +138,7 @@ void test_attr_lookup__match_variants(void) ...@@ -138,7 +138,7 @@ void test_attr_lookup__match_variants(void)
cl_assert_strequal(cl_fixture("attr/attr1"), file->path); cl_assert_strequal(cl_fixture("attr/attr1"), file->path);
cl_assert(file->rules.length == 10); cl_assert(file->rules.length == 10);
cl_git_pass(git_attr_path__init(&path, "/testing/for/pat0")); cl_git_pass(git_attr_path__init(&path, "/testing/for/pat0", NULL));
cl_assert_strequal("pat0", path.basename); cl_assert_strequal("pat0", path.basename);
run_test_cases(file, cases); run_test_cases(file, cases);
......
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