From 9429b3dfc91325b9bf0c6aca9554c6f1553ef088 Mon Sep 17 00:00:00 2001 From: nxtcoder17 Date: Thu, 12 Dec 2024 12:38:46 +0530 Subject: [PATCH] feat: multiple-watch directory support --- main.go | 28 ++++++---------- pkg/watcher/watcher.go | 76 ++++++++++++++++++++++++++++++------------ 2 files changed, 64 insertions(+), 40 deletions(-) diff --git a/main.go b/main.go index ad9ec21..69d9ce6 100644 --- a/main.go +++ b/main.go @@ -44,18 +44,11 @@ func main() { EnvVars: []string{}, TakesFile: false, }, - &cli.PathFlag{ + &cli.StringSliceFlag{ Name: "dir", Usage: "directory to watch on", Required: false, - Value: func() string { - cwd, err := os.Getwd() - if err != nil { - panic(err) - } - return cwd - }(), - Aliases: []string{"d"}, + Aliases: []string{"d"}, }, &cli.StringSliceFlag{ Name: "ignore-suffixes", @@ -64,7 +57,7 @@ func main() { Aliases: []string{"i"}, }, &cli.StringSliceFlag{ - Name: "only-watch-suffixes", + Name: "only-suffixes", Usage: "files suffixes to watch", Required: false, Aliases: []string{"w"}, @@ -73,7 +66,7 @@ func main() { Name: "exclude-dir", Usage: "directory to exclude from watching", Required: false, - Aliases: []string{"x", "e"}, + Aliases: []string{"x"}, }, &cli.BoolFlag{ Name: "no-default-ignore", @@ -134,8 +127,10 @@ func main() { }) watcher, err := fswatcher.NewWatcher(fswatcher.WatcherArgs{ - Logger: logger, - OnlyWatchSuffixes: cctx.StringSlice("only-watch-suffixes"), + Logger: logger, + + WatchDirs: cctx.StringSlice("dir"), + OnlySuffixes: cctx.StringSlice("only-suffixes"), IgnoreSuffixes: cctx.StringSlice("ignore-suffixes"), ExcludeDirs: cctx.StringSlice("exclude-dir"), UseDefaultIgnoreList: !cctx.Bool("no-global-ignore"), @@ -144,10 +139,6 @@ func main() { panic(err) } - if err := watcher.RecursiveAdd(cctx.String("dir")); err != nil { - panic(err) - } - go ex.Exec() go func() { @@ -157,8 +148,9 @@ func main() { os.Exit(0) }() + pwd, _ := os.Getwd() watcher.WatchEvents(func(event fswatcher.Event, fp string) error { - relPath, err := filepath.Rel(cctx.String("dir"), fp) + relPath, err := filepath.Rel(pwd, fp) if err != nil { return err } diff --git a/pkg/watcher/watcher.go b/pkg/watcher/watcher.go index 0da473b..9d468c2 100644 --- a/pkg/watcher/watcher.go +++ b/pkg/watcher/watcher.go @@ -24,15 +24,17 @@ type eventInfo struct { } type fsnWatcher struct { - watcher *fsnotify.Watcher - eventMap map[string]eventInfo + watcher *fsnotify.Watcher directoryCount int - Logger *slog.Logger - OnlyWatchSuffixes []string - IgnoreSuffixes []string - ExcludeDirs map[string]struct{} + Logger *slog.Logger + OnlySuffixes []string + IgnoreSuffixes []string + ExcludeDirs map[string]struct{} + watchingDirs map[string]struct{} + + cooldownDuration time.Duration } type Event fsnotify.Event @@ -71,13 +73,13 @@ func (f fsnWatcher) ignoreEvent(event fsnotify.Event) (ignore bool, reason strin } } - if len(f.OnlyWatchSuffixes) == 0 { + if len(f.OnlySuffixes) == 0 { return false, "event not in ignore list, and only-watch list is also empty" } matched := false - for _, suffix := range f.OnlyWatchSuffixes { - f.Logger.Debug("[only-watch-suffix] suffix: (%s), event.name: %s", suffix, event.Name) + for _, suffix := range f.OnlySuffixes { + f.Logger.Debug(fmt.Sprintf("[only-suffix] suffix: (%s), event.name: %s", suffix, event.Name)) if strings.HasSuffix(event.Name, suffix) { matched = true break @@ -123,8 +125,8 @@ func (f *fsnWatcher) WatchEvents(watcherFunc func(event Event, fp string) error) // eInfo.Counter += 1 // f.eventMap[event.Name] = eInfo - if time.Since(lastProcessingTime) < 100*time.Millisecond { - // f.Logger.Debug("too many events under 100ms, ignoring...", "counter", eInfo.Counter) + if time.Since(lastProcessingTime) < f.cooldownDuration { + f.Logger.Debug(fmt.Sprintf("too many events under %s, ignoring...", f.cooldownDuration.String()), "event.name", event.Name) continue } @@ -185,6 +187,11 @@ func (f *fsnWatcher) RecursiveAdd(dirs ...string) error { } func (f *fsnWatcher) addToWatchList(dir string) error { + if _, ok := f.watchingDirs[dir]; ok { + return nil + } + + f.watchingDirs[dir] = struct{}{} if err := f.watcher.Add(dir); err != nil { f.Logger.Error("failed to add directory", "dir", dir, "err", err) return err @@ -199,11 +206,16 @@ func (f *fsnWatcher) Close() error { } type WatcherArgs struct { - Logger *slog.Logger - OnlyWatchSuffixes []string - IgnoreSuffixes []string - ExcludeDirs []string + Logger *slog.Logger + + WatchDirs []string + OnlySuffixes []string + IgnoreSuffixes []string + ExcludeDirs []string + UseDefaultIgnoreList bool + + CooldownDuration *time.Duration } func NewWatcher(args WatcherArgs) (Watcher, error) { @@ -215,6 +227,12 @@ func NewWatcher(args WatcherArgs) (Watcher, error) { args.ExcludeDirs = append(args.ExcludeDirs, globalExcludeDirs...) } + cooldown := 500 * time.Millisecond + + if args.CooldownDuration != nil { + cooldown = *args.CooldownDuration + } + excludeDirs := map[string]struct{}{} for _, dir := range args.ExcludeDirs { excludeDirs[dir] = struct{}{} @@ -225,11 +243,25 @@ func NewWatcher(args WatcherArgs) (Watcher, error) { args.Logger.Error("failed to create watcher, got", "err", err) return nil, err } - return &fsnWatcher{ - watcher: watcher, - Logger: args.Logger, - ExcludeDirs: excludeDirs, - IgnoreSuffixes: args.IgnoreSuffixes, - OnlyWatchSuffixes: args.OnlyWatchSuffixes, - }, nil + + if args.WatchDirs == nil { + dir, _ := os.Getwd() + args.WatchDirs = append(args.WatchDirs, dir) + } + + fsw := &fsnWatcher{ + watcher: watcher, + Logger: args.Logger, + ExcludeDirs: excludeDirs, + IgnoreSuffixes: args.IgnoreSuffixes, + OnlySuffixes: args.OnlySuffixes, + cooldownDuration: cooldown, + watchingDirs: make(map[string]struct{}), + } + + if err := fsw.RecursiveAdd(args.WatchDirs...); err != nil { + return nil, err + } + + return fsw, nil }