mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-29 20:42:23 +00:00
Merge remote-tracking branch 'arrbee/status-bugs' into development
This commit is contained in:
commit
bf0107d1ec
@ -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(
|
|||||||
|
|
||||||
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(
|
|||||||
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(
|
|||||||
|
|
||||||
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(
|
|||||||
}
|
}
|
||||||
|
|
||||||
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(
|
|||||||
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(
|
|||||||
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 */
|
||||||
|
43
src/ignore.c
43
src/ignore.c
@ -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
|
|||||||
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
|
|||||||
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
|
|||||||
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)
|
|||||||
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);
|
||||||
|
12
src/ignore.h
12
src/ignore.h
@ -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
|
||||||
|
29
src/status.c
29
src/status.c
@ -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 {
|
|||||||
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(
|
|||||||
|
|
||||||
|
|
||||||
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(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* 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) {
|
||||||
return process_folder(st, tree_entry, full_path, path_type);
|
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)
|
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 *),
|
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:
|
|||||||
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
|
|||||||
}
|
}
|
||||||
|
|
||||||
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(
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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);
|
||||||
|
Loading…
Reference in New Issue
Block a user