diff --git a/pkg/compose/watch.go b/pkg/compose/watch.go index f63c51683a..1e22c9479a 100644 --- a/pkg/compose/watch.go +++ b/pkg/compose/watch.go @@ -198,8 +198,9 @@ func (s *composeService) watch(ctx context.Context, project *types.Project, opti eg, ctx := errgroup.WithContext(ctx) var ( - rules []watchRule - paths []string + rules []watchRule + paths []string + ignoreMatchers []watch.PathMatcher ) for serviceName, service := range project.Services { config, err := loadDevelopmentConfig(service, project) @@ -254,6 +255,11 @@ func (s *composeService) watch(ctx context.Context, project *types.Project, opti } } } + ignore, err := watch.NewDockerPatternMatcher(trigger.Path, trigger.Ignore) + if err != nil { + return nil, err + } + ignoreMatchers = append(ignoreMatchers, ignore) paths = append(paths, trigger.Path) } @@ -268,7 +274,7 @@ func (s *composeService) watch(ctx context.Context, project *types.Project, opti return nil, fmt.Errorf("none of the selected services is configured for watch, consider setting a 'develop' section") } - watcher, err := watch.NewWatcher(paths) + watcher, err := watch.NewWatcher(paths, watch.NewCompositeMatcher(ignoreMatchers...)) if err != nil { return nil, err } diff --git a/pkg/watch/notify.go b/pkg/watch/notify.go index d63f5caf28..71dcaf1156 100644 --- a/pkg/watch/notify.go +++ b/pkg/watch/notify.go @@ -80,8 +80,8 @@ func (EmptyMatcher) MatchesEntireDir(f string) (bool, error) { return false, nil var _ PathMatcher = EmptyMatcher{} -func NewWatcher(paths []string) (Notify, error) { - return newWatcher(paths) +func NewWatcher(paths []string, ignore PathMatcher) (Notify, error) { + return newWatcher(paths, ignore) } const WindowsBufferSizeEnvVar = "COMPOSE_WATCH_WINDOWS_BUFFER_SIZE" diff --git a/pkg/watch/notify_test.go b/pkg/watch/notify_test.go index b1ec9b9644..0e9a7bc63b 100644 --- a/pkg/watch/notify_test.go +++ b/pkg/watch/notify_test.go @@ -526,7 +526,7 @@ func (f *notifyFixture) rebuildWatcher() { } // create a new watcher - notify, err := NewWatcher(f.paths) + notify, err := NewWatcher(f.paths, EmptyMatcher{}) if err != nil { f.T().Fatal(err) } diff --git a/pkg/watch/watcher_darwin.go b/pkg/watch/watcher_darwin.go index a63612aedf..9486b9af37 100644 --- a/pkg/watch/watcher_darwin.go +++ b/pkg/watch/watcher_darwin.go @@ -115,7 +115,7 @@ func (d *fseventNotify) Errors() chan error { return d.errors } -func newWatcher(paths []string) (Notify, error) { +func newWatcher(paths []string, _ PathMatcher) (Notify, error) { dw := &fseventNotify{ stream: &fsevents.EventStream{ Latency: 50 * time.Millisecond, diff --git a/pkg/watch/watcher_naive.go b/pkg/watch/watcher_naive.go index 7798025e8b..135e058ce3 100644 --- a/pkg/watch/watcher_naive.go +++ b/pkg/watch/watcher_naive.go @@ -45,6 +45,7 @@ type naiveNotify struct { // the notify list. It might be better to store this in a tree // structure, so we can filter the list quickly. notifyList map[string]bool + ignore PathMatcher isWatcherRecursive bool watcher *fsnotify.Watcher @@ -113,6 +114,10 @@ func (d *naiveNotify) watchRecursively(dir string) error { return filepath.WalkDir(dir, func(path string, info fs.DirEntry, err error) error { if err != nil { + if os.IsPermission(err) && d.shouldIgnore(path) { + logrus.Debugf("Ignoring path: %s", path) + return nil + } return err } @@ -240,6 +245,11 @@ func (d *naiveNotify) shouldSkipDir(path string) bool { return false } + // If path is present in the ignore list then we should ignore it + if d.shouldIgnore(path) { + return true + } + // Suppose we're watching // /src/.tiltignore // but the .tiltignore file doesn't exist. @@ -260,6 +270,26 @@ func (d *naiveNotify) shouldSkipDir(path string) bool { return true } +func (d *naiveNotify) shouldIgnore(path string) bool { + if d.ignore == nil { + return false + } + matches, err := d.ignore.MatchesEntireDir(path) + if err != nil { + logrus.Debugf("error checking ignored directory %q: %v", path, err) + return false + } + if matches { + return true + } + matches, err = d.ignore.Matches(path) + if err != nil { + logrus.Debugf("error checking ignored path %q: %v", path, err) + return false + } + return matches +} + func (d *naiveNotify) add(path string) error { err := d.watcher.Add(path) if err != nil { @@ -270,7 +300,7 @@ func (d *naiveNotify) add(path string) error { return nil } -func newWatcher(paths []string) (Notify, error) { +func newWatcher(paths []string, ignore PathMatcher) (Notify, error) { fsw, err := fsnotify.NewWatcher() if err != nil { if strings.Contains(err.Error(), "too many open files") && runtime.GOOS == "linux" { @@ -297,9 +327,9 @@ func newWatcher(paths []string) (Notify, error) { } notifyList[path] = true } - wmw := &naiveNotify{ notifyList: notifyList, + ignore: ignore, watcher: fsw, events: fsw.Events, wrappedEvents: wrappedEvents,