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(
*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)
return git__rethrow(error, "Could not get attribute for %s", pathname);
......@@ -69,7 +70,8 @@ int git_attr_get_many(
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)
return git__rethrow(error, "Could not get attributes for %s", pathname);
......@@ -130,7 +132,8 @@ int git_attr_foreach(
git_attr_assignment *assign;
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)
return git__rethrow(error, "Could not get attributes for %s", pathname);
......
......@@ -200,6 +200,8 @@ int git_attr_fnmatch__match(
if (match->flags & GIT_ATTR_FNMATCH_FULLPATH)
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
matched = p_fnmatch(match->pattern, path->basename, 0);
......@@ -234,7 +236,7 @@ git_attr_assignment *git_attr_rule__lookup_assignment(
}
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);
info->path = path;
......@@ -243,7 +245,17 @@ int git_attr_path__init(
info->basename++;
if (!info->basename || !*info->basename)
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);
return GIT_SUCCESS;
}
......
......@@ -110,7 +110,7 @@ extern git_attr_assignment *git_attr_rule__lookup_assignment(
git_attr_rule *rule, const char *name);
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(
git_repository *repo, /* needed to expand macros */
......
......@@ -66,24 +66,20 @@ static int load_ignore_file(
#define push_ignore(R,S,B,F) \
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)
{
ignore_walk_up_info *info = (ignore_walk_up_info *)ref;
return push_ignore(info->repo, info->stack, path->ptr, GIT_IGNORE_FILE);
git_ignores *ign = (git_ignores *)ref;
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;
git_buf dir = GIT_BUF_INIT;
git_config *cfg;
const char *workdir = git_repository_workdir(repo);
ignore_walk_up_info info;
assert(ignores);
if ((error = git_attr_cache__init(repo)) < GIT_SUCCESS)
goto cleanup;
......@@ -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)
goto cleanup;
ignores->repo = repo;
ignores->dir = NULL;
git_vector_init(&ignores->stack, 2, NULL);
/* 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;
/* load .gitignore up the path */
info.repo = repo;
info.stack = stack;
if ((error = git_path_walk_up(&dir, workdir, push_one_ignore, &info)) < GIT_SUCCESS)
if ((error = git_path_walk_up(&dir, workdir, push_one_ignore, ignores)) < GIT_SUCCESS)
goto cleanup;
/* 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;
/* load core.excludesfile */
......@@ -110,7 +108,7 @@ int git_ignore__for_path(git_repository *repo, const char *path, git_vector *sta
const char *core_ignore;
error = git_config_get_string(cfg, GIT_IGNORE_CONFIG, &core_ignore);
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 {
error = GIT_SUCCESS;
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
cleanup:
if (error < GIT_SUCCESS)
git__rethrow(error, "Could not get ignore files for '%s'", path);
else
ignores->dir = git_buf_detach(&dir);
git_buf_free(&dir);
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;
unsigned int i, j;
......@@ -140,12 +142,13 @@ int git_ignore__lookup(git_vector *stack, const char *pathname, int *ignored)
git_attr_path path;
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);
*ignored = 0;
git_vector_foreach(stack, i, file) {
git_vector_foreach(&ignores->stack, i, file) {
git_vector_rforeach(&file->rules, j, match) {
if (git_attr_fnmatch__match(match, &path) == GIT_SUCCESS) {
*ignored = ((match->flags & GIT_ATTR_FNMATCH_NEGATIVE) == 0);
......
......@@ -10,8 +10,14 @@
#include "repository.h"
#include "vector.h"
extern int git_ignore__for_path(git_repository *repo, const char *path, git_vector *stack);
extern void git_ignore__free(git_vector *stack);
extern int git_ignore__lookup(git_vector *stack, const char *path, int *ignored);
typedef struct {
git_repository *repo;
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
......@@ -124,7 +124,7 @@ static int status_entry_is_ignorable(struct status_entry *e)
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;
......@@ -141,7 +141,7 @@ struct status_st {
git_vector *vector;
git_index *index;
git_tree *tree;
git_vector *ignores;
git_ignores *ignores;
int workdir_path_len;
git_buf head_tree_relative_path;
......@@ -233,7 +233,7 @@ static int process_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,
full_path->ptr + st->workdir_path_len, &ignores)) == GIT_SUCCESS)
......@@ -321,8 +321,18 @@ static int determine_status(
}
/* Last option, we're dealing with a leftover folder tree entry */
assert(in_head && !in_index && !in_workdir && (tree_entry_type == GIT_OBJ_TREE));
return process_folder(st, tree_entry, full_path, path_type);
if (tree_entry_type == GIT_OBJ_TREE) {
assert(in_head && !in_index && !in_workdir);
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)
......@@ -451,7 +461,8 @@ int git_status_foreach(
int (*callback)(const char *, unsigned int, void *),
void *payload)
{
git_vector entries, ignores = GIT_VECTOR_INIT;
git_vector entries;
git_ignores ignores;
git_index *index = NULL;
git_buf temp_path = GIT_BUF_INIT;
struct status_st dirent_st = {0};
......@@ -533,7 +544,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_ignore__free(&ignores);
git_tree_free(tree);
return error;
}
......@@ -651,7 +662,7 @@ int git_status_file(unsigned int *status_flags, git_repository *repo, const char
}
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)
error = status_entry_update_ignore(e, &ignores, path);
......@@ -766,7 +777,7 @@ static int alphasorted_futils_direach(
int git_status_should_ignore(git_repository *repo, const char *path, int *ignored)
{
int error;
git_vector ignores = GIT_VECTOR_INIT;
git_ignores ignores;
if ((error = git_ignore__for_path(repo, path, &ignores)) == GIT_SUCCESS)
error = git_ignore__lookup(&ignores, path, ignored);
......
......@@ -12,7 +12,7 @@ void test_attr_lookup__simple(void)
cl_assert_strequal(cl_fixture("attr/attr0"), file->path);
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.basename);
cl_assert(!path.is_dir);
......@@ -42,7 +42,7 @@ static void run_test_cases(git_attr_file *file, test_case *cases)
int error;
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)
path.is_dir = 1;
......@@ -138,7 +138,7 @@ void test_attr_lookup__match_variants(void)
cl_assert_strequal(cl_fixture("attr/attr1"), file->path);
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);
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