github.com/tilt-dev/tilt@v0.33.15-0.20240515162809-0a22ed45d8a0/internal/watch/notify.go (about) 1 package watch 2 3 import ( 4 "expvar" 5 "fmt" 6 "os" 7 "path/filepath" 8 "runtime" 9 "strconv" 10 "strings" 11 12 "github.com/tilt-dev/tilt/pkg/logger" 13 ) 14 15 var ( 16 numberOfWatches = expvar.NewInt("watch.naive.numberOfWatches") 17 ) 18 19 type FileEvent struct { 20 path string 21 } 22 23 func NewFileEvent(p string) FileEvent { 24 if !filepath.IsAbs(p) { 25 panic(fmt.Sprintf("NewFileEvent only accepts absolute paths. Actual: %s", p)) 26 } 27 return FileEvent{path: p} 28 } 29 30 func (e FileEvent) Path() string { 31 return e.path 32 } 33 34 type Notify interface { 35 // Start watching the paths set at init time 36 Start() error 37 38 // Stop watching and close all channels 39 Close() error 40 41 // A channel to read off incoming file changes 42 Events() chan FileEvent 43 44 // A channel to read off show-stopping errors 45 Errors() chan error 46 } 47 48 // When we specify directories to watch, we often want to 49 // ignore some subset of the files under those directories. 50 // 51 // For example: 52 // - Watch /src/repo, but ignore /src/repo/.git 53 // - Watch /src/repo, but ignore everything in /src/repo/bazel-bin except /src/repo/bazel-bin/app-binary 54 // 55 // The PathMatcher interface helps us manage these ignores. 56 type PathMatcher interface { 57 Matches(file string) (bool, error) 58 59 // If this matches the entire dir, we can often optimize filetree walks a bit. 60 MatchesEntireDir(file string) (bool, error) 61 } 62 63 type EmptyMatcher struct { 64 } 65 66 func (EmptyMatcher) Matches(f string) (bool, error) { return false, nil } 67 func (EmptyMatcher) MatchesEntireDir(f string) (bool, error) { return false, nil } 68 69 var _ PathMatcher = EmptyMatcher{} 70 71 func NewWatcher(paths []string, ignore PathMatcher, l logger.Logger) (Notify, error) { 72 return newWatcher(paths, ignore, l) 73 } 74 75 const WindowsBufferSizeEnvVar = "TILT_WATCH_WINDOWS_BUFFER_SIZE" 76 77 const defaultBufferSize int = 65536 78 79 func DesiredWindowsBufferSize() int { 80 envVar := os.Getenv(WindowsBufferSizeEnvVar) 81 if envVar != "" { 82 size, err := strconv.Atoi(envVar) 83 if err == nil { 84 return size 85 } 86 } 87 return defaultBufferSize 88 } 89 90 func IsWindowsShortReadError(err error) bool { 91 return runtime.GOOS == "windows" && err != nil && strings.Contains(err.Error(), "short read") 92 }