diff --git a/dedup.go b/dedup.go deleted file mode 100644 index b53b8ff18c2d1f70cca24e98544d2f8d771099bb..0000000000000000000000000000000000000000 --- a/dedup.go +++ /dev/null @@ -1,90 +0,0 @@ -package watch - -// -//// dedup is a function that watches a set of paths and prints a message when -//func (w *Watch) Decouple(waitFor time.Duration) { -// if waitFor == 0 { -// waitFor = 100 * time.Millisecond -// } -// go decoupleLoop(w.watcher, waitFor) -// <-make(chan struct{}) // Block forever -//} -// -//// dedupLoop is the main loop for dedup. -//func decoupleLoop(w *fsnotify.Watcher, waitFor time.Duration) { -// var ( -// mu sync.Mutex -// timers = make(map[string]*time.Timer) -// -// printEvent = func(e fsnotify.Event) { -// fmt.Printf("%s: %s\n", e.Op, e.Name) -// -// // Don't need to remove the timer if you don't have a lot of files. -// mu.Lock() -// delete(timers, e.Name) -// mu.Unlock() -// } -// ) -// -// for { -// select { -// // Read from Errors. -// case err, ok := <-w.Errors: -// if !ok { // Channel was closed (i.e. Watcher.Close() was called). -// return -// } -// fmt.Println("error:", err) -// // Read from Events. -// case e, ok := <-w.Events: -// if !ok { // Channel was closed (i.e. Watcher.Close() was called). -// return -// } -// -// if e.Op&fsnotify.Chmod == fsnotify.Chmod { -// //util.Remove(fullPath) -// } -// -// if e.Op&fsnotify.Write == fsnotify.Write { -// //util.Remove(fullPath) -// } -// -// if e.Op&fsnotify.Create == fsnotify.Create { -// //logging.LogInfo("watching: created file: %s", d) -// //scanDirectory(fullPath, "") -// //navigation.AddFile(fullPath) -// } -// -// if e.Op&fsnotify.Remove == fsnotify.Remove { -// //logging.LogInfo("watching: removed file: %s", d) -// //removeFromWatchlist(fullPath) -// //util.Remove(fullPath) -// //navigation.RemoveFile(fullPath) -// } -// -// if e.Op&fsnotify.Rename == fsnotify.Rename { -// //logging.LogInfo("watching: renamed file: %s", event.Name) -// //removeFromWatchlist(fullPath) -// //util.Remove(fullPath) -// //navigation.RemoveFile(fullPath) -// } -// -// // Get timer. -// mu.Lock() -// t, ok := timers[e.Name] -// mu.Unlock() -// -// // No timer yet, so create one. -// if !ok { -// t = time.AfterFunc(math.MaxInt64, func() { printEvent(e) }) -// t.Stop() -// -// mu.Lock() -// timers[e.Name] = t -// mu.Unlock() -// } -// -// // Reset the timer for this path, so it will start from 100ms again. -// t.Reset(waitFor) -// } -// } -//} diff --git a/lighthouse.go b/lighthouse.go index 723cbea3ae3cc80cd949fd0510df1bc78e81150f..a2b503c64c27a5b34fc733b1f3525a64abe83dc1 100644 --- a/lighthouse.go +++ b/lighthouse.go @@ -15,6 +15,7 @@ type Watch struct { OnChange EventCallback OnDelete EventCallback OnRename EventCallback + Tags []string } type EventErrorCallback func(err error) @@ -64,6 +65,10 @@ type Lighthouse interface { Sync() error IsInSync() bool + + WatchListByTags(tags []string) []string + + RemoveByTags(tags []string) error } // NewLighthouse creates a new lighthouse instance. @@ -121,6 +126,33 @@ func (l *lighthouse) WatchList() []string { } +// WatchListByTags returns a list of all watched paths with the given tags. +func (l *lighthouse) WatchListByTags(tags []string) []string { + + if len(tags) == 0 { + return l.WatchList() + } + + l.mutex.Lock() + defer l.mutex.Unlock() + var list []string + for k := range l.watchers { + + if len(l.watchers[k].Tags) == 0 { + continue + } + + for _, tag := range tags { + if tag == k { + list = append(list, k) + break + } + } + } + return list + +} + // IsInSync returns true if all paths are watched by fsnotify. func (l *lighthouse) IsInSync() bool { l.mutex.Lock() @@ -238,6 +270,46 @@ func (l *lighthouse) Add(watch *Watch) error { return nil } +func (l *lighthouse) RemoveByTags(tags []string) error { + + if len(tags) == 0 { + return nil + } + + l.mutex.Lock() + defer l.mutex.Unlock() + + var errReturn error + + for _, tag := range tags { + + for k := range l.watchers { + + if len(l.watchers[k].Tags) == 0 { + continue + } + + for _, t := range l.watchers[k].Tags { + if t == tag { + err := l.fsnotify.Remove(k) + if err != nil { + if errReturn == nil { + errReturn = err + } else { + errReturn = fmt.Errorf("%w, %v", errReturn, err) + } + } + delete(l.watchers, k) + break + } + } + } + } + + return errReturn + +} + // Remove removes a path from the watcher. If the path is not being watched or // the watcher is not active, an error is returned. func (l *lighthouse) Remove(path string) error { @@ -254,9 +326,9 @@ func (l *lighthouse) Remove(path string) error { return UnwatchedPathError{UnwatchedPath: path} } + err := l.fsnotify.Remove(path) delete(l.watchers, path) - err := l.fsnotify.Remove(path) if err != nil { return err } diff --git a/lighthouse_test.go b/lighthouse_test.go index f9118fd3938bc6a5d12995ae88dfaa0fda8dcc05..a62edbcc86f57a549de046782051fefd8bf3a6a9 100644 --- a/lighthouse_test.go +++ b/lighthouse_test.go @@ -2,12 +2,62 @@ package watch import ( "errors" + "github.com/stretchr/testify/assert" "os" "testing" - - "github.com/stretchr/testify/assert" + "time" ) +func TestRemoveByTagsAndWatchListByTags(t *testing.T) { + l := NewLighthouse() + l.SetDebounce(500 * time.Millisecond) + + tmpDir1 := t.TempDir() + tmpDir2 := t.TempDir() + tmpDir3 := t.TempDir() + + // Add a few watches + err := l.Add(&Watch{Path: tmpDir1, Tags: []string{"tag1", "tag2"}}) + if err != nil { + t.Errorf("Failed to add watch: %v", err) + } + + err = l.Add(&Watch{Path: tmpDir2, Tags: []string{"tag1"}}) + if err != nil { + t.Errorf("Failed to add watch: %v", err) + } + + err = l.Add(&Watch{Path: tmpDir3, Tags: []string{"tag2"}}) + if err != nil { + t.Errorf("Failed to add watch: %v", err) + } + + // Test WatchListByTags + list := l.WatchListByTags([]string{"tag1"}) + expectedList := []string{tmpDir1, tmpDir2} + for i, path := range list { + if path != expectedList[i] { + t.Errorf("Expected %s, got %s", expectedList[i], path) + } + } + + // Test RemoveByTags + err = l.RemoveByTags([]string{"tag1"}) + if err != nil { + t.Errorf("Failed to remove by tags: %v", err) + } + + // Confirm removal + if l.IsWatched(tmpDir1) || l.IsWatched(tmpDir2) { + t.Errorf("RemoveByTags did not remove the watches correctly") + } + + // Confirm remaining watch + if !l.IsWatched(tmpDir3) { + t.Errorf("RemoveByTags removed an unrelated watch") + } +} + func TestAddWatch(t *testing.T) { tempDir, err := os.MkdirTemp("", "watchtest") assert.Nil(t, err)