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  }