summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJakob Borg <jakob@nym.se>2016-05-06 15:45:11 +0000
committerAudrius Butkevicius <audrius.butkevicius@gmail.com>2016-05-06 15:45:11 +0000
commit5d337bb24fdefd9c61f4cacca329a436a6152ae1 (patch)
tree72c9cdfbc1b0e79a93c5463aafd823623490dd48
parentdd5909568f21c5a4f1a281a2771b6566bfb242af (diff)
lib/ignore: Handle bare commas in ignore patterns (fixes #3042)
GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/3048
-rw-r--r--lib/ignore/ignore.go58
-rw-r--r--lib/ignore/ignore_test.go30
2 files changed, 82 insertions, 6 deletions
diff --git a/lib/ignore/ignore.go b/lib/ignore/ignore.go
index 493e0046ec..0a0406b7fa 100644
--- a/lib/ignore/ignore.go
+++ b/lib/ignore/ignore.go
@@ -280,14 +280,14 @@ func parseIgnoreFile(fd io.Reader, currentFile string, seen map[string]bool) ([]
// Pattern is rooted in the current dir only
pattern.match, err = glob.Compile(line[1:])
if err != nil {
- return fmt.Errorf("invalid pattern %q in ignore file", line)
+ return fmt.Errorf("invalid pattern %q in ignore file (%v)", line, err)
}
patterns = append(patterns, pattern)
} else if strings.HasPrefix(line, "**/") {
// Add the pattern as is, and without **/ so it matches in current dir
pattern.match, err = glob.Compile(line)
if err != nil {
- return fmt.Errorf("invalid pattern %q in ignore file", line)
+ return fmt.Errorf("invalid pattern %q in ignore file (%v)", line, err)
}
patterns = append(patterns, pattern)
@@ -295,7 +295,7 @@ func parseIgnoreFile(fd io.Reader, currentFile string, seen map[string]bool) ([]
pattern.pattern = line
pattern.match, err = glob.Compile(line)
if err != nil {
- return fmt.Errorf("invalid pattern %q in ignore file", line)
+ return fmt.Errorf("invalid pattern %q in ignore file (%v)", line, err)
}
patterns = append(patterns, pattern)
} else if strings.HasPrefix(line, "#include ") {
@@ -311,7 +311,7 @@ func parseIgnoreFile(fd io.Reader, currentFile string, seen map[string]bool) ([]
// current directory and subdirs.
pattern.match, err = glob.Compile(line)
if err != nil {
- return fmt.Errorf("invalid pattern %q in ignore file", line)
+ return fmt.Errorf("invalid pattern %q in ignore file (%v)", line, err)
}
patterns = append(patterns, pattern)
@@ -319,7 +319,7 @@ func parseIgnoreFile(fd io.Reader, currentFile string, seen map[string]bool) ([]
pattern.pattern = line
pattern.match, err = glob.Compile(line)
if err != nil {
- return fmt.Errorf("invalid pattern %q in ignore file", line)
+ return fmt.Errorf("invalid pattern %q in ignore file (%v)", line, err)
}
patterns = append(patterns, pattern)
}
@@ -337,7 +337,7 @@ func parseIgnoreFile(fd io.Reader, currentFile string, seen map[string]bool) ([]
continue
}
- line = filepath.ToSlash(line)
+ line = escapeCommas(filepath.ToSlash(line))
switch {
case strings.HasPrefix(line, "#"):
err = addPattern(line)
@@ -358,3 +358,49 @@ func parseIgnoreFile(fd io.Reader, currentFile string, seen map[string]bool) ([]
return patterns, nil
}
+
+// escapes unescaped commas encountered outside of brackets
+func escapeCommas(s string) string {
+ buf := make([]rune, 0, len(s))
+ inEscape := false
+ inBrackets := 0
+ inSquareBrackets := 0
+ for _, r := range s {
+ // Escaped characters are passed on verbatim no matter what, and we
+ // clear the escape flag for the next character.
+ if inEscape {
+ buf = append(buf, r)
+ inEscape = false
+ continue
+ }
+
+ // Check for escapes and commas to escape. Also keep track of the
+ // brackets level by counting start and end brackets of the two
+ // types.
+
+ switch r {
+ case '\\':
+ inEscape = true
+
+ case '{':
+ inBrackets++
+ case '}':
+ inBrackets--
+ case '[':
+ inSquareBrackets++
+ case ']':
+ inSquareBrackets--
+
+ case ',':
+ // Commas should be escaped if we're not inside a brackets
+ // construction, and if they weren't already escaped (in which
+ // case we'll have taken the first branch way up top).
+ if inBrackets == 0 && inSquareBrackets == 0 {
+ buf = append(buf, '\\')
+ }
+ }
+
+ buf = append(buf, r)
+ }
+ return string(buf)
+}
diff --git a/lib/ignore/ignore_test.go b/lib/ignore/ignore_test.go
index a014371cbe..f74e9bfe87 100644
--- a/lib/ignore/ignore_test.go
+++ b/lib/ignore/ignore_test.go
@@ -635,3 +635,33 @@ func TestAutomaticCaseInsensitivity(t *testing.T) {
}
}
}
+
+func TestCommas(t *testing.T) {
+ stignore := `
+ foo,bar.txt
+ {baz,quux}.txt
+ `
+ pats := New(true)
+ err := pats.Parse(bytes.NewBufferString(stignore), ".stignore")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ tests := []struct {
+ name string
+ match bool
+ }{
+ {"foo.txt", false},
+ {"bar.txt", false},
+ {"foo,bar.txt", true},
+ {"baz.txt", true},
+ {"quux.txt", true},
+ {"baz,quux.txt", false},
+ }
+
+ for _, tc := range tests {
+ if pats.Match(tc.name).IsIgnored() != tc.match {
+ t.Errorf("Match of %s was %v, should be %v", tc.name, !tc.match, tc.match)
+ }
+ }
+}