From a1761795fe0ce1667352aab7cfc44d5216118c61 Mon Sep 17 00:00:00 2001 From: Simon Frei Date: Wed, 17 Jan 2018 16:56:53 +0000 Subject: [PATCH] lib/ignore: Only handle lines prefixed with #include specially (fixes #4680) GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/4684 LGTM: AudriusButkevicius, calmh --- lib/ignore/ignore.go | 26 ++++++++++++-------------- lib/ignore/ignore_test.go | 28 +++++++++++++++++++++++++++- 2 files changed, 39 insertions(+), 15 deletions(-) diff --git a/lib/ignore/ignore.go b/lib/ignore/ignore.go index d56f4157..22471657 100644 --- a/lib/ignore/ignore.go +++ b/lib/ignore/ignore.go @@ -304,7 +304,7 @@ func loadIgnoreFile(fs fs.Filesystem, file string, cd ChangeDetector) (fs.File, return fd, info, err } -func loadParseIncludeFile(filesystem fs.Filesystem, file string, cd ChangeDetector, linesSeen map[string]struct{}) ([]string, []Pattern, error) { +func loadParseIncludeFile(filesystem fs.Filesystem, file string, cd ChangeDetector, linesSeen map[string]struct{}) ([]Pattern, error) { // Allow escaping the folders filesystem. // TODO: Deprecate, somehow? if filesystem.Type() == fs.FilesystemTypeBasic { @@ -317,18 +317,19 @@ func loadParseIncludeFile(filesystem fs.Filesystem, file string, cd ChangeDetect } if cd.Seen(filesystem, file) { - return nil, nil, fmt.Errorf("multiple include of ignore file %q", file) + return nil, fmt.Errorf("multiple include of ignore file %q", file) } fd, info, err := loadIgnoreFile(filesystem, file, cd) if err != nil { - return nil, nil, err + return nil, err } defer fd.Close() cd.Remember(filesystem, file, info.ModTime()) - return parseIgnoreFile(filesystem, fd, file, cd, linesSeen) + _, patterns, err := parseIgnoreFile(filesystem, fd, file, cd, linesSeen) + return patterns, err } func parseIgnoreFile(fs fs.Filesystem, fd io.Reader, currentFile string, cd ChangeDetector, linesSeen map[string]struct{}) ([]string, []Pattern, error) { @@ -395,14 +396,6 @@ func parseIgnoreFile(fs fs.Filesystem, fd io.Reader, currentFile string, cd Chan return fmt.Errorf("invalid pattern %q in ignore file (%v)", line, err) } patterns = append(patterns, pattern) - } else if strings.HasPrefix(line, "#include ") { - includeRel := strings.TrimSpace(line[len("#include "):]) - includeFile := filepath.Join(filepath.Dir(currentFile), includeRel) - _, includePatterns, err := loadParseIncludeFile(fs, includeFile, cd, linesSeen) - if err != nil { - return fmt.Errorf("include of %q: %v", includeRel, err) - } - patterns = append(patterns, includePatterns...) } else { // Path name or pattern, add it so it matches files both in // current directory and subdirs. @@ -441,8 +434,13 @@ func parseIgnoreFile(fs fs.Filesystem, fd io.Reader, currentFile string, cd Chan line = filepath.ToSlash(line) switch { - case strings.HasPrefix(line, "#"): - err = addPattern(line) + case strings.HasPrefix(line, "#include"): + includeRel := strings.TrimSpace(line[len("#include "):]) + includeFile := filepath.Join(filepath.Dir(currentFile), includeRel) + var includePatterns []Pattern + if includePatterns, err = loadParseIncludeFile(fs, includeFile, cd, linesSeen); err == nil { + patterns = append(patterns, includePatterns...) + } case strings.HasSuffix(line, "/**"): err = addPattern(line) case strings.HasSuffix(line, "/"): diff --git a/lib/ignore/ignore_test.go b/lib/ignore/ignore_test.go index 74aa5793..108687c7 100644 --- a/lib/ignore/ignore_test.go +++ b/lib/ignore/ignore_test.go @@ -186,7 +186,6 @@ func TestBadPatterns(t *testing.T) { "**/[", "#include nonexistent", "#include .stignore", - "!#include makesnosense", } for _, pat := range badPatterns { @@ -930,3 +929,30 @@ func TestDuplicateLines(t *testing.T) { t.Fatalf("Parsed patterns differ when manually removing duplicate lines") } } + +func TestIssue4680(t *testing.T) { + stignore := ` + #snapshot + ` + + testcases := []struct { + file string + matches bool + }{ + {"#snapshot", true}, + {"#snapshot/foo", true}, + } + + pats := New(fs.NewFilesystem(fs.FilesystemTypeBasic, "."), WithCache(true)) + err := pats.Parse(bytes.NewBufferString(stignore), ".stignore") + if err != nil { + t.Fatal(err) + } + + for _, tc := range testcases { + res := pats.Match(tc.file).IsIgnored() + if res != tc.matches { + t.Errorf("Matches(%q) == %v, expected %v", tc.file, res, tc.matches) + } + } +}