summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Steinhardt <ps@pks.im>2019-06-06 14:11:44 +0200
committerPatrick Steinhardt <ps@pks.im>2019-06-06 14:44:43 +0200
commitd81e7866aba52625aa3100764d77c73adba58c8e (patch)
tree2ed857329b7202fd5b268ac0a103bd5bf320a558
parentb6967c393aaa9bc8fcb1f248f94a4deb897248cb (diff)
downloadlibgit2-d81e7866aba52625aa3100764d77c73adba58c8e.tar.gz
ignore: handle escaped trailing whitespace
The gitignore's pattern format specifies that "Trailing spaces are ignored unless they are quoted with backslash ("\")". We do not honor this currently and will treat a pattern "foo\ " as if it was "foo\" only and a pattern "foo\ \ " as "foo\ \". Fix our code to handle those special cases and add tests to avoid regressions.
-rw-r--r--src/attr_file.c6
-rw-r--r--tests/attr/ignore.c46
2 files changed, 50 insertions, 2 deletions
diff --git a/src/attr_file.c b/src/attr_file.c
index b2c60f204..40262eca6 100644
--- a/src/attr_file.c
+++ b/src/attr_file.c
@@ -560,13 +560,15 @@ void git_attr_path__free(git_attr_path *info)
*/
/*
- * Determine the length of trailing spaces.
+ * Determine the length of trailing spaces. Escaped spaces do not count as
+ * trailing whitespace.
*/
static size_t trailing_space_length(const char *p, size_t len)
{
size_t n;
for (n = len; n; n--) {
- if (p[n-1] != ' ' && p[n-1] != '\t')
+ if ((p[n-1] != ' ' && p[n-1] != '\t') ||
+ (n > 1 && p[n-2] == '\\'))
break;
}
return len - n;
diff --git a/tests/attr/ignore.c b/tests/attr/ignore.c
index 1bf06fc1f..ea8a14192 100644
--- a/tests/attr/ignore.c
+++ b/tests/attr/ignore.c
@@ -61,6 +61,52 @@ void test_attr_ignore__ignore_space(void)
assert_is_ignored(true, "NewFolder/NewFolder/File.txt");
}
+void test_attr_ignore__intermittent_space(void)
+{
+ cl_git_rewritefile("attr/.gitignore", "foo bar\n");
+
+ assert_is_ignored(false, "foo");
+ assert_is_ignored(false, "bar");
+ assert_is_ignored(true, "foo bar");
+}
+
+void test_attr_ignore__trailing_space(void)
+{
+ cl_git_rewritefile(
+ "attr/.gitignore",
+ "foo \n"
+ "bar \n"
+ );
+
+ assert_is_ignored(true, "foo");
+ assert_is_ignored(false, "foo ");
+ assert_is_ignored(true, "bar");
+ assert_is_ignored(false, "bar ");
+ assert_is_ignored(false, "bar ");
+}
+
+void test_attr_ignore__escaped_trailing_spaces(void)
+{
+ cl_git_rewritefile(
+ "attr/.gitignore",
+ "foo\\ \n"
+ "bar\\ \\ \n"
+ "baz \\ \n"
+ "qux\\ \n"
+ );
+
+ assert_is_ignored(false, "foo");
+ assert_is_ignored(true, "foo ");
+ assert_is_ignored(false, "bar");
+ assert_is_ignored(false, "bar ");
+ assert_is_ignored(true, "bar ");
+ assert_is_ignored(true, "baz ");
+ assert_is_ignored(false, "baz ");
+ assert_is_ignored(true, "qux ");
+ assert_is_ignored(false, "qux");
+ assert_is_ignored(false, "qux ");
+}
+
void test_attr_ignore__ignore_dir(void)
{
cl_git_rewritefile("attr/.gitignore", "dir/\n");