diff options
author | Vicent Marti <vicent@github.com> | 2014-04-07 11:22:23 +0200 |
---|---|---|
committer | Vicent Marti <vicent@github.com> | 2014-04-07 11:22:23 +0200 |
commit | 6720eef938d7614cd7a9fd2138a27da3667d62cf (patch) | |
tree | e022c239b0d39b860af0622a738ea629db304cac | |
parent | 52056db9c1d6cccf30fc2e22d9b391017bef5eea (diff) | |
parent | c7d9606066d3a9b75a87c4ca5dd3420a66d0b54f (diff) | |
download | libgit2-6720eef938d7614cd7a9fd2138a27da3667d62cf.tar.gz |
Merge pull request #2249 from libgit2/rb/starstar-fnmatch
Add support for ** matches in ignores
-rw-r--r-- | src/fnmatch.c | 13 | ||||
-rw-r--r-- | tests/attr/ignore.c | 67 | ||||
-rw-r--r-- | tests/clar_libgit2.h | 6 |
3 files changed, 77 insertions, 9 deletions
diff --git a/src/fnmatch.c b/src/fnmatch.c index e3e47f37b..3846bab3c 100644 --- a/src/fnmatch.c +++ b/src/fnmatch.c @@ -30,6 +30,7 @@ p_fnmatchx(const char *pattern, const char *string, int flags, size_t recurs) const char *stringstart; char *newp; char c, test; + int recurs_flags = flags & ~FNM_PERIOD; if (recurs-- == 0) return FNM_NORES; @@ -53,9 +54,15 @@ p_fnmatchx(const char *pattern, const char *string, int flags, size_t recurs) break; case '*': 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; + } if (*string == '.' && (flags & FNM_PERIOD) && (string == stringstart || @@ -80,7 +87,7 @@ p_fnmatchx(const char *pattern, const char *string, int flags, size_t recurs) while ((test = *string) != EOS) { int e; - e = p_fnmatchx(pattern, string, flags & ~FNM_PERIOD, recurs); + e = p_fnmatchx(pattern, string, recurs_flags, recurs); if (e != FNM_NOMATCH) return e; if (test == '/' && (flags & FNM_PATHNAME)) diff --git a/tests/attr/ignore.c b/tests/attr/ignore.c index 0f945ebf6..4ed92387c 100644 --- a/tests/attr/ignore.c +++ b/tests/attr/ignore.c @@ -16,13 +16,20 @@ void test_attr_ignore__cleanup(void) 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_assert_equal_b(expected, is_ignored); + cl_git_pass_( + 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) { @@ -54,6 +61,58 @@ void test_attr_ignore__ignore_root(void) 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) { diff --git a/tests/clar_libgit2.h b/tests/clar_libgit2.h index 915111244..3de80bfa0 100644 --- a/tests/clar_libgit2.h +++ b/tests/clar_libgit2.h @@ -11,11 +11,13 @@ * * 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; \ giterr_clear(); \ 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) /** |