Files
zqdgr/watcher.go
2024-11-16 04:17:27 -06:00

141 lines
2.9 KiB
Go

// There is some dead code in here because I pulled out the parts I needed to get it working, deal with this later lol.
package main
import (
"errors"
"fmt"
"log"
"os"
"path/filepath"
"syscall"
"github.com/bmatcuk/doublestar"
"github.com/fsnotify/fsnotify"
)
type globList []string
func (g *globList) Matches(value string) bool {
for _, v := range *g {
if match, err := filepath.Match(v, value); err != nil {
log.Fatalf("Bad pattern \"%s\": %s", v, err.Error())
} else if match {
return true
}
}
return false
}
func matchesPattern(pattern []string, path string) bool {
for _, p := range pattern {
if matched, _ := doublestar.Match(p, path); matched {
return true
}
}
return false
}
func directoryShouldBeTracked(cfg *WatcherConfig, path string) bool {
base := filepath.Dir(path)
return matchesPattern(cfg.pattern, path) && !cfg.excludedDirs.Matches(base)
}
func pathMatches(cfg *WatcherConfig, path string) bool {
return matchesPattern(cfg.pattern, path)
}
type WatcherConfig struct {
excludedDirs globList
pattern globList
}
type FileWatcher interface {
Close() error
AddFiles() error
add(path string) error
Watch(jobs chan<- string)
getConfig() *WatcherConfig
}
type NotifyWatcher struct {
watcher *fsnotify.Watcher
cfg *WatcherConfig
}
func (n NotifyWatcher) Close() error {
return n.watcher.Close()
}
func (n NotifyWatcher) AddFiles() error {
return addFiles(n)
}
func (n NotifyWatcher) Watch(jobs chan<- string) {
for {
select {
case ev := <-n.watcher.Events:
if ev.Op&fsnotify.Remove == fsnotify.Remove || ev.Op&fsnotify.Write == fsnotify.Write || ev.Op&fsnotify.Create == fsnotify.Create {
// Assume it is a directory and track it.
if directoryShouldBeTracked(n.cfg, ev.Name) {
n.watcher.Add(ev.Name)
}
if pathMatches(n.cfg, ev.Name) {
jobs <- ev.Name
}
}
case err := <-n.watcher.Errors:
if v, ok := err.(*os.SyscallError); ok {
if v.Err == syscall.EINTR {
continue
}
log.Fatal("watcher.Error: SyscallError:", v)
}
log.Fatal("watcher.Error:", err)
}
}
}
func (n NotifyWatcher) add(path string) error {
return n.watcher.Add(path)
}
func (n NotifyWatcher) getConfig() *WatcherConfig {
return n.cfg
}
func NewWatcher(cfg *WatcherConfig) (FileWatcher, error) {
if cfg == nil {
err := errors.New("no config specified")
return nil, err
}
w, err := fsnotify.NewWatcher()
if err != nil {
return nil, err
}
return NotifyWatcher{
watcher: w,
cfg: cfg,
}, nil
}
func addFiles(fw FileWatcher) error {
cfg := fw.getConfig()
for _, pattern := range cfg.pattern {
matches, err := doublestar.Glob(pattern)
if err != nil {
log.Fatalf("Bad pattern \"%s\": %s", pattern, err.Error())
}
for _, match := range matches {
if directoryShouldBeTracked(cfg, match) {
if err := fw.add(match); err != nil {
return fmt.Errorf("FileWatcher.Add(): %v", err)
}
}
}
}
return nil
}