chore: remove ignore file caching entirely (#10813)
Effectively nobody uses it, it cost more than it was worth, the code doesn't carry its weight. Remove it and let any similar mechanism in the future be an internal implementation detail. Closes #10812 Signed-off-by: Jakob Borg <jakob@kastelo.net>
This commit is contained in:
Vendored
-1
@@ -116,7 +116,6 @@
|
||||
<autoUpgradeIntervalH>12</autoUpgradeIntervalH>
|
||||
<upgradeToPreReleases>false</upgradeToPreReleases>
|
||||
<keepTemporariesH>24</keepTemporariesH>
|
||||
<cacheIgnoredFiles>false</cacheIgnoredFiles>
|
||||
<progressUpdateIntervalS>5</progressUpdateIntervalS>
|
||||
<limitBandwidthInLan>false</limitBandwidthInLan>
|
||||
<minHomeDiskFree unit="%">1</minHomeDiskFree>
|
||||
|
||||
@@ -72,7 +72,6 @@ func TestDefaultValues(t *testing.T) {
|
||||
NATTimeoutS: 10,
|
||||
AutoUpgradeIntervalH: 12,
|
||||
KeepTemporariesH: 24,
|
||||
CacheIgnoredFiles: false,
|
||||
ProgressUpdateIntervalS: 5,
|
||||
LimitBandwidthInLan: false,
|
||||
MinHomeDiskFree: Size{1, "%"},
|
||||
@@ -278,7 +277,6 @@ func TestOverriddenValues(t *testing.T) {
|
||||
NATTimeoutS: 15,
|
||||
AutoUpgradeIntervalH: 24,
|
||||
KeepTemporariesH: 48,
|
||||
CacheIgnoredFiles: true,
|
||||
ProgressUpdateIntervalS: 10,
|
||||
LimitBandwidthInLan: true,
|
||||
MinHomeDiskFree: Size{5.2, "%"},
|
||||
|
||||
@@ -320,10 +320,6 @@ func migrateToConfigV15(cfg *Configuration) {
|
||||
}
|
||||
|
||||
func migrateToConfigV14(cfg *Configuration) {
|
||||
// Not using the ignore cache is the new default. Disable it on existing
|
||||
// configurations.
|
||||
cfg.Options.CacheIgnoredFiles = false
|
||||
|
||||
// Migrate UPnP -> NAT options
|
||||
cfg.Options.NATEnabled = cfg.Options.DeprecatedUPnPEnabled
|
||||
cfg.Options.DeprecatedUPnPEnabled = false
|
||||
|
||||
@@ -45,7 +45,6 @@ type OptionsConfiguration struct {
|
||||
AutoUpgradeIntervalH int `json:"autoUpgradeIntervalH" xml:"autoUpgradeIntervalH" default:"12"`
|
||||
UpgradeToPreReleases bool `json:"upgradeToPreReleases" xml:"upgradeToPreReleases"`
|
||||
KeepTemporariesH int `json:"keepTemporariesH" xml:"keepTemporariesH" default:"24"`
|
||||
CacheIgnoredFiles bool `json:"cacheIgnoredFiles" xml:"cacheIgnoredFiles" default:"false"`
|
||||
ProgressUpdateIntervalS int `json:"progressUpdateIntervalS" xml:"progressUpdateIntervalS" default:"5"`
|
||||
LimitBandwidthInLan bool `json:"limitBandwidthInLan" xml:"limitBandwidthInLan" default:"false"`
|
||||
MinHomeDiskFree Size `json:"minHomeDiskFree" xml:"minHomeDiskFree" default:"1 %"`
|
||||
|
||||
Vendored
-1
@@ -42,7 +42,6 @@
|
||||
<restartOnWakeup>true</restartOnWakeup>
|
||||
<autoUpgradeIntervalH>0</autoUpgradeIntervalH>
|
||||
<keepTemporariesH>24</keepTemporariesH>
|
||||
<cacheIgnoredFiles>true</cacheIgnoredFiles>
|
||||
<progressUpdateIntervalS>5</progressUpdateIntervalS>
|
||||
<symlinksEnabled>true</symlinksEnabled>
|
||||
<limitBandwidthInLan>false</limitBandwidthInLan>
|
||||
|
||||
-1
@@ -22,7 +22,6 @@
|
||||
<restartOnWakeup>false</restartOnWakeup>
|
||||
<autoUpgradeIntervalH>24</autoUpgradeIntervalH>
|
||||
<keepTemporariesH>48</keepTemporariesH>
|
||||
<cacheIgnoredFiles>true</cacheIgnoredFiles>
|
||||
<progressUpdateIntervalS>10</progressUpdateIntervalS>
|
||||
<symlinksEnabled>false</symlinksEnabled>
|
||||
<limitBandwidthInLan>true</limitBandwidthInLan>
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
// Copyright (C) 2014 The Syncthing Authors.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
// You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
package ignore
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/syncthing/syncthing/lib/ignore/ignoreresult"
|
||||
)
|
||||
|
||||
type nower interface {
|
||||
Now() time.Time
|
||||
}
|
||||
|
||||
var clock = nower(defaultClock{})
|
||||
|
||||
type cache struct {
|
||||
entries map[string]cacheEntry
|
||||
}
|
||||
|
||||
type cacheEntry struct {
|
||||
result ignoreresult.R
|
||||
access int64 // Unix nanosecond count. Sufficient until the year 2262.
|
||||
}
|
||||
|
||||
func newCache() *cache {
|
||||
return &cache{
|
||||
entries: make(map[string]cacheEntry),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *cache) clean(d time.Duration) {
|
||||
for k, v := range c.entries {
|
||||
if clock.Now().Sub(time.Unix(0, v.access)) > d {
|
||||
delete(c.entries, k)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *cache) get(key string) (ignoreresult.R, bool) {
|
||||
entry, ok := c.entries[key]
|
||||
if ok {
|
||||
entry.access = clock.Now().UnixNano()
|
||||
c.entries[key] = entry
|
||||
}
|
||||
return entry.result, ok
|
||||
}
|
||||
|
||||
func (c *cache) set(key string, result ignoreresult.R) {
|
||||
c.entries[key] = cacheEntry{result, time.Now().UnixNano()}
|
||||
}
|
||||
|
||||
func (c *cache) len() int {
|
||||
l := len(c.entries)
|
||||
return l
|
||||
}
|
||||
|
||||
type defaultClock struct{}
|
||||
|
||||
func (defaultClock) Now() time.Time {
|
||||
return time.Now()
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
// Copyright (C) 2014 The Syncthing Authors.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
// You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
package ignore
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/syncthing/syncthing/lib/ignore/ignoreresult"
|
||||
)
|
||||
|
||||
func TestCache(t *testing.T) {
|
||||
fc := new(fakeClock)
|
||||
oldClock := clock
|
||||
clock = fc
|
||||
defer func() {
|
||||
clock = oldClock
|
||||
}()
|
||||
|
||||
c := newCache()
|
||||
|
||||
res, ok := c.get("nonexistent")
|
||||
if res.IsIgnored() || res.IsDeletable() || ok {
|
||||
t.Errorf("res %v, ok %v for nonexistent item", res, ok)
|
||||
}
|
||||
|
||||
// Set and check some items
|
||||
|
||||
c.set("true", ignoreresult.IgnoredDeletable)
|
||||
c.set("false", 0)
|
||||
|
||||
res, ok = c.get("true")
|
||||
if !res.IsIgnored() || !res.IsDeletable() || !ok {
|
||||
t.Errorf("res %v, ok %v for true item", res, ok)
|
||||
}
|
||||
|
||||
res, ok = c.get("false")
|
||||
if res.IsIgnored() || res.IsDeletable() || !ok {
|
||||
t.Errorf("res %v, ok %v for false item", res, ok)
|
||||
}
|
||||
|
||||
// Don't clean anything
|
||||
|
||||
c.clean(time.Second)
|
||||
|
||||
// Same values should exist
|
||||
|
||||
res, ok = c.get("true")
|
||||
if !res.IsIgnored() || !res.IsDeletable() || !ok {
|
||||
t.Errorf("res %v, ok %v for true item", res, ok)
|
||||
}
|
||||
|
||||
res, ok = c.get("false")
|
||||
if res.IsIgnored() || res.IsDeletable() || !ok {
|
||||
t.Errorf("res %v, ok %v for false item", res, ok)
|
||||
}
|
||||
|
||||
// Sleep and access, to get some data for clean
|
||||
|
||||
*fc += 500 // milliseconds
|
||||
|
||||
c.get("true")
|
||||
|
||||
*fc += 100 // milliseconds
|
||||
|
||||
// "false" was accessed ~600 ms ago, "true" was accessed ~100 ms ago.
|
||||
// This should clean out "false" but not "true"
|
||||
|
||||
c.clean(300 * time.Millisecond)
|
||||
|
||||
// Same values should exist
|
||||
|
||||
_, ok = c.get("true")
|
||||
if !ok {
|
||||
t.Error("item should still exist")
|
||||
}
|
||||
|
||||
_, ok = c.get("false")
|
||||
if ok {
|
||||
t.Errorf("item should have been cleaned")
|
||||
}
|
||||
}
|
||||
|
||||
type fakeClock int64 // milliseconds
|
||||
|
||||
func (f *fakeClock) Now() time.Time {
|
||||
t := time.Unix(int64(*f)/1000, (int64(*f)%1000)*int64(time.Millisecond))
|
||||
*f++
|
||||
return t
|
||||
}
|
||||
+2
-53
@@ -124,10 +124,7 @@ type Matcher struct {
|
||||
fs fs.Filesystem
|
||||
lines []string // exact lines read from .stignore
|
||||
patterns []Pattern // patterns including those from included files
|
||||
withCache bool
|
||||
matches *cache
|
||||
curHash string
|
||||
stop chan struct{}
|
||||
changeDetector ChangeDetector
|
||||
mut sync.Mutex
|
||||
}
|
||||
@@ -135,13 +132,6 @@ type Matcher struct {
|
||||
// An Option can be passed to New()
|
||||
type Option func(*Matcher)
|
||||
|
||||
// WithCache enables or disables lookup caching. The default is disabled.
|
||||
func WithCache(v bool) Option {
|
||||
return func(m *Matcher) {
|
||||
m.withCache = v
|
||||
}
|
||||
}
|
||||
|
||||
// WithChangeDetector sets a custom ChangeDetector. The default is to simply
|
||||
// use the on disk modtime for comparison.
|
||||
func WithChangeDetector(cd ChangeDetector) Option {
|
||||
@@ -152,8 +142,7 @@ func WithChangeDetector(cd ChangeDetector) Option {
|
||||
|
||||
func New(fs fs.Filesystem, opts ...Option) *Matcher {
|
||||
m := &Matcher{
|
||||
fs: fs,
|
||||
stop: make(chan struct{}),
|
||||
fs: fs,
|
||||
}
|
||||
for _, opt := range opts {
|
||||
opt(m)
|
||||
@@ -161,9 +150,6 @@ func New(fs fs.Filesystem, opts ...Option) *Matcher {
|
||||
if m.changeDetector == nil {
|
||||
m.changeDetector = newModtimeChecker()
|
||||
}
|
||||
if m.withCache {
|
||||
go m.clean(2 * time.Hour)
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
@@ -219,9 +205,6 @@ func (m *Matcher) parseLocked(r io.Reader, file string) error {
|
||||
|
||||
m.curHash = newHash
|
||||
m.patterns = patterns
|
||||
if m.withCache {
|
||||
m.matches = newCache()
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
@@ -232,7 +215,7 @@ func (m *Matcher) parseLocked(r io.Reader, file string) error {
|
||||
// NFC everywhere else). This is always the case in real usage in syncthing, as
|
||||
// we ensure native unicode normalisation on all entry points (scanning and from
|
||||
// protocol) - so no need to normalize when calling this, except e.g. in tests.
|
||||
func (m *Matcher) Match(file string) (result ignoreresult.R) {
|
||||
func (m *Matcher) Match(file string) ignoreresult.R {
|
||||
switch {
|
||||
case fs.IsTemporary(file):
|
||||
return ignoreresult.IgnoreAndSkip
|
||||
@@ -254,19 +237,6 @@ func (m *Matcher) Match(file string) (result ignoreresult.R) {
|
||||
// Change backslashes to slashes (on Windows only)
|
||||
file = filepath.ToSlash(file)
|
||||
|
||||
if m.matches != nil {
|
||||
// Check the cache for a known result.
|
||||
res, ok := m.matches.get(file)
|
||||
if ok {
|
||||
return res
|
||||
}
|
||||
|
||||
// Update the cache with the result at return time
|
||||
defer func() {
|
||||
m.matches.set(file, result)
|
||||
}()
|
||||
}
|
||||
|
||||
// Check all the patterns for a match. Track whether the patterns so far
|
||||
// allow skipping matched directories or not. As soon as we hit an
|
||||
// exclude pattern (with some exceptions), we can't skip directories
|
||||
@@ -327,27 +297,6 @@ func (m *Matcher) Hash() string {
|
||||
return m.curHash
|
||||
}
|
||||
|
||||
func (m *Matcher) Stop() {
|
||||
close(m.stop)
|
||||
}
|
||||
|
||||
func (m *Matcher) clean(d time.Duration) {
|
||||
t := time.NewTimer(d / 2)
|
||||
for {
|
||||
select {
|
||||
case <-m.stop:
|
||||
return
|
||||
case <-t.C:
|
||||
m.mut.Lock()
|
||||
if m.matches != nil {
|
||||
m.matches.clean(d)
|
||||
}
|
||||
t.Reset(d / 2)
|
||||
m.mut.Unlock()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func hashPatterns(patterns []Pattern) string {
|
||||
h := sha256.New()
|
||||
for _, pat := range patterns {
|
||||
|
||||
+33
-206
@@ -52,7 +52,7 @@ func newTestFS() fs.Filesystem {
|
||||
func TestIgnore(t *testing.T) {
|
||||
testFs := newTestFS()
|
||||
|
||||
pats := New(testFs, WithCache(true))
|
||||
pats := New(testFs)
|
||||
err := pats.Load(".stignore")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -104,7 +104,7 @@ func TestExcludes(t *testing.T) {
|
||||
i*2
|
||||
!ign2
|
||||
`
|
||||
pats := New(testFs, WithCache(true))
|
||||
pats := New(testFs)
|
||||
err := pats.Parse(bytes.NewBufferString(stignore), ".stignore")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -151,7 +151,7 @@ func TestFlagOrder(t *testing.T) {
|
||||
(?i)(?d)(?d)!ign9
|
||||
(?d)(?d)!ign10
|
||||
`
|
||||
pats := New(testFs, WithCache(true))
|
||||
pats := New(testFs)
|
||||
err := pats.Parse(bytes.NewBufferString(stignore), ".stignore")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -188,7 +188,7 @@ func TestDeletables(t *testing.T) {
|
||||
ign7
|
||||
(?i)ign8
|
||||
`
|
||||
pats := New(testFs, WithCache(true))
|
||||
pats := New(testFs)
|
||||
err := pats.Parse(bytes.NewBufferString(stignore), ".stignore")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -229,7 +229,7 @@ func TestBadPatterns(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, pat := range badPatterns {
|
||||
err := New(testFs, WithCache(true)).Parse(bytes.NewBufferString(pat), ".stignore")
|
||||
err := New(testFs).Parse(bytes.NewBufferString(pat), ".stignore")
|
||||
if err == nil {
|
||||
t.Errorf("No error for pattern %q", pat)
|
||||
}
|
||||
@@ -247,7 +247,7 @@ func TestBadPatterns(t *testing.T) {
|
||||
func TestCaseSensitivity(t *testing.T) {
|
||||
testFs := newTestFS()
|
||||
|
||||
ign := New(testFs, WithCache(true))
|
||||
ign := New(testFs)
|
||||
err := ign.Parse(bytes.NewBufferString("test"), ".stignore")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
@@ -275,126 +275,6 @@ func TestCaseSensitivity(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestCaching(t *testing.T) {
|
||||
fs := fs.NewFilesystem(fs.FilesystemTypeFake, rand.String(32)+"?content=true")
|
||||
|
||||
fd1, err := osutil.TempFile(fs, "", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
fd2, err := osutil.TempFile(fs, "", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
defer fd1.Close()
|
||||
defer fd2.Close()
|
||||
defer fs.Remove(fd1.Name())
|
||||
defer fs.Remove(fd2.Name())
|
||||
|
||||
_, err = fd1.Write([]byte("/x/\n#include " + filepath.Base(fd2.Name()) + "\n"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
fd2.Write([]byte("/y/\n"))
|
||||
|
||||
pats := New(fs, WithCache(true))
|
||||
err = pats.Load(fd1.Name())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if pats.matches.len() != 0 {
|
||||
t.Fatal("Expected empty cache")
|
||||
}
|
||||
|
||||
// Cache some outcomes
|
||||
|
||||
for _, letter := range []string{"a", "b", "x", "y"} {
|
||||
pats.Match(letter)
|
||||
}
|
||||
|
||||
if pats.matches.len() != 4 {
|
||||
t.Fatal("Expected 4 cached results")
|
||||
}
|
||||
|
||||
// Reload file, expect old outcomes to be preserved
|
||||
|
||||
err = pats.Load(fd1.Name())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if pats.matches.len() != 4 {
|
||||
t.Fatal("Expected 4 cached results")
|
||||
}
|
||||
|
||||
// Modify the include file, expect empty cache. Ensure the timestamp on
|
||||
// the file changes.
|
||||
|
||||
fd2.Write([]byte("/z/\n"))
|
||||
fd2.Sync()
|
||||
fakeTime := time.Now().Add(5 * time.Second)
|
||||
fs.Chtimes(fd2.Name(), fakeTime, fakeTime)
|
||||
|
||||
err = pats.Load(fd1.Name())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if pats.matches.len() != 0 {
|
||||
t.Fatal("Expected 0 cached results")
|
||||
}
|
||||
|
||||
// Cache some outcomes again
|
||||
|
||||
for _, letter := range []string{"b", "x", "y"} {
|
||||
pats.Match(letter)
|
||||
}
|
||||
|
||||
// Verify that outcomes preserved on next load
|
||||
|
||||
err = pats.Load(fd1.Name())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if pats.matches.len() != 3 {
|
||||
t.Fatal("Expected 3 cached results")
|
||||
}
|
||||
|
||||
// Modify the root file, expect cache to be invalidated
|
||||
|
||||
fd1.Write([]byte("/a/\n"))
|
||||
fd1.Sync()
|
||||
fakeTime = time.Now().Add(5 * time.Second)
|
||||
fs.Chtimes(fd1.Name(), fakeTime, fakeTime)
|
||||
|
||||
err = pats.Load(fd1.Name())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if pats.matches.len() != 0 {
|
||||
t.Fatal("Expected cache invalidation")
|
||||
}
|
||||
|
||||
// Cache some outcomes again
|
||||
|
||||
for _, letter := range []string{"b", "x", "y"} {
|
||||
pats.Match(letter)
|
||||
}
|
||||
|
||||
// Verify that outcomes provided on next load
|
||||
|
||||
err = pats.Load(fd1.Name())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if pats.matches.len() != 3 {
|
||||
t.Fatal("Expected 3 cached results")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommentsAndBlankLines(t *testing.T) {
|
||||
testFs := newTestFS()
|
||||
|
||||
@@ -409,7 +289,7 @@ func TestCommentsAndBlankLines(t *testing.T) {
|
||||
|
||||
|
||||
`
|
||||
pats := New(testFs, WithCache(true))
|
||||
pats := New(testFs)
|
||||
err := pats.Parse(bytes.NewBufferString(stignore), ".stignore")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
@@ -451,59 +331,6 @@ flamingo
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMatchCached(b *testing.B) {
|
||||
stignore := `
|
||||
.frog
|
||||
.frog*
|
||||
.frogfox
|
||||
.whale
|
||||
.whale/*
|
||||
.dolphin
|
||||
.dolphin/*
|
||||
~ferret~.*
|
||||
.ferret.*
|
||||
flamingo.*
|
||||
flamingo
|
||||
*.crow
|
||||
*.crow
|
||||
`
|
||||
// Caches per file, hence write the patterns to a file.
|
||||
|
||||
fs := fs.NewFilesystem(fs.FilesystemTypeFake, rand.String(32)+"?content=true")
|
||||
|
||||
fd, err := osutil.TempFile(fs, "", "")
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
_, err = fd.Write([]byte(stignore))
|
||||
defer fd.Close()
|
||||
defer fs.Remove(fd.Name())
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
// Load the patterns
|
||||
pats := New(fs, WithCache(true))
|
||||
err = pats.Load(fd.Name())
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
// Cache the outcome for "filename"
|
||||
pats.Match("filename")
|
||||
|
||||
// This load should now load the cached outcomes as the set of patterns
|
||||
// has not changed.
|
||||
err = pats.Load(fd.Name())
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
result = pats.Match("filename")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCacheReload(t *testing.T) {
|
||||
fs := fs.NewFilesystem(fs.FilesystemTypeFake, rand.String(32)+"?content=true")
|
||||
|
||||
@@ -522,7 +349,7 @@ func TestCacheReload(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
pats := New(fs, WithCache(true))
|
||||
pats := New(fs)
|
||||
err = pats.Load(fd.Name())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -579,7 +406,7 @@ func TestCacheReload(t *testing.T) {
|
||||
func TestHash(t *testing.T) {
|
||||
testFs := newTestFS()
|
||||
|
||||
p1 := New(testFs, WithCache(true))
|
||||
p1 := New(testFs)
|
||||
err := p1.Load(".stignore")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -595,7 +422,7 @@ func TestHash(t *testing.T) {
|
||||
/ffile
|
||||
lost+found
|
||||
`
|
||||
p2 := New(testFs, WithCache(true))
|
||||
p2 := New(testFs)
|
||||
err = p2.Parse(bytes.NewBufferString(stignore), ".stignore")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -610,7 +437,7 @@ func TestHash(t *testing.T) {
|
||||
/ffile
|
||||
lost+found
|
||||
`
|
||||
p3 := New(testFs, WithCache(true))
|
||||
p3 := New(testFs)
|
||||
err = p3.Parse(bytes.NewBufferString(stignore), ".stignore")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -636,7 +463,7 @@ func TestHash(t *testing.T) {
|
||||
func TestHashOfEmpty(t *testing.T) {
|
||||
testFs := newTestFS()
|
||||
|
||||
p1 := New(testFs, WithCache(true))
|
||||
p1 := New(testFs)
|
||||
|
||||
err := p1.Load(".stignore")
|
||||
if err != nil {
|
||||
@@ -678,7 +505,7 @@ func TestWindowsPatterns(t *testing.T) {
|
||||
a/b
|
||||
c\d
|
||||
`
|
||||
pats := New(testFs, WithCache(true))
|
||||
pats := New(testFs)
|
||||
|
||||
err := pats.Parse(bytes.NewBufferString(stignore), ".stignore")
|
||||
if err != nil {
|
||||
@@ -706,7 +533,7 @@ func TestAutomaticCaseInsensitivity(t *testing.T) {
|
||||
A/B
|
||||
c/d
|
||||
`
|
||||
pats := New(testFs, WithCache(true))
|
||||
pats := New(testFs)
|
||||
|
||||
err := pats.Parse(bytes.NewBufferString(stignore), ".stignore")
|
||||
if err != nil {
|
||||
@@ -728,7 +555,7 @@ func TestCommas(t *testing.T) {
|
||||
foo,bar.txt
|
||||
{baz,quux}.txt
|
||||
`
|
||||
pats := New(testFs, WithCache(true))
|
||||
pats := New(testFs)
|
||||
|
||||
err := pats.Parse(bytes.NewBufferString(stignore), ".stignore")
|
||||
if err != nil {
|
||||
@@ -762,7 +589,7 @@ func TestIssue3164(t *testing.T) {
|
||||
(?d)(?i)/foo
|
||||
(?d)(?i)**/bar
|
||||
`
|
||||
pats := New(testFs, WithCache(true))
|
||||
pats := New(testFs)
|
||||
|
||||
err := pats.Parse(bytes.NewBufferString(stignore), ".stignore")
|
||||
if err != nil {
|
||||
@@ -801,7 +628,7 @@ func TestIssue3174(t *testing.T) {
|
||||
stignore := `
|
||||
*ä*
|
||||
`
|
||||
pats := New(testFs, WithCache(true))
|
||||
pats := New(testFs)
|
||||
|
||||
err := pats.Parse(bytes.NewBufferString(stignore), ".stignore")
|
||||
if err != nil {
|
||||
@@ -822,7 +649,7 @@ func TestIssue3639(t *testing.T) {
|
||||
stignore := `
|
||||
foo/
|
||||
`
|
||||
pats := New(testFs, WithCache(true))
|
||||
pats := New(testFs)
|
||||
|
||||
err := pats.Parse(bytes.NewBufferString(stignore), ".stignore")
|
||||
if err != nil {
|
||||
@@ -858,7 +685,7 @@ func TestIssue3674(t *testing.T) {
|
||||
{"as/dc", true},
|
||||
}
|
||||
|
||||
pats := New(testFs, WithCache(true))
|
||||
pats := New(testFs)
|
||||
|
||||
err := pats.Parse(bytes.NewBufferString(stignore), ".stignore")
|
||||
if err != nil {
|
||||
@@ -893,7 +720,7 @@ func TestGobwasGlobIssue18(t *testing.T) {
|
||||
{"bbaa", false},
|
||||
}
|
||||
|
||||
pats := New(testFs, WithCache(true))
|
||||
pats := New(testFs)
|
||||
|
||||
err := pats.Parse(bytes.NewBufferString(stignore), ".stignore")
|
||||
if err != nil {
|
||||
@@ -925,7 +752,7 @@ func TestRoot(t *testing.T) {
|
||||
{"b", true},
|
||||
}
|
||||
|
||||
pats := New(testFs, WithCache(true))
|
||||
pats := New(testFs)
|
||||
|
||||
err := pats.Parse(bytes.NewBufferString(stignore), ".stignore")
|
||||
if err != nil {
|
||||
@@ -951,7 +778,7 @@ func TestLines(t *testing.T) {
|
||||
!/a
|
||||
`
|
||||
|
||||
pats := New(testFs, WithCache(true))
|
||||
pats := New(testFs)
|
||||
|
||||
err := pats.Parse(bytes.NewBufferString(stignore), ".stignore")
|
||||
if err != nil {
|
||||
@@ -992,7 +819,7 @@ func TestDuplicateLines(t *testing.T) {
|
||||
/*
|
||||
`
|
||||
|
||||
pats := New(testFs, WithCache(true))
|
||||
pats := New(testFs)
|
||||
|
||||
err := pats.Parse(bytes.NewBufferString(stignore), ".stignore")
|
||||
if err != nil {
|
||||
@@ -1025,7 +852,7 @@ func TestIssue4680(t *testing.T) {
|
||||
{"#snapshot/foo", true},
|
||||
}
|
||||
|
||||
pats := New(testFs, WithCache(true))
|
||||
pats := New(testFs)
|
||||
|
||||
err := pats.Parse(bytes.NewBufferString(stignore), ".stignore")
|
||||
if err != nil {
|
||||
@@ -1045,7 +872,7 @@ func TestIssue4689(t *testing.T) {
|
||||
|
||||
stignore := `// orig`
|
||||
|
||||
pats := New(testFs, WithCache(true))
|
||||
pats := New(testFs)
|
||||
|
||||
err := pats.Parse(bytes.NewBufferString(stignore), ".stignore")
|
||||
if err != nil {
|
||||
@@ -1076,7 +903,7 @@ func TestIssue4901(t *testing.T) {
|
||||
puppy
|
||||
`
|
||||
|
||||
pats := New(testFs, WithCache(true))
|
||||
pats := New(testFs)
|
||||
|
||||
fd, err := pats.fs.Create(".stignore")
|
||||
if err != nil {
|
||||
@@ -1119,7 +946,7 @@ func TestIssue4901(t *testing.T) {
|
||||
func TestIssue5009(t *testing.T) {
|
||||
testFs := newTestFS()
|
||||
|
||||
pats := New(testFs, WithCache(true))
|
||||
pats := New(testFs)
|
||||
|
||||
stignore := `
|
||||
ign1
|
||||
@@ -1152,7 +979,7 @@ func TestIssue5009(t *testing.T) {
|
||||
func TestSpecialChars(t *testing.T) {
|
||||
testFs := newTestFS()
|
||||
|
||||
pats := New(testFs, WithCache(true))
|
||||
pats := New(testFs)
|
||||
|
||||
stignore := `(?i)/#recycle
|
||||
(?i)/#nosync
|
||||
@@ -1179,7 +1006,7 @@ func TestSpecialChars(t *testing.T) {
|
||||
func TestIntlWildcards(t *testing.T) {
|
||||
testFs := newTestFS()
|
||||
|
||||
pats := New(testFs, WithCache(true))
|
||||
pats := New(testFs)
|
||||
|
||||
stignore := `1000春
|
||||
200?春
|
||||
@@ -1208,7 +1035,7 @@ func TestPartialIncludeLine(t *testing.T) {
|
||||
|
||||
// Loading a partial #include line (no file mentioned) should error but not crash.
|
||||
|
||||
pats := New(testFs, WithCache(true))
|
||||
pats := New(testFs)
|
||||
|
||||
cases := []string{
|
||||
"#include",
|
||||
@@ -1267,7 +1094,7 @@ func TestSkipIgnoredDirs(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
pats := New(testFs, WithCache(true))
|
||||
pats := New(testFs)
|
||||
|
||||
stignore := `
|
||||
/foo/ign*
|
||||
@@ -1711,7 +1538,7 @@ func testEscape(t *testing.T, tests []escapeTest, noErrors bool) {
|
||||
for name, content := range testEscapeFiles {
|
||||
fs.WriteFile(testFS, name, []byte(content), 0o666)
|
||||
}
|
||||
pats := New(testFS, WithCache(true))
|
||||
pats := New(testFS)
|
||||
|
||||
err := pats.Parse(bytes.NewBufferString(test.pattern), ".stignore")
|
||||
if noErrors {
|
||||
@@ -1753,7 +1580,7 @@ func TestIgnoreThroughSymlink(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
pats := New(testFS, WithCache(true))
|
||||
pats := New(testFS)
|
||||
if err := pats.Load(".stignore"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
+10
-10
@@ -300,7 +300,7 @@ func (m *model) initFolders(cfg config.Configuration) error {
|
||||
folderCfg.CreateRoot()
|
||||
continue
|
||||
}
|
||||
err := m.newFolder(folderCfg, cfg.Options.CacheIgnoredFiles)
|
||||
err := m.newFolder(folderCfg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -335,8 +335,8 @@ func (m *model) fatal(err error) {
|
||||
}
|
||||
|
||||
// Need to hold lock on m.mut when calling this.
|
||||
func (m *model) addAndStartFolderLocked(cfg config.FolderConfiguration, cacheIgnoredFiles bool) {
|
||||
ignores := ignore.New(cfg.Filesystem(), ignore.WithCache(cacheIgnoredFiles))
|
||||
func (m *model) addAndStartFolderLocked(cfg config.FolderConfiguration) {
|
||||
ignores := ignore.New(cfg.Filesystem())
|
||||
if cfg.Type != config.FolderTypeReceiveEncrypted {
|
||||
if err := ignores.Load(".stignore"); err != nil && !fs.IsNotExist(err) {
|
||||
slog.Error("Failed to load ignores", slogutil.Error(err))
|
||||
@@ -509,7 +509,7 @@ func (m *model) cleanupFolderLocked(cfg config.FolderConfiguration) {
|
||||
delete(m.folderEncryptionFailures, cfg.ID)
|
||||
}
|
||||
|
||||
func (m *model) restartFolder(from, to config.FolderConfiguration, cacheIgnoredFiles bool) error {
|
||||
func (m *model) restartFolder(from, to config.FolderConfiguration) error {
|
||||
if to.ID == "" {
|
||||
panic("bug: cannot restart empty folder ID")
|
||||
}
|
||||
@@ -539,7 +539,7 @@ func (m *model) restartFolder(from, to config.FolderConfiguration, cacheIgnoredF
|
||||
|
||||
m.cleanupFolderLocked(from)
|
||||
if !to.Paused {
|
||||
m.addAndStartFolderLocked(to, cacheIgnoredFiles)
|
||||
m.addAndStartFolderLocked(to)
|
||||
}
|
||||
|
||||
runner, _ := m.folderRunners.Get(to.ID)
|
||||
@@ -560,11 +560,11 @@ func (m *model) restartFolder(from, to config.FolderConfiguration, cacheIgnoredF
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *model) newFolder(cfg config.FolderConfiguration, cacheIgnoredFiles bool) error {
|
||||
func (m *model) newFolder(cfg config.FolderConfiguration) error {
|
||||
m.mut.Lock()
|
||||
defer m.mut.Unlock()
|
||||
|
||||
m.addAndStartFolderLocked(cfg, cacheIgnoredFiles)
|
||||
m.addAndStartFolderLocked(cfg)
|
||||
|
||||
// Cluster configs might be received and processed before reaching this
|
||||
// point, i.e. before the folder is started. If that's the case, start
|
||||
@@ -2972,7 +2972,7 @@ func (m *model) CommitConfiguration(from, to config.Configuration) bool {
|
||||
slog.Info("Paused folder", cfg.LogAttr())
|
||||
} else {
|
||||
slog.Info("Adding folder", cfg.LogAttr())
|
||||
if err := m.newFolder(cfg, to.Options.CacheIgnoredFiles); err != nil {
|
||||
if err := m.newFolder(cfg); err != nil {
|
||||
m.fatal(err)
|
||||
return true
|
||||
}
|
||||
@@ -2998,8 +2998,8 @@ func (m *model) CommitConfiguration(from, to config.Configuration) bool {
|
||||
|
||||
// This folder exists on both sides. Settings might have changed.
|
||||
// Check if anything differs that requires a restart.
|
||||
if !reflect.DeepEqual(fromCfg.RequiresRestartOnly(), toCfg.RequiresRestartOnly()) || from.Options.CacheIgnoredFiles != to.Options.CacheIgnoredFiles {
|
||||
if err := m.restartFolder(fromCfg, toCfg, to.Options.CacheIgnoredFiles); err != nil {
|
||||
if !reflect.DeepEqual(fromCfg.RequiresRestartOnly(), toCfg.RequiresRestartOnly()) {
|
||||
if err := m.restartFolder(fromCfg, toCfg); err != nil {
|
||||
m.fatal(err)
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -1603,7 +1603,7 @@ func TestIgnores(t *testing.T) {
|
||||
ID: "fresh", Path: "XXX",
|
||||
FilesystemType: config.FilesystemTypeFake,
|
||||
}
|
||||
ignores := ignore.New(fcfg.Filesystem(), ignore.WithCache(m.cfg.Options().CacheIgnoredFiles))
|
||||
ignores := ignore.New(fcfg.Filesystem())
|
||||
m.mut.Lock()
|
||||
m.folderCfgs[fcfg.ID] = fcfg
|
||||
m.folderIgnores[fcfg.ID] = ignores
|
||||
@@ -1618,7 +1618,7 @@ func TestIgnores(t *testing.T) {
|
||||
pausedDefaultFolderConfig := defaultFolderConfig
|
||||
pausedDefaultFolderConfig.Paused = true
|
||||
|
||||
m.restartFolder(defaultFolderConfig, pausedDefaultFolderConfig, false)
|
||||
m.restartFolder(defaultFolderConfig, pausedDefaultFolderConfig)
|
||||
// Here folder initialization is not an issue as a paused folder isn't
|
||||
// added to the model and thus there is no initial scan happening.
|
||||
|
||||
@@ -2216,7 +2216,7 @@ func TestIndexesForUnknownDevicesDropped(t *testing.T) {
|
||||
t.Error("expected two devices")
|
||||
}
|
||||
|
||||
m.newFolder(defaultFolderConfig, false)
|
||||
m.newFolder(defaultFolderConfig)
|
||||
defer cleanupModel(m)
|
||||
|
||||
if devs, err := m.sdb.ListDevicesForFolder("default"); err != nil || len(devs) != 1 {
|
||||
|
||||
@@ -250,7 +250,7 @@ func (*alwaysChanged) Changed() bool {
|
||||
func folderIgnoresAlwaysReload(t testing.TB, m *testModel, fcfg config.FolderConfiguration) {
|
||||
t.Helper()
|
||||
m.removeFolder(fcfg)
|
||||
ignores := ignore.New(fcfg.Filesystem(), ignore.WithCache(true), ignore.WithChangeDetector(newAlwaysChanged()))
|
||||
ignores := ignore.New(fcfg.Filesystem(), ignore.WithChangeDetector(newAlwaysChanged()))
|
||||
m.mut.Lock()
|
||||
m.addAndStartFolderLockedWithIgnores(fcfg, ignores)
|
||||
m.mut.Unlock()
|
||||
|
||||
@@ -749,7 +749,7 @@ func TestRecurseInclude(t *testing.T) {
|
||||
*
|
||||
`
|
||||
testFs := newTestFs()
|
||||
ignores := ignore.New(testFs, ignore.WithCache(true))
|
||||
ignores := ignore.New(testFs)
|
||||
if err := ignores.Parse(bytes.NewBufferString(stignore), ".stignore"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -859,7 +859,7 @@ func TestSkipIgnoredDirs(t *testing.T) {
|
||||
|
||||
w := &walker{}
|
||||
|
||||
pats := ignore.New(fss, ignore.WithCache(true))
|
||||
pats := ignore.New(fss)
|
||||
|
||||
stignore := `
|
||||
/foo/ign*
|
||||
@@ -892,7 +892,7 @@ func TestIncludedSubdir(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
pats := ignore.New(fss, ignore.WithCache(true))
|
||||
pats := ignore.New(fss)
|
||||
|
||||
stignore := `
|
||||
!/foo/bar
|
||||
|
||||
@@ -91,7 +91,6 @@ type Report struct {
|
||||
NATType string `json:"natType,omitempty" metric:"nat_detection,gaugeVec:type" since:"3"`
|
||||
|
||||
AlwaysLocalNets bool `json:"alwaysLocalNets,omitempty" metric:"feature_count{feature=AlwaysLocalNets},gauge" since:"3"`
|
||||
CacheIgnoredFiles bool `json:"cacheIgnoredFiles,omitempty" metric:"feature_count{feature=CacheIgnoredFiles},gauge" since:"3"`
|
||||
OverwriteRemoteDeviceNames bool `json:"overwriteRemoteDeviceNames,omitempty" metric:"feature_count{feature=OverwriteRemoteDeviceNames},gauge" since:"3"`
|
||||
ProgressEmitterEnabled bool `json:"progressEmitterEnabled,omitempty" metric:"feature_count{feature=ProgressEmitterEnabled},gauge" since:"3"`
|
||||
CustomDefaultFolderPath bool `json:"customDefaultFolderPath,omitempty" metric:"feature_count{feature=CustomDefaultFolderPath},gauge" since:"3"`
|
||||
|
||||
@@ -217,7 +217,6 @@ func (s *Service) reportData(ctx context.Context, urVersion int, preview bool) (
|
||||
report.Uptime = s.UptimeS()
|
||||
report.NATType = s.connectionsService.NATType()
|
||||
report.AlwaysLocalNets = len(opts.AlwaysLocalNets) > 0
|
||||
report.CacheIgnoredFiles = opts.CacheIgnoredFiles
|
||||
report.OverwriteRemoteDeviceNames = opts.OverwriteRemoteDevNames
|
||||
report.ProgressEmitterEnabled = opts.ProgressUpdateIntervalS > -1
|
||||
report.CustomDefaultFolderPath = defaultFolder.Path != "~"
|
||||
|
||||
@@ -101,7 +101,6 @@
|
||||
<autoUpgradeIntervalH>12</autoUpgradeIntervalH>
|
||||
<upgradeToPreReleases>false</upgradeToPreReleases>
|
||||
<keepTemporariesH>24</keepTemporariesH>
|
||||
<cacheIgnoredFiles>false</cacheIgnoredFiles>
|
||||
<progressUpdateIntervalS>5</progressUpdateIntervalS>
|
||||
<limitBandwidthInLan>false</limitBandwidthInLan>
|
||||
<minHomeDiskFree unit="%">1</minHomeDiskFree>
|
||||
|
||||
@@ -99,7 +99,6 @@
|
||||
<autoUpgradeIntervalH>12</autoUpgradeIntervalH>
|
||||
<upgradeToPreReleases>false</upgradeToPreReleases>
|
||||
<keepTemporariesH>24</keepTemporariesH>
|
||||
<cacheIgnoredFiles>false</cacheIgnoredFiles>
|
||||
<progressUpdateIntervalS>5</progressUpdateIntervalS>
|
||||
<limitBandwidthInLan>true</limitBandwidthInLan>
|
||||
<minHomeDiskFree unit="%">1</minHomeDiskFree>
|
||||
|
||||
@@ -117,7 +117,6 @@
|
||||
<autoUpgradeIntervalH>12</autoUpgradeIntervalH>
|
||||
<upgradeToPreReleases>false</upgradeToPreReleases>
|
||||
<keepTemporariesH>24</keepTemporariesH>
|
||||
<cacheIgnoredFiles>false</cacheIgnoredFiles>
|
||||
<progressUpdateIntervalS>5</progressUpdateIntervalS>
|
||||
<limitBandwidthInLan>false</limitBandwidthInLan>
|
||||
<minHomeDiskFree unit="%">1</minHomeDiskFree>
|
||||
|
||||
@@ -69,7 +69,6 @@
|
||||
<autoUpgradeIntervalH>12</autoUpgradeIntervalH>
|
||||
<upgradeToPreReleases>false</upgradeToPreReleases>
|
||||
<keepTemporariesH>24</keepTemporariesH>
|
||||
<cacheIgnoredFiles>false</cacheIgnoredFiles>
|
||||
<progressUpdateIntervalS>5</progressUpdateIntervalS>
|
||||
<limitBandwidthInLan>false</limitBandwidthInLan>
|
||||
<minHomeDiskFree unit="%">1</minHomeDiskFree>
|
||||
|
||||
Reference in New Issue
Block a user