From d744c97f13d6971839911e720e8f89ad9ee1022f Mon Sep 17 00:00:00 2001 From: Nick Santos Date: Tue, 16 Jul 2019 16:12:08 -0400 Subject: [PATCH] watch: add a simple check when there are no exclusions (#1863) --- pkg/watch/notify_test.go | 27 +++++++++++++++++++++-- pkg/watch/watcher_naive.go | 45 +++++++++++++++++++++++++++++++++++++- 2 files changed, 69 insertions(+), 3 deletions(-) diff --git a/pkg/watch/notify_test.go b/pkg/watch/notify_test.go index 432247b7e..7754b14f6 100644 --- a/pkg/watch/notify_test.go +++ b/pkg/watch/notify_test.go @@ -488,7 +488,7 @@ func TestWatchCountInnerFileWithIgnore(t *testing.T) { assert.Equal(t, expectedWatches, int(numberOfWatches.Value())) } -func TestIgnore(t *testing.T) { +func TestIgnoreCreatedDir(t *testing.T) { f := newNotifyFixture(t) defer f.tearDown() @@ -502,13 +502,36 @@ func TestIgnore(t *testing.T) { f.WriteFile(file, "hello") f.assertEvents(a) - expectedWatches := 3 + expectedWatches := 2 if runtime.GOOS == "darwin" { expectedWatches = 1 } assert.Equal(t, expectedWatches, int(numberOfWatches.Value())) } +func TestIgnoreInitialDir(t *testing.T) { + f := newNotifyFixture(t) + defer f.tearDown() + + root := f.TempDir("root") + ignore, _ := dockerignore.NewDockerPatternMatcher(root, []string{"a/b"}) + f.setIgnore(ignore) + + a := f.JoinPath(root, "a") + b := f.JoinPath(a, "b") + file := f.JoinPath(b, "bigFile") + f.WriteFile(file, "hello") + f.watch(root) + + f.assertEvents() + + expectedWatches := 3 + if runtime.GOOS == "darwin" { + expectedWatches = 2 + } + assert.Equal(t, expectedWatches, int(numberOfWatches.Value())) +} + type notifyFixture struct { out *bytes.Buffer *tempdir.TempDirFixture diff --git a/pkg/watch/watcher_naive.go b/pkg/watch/watcher_naive.go index 569b68080..a3b468f1f 100644 --- a/pkg/watch/watcher_naive.go +++ b/pkg/watch/watcher_naive.go @@ -78,6 +78,16 @@ func (d *naiveNotify) watchRecursively(dir string) error { if !mode.IsDir() { return nil } + + shouldSkipDir, err := d.shouldSkipDir(path) + if err != nil { + return err + } + + if shouldSkipDir { + return filepath.SkipDir + } + err = d.add(path) if err != nil { if os.IsNotExist(err) { @@ -145,7 +155,15 @@ func (d *naiveNotify) loop() { shouldWatch := false if mode.IsDir() { - // watch all directories + // watch directories unless we can skip them entirely + shouldSkipDir, err := d.shouldSkipDir(path) + if err != nil { + return err + } + if shouldSkipDir { + return filepath.SkipDir + } + shouldWatch = true } else { // watch files that are explicitly named, but don't watch others @@ -188,6 +206,31 @@ func (d *naiveNotify) shouldNotify(path string) bool { return false } +func (d *naiveNotify) shouldSkipDir(path string) (bool, error) { + var err error + ignore := false + + // If path is directly in the notifyList, we should always watch it. + if !d.notifyList[path] { + ignore, err = d.ignore.Matches(path) + if err != nil { + return false, errors.Wrapf(err, "Error matching %s: %v", path, err) + } + } + + // The ignore filter is telling us to ignore this file, + // but we may have to watch it anyway to catch files underneath it. + if ignore { + if !d.ignore.Exclusions() { + return true, nil + } + + // TODO(nick): Add more complex logic for interpreting exclusion patterns. + } + + return false, nil +} + func (d *naiveNotify) add(path string) error { err := d.watcher.Add(path) if err != nil {