mirror of
https://github.com/octoleo/syncthing.git
synced 2024-11-08 22:31:04 +00:00
lib/ignore: Handle bare commas in ignore patterns (fixes #3042)
GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/3048
This commit is contained in:
parent
dd5909568f
commit
5d337bb24f
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user