mirror of
https://git.proxmox.com/git/libgit2
synced 2025-06-21 21:50:53 +00:00
Merge pull request #2249 from libgit2/rb/starstar-fnmatch
Add support for ** matches in ignores
This commit is contained in:
commit
6720eef938
@ -30,6 +30,7 @@ p_fnmatchx(const char *pattern, const char *string, int flags, size_t recurs)
|
|||||||
const char *stringstart;
|
const char *stringstart;
|
||||||
char *newp;
|
char *newp;
|
||||||
char c, test;
|
char c, test;
|
||||||
|
int recurs_flags = flags & ~FNM_PERIOD;
|
||||||
|
|
||||||
if (recurs-- == 0)
|
if (recurs-- == 0)
|
||||||
return FNM_NORES;
|
return FNM_NORES;
|
||||||
@ -53,9 +54,15 @@ p_fnmatchx(const char *pattern, const char *string, int flags, size_t recurs)
|
|||||||
break;
|
break;
|
||||||
case '*':
|
case '*':
|
||||||
c = *pattern;
|
c = *pattern;
|
||||||
/* Collapse multiple stars. */
|
|
||||||
while (c == '*')
|
/* Let '**' override PATHNAME match for this segment.
|
||||||
|
* It will be restored if/when we recurse below.
|
||||||
|
*/
|
||||||
|
if (c == '*') {
|
||||||
|
flags &= ~FNM_PATHNAME;
|
||||||
|
while (c == '*')
|
||||||
c = *++pattern;
|
c = *++pattern;
|
||||||
|
}
|
||||||
|
|
||||||
if (*string == '.' && (flags & FNM_PERIOD) &&
|
if (*string == '.' && (flags & FNM_PERIOD) &&
|
||||||
(string == stringstart ||
|
(string == stringstart ||
|
||||||
@ -80,7 +87,7 @@ p_fnmatchx(const char *pattern, const char *string, int flags, size_t recurs)
|
|||||||
while ((test = *string) != EOS) {
|
while ((test = *string) != EOS) {
|
||||||
int e;
|
int e;
|
||||||
|
|
||||||
e = p_fnmatchx(pattern, string, flags & ~FNM_PERIOD, recurs);
|
e = p_fnmatchx(pattern, string, recurs_flags, recurs);
|
||||||
if (e != FNM_NOMATCH)
|
if (e != FNM_NOMATCH)
|
||||||
return e;
|
return e;
|
||||||
if (test == '/' && (flags & FNM_PATHNAME))
|
if (test == '/' && (flags & FNM_PATHNAME))
|
||||||
|
@ -16,13 +16,20 @@ void test_attr_ignore__cleanup(void)
|
|||||||
g_repo = NULL;
|
g_repo = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void assert_is_ignored(bool expected, const char *filepath)
|
void assert_is_ignored_(
|
||||||
|
bool expected, const char *filepath, const char *file, int line)
|
||||||
{
|
{
|
||||||
int is_ignored;
|
int is_ignored = 0;
|
||||||
|
|
||||||
cl_git_pass(git_ignore_path_is_ignored(&is_ignored, g_repo, filepath));
|
cl_git_pass_(
|
||||||
cl_assert_equal_b(expected, is_ignored);
|
git_ignore_path_is_ignored(&is_ignored, g_repo, filepath), file, line);
|
||||||
|
|
||||||
|
clar__assert_equal(
|
||||||
|
file, line, "expected != is_ignored", 1, "%d",
|
||||||
|
(int)(expected != 0), (int)(is_ignored != 0));
|
||||||
}
|
}
|
||||||
|
#define assert_is_ignored(expected, filepath) \
|
||||||
|
assert_is_ignored_(expected, filepath, __FILE__, __LINE__)
|
||||||
|
|
||||||
void test_attr_ignore__honor_temporary_rules(void)
|
void test_attr_ignore__honor_temporary_rules(void)
|
||||||
{
|
{
|
||||||
@ -54,6 +61,58 @@ void test_attr_ignore__ignore_root(void)
|
|||||||
assert_is_ignored(true, "NewFolder/NewFolder/File.txt");
|
assert_is_ignored(true, "NewFolder/NewFolder/File.txt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_attr_ignore__full_paths(void)
|
||||||
|
{
|
||||||
|
cl_git_rewritefile("attr/.gitignore", "Folder/*/Contained");
|
||||||
|
|
||||||
|
assert_is_ignored(true, "Folder/Middle/Contained");
|
||||||
|
assert_is_ignored(false, "Folder/Middle/More/More/Contained");
|
||||||
|
|
||||||
|
cl_git_rewritefile("attr/.gitignore", "Folder/**/Contained");
|
||||||
|
|
||||||
|
assert_is_ignored(true, "Folder/Middle/Contained");
|
||||||
|
assert_is_ignored(true, "Folder/Middle/More/More/Contained");
|
||||||
|
|
||||||
|
cl_git_rewritefile("attr/.gitignore", "Folder/**/Contained/*/Child");
|
||||||
|
|
||||||
|
assert_is_ignored(true, "Folder/Middle/Contained/Happy/Child");
|
||||||
|
assert_is_ignored(false, "Folder/Middle/Contained/Not/Happy/Child");
|
||||||
|
assert_is_ignored(true, "Folder/Middle/More/More/Contained/Happy/Child");
|
||||||
|
assert_is_ignored(false, "Folder/Middle/More/More/Contained/Not/Happy/Child");
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_attr_ignore__leading_stars(void)
|
||||||
|
{
|
||||||
|
cl_git_rewritefile(
|
||||||
|
"attr/.gitignore",
|
||||||
|
"*/onestar\n"
|
||||||
|
"**/twostars\n"
|
||||||
|
"*/parent1/kid1/*\n"
|
||||||
|
"**/parent2/kid2/*\n");
|
||||||
|
|
||||||
|
assert_is_ignored(true, "dir1/onestar");
|
||||||
|
assert_is_ignored(true, "dir1/onestar/child"); /* in ignored dir */
|
||||||
|
assert_is_ignored(false, "dir1/dir2/onestar");
|
||||||
|
|
||||||
|
assert_is_ignored(true, "dir1/twostars");
|
||||||
|
assert_is_ignored(true, "dir1/twostars/child"); /* in ignored dir */
|
||||||
|
assert_is_ignored(true, "dir1/dir2/twostars");
|
||||||
|
assert_is_ignored(true, "dir1/dir2/twostars/child"); /* in ignored dir */
|
||||||
|
assert_is_ignored(true, "dir1/dir2/dir3/twostars");
|
||||||
|
|
||||||
|
assert_is_ignored(true, "dir1/parent1/kid1/file");
|
||||||
|
assert_is_ignored(true, "dir1/parent1/kid1/file/inside/parent");
|
||||||
|
assert_is_ignored(false, "dir1/dir2/parent1/kid1/file");
|
||||||
|
assert_is_ignored(false, "dir1/parent1/file");
|
||||||
|
assert_is_ignored(false, "dir1/kid1/file");
|
||||||
|
|
||||||
|
assert_is_ignored(true, "dir1/parent2/kid2/file");
|
||||||
|
assert_is_ignored(true, "dir1/parent2/kid2/file/inside/parent");
|
||||||
|
assert_is_ignored(true, "dir1/dir2/parent2/kid2/file");
|
||||||
|
assert_is_ignored(true, "dir1/dir2/dir3/parent2/kid2/file");
|
||||||
|
assert_is_ignored(false, "dir1/parent2/file");
|
||||||
|
assert_is_ignored(false, "dir1/kid2/file");
|
||||||
|
}
|
||||||
|
|
||||||
void test_attr_ignore__skip_gitignore_directory(void)
|
void test_attr_ignore__skip_gitignore_directory(void)
|
||||||
{
|
{
|
||||||
|
@ -11,11 +11,13 @@
|
|||||||
*
|
*
|
||||||
* Use this wrapper around all `git_` library calls that return error codes!
|
* Use this wrapper around all `git_` library calls that return error codes!
|
||||||
*/
|
*/
|
||||||
#define cl_git_pass(expr) do { \
|
#define cl_git_pass(expr) cl_git_pass_(expr, __FILE__, __LINE__)
|
||||||
|
|
||||||
|
#define cl_git_pass_(expr, file, line) do { \
|
||||||
int _lg2_error; \
|
int _lg2_error; \
|
||||||
giterr_clear(); \
|
giterr_clear(); \
|
||||||
if ((_lg2_error = (expr)) != 0) \
|
if ((_lg2_error = (expr)) != 0) \
|
||||||
cl_git_report_failure(_lg2_error, __FILE__, __LINE__, "Function call failed: " #expr); \
|
cl_git_report_failure(_lg2_error, file, line, "Function call failed: " #expr); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user