diff options
author | Edward Thomson <ethomson@github.com> | 2016-04-19 15:24:14 -0400 |
---|---|---|
committer | Edward Thomson <ethomson@github.com> | 2016-04-19 15:24:14 -0400 |
commit | 95fbc81dafd64400d51637a27ecd49de5ea63145 (patch) | |
tree | c2c66e18fbfef1fd323906138516e96f99ba5a73 | |
parent | 029c93464f3124556286ccc46164c1d4181edfcc (diff) | |
parent | d45928cc0d969f255337e11edd59b4da6dc4926d (diff) | |
download | libgit2-95fbc81dafd64400d51637a27ecd49de5ea63145.tar.gz |
Merge pull request #3745 from libgit2/cmn/ignore-starstar
Improve star-star matching
-rw-r--r-- | src/fnmatch.c | 23 | ||||
-rw-r--r-- | tests/attr/ignore.c | 26 |
2 files changed, 44 insertions, 5 deletions
diff --git a/src/fnmatch.c b/src/fnmatch.c index a2945b8db..33c8a2512 100644 --- a/src/fnmatch.c +++ b/src/fnmatch.c @@ -93,11 +93,24 @@ p_fnmatchx(const char *pattern, const char *string, int flags, size_t recurs) * It will be restored if/when we recurse below. */ if (c == '*') { - flags &= ~FNM_PATHNAME; - while (c == '*') - c = *++pattern; - if (c == '/') - c = *++pattern; + c = *++pattern; + /* star-star-slash is at the end, match by default */ + if (c == EOS) + return 0; + /* Double-star must be at end or between slashes */ + if (c != '/') + return (FNM_NOMATCH); + + c = *++pattern; + do { + int e = p_fnmatchx(pattern, string, recurs_flags, recurs); + if (e != FNM_NOMATCH) + return e; + string = strchr(string, '/'); + } while (string++); + + /* If we get here, we didn't find a match */ + return FNM_NOMATCH; } if (*string == '.' && (flags & FNM_PERIOD) && diff --git a/tests/attr/ignore.c b/tests/attr/ignore.c index 91bf984a1..f1fe1c71f 100644 --- a/tests/attr/ignore.c +++ b/tests/attr/ignore.c @@ -132,6 +132,32 @@ void test_attr_ignore__leading_stars(void) assert_is_ignored(false, "dir1/kid2/file"); } +void test_attr_ignore__globs_and_path_delimiters(void) +{ + cl_git_rewritefile("attr/.gitignore", "foo/bar/**"); + assert_is_ignored(true, "foo/bar/baz"); + assert_is_ignored(true, "foo/bar/baz/quux"); + + cl_git_rewritefile("attr/.gitignore", "_*/"); + assert_is_ignored(true, "sub/_test/a/file"); + assert_is_ignored(false, "test_folder/file"); + assert_is_ignored(true, "_test/file"); + assert_is_ignored(true, "_test/a/file"); + + cl_git_rewritefile("attr/.gitignore", "**/_*/"); + assert_is_ignored(true, "sub/_test/a/file"); + assert_is_ignored(false, "test_folder/file"); + assert_is_ignored(true, "_test/file"); + assert_is_ignored(true, "_test/a/file"); + + cl_git_rewritefile("attr/.gitignore", "**/_*/foo/bar/*ux"); + + assert_is_ignored(true, "sub/_test/foo/bar/qux/file"); + assert_is_ignored(true, "_test/foo/bar/qux/file"); + assert_is_ignored(true, "_test/foo/bar/crux/file"); + assert_is_ignored(false, "_test/foo/bar/code/file"); +} + void test_attr_ignore__skip_gitignore_directory(void) { cl_git_rewritefile("attr/.git/info/exclude", "/NewFolder\n/NewFolder/NewFolder"); |