diff --git a/pkg/watch/notify.go b/pkg/watch/notify.go index cf67cb28..86b66c32 100644 --- a/pkg/watch/notify.go +++ b/pkg/watch/notify.go @@ -3,7 +3,11 @@ package watch import ( "expvar" "fmt" + "os" "path/filepath" + "runtime" + "strconv" + "strings" "github.com/tilt-dev/tilt/pkg/logger" ) @@ -67,3 +71,22 @@ var _ PathMatcher = EmptyMatcher{} func NewWatcher(paths []string, ignore PathMatcher, l logger.Logger) (Notify, error) { return newWatcher(paths, ignore, l) } + +const WindowsBufferSizeEnvVar = "TILT_WATCH_WINDOWS_BUFFER_SIZE" + +const defaultBufferSize int = 65536 + +func DesiredWindowsBufferSize() int { + envVar := os.Getenv(WindowsBufferSizeEnvVar) + if envVar != "" { + size, err := strconv.Atoi(envVar) + if err != nil { + return size + } + } + return defaultBufferSize +} + +func IsWindowsShortReadError(err error) bool { + return runtime.GOOS == "windows" && err != nil && strings.Contains(err.Error(), "short read") +} diff --git a/pkg/watch/watcher_naive.go b/pkg/watch/watcher_naive.go index 3993738d..2874fd45 100644 --- a/pkg/watch/watcher_naive.go +++ b/pkg/watch/watcher_naive.go @@ -136,6 +136,12 @@ func (d *naiveNotify) Errors() chan error { func (d *naiveNotify) loop() { defer close(d.wrappedEvents) for e := range d.events { + // The Windows fsnotify event stream sometimes gets events with empty names + // that are also sent to the error stream. Hmmmm... + if e.Name == "" { + continue + } + if e.Op&fsnotify.Create != fsnotify.Create { if d.shouldNotify(e.Name) { d.wrappedEvents <- FileEvent{e.Name} @@ -251,6 +257,7 @@ func newWatcher(paths []string, ignore PathMatcher, l logger.Logger) (*naiveNoti if err != nil { return nil, err } + MaybeIncreaseBufferSize(fsw) err = fsw.SetRecursive() isWatcherRecursive := err == nil diff --git a/pkg/watch/watcher_nonwin.go b/pkg/watch/watcher_nonwin.go new file mode 100644 index 00000000..a8d9da41 --- /dev/null +++ b/pkg/watch/watcher_nonwin.go @@ -0,0 +1,9 @@ +// +build !windows + +package watch + +import "github.com/tilt-dev/fsnotify" + +func MaybeIncreaseBufferSize(w *fsnotify.Watcher) { + // Not needed on non-windows +} diff --git a/pkg/watch/watcher_windows.go b/pkg/watch/watcher_windows.go new file mode 100644 index 00000000..38538b66 --- /dev/null +++ b/pkg/watch/watcher_windows.go @@ -0,0 +1,19 @@ +// +build windows + +package watch + +import ( + "github.com/tilt-dev/fsnotify" +) + +// TODO(nick): I think the ideal API would be to automatically increase the +// size of the buffer when we exceed capacity. But this gets messy, +// because each time we get a short read error, we need to invalidate +// everything we know about the currently changed files. So for now, +// we just provide a way for people to increase the buffer ourselves. +// +// It might also pay to be clever about sizing the buffer +// relative the number of files in the directory we're watching. +func MaybeIncreaseBufferSize(w *fsnotify.Watcher) { + w.SetBufferSize(DesiredWindowsBufferSize()) +}