Commit 2e40a60e by yorah

status: fix handling of filenames with special prefixes

Fix libgit2/libgit2sharp#379
parent 2d2260da
...@@ -85,7 +85,7 @@ int git_attr_file__parse_buffer( ...@@ -85,7 +85,7 @@ int git_attr_file__parse_buffer(
} }
/* parse the next "pattern attr attr attr" line */ /* parse the next "pattern attr attr attr" line */
if (!(error = git_attr_fnmatch__parse( if (!(error = git_attr_fnmatch__parse_gitattr_format(
&rule->match, attrs->pool, context, &scan)) && &rule->match, attrs->pool, context, &scan)) &&
!(error = git_attr_assignment__parse( !(error = git_attr_assignment__parse(
repo, attrs->pool, &rule->assigns, &scan))) repo, attrs->pool, &rule->assigns, &scan)))
...@@ -337,23 +337,16 @@ void git_attr_path__free(git_attr_path *info) ...@@ -337,23 +337,16 @@ void git_attr_path__free(git_attr_path *info)
* GIT_ENOTFOUND if the fnmatch does not require matching, or * GIT_ENOTFOUND if the fnmatch does not require matching, or
* another error code there was an actual problem. * another error code there was an actual problem.
*/ */
int git_attr_fnmatch__parse( int git_attr_fnmatch__parse_gitattr_format(
git_attr_fnmatch *spec, git_attr_fnmatch *spec,
git_pool *pool, git_pool *pool,
const char *source, const char *source,
const char **base) const char **base)
{ {
const char *pattern, *scan; const char *pattern;
int slash_count, allow_space;
assert(spec && base && *base); assert(spec && base && *base);
if (parse_optimized_patterns(spec, pool, *base))
return 0;
spec->flags = (spec->flags & GIT_ATTR_FNMATCH_ALLOWSPACE);
allow_space = (spec->flags != 0);
pattern = *base; pattern = *base;
while (git__isspace(*pattern)) pattern++; while (git__isspace(*pattern)) pattern++;
...@@ -375,6 +368,39 @@ int git_attr_fnmatch__parse( ...@@ -375,6 +368,39 @@ int git_attr_fnmatch__parse(
pattern++; pattern++;
} }
if (git_attr_fnmatch__parse_shellglob_format(spec, pool,
source, &pattern) < 0)
return -1;
*base = pattern;
return 0;
}
/*
* Fills a spec for the purpose of pure pathspec matching, not
* related to a gitattribute file parsing.
*
* This will return 0 if the spec was filled out, or
* another error code there was an actual problem.
*/
int git_attr_fnmatch__parse_shellglob_format(
git_attr_fnmatch *spec,
git_pool *pool,
const char *source,
const char **base)
{
const char *pattern, *scan;
int slash_count, allow_space;
assert(spec && base && *base);
if (parse_optimized_patterns(spec, pool, *base))
return 0;
allow_space = (spec->flags & GIT_ATTR_FNMATCH_ALLOWSPACE) != 0;
pattern = *base;
slash_count = 0; slash_count = 0;
for (scan = pattern; *scan != '\0'; ++scan) { for (scan = pattern; *scan != '\0'; ++scan) {
/* scan until (non-escaped) white space */ /* scan until (non-escaped) white space */
...@@ -609,6 +635,7 @@ static void git_attr_rule__clear(git_attr_rule *rule) ...@@ -609,6 +635,7 @@ static void git_attr_rule__clear(git_attr_rule *rule)
/* match.pattern is stored in a git_pool, so no need to free */ /* match.pattern is stored in a git_pool, so no need to free */
rule->match.pattern = NULL; rule->match.pattern = NULL;
rule->match.length = 0; rule->match.length = 0;
rule->match.flags = 0;
} }
void git_attr_rule__free(git_attr_rule *rule) void git_attr_rule__free(git_attr_rule *rule)
......
...@@ -115,7 +115,13 @@ extern uint32_t git_attr_file__name_hash(const char *name); ...@@ -115,7 +115,13 @@ extern uint32_t git_attr_file__name_hash(const char *name);
* other utilities * other utilities
*/ */
extern int git_attr_fnmatch__parse( extern int git_attr_fnmatch__parse_gitattr_format(
git_attr_fnmatch *spec,
git_pool *pool,
const char *source,
const char **base);
extern int git_attr_fnmatch__parse_shellglob_format(
git_attr_fnmatch *spec, git_attr_fnmatch *spec,
git_pool *pool, git_pool *pool,
const char *source, const char *source,
......
...@@ -49,7 +49,7 @@ static int parse_ignore_file( ...@@ -49,7 +49,7 @@ static int parse_ignore_file(
match->flags = GIT_ATTR_FNMATCH_ALLOWSPACE; match->flags = GIT_ATTR_FNMATCH_ALLOWSPACE;
if (!(error = git_attr_fnmatch__parse( if (!(error = git_attr_fnmatch__parse_gitattr_format(
match, ignores->pool, context, &scan))) match, ignores->pool, context, &scan)))
{ {
match->flags |= GIT_ATTR_FNMATCH_IGNORE; match->flags |= GIT_ATTR_FNMATCH_IGNORE;
......
...@@ -78,7 +78,7 @@ int git_pathspec_init( ...@@ -78,7 +78,7 @@ int git_pathspec_init(
match->flags = GIT_ATTR_FNMATCH_ALLOWSPACE; match->flags = GIT_ATTR_FNMATCH_ALLOWSPACE;
ret = git_attr_fnmatch__parse(match, strpool, NULL, &pattern); ret = git_attr_fnmatch__parse_shellglob_format(match, strpool, NULL, &pattern);
if (ret == GIT_ENOTFOUND) { if (ret == GIT_ENOTFOUND) {
git__free(match); git__free(match);
continue; continue;
......
...@@ -459,3 +459,37 @@ void test_status_ignore__automatically_ignore_bad_files(void) ...@@ -459,3 +459,37 @@ void test_status_ignore__automatically_ignore_bad_files(void)
cl_git_pass(git_status_should_ignore(&ignored, g_repo, "path/whatever.c")); cl_git_pass(git_status_should_ignore(&ignored, g_repo, "path/whatever.c"));
cl_assert(!ignored); cl_assert(!ignored);
} }
void test_status_ignore__filenames_with_special_prefixes_do_not_interfere_with_status_retrieval(void)
{
status_entry_single st;
char *test_cases[] = {
"!file",
"#blah",
"[blah]",
"[attr]",
"[attr]blah",
NULL
};
int i;
for (i = 0; *(test_cases + i) != NULL; i++) {
git_buf file = GIT_BUF_INIT;
char *file_name = *(test_cases + i);
git_repository *repo = cl_git_sandbox_init("empty_standard_repo");
cl_git_pass(git_buf_joinpath(&file, "empty_standard_repo", file_name));
cl_git_mkfile(git_buf_cstr(&file), "Please don't ignore me!");
memset(&st, 0, sizeof(st));
cl_git_pass(git_status_foreach(repo, cb_status__single, &st));
cl_assert(st.count == 1);
cl_assert(st.status == GIT_STATUS_WT_NEW);
cl_git_pass(git_status_file(&st.status, repo, file_name));
cl_assert(st.status == GIT_STATUS_WT_NEW);
cl_git_sandbox_cleanup();
git_buf_free(&file);
}
}
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