diff options
Diffstat (limited to 'cli/internal/filewatcher/filewatcher.go')
| -rw-r--r-- | cli/internal/filewatcher/filewatcher.go | 167 |
1 files changed, 0 insertions, 167 deletions
diff --git a/cli/internal/filewatcher/filewatcher.go b/cli/internal/filewatcher/filewatcher.go deleted file mode 100644 index 4f79495..0000000 --- a/cli/internal/filewatcher/filewatcher.go +++ /dev/null @@ -1,167 +0,0 @@ -// Package filewatcher is used to handle watching for file changes inside the monorepo -package filewatcher - -import ( - "path/filepath" - "strings" - "sync" - - "github.com/hashicorp/go-hclog" - "github.com/pkg/errors" - "github.com/vercel/turbo/cli/internal/turbopath" -) - -// _ignores is the set of paths we exempt from file-watching -var _ignores = []string{".git", "node_modules"} - -// FileWatchClient defines the callbacks used by the file watching loop. -// All methods are called from the same goroutine so they: -// 1) do not need synchronization -// 2) should minimize the work they are doing when called, if possible -type FileWatchClient interface { - OnFileWatchEvent(ev Event) - OnFileWatchError(err error) - OnFileWatchClosed() -} - -// FileEvent is an enum covering the kinds of things that can happen -// to files that we might be interested in -type FileEvent int - -const ( - // FileAdded - this is a new file - FileAdded FileEvent = iota + 1 - // FileDeleted - this file has been removed - FileDeleted - // FileModified - this file has been changed in some way - FileModified - // FileRenamed - a file's name has changed - FileRenamed - // FileOther - some other backend-specific event has happened - FileOther -) - -var ( - // ErrFilewatchingClosed is returned when filewatching has been closed - ErrFilewatchingClosed = errors.New("Close() has already been called for filewatching") - // ErrFailedToStart is returned when filewatching fails to start up - ErrFailedToStart = errors.New("filewatching failed to start") -) - -// Event is the backend-independent information about a file change -type Event struct { - Path turbopath.AbsoluteSystemPath - EventType FileEvent -} - -// Backend is the interface that describes what an underlying filesystem watching backend -// must provide. -type Backend interface { - AddRoot(root turbopath.AbsoluteSystemPath, excludePatterns ...string) error - Events() <-chan Event - Errors() <-chan error - Close() error - Start() error -} - -// FileWatcher handles watching all of the files in the monorepo. -// We currently ignore .git and top-level node_modules. We can revisit -// if necessary. -type FileWatcher struct { - backend Backend - - logger hclog.Logger - repoRoot turbopath.AbsoluteSystemPath - excludePattern string - - clientsMu sync.RWMutex - clients []FileWatchClient - closed bool -} - -// New returns a new FileWatcher instance -func New(logger hclog.Logger, repoRoot turbopath.AbsoluteSystemPath, backend Backend) *FileWatcher { - excludes := make([]string, len(_ignores)) - for i, ignore := range _ignores { - excludes[i] = filepath.ToSlash(repoRoot.UntypedJoin(ignore).ToString() + "/**") - } - excludePattern := "{" + strings.Join(excludes, ",") + "}" - return &FileWatcher{ - backend: backend, - logger: logger, - repoRoot: repoRoot, - excludePattern: excludePattern, - } -} - -// Close shuts down filewatching -func (fw *FileWatcher) Close() error { - return fw.backend.Close() -} - -// Start recursively adds all directories from the repo root, redacts the excluded ones, -// then fires off a goroutine to respond to filesystem events -func (fw *FileWatcher) Start() error { - if err := fw.backend.AddRoot(fw.repoRoot, fw.excludePattern); err != nil { - return err - } - if err := fw.backend.Start(); err != nil { - return err - } - go fw.watch() - return nil -} - -// AddRoot registers the root a filesystem hierarchy to be watched for changes. Events are *not* -// fired for existing files when AddRoot is called, only for subsequent changes. -// NOTE: if it appears helpful, we could change this behavior so that we provide a stream of initial -// events. -func (fw *FileWatcher) AddRoot(root turbopath.AbsoluteSystemPath, excludePatterns ...string) error { - return fw.backend.AddRoot(root, excludePatterns...) -} - -// watch is the main file-watching loop. Watching is not recursive, -// so when new directories are added, they are manually recursively watched. -func (fw *FileWatcher) watch() { -outer: - for { - select { - case ev, ok := <-fw.backend.Events(): - if !ok { - fw.logger.Info("Events channel closed. Exiting watch loop") - break outer - } - fw.clientsMu.RLock() - for _, client := range fw.clients { - client.OnFileWatchEvent(ev) - } - fw.clientsMu.RUnlock() - case err, ok := <-fw.backend.Errors(): - if !ok { - fw.logger.Info("Errors channel closed. Exiting watch loop") - break outer - } - fw.clientsMu.RLock() - for _, client := range fw.clients { - client.OnFileWatchError(err) - } - fw.clientsMu.RUnlock() - } - } - fw.clientsMu.Lock() - fw.closed = true - for _, client := range fw.clients { - client.OnFileWatchClosed() - } - fw.clientsMu.Unlock() -} - -// AddClient registers a client for filesystem events -func (fw *FileWatcher) AddClient(client FileWatchClient) { - fw.clientsMu.Lock() - defer fw.clientsMu.Unlock() - fw.clients = append(fw.clients, client) - if fw.closed { - client.OnFileWatchClosed() - } -} |
