github.com/ActiveState/cli@v0.0.0-20240508170324-6801f60cd051/internal/fileevents/watcher/watcher.go (about) 1 package watcher 2 3 import ( 4 "github.com/fsnotify/fsnotify" 5 6 "github.com/ActiveState/cli/internal/errs" 7 "github.com/ActiveState/cli/internal/fileutils" 8 "github.com/ActiveState/cli/internal/locale" 9 "github.com/ActiveState/cli/internal/logging" 10 "github.com/ActiveState/cli/internal/multilog" 11 ) 12 13 type Closer func() 14 15 type OnEvent func(filepath string, log logging.Logger) error 16 17 func logInfo(msg string, args ...interface{}) { 18 logging.Info("File-Event: "+msg, args...) 19 } 20 21 func logError(msg string, args ...interface{}) { 22 multilog.Error("File-Event: "+msg, args...) 23 } 24 25 type Watcher struct { 26 fswatcher *fsnotify.Watcher 27 done chan bool 28 onEvent *OnEvent 29 } 30 31 func New() (*Watcher, error) { 32 w := &Watcher{} 33 var err error 34 w.fswatcher, err = fsnotify.NewWatcher() 35 if err != nil { 36 return nil, errs.Wrap(err, "Could not create filesystem watcher") 37 } 38 39 w.done = make(chan bool) 40 go func() { 41 for { 42 select { 43 case <-w.done: 44 return 45 case event, ok := <-w.fswatcher.Events: 46 if !ok || w.onEvent == nil { 47 continue 48 } 49 50 if event.Op&fsnotify.Write != fsnotify.Write { 51 logging.Debug(event.String() + ": Skip") 52 continue 53 } 54 55 logInfo(event.String()) 56 57 if err := (*w.onEvent)(event.Name, logInfo); err != nil { 58 logError(errs.JoinMessage(err)) 59 continue 60 } 61 case err, ok := <-w.fswatcher.Errors: 62 if !ok { 63 return 64 } 65 logError(err.Error()) 66 } 67 } 68 }() 69 70 return w, nil 71 } 72 73 func (w *Watcher) Add(filepath string) error { 74 logInfo(locale.Tl("fileevent_watchig", "Watching {{.V0}}", filepath)) 75 if !fileutils.TargetExists(filepath) { 76 return locale.NewInputError("err_fileevent_filenotexist", "Path does not exist: {{.V0}}.", filepath) 77 } 78 if err := w.fswatcher.Add(filepath); err != nil { 79 return locale.WrapExternalError(err, "err_fileevent_invalidpath", "Could not add filepath to filesystem watcher: {{.V0}}", filepath) 80 } 81 return nil 82 } 83 84 func (w *Watcher) OnEvent(cb OnEvent) error { 85 if w.onEvent != nil { 86 return errs.New("Already listening to events") 87 } 88 w.onEvent = &cb 89 return nil 90 } 91 92 func (w *Watcher) Close() { 93 logging.Debug("Closing watcher") 94 w.fswatcher.Close() 95 close(w.done) 96 logging.Debug("Watcher closed") 97 }