all repos — erl @ c8ab7c849959313a035bf9e448d110e794190a4f

Execute Reload Loop

initial commit

Alan Pearce
commit

c8ab7c849959313a035bf9e448d110e794190a4f

1 file changed, 109 insertions(+), 0 deletions(-)

changed files
A watcher/watcher.go
@@ -0,0 +1,109 @@
+package watcher + +import ( + "fmt" + "io/fs" + "os" + "path/filepath" + "slices" + + "github.com/fsnotify/fsnotify" +) + +type Event fsnotify.Event + +type Watcher interface { + AddRecursive(pathname string) error + Monitor() (<-chan Event, <-chan error) + WatchList() []string + Remove(pathname string) error + Close() error +} + +// FSWatcher implements the Watcher interface using fsnotify. +type FSWatcher struct { + watcher fsnotify.Watcher +} + +var IgnoredDirs = []string{ + ".git", +} + +func New() (*FSWatcher, error) { + watcher, err := fsnotify.NewWatcher() + if err != nil { + return nil, fmt.Errorf("failed to create watcher: %v", err) + } + + return &FSWatcher{ + watcher: *watcher, + }, nil +} + +func (w *FSWatcher) AddRecursive(pathname string) error { + stat, err := os.Stat(pathname) + if err != nil { + return fmt.Errorf("failed to stat %s: %v", pathname, err) + } + if !stat.IsDir() { + pathname = filepath.Dir(pathname) + } + + return w.addDirRecursive(pathname) +} + +func (w *FSWatcher) Remove(pathname string) error { + return w.watcher.Remove(pathname) +} + +func (w *FSWatcher) Monitor() (<-chan Event, <-chan error) { + events := make(chan Event, 1) + errors := make(chan error, 1) + + go func() { + for { + select { + case event := <-w.watcher.Events: + events <- Event(event) + case err := <-w.watcher.Errors: + errors <- err + } + } + }() + + return events, errors +} + +func (w *FSWatcher) WatchList() []string { + return w.watcher.WatchList() +} + +func (w *FSWatcher) Close() error { + return w.watcher.Close() +} + +func (w *FSWatcher) addDirRecursive(dir string) error { + err := filepath.Walk(dir, func(path string, entry fs.FileInfo, err error) error { + if err != nil { + return err + } + + if entry.IsDir() { + if slices.Contains(IgnoredDirs, entry.Name()) { + return fs.SkipDir + } + + err = w.watcher.Add(path) + if err != nil { + return fmt.Errorf("failed to add directory to watcher: %v", err) + } + } + + return nil + }) + if err != nil { + return fmt.Errorf("failed to walk directory: %v", err) + } + + return nil +}