github.com/bazelbuild/bazel-watcher@v0.25.2/internal/ibazel/fswatcher/fsnotify/fsnotify.go (about) 1 // Copyright 2017 The Bazel Authors. All rights reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package fsnotify 16 17 import ( 18 "errors" 19 "fmt" 20 "strings" 21 22 "github.com/fsnotify/fsnotify" 23 24 "github.com/bazelbuild/bazel-watcher/internal/ibazel/fswatcher/common" 25 ) 26 27 // We have to declare our own partial interface in order to mock it out in test 28 // as the real struct varies from platform to platform 29 type fsNotifyWatcher interface { 30 Add(name string) error 31 Remove(name string) error 32 Close() error 33 Events() chan fsnotify.Event 34 } 35 type fsNotifyWatcherWrapper struct { 36 watcher *fsnotify.Watcher 37 } 38 39 func (w *fsNotifyWatcherWrapper) Add(name string) error { return w.watcher.Add(name) } 40 func (w *fsNotifyWatcherWrapper) Remove(name string) error { return w.watcher.Remove(name) } 41 func (w *fsNotifyWatcherWrapper) Close() error { return w.watcher.Close() } 42 func (w *fsNotifyWatcherWrapper) Events() chan fsnotify.Event { return w.watcher.Events } 43 44 type realFSNotifyWatcher struct { 45 watched map[string]struct{} 46 wrapper fsNotifyWatcher 47 } 48 49 var _ common.Watcher = &realFSNotifyWatcher{} 50 51 // UpdateAll implements ibazel/fswatcher/common.Watcher 52 func (w *realFSNotifyWatcher) UpdateAll(names []string) error { 53 var errs []string 54 prev_watched := w.watched 55 new_watched := make(map[string]struct{}, len(names)) 56 57 for _, name := range names { 58 new_watched[name] = struct{}{} 59 60 _, ok := prev_watched[name] 61 if ok { 62 delete(w.watched, name) 63 } else { 64 err := w.wrapper.Add(name) 65 if err != nil { 66 errs = append(errs, fmt.Sprintf("Error watching file %q error: %v", name, err)) 67 } 68 } 69 } 70 71 for name, _ := range prev_watched { 72 err := w.wrapper.Remove(name) 73 if err != nil { 74 errs = append(errs, fmt.Sprintf("Error unwatching file %q error: %v\n", name, err)) 75 } 76 } 77 78 w.watched = new_watched 79 80 if len(errs) > 0 { 81 return errors.New(strings.Join(errs, "\n")) 82 } 83 return nil 84 } 85 86 // Close implements ibazel/fswatcher/common.Watcher 87 func (w *realFSNotifyWatcher) Close() error { 88 return w.wrapper.Close() 89 } 90 91 // Events implements ibazel/fswatcher/common.Watcher 92 func (w *realFSNotifyWatcher) Events() chan common.Event { 93 return w.wrapper.Events() 94 } 95 96 func NewWatcher() (common.Watcher, error) { 97 watcher, err := fsnotify.NewWatcher() 98 wrapper := &fsNotifyWatcherWrapper{watcher: watcher} 99 return &realFSNotifyWatcher{wrapper: wrapper}, err 100 }