Commit 2b6b85f1168206f6f53144b9c98ecc4ce2e74a88

Russell Belfer 2014-04-04T17:02:12

Add support for ** matches in ignores This is an experimental addition to add ** support to fnmatch pattern matching in libgit2. It needs more testing.

diff --git a/src/fnmatch.c b/src/fnmatch.c
index e3e47f3..8e5424b 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,13 @@ p_fnmatchx(const char *pattern, const char *string, int flags, size_t recurs)
 						break;
 				case '*':
 						c = *pattern;
-						/* Collapse multiple stars. */
-						while (c == '*')
+
+						/* Apply '**' to overwrite PATHNAME match */
+						if (c == '*') {
+							flags &= ~FNM_PATHNAME;
+							while (c == '*')
 								c = *++pattern;
+						}
 
 						if (*string == '.' && (flags & FNM_PERIOD) &&
 							(string == stringstart ||
@@ -80,7 +85,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 0f945eb..692f5e4 100644
--- a/tests/attr/ignore.c
+++ b/tests/attr/ignore.c
@@ -54,6 +54,19 @@ 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");
+}
+
 
 void test_attr_ignore__skip_gitignore_directory(void)
 {