|
@@ -19,6 +19,7 @@ import (
|
|
|
"time"
|
|
|
|
|
|
"github.com/gobwas/glob"
|
|
|
+ "github.com/syncthing/syncthing/lib/osutil"
|
|
|
"github.com/syncthing/syncthing/lib/sync"
|
|
|
)
|
|
|
|
|
@@ -64,6 +65,7 @@ func (r Result) IsCaseFolded() bool {
|
|
|
}
|
|
|
|
|
|
type Matcher struct {
|
|
|
+ lines []string
|
|
|
patterns []Pattern
|
|
|
withCache bool
|
|
|
matches *cache
|
|
@@ -120,7 +122,7 @@ func (m *Matcher) Parse(r io.Reader, file string) error {
|
|
|
}
|
|
|
|
|
|
func (m *Matcher) parseLocked(r io.Reader, file string) error {
|
|
|
- patterns, err := parseIgnoreFile(r, file, m.modtimes)
|
|
|
+ lines, patterns, err := parseIgnoreFile(r, file, m.modtimes)
|
|
|
// Error is saved and returned at the end. We process the patterns
|
|
|
// (possibly blank) anyway.
|
|
|
|
|
@@ -131,6 +133,7 @@ func (m *Matcher) parseLocked(r io.Reader, file string) error {
|
|
|
}
|
|
|
|
|
|
m.curHash = newHash
|
|
|
+ m.lines = lines
|
|
|
m.patterns = patterns
|
|
|
if m.withCache {
|
|
|
m.matches = newCache(patterns)
|
|
@@ -206,6 +209,13 @@ func (m *Matcher) Match(file string) (result Result) {
|
|
|
return resultNotMatched
|
|
|
}
|
|
|
|
|
|
+// Lines return a list of the unprocessed lines in .stignore at last load
|
|
|
+func (m *Matcher) Lines() []string {
|
|
|
+ m.mut.Lock()
|
|
|
+ defer m.mut.Unlock()
|
|
|
+ return m.lines
|
|
|
+}
|
|
|
+
|
|
|
// Patterns return a list of the loaded patterns, as they've been parsed
|
|
|
func (m *Matcher) Patterns() []string {
|
|
|
if m == nil {
|
|
@@ -274,27 +284,28 @@ func hashPatterns(patterns []Pattern) string {
|
|
|
return fmt.Sprintf("%x", h.Sum(nil))
|
|
|
}
|
|
|
|
|
|
-func loadIgnoreFile(file string, modtimes map[string]time.Time) ([]Pattern, error) {
|
|
|
+func loadIgnoreFile(file string, modtimes map[string]time.Time) ([]string, []Pattern, error) {
|
|
|
if _, ok := modtimes[file]; ok {
|
|
|
- return nil, fmt.Errorf("Multiple include of ignore file %q", file)
|
|
|
+ return nil, nil, fmt.Errorf("multiple include of ignore file %q", file)
|
|
|
}
|
|
|
|
|
|
fd, err := os.Open(file)
|
|
|
if err != nil {
|
|
|
- return nil, err
|
|
|
+ return nil, nil, err
|
|
|
}
|
|
|
defer fd.Close()
|
|
|
|
|
|
info, err := fd.Stat()
|
|
|
if err != nil {
|
|
|
- return nil, err
|
|
|
+ return nil, nil, err
|
|
|
}
|
|
|
modtimes[file] = info.ModTime()
|
|
|
|
|
|
return parseIgnoreFile(fd, file, modtimes)
|
|
|
}
|
|
|
|
|
|
-func parseIgnoreFile(fd io.Reader, currentFile string, modtimes map[string]time.Time) ([]Pattern, error) {
|
|
|
+func parseIgnoreFile(fd io.Reader, currentFile string, modtimes map[string]time.Time) ([]string, []Pattern, error) {
|
|
|
+ var lines []string
|
|
|
var patterns []Pattern
|
|
|
|
|
|
defaultResult := resultInclude
|
|
@@ -360,11 +371,12 @@ func parseIgnoreFile(fd io.Reader, currentFile string, modtimes map[string]time.
|
|
|
} else if strings.HasPrefix(line, "#include ") {
|
|
|
includeRel := line[len("#include "):]
|
|
|
includeFile := filepath.Join(filepath.Dir(currentFile), includeRel)
|
|
|
- includes, err := loadIgnoreFile(includeFile, modtimes)
|
|
|
+ includeLines, includePatterns, err := loadIgnoreFile(includeFile, modtimes)
|
|
|
if err != nil {
|
|
|
return fmt.Errorf("include of %q: %v", includeRel, err)
|
|
|
}
|
|
|
- patterns = append(patterns, includes...)
|
|
|
+ lines = append(lines, includeLines...)
|
|
|
+ patterns = append(patterns, includePatterns...)
|
|
|
} else {
|
|
|
// Path name or pattern, add it so it matches files both in
|
|
|
// current directory and subdirs.
|
|
@@ -389,6 +401,7 @@ func parseIgnoreFile(fd io.Reader, currentFile string, modtimes map[string]time.
|
|
|
var err error
|
|
|
for scanner.Scan() {
|
|
|
line := strings.TrimSpace(scanner.Text())
|
|
|
+ lines = append(lines, line)
|
|
|
switch {
|
|
|
case line == "":
|
|
|
continue
|
|
@@ -411,11 +424,11 @@ func parseIgnoreFile(fd io.Reader, currentFile string, modtimes map[string]time.
|
|
|
}
|
|
|
}
|
|
|
if err != nil {
|
|
|
- return nil, err
|
|
|
+ return nil, nil, err
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- return patterns, nil
|
|
|
+ return lines, patterns, nil
|
|
|
}
|
|
|
|
|
|
// IsInternal returns true if the file, as a path relative to the folder
|
|
@@ -434,3 +447,22 @@ func IsInternal(file string) bool {
|
|
|
}
|
|
|
return false
|
|
|
}
|
|
|
+
|
|
|
+// WriteIgnores is a convenience function to avoid code duplication
|
|
|
+func WriteIgnores(path string, content []string) error {
|
|
|
+ fd, err := osutil.CreateAtomic(path)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ for _, line := range content {
|
|
|
+ fmt.Fprintln(fd, line)
|
|
|
+ }
|
|
|
+
|
|
|
+ if err := fd.Close(); err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ osutil.HideFile(path)
|
|
|
+
|
|
|
+ return nil
|
|
|
+}
|