pkg/filenotify isn't used anymore and it causes problems with
hack/vendor.sh (nothing uses it, so hack/vendor.sh will remove the
vendored code).
Signed-off-by: Aleksa Sarai <asarai@suse.com>
1 | 1 |
deleted file mode 100644 |
... | ... |
@@ -1,40 +0,0 @@ |
1 |
-// Package filenotify provides a mechanism for watching file(s) for changes. |
|
2 |
-// Generally leans on fsnotify, but provides a poll-based notifier which fsnotify does not support. |
|
3 |
-// These are wrapped up in a common interface so that either can be used interchangeably in your code. |
|
4 |
-package filenotify |
|
5 |
- |
|
6 |
-import "gopkg.in/fsnotify.v1" |
|
7 |
- |
|
8 |
-// FileWatcher is an interface for implementing file notification watchers |
|
9 |
-type FileWatcher interface { |
|
10 |
- Events() <-chan fsnotify.Event |
|
11 |
- Errors() <-chan error |
|
12 |
- Add(name string) error |
|
13 |
- Remove(name string) error |
|
14 |
- Close() error |
|
15 |
-} |
|
16 |
- |
|
17 |
-// New tries to use an fs-event watcher, and falls back to the poller if there is an error |
|
18 |
-func New() (FileWatcher, error) { |
|
19 |
- if watcher, err := NewEventWatcher(); err == nil { |
|
20 |
- return watcher, nil |
|
21 |
- } |
|
22 |
- return NewPollingWatcher(), nil |
|
23 |
-} |
|
24 |
- |
|
25 |
-// NewPollingWatcher returns a poll-based file watcher |
|
26 |
-func NewPollingWatcher() FileWatcher { |
|
27 |
- return &filePoller{ |
|
28 |
- events: make(chan fsnotify.Event), |
|
29 |
- errors: make(chan error), |
|
30 |
- } |
|
31 |
-} |
|
32 |
- |
|
33 |
-// NewEventWatcher returns an fs-event based file watcher |
|
34 |
-func NewEventWatcher() (FileWatcher, error) { |
|
35 |
- watcher, err := fsnotify.NewWatcher() |
|
36 |
- if err != nil { |
|
37 |
- return nil, err |
|
38 |
- } |
|
39 |
- return &fsNotifyWatcher{watcher}, nil |
|
40 |
-} |
41 | 1 |
deleted file mode 100644 |
... | ... |
@@ -1,18 +0,0 @@ |
1 |
-package filenotify |
|
2 |
- |
|
3 |
-import "gopkg.in/fsnotify.v1" |
|
4 |
- |
|
5 |
-// fsNotify wraps the fsnotify package to satisfy the FileNotifer interface |
|
6 |
-type fsNotifyWatcher struct { |
|
7 |
- *fsnotify.Watcher |
|
8 |
-} |
|
9 |
- |
|
10 |
-// GetEvents returns the fsnotify event channel receiver |
|
11 |
-func (w *fsNotifyWatcher) Events() <-chan fsnotify.Event { |
|
12 |
- return w.Watcher.Events |
|
13 |
-} |
|
14 |
- |
|
15 |
-// GetErrors returns the fsnotify error channel receiver |
|
16 |
-func (w *fsNotifyWatcher) Errors() <-chan error { |
|
17 |
- return w.Watcher.Errors |
|
18 |
-} |
19 | 1 |
deleted file mode 100644 |
... | ... |
@@ -1,205 +0,0 @@ |
1 |
-package filenotify |
|
2 |
- |
|
3 |
-import ( |
|
4 |
- "errors" |
|
5 |
- "fmt" |
|
6 |
- "os" |
|
7 |
- "sync" |
|
8 |
- "time" |
|
9 |
- |
|
10 |
- "github.com/Sirupsen/logrus" |
|
11 |
- |
|
12 |
- "gopkg.in/fsnotify.v1" |
|
13 |
-) |
|
14 |
- |
|
15 |
-var ( |
|
16 |
- // errPollerClosed is returned when the poller is closed |
|
17 |
- errPollerClosed = errors.New("poller is closed") |
|
18 |
- // errNoSuchPoller is returned when trying to remove a watch that doesn't exist |
|
19 |
- errNoSuchWatch = errors.New("poller does not exist") |
|
20 |
-) |
|
21 |
- |
|
22 |
-// watchWaitTime is the time to wait between file poll loops |
|
23 |
-const watchWaitTime = 200 * time.Millisecond |
|
24 |
- |
|
25 |
-// filePoller is used to poll files for changes, especially in cases where fsnotify |
|
26 |
-// can't be run (e.g. when inotify handles are exhausted) |
|
27 |
-// filePoller satisfies the FileWatcher interface |
|
28 |
-type filePoller struct { |
|
29 |
- // watches is the list of files currently being polled, close the associated channel to stop the watch |
|
30 |
- watches map[string]chan struct{} |
|
31 |
- // events is the channel to listen to for watch events |
|
32 |
- events chan fsnotify.Event |
|
33 |
- // errors is the channel to listen to for watch errors |
|
34 |
- errors chan error |
|
35 |
- // mu locks the poller for modification |
|
36 |
- mu sync.Mutex |
|
37 |
- // closed is used to specify when the poller has already closed |
|
38 |
- closed bool |
|
39 |
-} |
|
40 |
- |
|
41 |
-// Add adds a filename to the list of watches |
|
42 |
-// once added the file is polled for changes in a separate goroutine |
|
43 |
-func (w *filePoller) Add(name string) error { |
|
44 |
- w.mu.Lock() |
|
45 |
- defer w.mu.Unlock() |
|
46 |
- |
|
47 |
- if w.closed == true { |
|
48 |
- return errPollerClosed |
|
49 |
- } |
|
50 |
- |
|
51 |
- f, err := os.Open(name) |
|
52 |
- if err != nil { |
|
53 |
- return err |
|
54 |
- } |
|
55 |
- fi, err := os.Stat(name) |
|
56 |
- if err != nil { |
|
57 |
- return err |
|
58 |
- } |
|
59 |
- |
|
60 |
- if w.watches == nil { |
|
61 |
- w.watches = make(map[string]chan struct{}) |
|
62 |
- } |
|
63 |
- if _, exists := w.watches[name]; exists { |
|
64 |
- return fmt.Errorf("watch exists") |
|
65 |
- } |
|
66 |
- chClose := make(chan struct{}) |
|
67 |
- w.watches[name] = chClose |
|
68 |
- |
|
69 |
- go w.watch(f, fi, chClose) |
|
70 |
- return nil |
|
71 |
-} |
|
72 |
- |
|
73 |
-// Remove stops and removes watch with the specified name |
|
74 |
-func (w *filePoller) Remove(name string) error { |
|
75 |
- w.mu.Lock() |
|
76 |
- defer w.mu.Unlock() |
|
77 |
- return w.remove(name) |
|
78 |
-} |
|
79 |
- |
|
80 |
-func (w *filePoller) remove(name string) error { |
|
81 |
- if w.closed == true { |
|
82 |
- return errPollerClosed |
|
83 |
- } |
|
84 |
- |
|
85 |
- chClose, exists := w.watches[name] |
|
86 |
- if !exists { |
|
87 |
- return errNoSuchWatch |
|
88 |
- } |
|
89 |
- close(chClose) |
|
90 |
- delete(w.watches, name) |
|
91 |
- return nil |
|
92 |
-} |
|
93 |
- |
|
94 |
-// Events returns the event channel |
|
95 |
-// This is used for notifications on events about watched files |
|
96 |
-func (w *filePoller) Events() <-chan fsnotify.Event { |
|
97 |
- return w.events |
|
98 |
-} |
|
99 |
- |
|
100 |
-// Errors returns the errors channel |
|
101 |
-// This is used for notifications about errors on watched files |
|
102 |
-func (w *filePoller) Errors() <-chan error { |
|
103 |
- return w.errors |
|
104 |
-} |
|
105 |
- |
|
106 |
-// Close closes the poller |
|
107 |
-// All watches are stopped, removed, and the poller cannot be added to |
|
108 |
-func (w *filePoller) Close() error { |
|
109 |
- w.mu.Lock() |
|
110 |
- defer w.mu.Unlock() |
|
111 |
- |
|
112 |
- if w.closed { |
|
113 |
- return nil |
|
114 |
- } |
|
115 |
- |
|
116 |
- w.closed = true |
|
117 |
- for name := range w.watches { |
|
118 |
- w.remove(name) |
|
119 |
- delete(w.watches, name) |
|
120 |
- } |
|
121 |
- close(w.events) |
|
122 |
- close(w.errors) |
|
123 |
- return nil |
|
124 |
-} |
|
125 |
- |
|
126 |
-// sendEvent publishes the specified event to the events channel |
|
127 |
-func (w *filePoller) sendEvent(e fsnotify.Event, chClose <-chan struct{}) error { |
|
128 |
- select { |
|
129 |
- case w.events <- e: |
|
130 |
- case <-chClose: |
|
131 |
- return fmt.Errorf("closed") |
|
132 |
- } |
|
133 |
- return nil |
|
134 |
-} |
|
135 |
- |
|
136 |
-// sendErr publishes the specified error to the errors channel |
|
137 |
-func (w *filePoller) sendErr(e error, chClose <-chan struct{}) error { |
|
138 |
- select { |
|
139 |
- case w.errors <- e: |
|
140 |
- case <-chClose: |
|
141 |
- return fmt.Errorf("closed") |
|
142 |
- } |
|
143 |
- return nil |
|
144 |
-} |
|
145 |
- |
|
146 |
-// watch is responsible for polling the specified file for changes |
|
147 |
-// upon finding changes to a file or errors, sendEvent/sendErr is called |
|
148 |
-func (w *filePoller) watch(f *os.File, lastFi os.FileInfo, chClose chan struct{}) { |
|
149 |
- for { |
|
150 |
- time.Sleep(watchWaitTime) |
|
151 |
- select { |
|
152 |
- case <-chClose: |
|
153 |
- logrus.Debugf("watch for %s closed", f.Name()) |
|
154 |
- return |
|
155 |
- default: |
|
156 |
- } |
|
157 |
- |
|
158 |
- fi, err := os.Stat(f.Name()) |
|
159 |
- if err != nil { |
|
160 |
- // if we got an error here and lastFi is not set, we can presume that nothing has changed |
|
161 |
- // This should be safe since before `watch()` is called, a stat is performed, there is any error `watch` is not called |
|
162 |
- if lastFi == nil { |
|
163 |
- continue |
|
164 |
- } |
|
165 |
- // If it doesn't exist at this point, it must have been removed |
|
166 |
- // no need to send the error here since this is a valid operation |
|
167 |
- if os.IsNotExist(err) { |
|
168 |
- if err := w.sendEvent(fsnotify.Event{Op: fsnotify.Remove, Name: f.Name()}, chClose); err != nil { |
|
169 |
- return |
|
170 |
- } |
|
171 |
- lastFi = nil |
|
172 |
- continue |
|
173 |
- } |
|
174 |
- // at this point, send the error |
|
175 |
- if err := w.sendErr(err, chClose); err != nil { |
|
176 |
- return |
|
177 |
- } |
|
178 |
- continue |
|
179 |
- } |
|
180 |
- |
|
181 |
- if lastFi == nil { |
|
182 |
- if err := w.sendEvent(fsnotify.Event{Op: fsnotify.Create, Name: fi.Name()}, chClose); err != nil { |
|
183 |
- return |
|
184 |
- } |
|
185 |
- lastFi = fi |
|
186 |
- continue |
|
187 |
- } |
|
188 |
- |
|
189 |
- if fi.Mode() != lastFi.Mode() { |
|
190 |
- if err := w.sendEvent(fsnotify.Event{Op: fsnotify.Chmod, Name: fi.Name()}, chClose); err != nil { |
|
191 |
- return |
|
192 |
- } |
|
193 |
- lastFi = fi |
|
194 |
- continue |
|
195 |
- } |
|
196 |
- |
|
197 |
- if fi.ModTime() != lastFi.ModTime() || fi.Size() != lastFi.Size() { |
|
198 |
- if err := w.sendEvent(fsnotify.Event{Op: fsnotify.Write, Name: fi.Name()}, chClose); err != nil { |
|
199 |
- return |
|
200 |
- } |
|
201 |
- lastFi = fi |
|
202 |
- continue |
|
203 |
- } |
|
204 |
- } |
|
205 |
-} |
206 | 1 |
deleted file mode 100644 |
... | ... |
@@ -1,137 +0,0 @@ |
1 |
-package filenotify |
|
2 |
- |
|
3 |
-import ( |
|
4 |
- "fmt" |
|
5 |
- "io/ioutil" |
|
6 |
- "os" |
|
7 |
- "runtime" |
|
8 |
- "testing" |
|
9 |
- "time" |
|
10 |
- |
|
11 |
- "gopkg.in/fsnotify.v1" |
|
12 |
-) |
|
13 |
- |
|
14 |
-func TestPollerAddRemove(t *testing.T) { |
|
15 |
- w := NewPollingWatcher() |
|
16 |
- |
|
17 |
- if err := w.Add("no-such-file"); err == nil { |
|
18 |
- t.Fatal("should have gotten error when adding a non-existent file") |
|
19 |
- } |
|
20 |
- if err := w.Remove("no-such-file"); err == nil { |
|
21 |
- t.Fatal("should have gotten error when removing non-existent watch") |
|
22 |
- } |
|
23 |
- |
|
24 |
- f, err := ioutil.TempFile("", "asdf") |
|
25 |
- if err != nil { |
|
26 |
- t.Fatal(err) |
|
27 |
- } |
|
28 |
- defer os.RemoveAll(f.Name()) |
|
29 |
- |
|
30 |
- if err := w.Add(f.Name()); err != nil { |
|
31 |
- t.Fatal(err) |
|
32 |
- } |
|
33 |
- |
|
34 |
- if err := w.Remove(f.Name()); err != nil { |
|
35 |
- t.Fatal(err) |
|
36 |
- } |
|
37 |
-} |
|
38 |
- |
|
39 |
-func TestPollerEvent(t *testing.T) { |
|
40 |
- if runtime.GOOS == "windows" { |
|
41 |
- t.Skip("No chmod on Windows") |
|
42 |
- } |
|
43 |
- w := NewPollingWatcher() |
|
44 |
- |
|
45 |
- f, err := ioutil.TempFile("", "test-poller") |
|
46 |
- if err != nil { |
|
47 |
- t.Fatal("error creating temp file") |
|
48 |
- } |
|
49 |
- defer os.RemoveAll(f.Name()) |
|
50 |
- f.Close() |
|
51 |
- |
|
52 |
- if err := w.Add(f.Name()); err != nil { |
|
53 |
- t.Fatal(err) |
|
54 |
- } |
|
55 |
- |
|
56 |
- select { |
|
57 |
- case <-w.Events(): |
|
58 |
- t.Fatal("got event before anything happened") |
|
59 |
- case <-w.Errors(): |
|
60 |
- t.Fatal("got error before anything happened") |
|
61 |
- default: |
|
62 |
- } |
|
63 |
- |
|
64 |
- if err := ioutil.WriteFile(f.Name(), []byte("hello"), 644); err != nil { |
|
65 |
- t.Fatal(err) |
|
66 |
- } |
|
67 |
- if err := assertEvent(w, fsnotify.Write); err != nil { |
|
68 |
- t.Fatal(err) |
|
69 |
- } |
|
70 |
- |
|
71 |
- if err := os.Chmod(f.Name(), 600); err != nil { |
|
72 |
- t.Fatal(err) |
|
73 |
- } |
|
74 |
- if err := assertEvent(w, fsnotify.Chmod); err != nil { |
|
75 |
- t.Fatal(err) |
|
76 |
- } |
|
77 |
- |
|
78 |
- if err := os.Remove(f.Name()); err != nil { |
|
79 |
- t.Fatal(err) |
|
80 |
- } |
|
81 |
- if err := assertEvent(w, fsnotify.Remove); err != nil { |
|
82 |
- t.Fatal(err) |
|
83 |
- } |
|
84 |
-} |
|
85 |
- |
|
86 |
-func TestPollerClose(t *testing.T) { |
|
87 |
- w := NewPollingWatcher() |
|
88 |
- if err := w.Close(); err != nil { |
|
89 |
- t.Fatal(err) |
|
90 |
- } |
|
91 |
- // test double-close |
|
92 |
- if err := w.Close(); err != nil { |
|
93 |
- t.Fatal(err) |
|
94 |
- } |
|
95 |
- |
|
96 |
- select { |
|
97 |
- case _, open := <-w.Events(): |
|
98 |
- if open { |
|
99 |
- t.Fatal("event chan should be closed") |
|
100 |
- } |
|
101 |
- default: |
|
102 |
- t.Fatal("event chan should be closed") |
|
103 |
- } |
|
104 |
- |
|
105 |
- select { |
|
106 |
- case _, open := <-w.Errors(): |
|
107 |
- if open { |
|
108 |
- t.Fatal("errors chan should be closed") |
|
109 |
- } |
|
110 |
- default: |
|
111 |
- t.Fatal("errors chan should be closed") |
|
112 |
- } |
|
113 |
- |
|
114 |
- f, err := ioutil.TempFile("", "asdf") |
|
115 |
- if err != nil { |
|
116 |
- t.Fatal(err) |
|
117 |
- } |
|
118 |
- defer os.RemoveAll(f.Name()) |
|
119 |
- if err := w.Add(f.Name()); err == nil { |
|
120 |
- t.Fatal("should have gotten error adding watch for closed watcher") |
|
121 |
- } |
|
122 |
-} |
|
123 |
- |
|
124 |
-func assertEvent(w FileWatcher, eType fsnotify.Op) error { |
|
125 |
- var err error |
|
126 |
- select { |
|
127 |
- case e := <-w.Events(): |
|
128 |
- if e.Op != eType { |
|
129 |
- err = fmt.Errorf("got wrong event type, expected %q: %v", eType, e) |
|
130 |
- } |
|
131 |
- case e := <-w.Errors(): |
|
132 |
- err = fmt.Errorf("got unexpected error waiting for events %v: %v", eType, e) |
|
133 |
- case <-time.After(watchWaitTime * 3): |
|
134 |
- err = fmt.Errorf("timeout waiting for event %v", eType) |
|
135 |
- } |
|
136 |
- return err |
|
137 |
-} |