Move fsnotify to gx
License: MIT Signed-off-by: Jakub Sztandera <kubuxu@protonmail.ch>
Jakub Sztandera committed
Jun 9, 2016 at 11:11 UTC
fb0aa6358774e469cf74ca93e1d560994699213a
23 files changed
+7
-3812
Godeps/Godeps.json
-5
@@ -72,11 +72,6 @@
72
{
73
"ImportPath": "github.com/whyrusleeping/chunker",
74
"Rev": "537e901819164627ca4bb5ce4e3faa8ce7956564"
75
- },
76
- {
77
- "ImportPath": "gopkg.in/fsnotify.v1",
78
- "Comment": "v1.2.0",
79
- "Rev": "96c060f6a6b7e0d6f75fddd10efeaca3e5d1bcb0"
75
}
76
]
77
}
Godeps/_workspace/src/gopkg.in/fsnotify.v1/.gitignore
deleted
-6
@@ -1,6 +0,0 @@
1
-# Setup a Global .gitignore for OS and editor generated files:
2
-# https://help.github.com/articles/ignoring-files
3
-# git config --global core.excludesfile ~/.gitignore_global
4
-
5
-.vagrant
6
-*.sublime-project
Godeps/_workspace/src/gopkg.in/fsnotify.v1/.travis.yml
deleted
-15
@@ -1,15 +0,0 @@
1
-sudo: false
2
-language: go
3
-
4
-go:
5
- - 1.4.1
6
-
7
-before_script:
8
- - FIXED=$(go fmt ./... | wc -l); if [ $FIXED -gt 0 ]; then echo "gofmt - $FIXED file(s) not formatted correctly, please run gofmt to fix this." && exit 1; fi
9
-
10
-os:
11
- - linux
12
- - osx
13
-
14
-notifications:
15
- email: false
Godeps/_workspace/src/gopkg.in/fsnotify.v1/AUTHORS
deleted
-34
@@ -1,34 +0,0 @@
1
-# Names should be added to this file as
2
-# Name or Organization <email address>
3
-# The email address is not required for organizations.
4
-
5
-# You can update this list using the following command:
6
-#
7
-# $ git shortlog -se | awk '{print $2 " " $3 " " $4}'
8
-
9
-# Please keep the list sorted.
10
-
11
-Adrien Bustany <adrien@bustany.org>
12
-Caleb Spare <cespare@gmail.com>
13
-Case Nelson <case@teammating.com>
14
-Chris Howey <howeyc@gmail.com> <chris@howey.me>
15
-Christoffer Buchholz <christoffer.buchholz@gmail.com>
16
-Dave Cheney <dave@cheney.net>
17
-Francisco Souza <f@souza.cc>
18
-Hari haran <hariharan.uno@gmail.com>
19
-John C Barstow
20
-Kelvin Fo <vmirage@gmail.com>
21
-Matt Layher <mdlayher@gmail.com>
22
-Nathan Youngman <git@nathany.com>
23
-Paul Hammond <paul@paulhammond.org>
24
-Pieter Droogendijk <pieter@binky.org.uk>
25
-Pursuit92 <JoshChase@techpursuit.net>
26
-Rob Figueiredo <robfig@gmail.com>
27
-Soge Zhang <zhssoge@gmail.com>
28
-Tilak Sharma <tilaks@google.com>
29
-Travis Cline <travis.cline@gmail.com>
30
-Tudor Golubenco <tudor.g@gmail.com>
31
-Yukang <moorekang@gmail.com>
32
-bronze1man <bronze1man@gmail.com>
33
-debrando <denis.brandolini@gmail.com>
34
-henrikedwards <henrik.edwards@gmail.com>
Godeps/_workspace/src/gopkg.in/fsnotify.v1/CHANGELOG.md
deleted
-263
@@ -1,263 +0,0 @@
1
-# Changelog
2
-
3
-## v1.2.0 / 2015-02-08
4
-
5
-* inotify: use epoll to wake up readEvents [#66](https://github.com/go-fsnotify/fsnotify/pull/66) (thanks @PieterD)
6
-* inotify: closing watcher should now always shut down goroutine [#63](https://github.com/go-fsnotify/fsnotify/pull/63) (thanks @PieterD)
7
-* kqueue: close kqueue after removing watches, fixes [#59](https://github.com/go-fsnotify/fsnotify/issues/59)
8
-
9
-## v1.1.1 / 2015-02-05
10
-
11
-* inotify: Retry read on EINTR [#61](https://github.com/go-fsnotify/fsnotify/issues/61) (thanks @PieterD)
12
-
13
-## v1.1.0 / 2014-12-12
14
-
15
-* kqueue: rework internals [#43](https://github.com/go-fsnotify/fsnotify/pull/43)
16
- * add low-level functions
17
- * only need to store flags on directories
18
- * less mutexes [#13](https://github.com/go-fsnotify/fsnotify/issues/13)
19
- * done can be an unbuffered channel
20
- * remove calls to os.NewSyscallError
21
-* More efficient string concatenation for Event.String() [#52](https://github.com/go-fsnotify/fsnotify/pull/52) (thanks @mdlayher)
22
-* kqueue: fix regression in rework causing subdirectories to be watched [#48](https://github.com/go-fsnotify/fsnotify/issues/48)
23
-* kqueue: cleanup internal watch before sending remove event [#51](https://github.com/go-fsnotify/fsnotify/issues/51)
24
-
25
-## v1.0.4 / 2014-09-07
26
-
27
-* kqueue: add dragonfly to the build tags.
28
-* Rename source code files, rearrange code so exported APIs are at the top.
29
-* Add done channel to example code. [#37](https://github.com/go-fsnotify/fsnotify/pull/37) (thanks @chenyukang)
30
-
31
-## v1.0.3 / 2014-08-19
32
-
33
-* [Fix] Windows MOVED_TO now translates to Create like on BSD and Linux. [#36](https://github.com/go-fsnotify/fsnotify/issues/36)
34
-
35
-## v1.0.2 / 2014-08-17
36
-
37
-* [Fix] Missing create events on OS X. [#14](https://github.com/go-fsnotify/fsnotify/issues/14) (thanks @zhsso)
38
-* [Fix] Make ./path and path equivalent. (thanks @zhsso)
39
-
40
-## v1.0.0 / 2014-08-15
41
-
42
-* [API] Remove AddWatch on Windows, use Add.
43
-* Improve documentation for exported identifiers. [#30](https://github.com/go-fsnotify/fsnotify/issues/30)
44
-* Minor updates based on feedback from golint.
45
-
46
-## dev / 2014-07-09
47
-
48
-* Moved to [github.com/go-fsnotify/fsnotify](https://github.com/go-fsnotify/fsnotify).
49
-* Use os.NewSyscallError instead of returning errno (thanks @hariharan-uno)
50
-
51
-## dev / 2014-07-04
52
-
53
-* kqueue: fix incorrect mutex used in Close()
54
-* Update example to demonstrate usage of Op.
55
-
56
-## dev / 2014-06-28
57
-
58
-* [API] Don't set the Write Op for attribute notifications [#4](https://github.com/go-fsnotify/fsnotify/issues/4)
59
-* Fix for String() method on Event (thanks Alex Brainman)
60
-* Don't build on Plan 9 or Solaris (thanks @4ad)
61
-
62
-## dev / 2014-06-21
63
-
64
-* Events channel of type Event rather than *Event.
65
-* [internal] use syscall constants directly for inotify and kqueue.
66
-* [internal] kqueue: rename events to kevents and fileEvent to event.
67
-
68
-## dev / 2014-06-19
69
-
70
-* Go 1.3+ required on Windows (uses syscall.ERROR_MORE_DATA internally).
71
-* [internal] remove cookie from Event struct (unused).
72
-* [internal] Event struct has the same definition across every OS.
73
-* [internal] remove internal watch and removeWatch methods.
74
-
75
-## dev / 2014-06-12
76
-
77
-* [API] Renamed Watch() to Add() and RemoveWatch() to Remove().
78
-* [API] Pluralized channel names: Events and Errors.
79
-* [API] Renamed FileEvent struct to Event.
80
-* [API] Op constants replace methods like IsCreate().
81
-
82
-## dev / 2014-06-12
83
-
84
-* Fix data race on kevent buffer (thanks @tilaks) [#98](https://github.com/howeyc/fsnotify/pull/98)
85
-
86
-## dev / 2014-05-23
87
-
88
-* [API] Remove current implementation of WatchFlags.
89
- * current implementation doesn't take advantage of OS for efficiency
90
- * provides little benefit over filtering events as they are received, but has extra bookkeeping and mutexes
91
- * no tests for the current implementation
92
- * not fully implemented on Windows [#93](https://github.com/howeyc/fsnotify/issues/93#issuecomment-39285195)
93
-
94
-## v0.9.3 / 2014-12-31
95
-
96
-* kqueue: cleanup internal watch before sending remove event [#51](https://github.com/go-fsnotify/fsnotify/issues/51)
97
-
98
-## v0.9.2 / 2014-08-17
99
-
100
-* [Backport] Fix missing create events on OS X. [#14](https://github.com/go-fsnotify/fsnotify/issues/14) (thanks @zhsso)
101
-
102
-## v0.9.1 / 2014-06-12
103
-
104
-* Fix data race on kevent buffer (thanks @tilaks) [#98](https://github.com/howeyc/fsnotify/pull/98)
105
-
106
-## v0.9.0 / 2014-01-17
107
-
108
-* IsAttrib() for events that only concern a file's metadata [#79][] (thanks @abustany)
109
-* [Fix] kqueue: fix deadlock [#77][] (thanks @cespare)
110
-* [NOTICE] Development has moved to `code.google.com/p/go.exp/fsnotify` in preparation for inclusion in the Go standard library.
111
-
112
-## v0.8.12 / 2013-11-13
113
-
114
-* [API] Remove FD_SET and friends from Linux adapter
115
-
116
-## v0.8.11 / 2013-11-02
117
-
118
-* [Doc] Add Changelog [#72][] (thanks @nathany)
119
-* [Doc] Spotlight and double modify events on OS X [#62][] (reported by @paulhammond)
120
-
121
-## v0.8.10 / 2013-10-19
122
-
123
-* [Fix] kqueue: remove file watches when parent directory is removed [#71][] (reported by @mdwhatcott)
124
-* [Fix] kqueue: race between Close and readEvents [#70][] (reported by @bernerdschaefer)
125
-* [Doc] specify OS-specific limits in README (thanks @debrando)
126
-
127
-## v0.8.9 / 2013-09-08
128
-
129
-* [Doc] Contributing (thanks @nathany)
130
-* [Doc] update package path in example code [#63][] (thanks @paulhammond)
131
-* [Doc] GoCI badge in README (Linux only) [#60][]
132
-* [Doc] Cross-platform testing with Vagrant [#59][] (thanks @nathany)
133
-
134
-## v0.8.8 / 2013-06-17
135
-
136
-* [Fix] Windows: handle `ERROR_MORE_DATA` on Windows [#49][] (thanks @jbowtie)
137
-
138
-## v0.8.7 / 2013-06-03
139
-
140
-* [API] Make syscall flags internal
141
-* [Fix] inotify: ignore event changes
142
-* [Fix] race in symlink test [#45][] (reported by @srid)
143
-* [Fix] tests on Windows
144
-* lower case error messages
145
-
146
-## v0.8.6 / 2013-05-23
147
-
148
-* kqueue: Use EVT_ONLY flag on Darwin
149
-* [Doc] Update README with full example
150
-
151
-## v0.8.5 / 2013-05-09
152
-
153
-* [Fix] inotify: allow monitoring of "broken" symlinks (thanks @tsg)
154
-
155
-## v0.8.4 / 2013-04-07
156
-
157
-* [Fix] kqueue: watch all file events [#40][] (thanks @ChrisBuchholz)
158
-
159
-## v0.8.3 / 2013-03-13
160
-
161
-* [Fix] inoitfy/kqueue memory leak [#36][] (reported by @nbkolchin)
162
-* [Fix] kqueue: use fsnFlags for watching a directory [#33][] (reported by @nbkolchin)
163
-
164
-## v0.8.2 / 2013-02-07
165
-
166
-* [Doc] add Authors
167
-* [Fix] fix data races for map access [#29][] (thanks @fsouza)
168
-
169
-## v0.8.1 / 2013-01-09
170
-
171
-* [Fix] Windows path separators
172
-* [Doc] BSD License
173
-
174
-## v0.8.0 / 2012-11-09
175
-
176
-* kqueue: directory watching improvements (thanks @vmirage)
177
-* inotify: add `IN_MOVED_TO` [#25][] (requested by @cpisto)
178
-* [Fix] kqueue: deleting watched directory [#24][] (reported by @jakerr)
179
-
180
-## v0.7.4 / 2012-10-09
181
-
182
-* [Fix] inotify: fixes from https://codereview.appspot.com/5418045/ (ugorji)
183
-* [Fix] kqueue: preserve watch flags when watching for delete [#21][] (reported by @robfig)
184
-* [Fix] kqueue: watch the directory even if it isn't a new watch (thanks @robfig)
185
-* [Fix] kqueue: modify after recreation of file
186
-
187
-## v0.7.3 / 2012-09-27
188
-
189
-* [Fix] kqueue: watch with an existing folder inside the watched folder (thanks @vmirage)
190
-* [Fix] kqueue: no longer get duplicate CREATE events
191
-
192
-## v0.7.2 / 2012-09-01
193
-
194
-* kqueue: events for created directories
195
-
196
-## v0.7.1 / 2012-07-14
197
-
198
-* [Fix] for renaming files
199
-
200
-## v0.7.0 / 2012-07-02
201
-
202
-* [Feature] FSNotify flags
203
-* [Fix] inotify: Added file name back to event path
204
-
205
-## v0.6.0 / 2012-06-06
206
-
207
-* kqueue: watch files after directory created (thanks @tmc)
208
-
209
-## v0.5.1 / 2012-05-22
210
-
211
-* [Fix] inotify: remove all watches before Close()
212
-
213
-## v0.5.0 / 2012-05-03
214
-
215
-* [API] kqueue: return errors during watch instead of sending over channel
216
-* kqueue: match symlink behavior on Linux
217
-* inotify: add `DELETE_SELF` (requested by @taralx)
218
-* [Fix] kqueue: handle EINTR (reported by @robfig)
219
-* [Doc] Godoc example [#1][] (thanks @davecheney)
220
-
221
-## v0.4.0 / 2012-03-30
222
-
223
-* Go 1 released: build with go tool
224
-* [Feature] Windows support using winfsnotify
225
-* Windows does not have attribute change notifications
226
-* Roll attribute notifications into IsModify
227
-
228
-## v0.3.0 / 2012-02-19
229
-
230
-* kqueue: add files when watch directory
231
-
232
-## v0.2.0 / 2011-12-30
233
-
234
-* update to latest Go weekly code
235
-
236
-## v0.1.0 / 2011-10-19
237
-
238
-* kqueue: add watch on file creation to match inotify
239
-* kqueue: create file event
240
-* inotify: ignore `IN_IGNORED` events
241
-* event String()
242
-* linux: common FileEvent functions
243
-* initial commit
244
-
245
-[#79]: https://github.com/howeyc/fsnotify/pull/79
246
-[#77]: https://github.com/howeyc/fsnotify/pull/77
247
-[#72]: https://github.com/howeyc/fsnotify/issues/72
248
-[#71]: https://github.com/howeyc/fsnotify/issues/71
249
-[#70]: https://github.com/howeyc/fsnotify/issues/70
250
-[#63]: https://github.com/howeyc/fsnotify/issues/63
251
-[#62]: https://github.com/howeyc/fsnotify/issues/62
252
-[#60]: https://github.com/howeyc/fsnotify/issues/60
253
-[#59]: https://github.com/howeyc/fsnotify/issues/59
254
-[#49]: https://github.com/howeyc/fsnotify/issues/49
255
-[#45]: https://github.com/howeyc/fsnotify/issues/45
256
-[#40]: https://github.com/howeyc/fsnotify/issues/40
257
-[#36]: https://github.com/howeyc/fsnotify/issues/36
258
-[#33]: https://github.com/howeyc/fsnotify/issues/33
259
-[#29]: https://github.com/howeyc/fsnotify/issues/29
260
-[#25]: https://github.com/howeyc/fsnotify/issues/25
261
-[#24]: https://github.com/howeyc/fsnotify/issues/24
262
-[#21]: https://github.com/howeyc/fsnotify/issues/21
263
-
Godeps/_workspace/src/gopkg.in/fsnotify.v1/CONTRIBUTING.md
deleted
-77
@@ -1,77 +0,0 @@
1
-# Contributing
2
-
3
-## Issues
4
-
5
-* Request features and report bugs using the [GitHub Issue Tracker](https://github.com/go-fsnotify/fsnotify/issues).
6
-* Please indicate the platform you are using fsnotify on.
7
-* A code example to reproduce the problem is appreciated.
8
-
9
-## Pull Requests
10
-
11
-### Contributor License Agreement
12
-
13
-fsnotify is derived from code in the [golang.org/x/exp](https://godoc.org/golang.org/x/exp) package and it may be included [in the standard library](https://github.com/go-fsnotify/fsnotify/issues/1) in the future. Therefore fsnotify carries the same [LICENSE](https://github.com/go-fsnotify/fsnotify/blob/master/LICENSE) as Go. Contributors retain their copyright, so you need to fill out a short form before we can accept your contribution: [Google Individual Contributor License Agreement](https://developers.google.com/open-source/cla/individual).
14
-
15
-Please indicate that you have signed the CLA in your pull request.
16
-
17
-### How fsnotify is Developed
18
-
19
-* Development is done on feature branches.
20
-* Tests are run on BSD, Linux, OS X and Windows.
21
-* Pull requests are reviewed and [applied to master][am] using [hub][].
22
- * Maintainers may modify or squash commits rather than asking contributors to.
23
-* To issue a new release, the maintainers will:
24
- * Update the CHANGELOG
25
- * Tag a version, which will become available through gopkg.in.
26
-
27
-### How to Fork
28
-
29
-For smooth sailing, always use the original import path. Installing with `go get` makes this easy.
30
-
31
-1. Install from GitHub (`go get -u github.com/go-fsnotify/fsnotify`)
32
-2. Create your feature branch (`git checkout -b my-new-feature`)
33
-3. Ensure everything works and the tests pass (see below)
34
-4. Commit your changes (`git commit -am 'Add some feature'`)
35
-
36
-Contribute upstream:
37
-
38
-1. Fork fsnotify on GitHub
39
-2. Add your remote (`git remote add fork git@github.com:mycompany/repo.git`)
40
-3. Push to the branch (`git push fork my-new-feature`)
41
-4. Create a new Pull Request on GitHub
42
-
43
-This workflow is [thoroughly explained by Katrina Owen](https://blog.splice.com/contributing-open-source-git-repositories-go/).
44
-
45
-### Testing
46
-
47
-fsnotify uses build tags to compile different code on Linux, BSD, OS X, and Windows.
48
-
49
-Before doing a pull request, please do your best to test your changes on multiple platforms, and list which platforms you were able/unable to test on.
50
-
51
-To aid in cross-platform testing there is a Vagrantfile for Linux and BSD.
52
-
53
-* Install [Vagrant](http://www.vagrantup.com/) and [VirtualBox](https://www.virtualbox.org/)
54
-* Setup [Vagrant Gopher](https://github.com/nathany/vagrant-gopher) in your `src` folder.
55
-* Run `vagrant up` from the project folder. You can also setup just one box with `vagrant up linux` or `vagrant up bsd` (note: the BSD box doesn't support Windows hosts at this time, and NFS may prompt for your host OS password)
56
-* Once setup, you can run the test suite on a given OS with a single command `vagrant ssh linux -c 'cd go-fsnotify/fsnotify; go test'`.
57
-* When you're done, you will want to halt or destroy the Vagrant boxes.
58
-
59
-Notice: fsnotify file system events won't trigger in shared folders. The tests get around this limitation by using the /tmp directory.
60
-
61
-Right now there is no equivalent solution for Windows and OS X, but there are Windows VMs [freely available from Microsoft](http://www.modern.ie/en-us/virtualization-tools#downloads).
62
-
63
-### Maintainers
64
-
65
-Help maintaining fsnotify is welcome. To be a maintainer:
66
-
67
-* Submit a pull request and sign the CLA as above.
68
-* You must be able to run the test suite on Mac, Windows, Linux and BSD.
69
-
70
-To keep master clean, the fsnotify project uses the "apply mail" workflow outlined in Nathaniel Talbott's post ["Merge pull request" Considered Harmful][am]. This requires installing [hub][].
71
-
72
-All code changes should be internal pull requests.
73
-
74
-Releases are tagged using [Semantic Versioning](http://semver.org/).
75
-
76
-[hub]: https://github.com/github/hub
77
-[am]: http://blog.spreedly.com/2014/06/24/merge-pull-request-considered-harmful/#.VGa5yZPF_Zs
Godeps/_workspace/src/gopkg.in/fsnotify.v1/LICENSE
deleted
-28
@@ -1,28 +0,0 @@
1
-Copyright (c) 2012 The Go Authors. All rights reserved.
2
-Copyright (c) 2012 fsnotify Authors. All rights reserved.
3
-
4
-Redistribution and use in source and binary forms, with or without
5
-modification, are permitted provided that the following conditions are
6
-met:
7
-
8
- * Redistributions of source code must retain the above copyright
9
-notice, this list of conditions and the following disclaimer.
10
- * Redistributions in binary form must reproduce the above
11
-copyright notice, this list of conditions and the following disclaimer
12
-in the documentation and/or other materials provided with the
13
-distribution.
14
- * Neither the name of Google Inc. nor the names of its
15
-contributors may be used to endorse or promote products derived from
16
-this software without specific prior written permission.
17
-
18
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Godeps/_workspace/src/gopkg.in/fsnotify.v1/NotUsed.xcworkspace
Godeps/_workspace/src/gopkg.in/fsnotify.v1/README.md
deleted
-59
@@ -1,59 +0,0 @@
1
-# File system notifications for Go
2
-
3
-[](http://gocover.io/github.com/go-fsnotify/fsnotify) [](https://godoc.org/gopkg.in/fsnotify.v1)
4
-
5
-Go 1.3+ required.
6
-
7
-Cross platform: Windows, Linux, BSD and OS X.
8
-
9
-|Adapter |OS |Status |
10
-|----------|----------|----------|
11
-|inotify |Linux, Android\*|Supported [](https://travis-ci.org/go-fsnotify/fsnotify)|
12
-|kqueue |BSD, OS X, iOS\*|Supported [](https://circleci.com/gh/go-fsnotify/fsnotify)|
13
-|ReadDirectoryChangesW|Windows|Supported [](https://ci.appveyor.com/project/NathanYoungman/fsnotify/branch/master)|
14
-|FSEvents |OS X |[Planned](https://github.com/go-fsnotify/fsnotify/issues/11)|
15
-|FEN |Solaris 11 |[Planned](https://github.com/go-fsnotify/fsnotify/issues/12)|
16
-|fanotify |Linux 2.6.37+ | |
17
-|USN Journals |Windows |[Maybe](https://github.com/go-fsnotify/fsnotify/issues/53)|
18
-|Polling |*All* |[Maybe](https://github.com/go-fsnotify/fsnotify/issues/9)|
19
-
20
-\* Android and iOS are untested.
21
-
22
-Please see [the documentation](https://godoc.org/gopkg.in/fsnotify.v1) for usage. Consult the [Wiki](https://github.com/go-fsnotify/fsnotify/wiki) for the FAQ and further information.
23
-
24
-## API stability
25
-
26
-Two major versions of fsnotify exist.
27
-
28
-**[fsnotify.v0](https://gopkg.in/fsnotify.v0)** is API-compatible with [howeyc/fsnotify](https://godoc.org/github.com/howeyc/fsnotify). Bugfixes *may* be backported, but I recommend upgrading to v1.
29
-
30
-```go
31
-import "gopkg.in/fsnotify.v0"
32
-```
33
-
34
-\* Refer to the package as fsnotify (without the .v0 suffix).
35
-
36
-**[fsnotify.v1](https://gopkg.in/fsnotify.v1)** provides [a new API](https://godoc.org/gopkg.in/fsnotify.v1) based on [this design document](http://goo.gl/MrYxyA). You can import v1 with:
37
-
38
-```go
39
-import "gopkg.in/fsnotify.v1"
40
-```
41
-
42
-Further API changes are [planned](https://github.com/go-fsnotify/fsnotify/milestones), but a new major revision will be tagged, so you can depend on the v1 API.
43
-
44
-**Master** may have unreleased changes. Use it to test the very latest code or when [contributing][], but don't expect it to remain API-compatible:
45
-
46
-```go
47
-import "github.com/go-fsnotify/fsnotify"
48
-```
49
-
50
-## Contributing
51
-
52
-Please refer to [CONTRIBUTING][] before opening an issue or pull request.
53
-
54
-## Example
55
-
56
-See [example_test.go](https://github.com/go-fsnotify/fsnotify/blob/master/example_test.go).
57
-
58
-
59
-[contributing]: https://github.com/go-fsnotify/fsnotify/blob/master/CONTRIBUTING.md
Godeps/_workspace/src/gopkg.in/fsnotify.v1/circle.yml
deleted
-26
@@ -1,26 +0,0 @@
1
-## OS X build (CircleCI iOS beta)
2
-
3
-# Pretend like it's an Xcode project, at least to get it running.
4
-machine:
5
- environment:
6
- XCODE_WORKSPACE: NotUsed.xcworkspace
7
- XCODE_SCHEME: NotUsed
8
- # This is where the go project is actually checked out to:
9
- CIRCLE_BUILD_DIR: $HOME/.go_project/src/github.com/go-fsnotify/fsnotify
10
-
11
-dependencies:
12
- pre:
13
- - brew upgrade go
14
-
15
-test:
16
- override:
17
- - go test ./...
18
-
19
-# Idealized future config, eventually with cross-platform build matrix :-)
20
-
21
-# machine:
22
-# go:
23
-# version: 1.4
24
-# os:
25
-# - osx
26
-# - linux
Godeps/_workspace/src/gopkg.in/fsnotify.v1/example_test.go
deleted
-42
@@ -1,42 +0,0 @@
1
-// Copyright 2012 The Go Authors. All rights reserved.
2
-// Use of this source code is governed by a BSD-style
3
-// license that can be found in the LICENSE file.
4
-
5
-// +build !plan9,!solaris
6
-
7
-package fsnotify_test
8
-
9
-import (
10
- "log"
11
-
12
- "github.com/go-fsnotify/fsnotify"
13
-)
14
-
15
-func ExampleNewWatcher() {
16
- watcher, err := fsnotify.NewWatcher()
17
- if err != nil {
18
- log.Fatal(err)
19
- }
20
- defer watcher.Close()
21
-
22
- done := make(chan bool)
23
- go func() {
24
- for {
25
- select {
26
- case event := <-watcher.Events:
27
- log.Println("event:", event)
28
- if event.Op&fsnotify.Write == fsnotify.Write {
29
- log.Println("modified file:", event.Name)
30
- }
31
- case err := <-watcher.Errors:
32
- log.Println("error:", err)
33
- }
34
- }
35
- }()
36
-
37
- err = watcher.Add("/tmp/foo")
38
- if err != nil {
39
- log.Fatal(err)
40
- }
41
- <-done
42
-}
Godeps/_workspace/src/gopkg.in/fsnotify.v1/fsnotify.go
deleted
-62
@@ -1,62 +0,0 @@
1
-// Copyright 2012 The Go Authors. All rights reserved.
2
-// Use of this source code is governed by a BSD-style
3
-// license that can be found in the LICENSE file.
4
-
5
-// +build !plan9,!solaris
6
-
7
-// Package fsnotify provides a platform-independent interface for file system notifications.
8
-package fsnotify
9
-
10
-import (
11
- "bytes"
12
- "fmt"
13
-)
14
-
15
-// Event represents a single file system notification.
16
-type Event struct {
17
- Name string // Relative path to the file or directory.
18
- Op Op // File operation that triggered the event.
19
-}
20
-
21
-// Op describes a set of file operations.
22
-type Op uint32
23
-
24
-// These are the generalized file operations that can trigger a notification.
25
-const (
26
- Create Op = 1 << iota
27
- Write
28
- Remove
29
- Rename
30
- Chmod
31
-)
32
-
33
-// String returns a string representation of the event in the form
34
-// "file: REMOVE|WRITE|..."
35
-func (e Event) String() string {
36
- // Use a buffer for efficient string concatenation
37
- var buffer bytes.Buffer
38
-
39
- if e.Op&Create == Create {
40
- buffer.WriteString("|CREATE")
41
- }
42
- if e.Op&Remove == Remove {
43
- buffer.WriteString("|REMOVE")
44
- }
45
- if e.Op&Write == Write {
46
- buffer.WriteString("|WRITE")
47
- }
48
- if e.Op&Rename == Rename {
49
- buffer.WriteString("|RENAME")
50
- }
51
- if e.Op&Chmod == Chmod {
52
- buffer.WriteString("|CHMOD")
53
- }
54
-
55
- // If buffer remains empty, return no event names
56
- if buffer.Len() == 0 {
57
- return fmt.Sprintf("%q: ", e.Name)
58
- }
59
-
60
- // Return a list of event names, with leading pipe character stripped
61
- return fmt.Sprintf("%q: %s", e.Name, buffer.String()[1:])
62
-}
Godeps/_workspace/src/gopkg.in/fsnotify.v1/inotify.go
deleted
-306
@@ -1,306 +0,0 @@
1
-// Copyright 2010 The Go Authors. All rights reserved.
2
-// Use of this source code is governed by a BSD-style
3
-// license that can be found in the LICENSE file.
4
-
5
-// +build linux
6
-
7
-package fsnotify
8
-
9
-import (
10
- "errors"
11
- "fmt"
12
- "io"
13
- "os"
14
- "path/filepath"
15
- "strings"
16
- "sync"
17
- "syscall"
18
- "unsafe"
19
-)
20
-
21
-// Watcher watches a set of files, delivering events to a channel.
22
-type Watcher struct {
23
- Events chan Event
24
- Errors chan error
25
- mu sync.Mutex // Map access
26
- fd int
27
- poller *fdPoller
28
- watches map[string]*watch // Map of inotify watches (key: path)
29
- paths map[int]string // Map of watched paths (key: watch descriptor)
30
- done chan struct{} // Channel for sending a "quit message" to the reader goroutine
31
- doneResp chan struct{} // Channel to respond to Close
32
-}
33
-
34
-// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events.
35
-func NewWatcher() (*Watcher, error) {
36
- // Create inotify fd
37
- fd, errno := syscall.InotifyInit()
38
- if fd == -1 {
39
- return nil, errno
40
- }
41
- // Create epoll
42
- poller, err := newFdPoller(fd)
43
- if err != nil {
44
- syscall.Close(fd)
45
- return nil, err
46
- }
47
- w := &Watcher{
48
- fd: fd,
49
- poller: poller,
50
- watches: make(map[string]*watch),
51
- paths: make(map[int]string),
52
- Events: make(chan Event),
53
- Errors: make(chan error),
54
- done: make(chan struct{}),
55
- doneResp: make(chan struct{}),
56
- }
57
-
58
- go w.readEvents()
59
- return w, nil
60
-}
61
-
62
-func (w *Watcher) isClosed() bool {
63
- select {
64
- case <-w.done:
65
- return true
66
- default:
67
- return false
68
- }
69
-}
70
-
71
-// Close removes all watches and closes the events channel.
72
-func (w *Watcher) Close() error {
73
- if w.isClosed() {
74
- return nil
75
- }
76
-
77
- // Send 'close' signal to goroutine, and set the Watcher to closed.
78
- close(w.done)
79
-
80
- // Wake up goroutine
81
- w.poller.wake()
82
-
83
- // Wait for goroutine to close
84
- <-w.doneResp
85
-
86
- return nil
87
-}
88
-
89
-// Add starts watching the named file or directory (non-recursively).
90
-func (w *Watcher) Add(name string) error {
91
- name = filepath.Clean(name)
92
- if w.isClosed() {
93
- return errors.New("inotify instance already closed")
94
- }
95
-
96
- const agnosticEvents = syscall.IN_MOVED_TO | syscall.IN_MOVED_FROM |
97
- syscall.IN_CREATE | syscall.IN_ATTRIB | syscall.IN_MODIFY |
98
- syscall.IN_MOVE_SELF | syscall.IN_DELETE | syscall.IN_DELETE_SELF
99
-
100
- var flags uint32 = agnosticEvents
101
-
102
- w.mu.Lock()
103
- watchEntry, found := w.watches[name]
104
- w.mu.Unlock()
105
- if found {
106
- watchEntry.flags |= flags
107
- flags |= syscall.IN_MASK_ADD
108
- }
109
- wd, errno := syscall.InotifyAddWatch(w.fd, name, flags)
110
- if wd == -1 {
111
- return errno
112
- }
113
-
114
- w.mu.Lock()
115
- w.watches[name] = &watch{wd: uint32(wd), flags: flags}
116
- w.paths[wd] = name
117
- w.mu.Unlock()
118
-
119
- return nil
120
-}
121
-
122
-// Remove stops watching the named file or directory (non-recursively).
123
-func (w *Watcher) Remove(name string) error {
124
- name = filepath.Clean(name)
125
-
126
- // Fetch the watch.
127
- w.mu.Lock()
128
- defer w.mu.Unlock()
129
- watch, ok := w.watches[name]
130
-
131
- // Remove it from inotify.
132
- if !ok {
133
- return fmt.Errorf("can't remove non-existent inotify watch for: %s", name)
134
- }
135
- // inotify_rm_watch will return EINVAL if the file has been deleted;
136
- // the inotify will already have been removed.
137
- // That means we can safely delete it from our watches, whatever inotify_rm_watch does.
138
- delete(w.watches, name)
139
- success, errno := syscall.InotifyRmWatch(w.fd, watch.wd)
140
- if success == -1 {
141
- // TODO: Perhaps it's not helpful to return an error here in every case.
142
- // the only two possible errors are:
143
- // EBADF, which happens when w.fd is not a valid file descriptor of any kind.
144
- // EINVAL, which is when fd is not an inotify descriptor or wd is not a valid watch descriptor.
145
- // Watch descriptors are invalidated when they are removed explicitly or implicitly;
146
- // explicitly by inotify_rm_watch, implicitly when the file they are watching is deleted.
147
- return errno
148
- }
149
- return nil
150
-}
151
-
152
-type watch struct {
153
- wd uint32 // Watch descriptor (as returned by the inotify_add_watch() syscall)
154
- flags uint32 // inotify flags of this watch (see inotify(7) for the list of valid flags)
155
-}
156
-
157
-// readEvents reads from the inotify file descriptor, converts the
158
-// received events into Event objects and sends them via the Events channel
159
-func (w *Watcher) readEvents() {
160
- var (
161
- buf [syscall.SizeofInotifyEvent * 4096]byte // Buffer for a maximum of 4096 raw events
162
- n int // Number of bytes read with read()
163
- errno error // Syscall errno
164
- ok bool // For poller.wait
165
- )
166
-
167
- defer close(w.doneResp)
168
- defer close(w.Errors)
169
- defer close(w.Events)
170
- defer syscall.Close(w.fd)
171
- defer w.poller.close()
172
-
173
- for {
174
- // See if we have been closed.
175
- if w.isClosed() {
176
- return
177
- }
178
-
179
- ok, errno = w.poller.wait()
180
- if errno != nil {
181
- select {
182
- case w.Errors <- errno:
183
- case <-w.done:
184
- return
185
- }
186
- continue
187
- }
188
-
189
- if !ok {
190
- continue
191
- }
192
-
193
- n, errno = syscall.Read(w.fd, buf[:])
194
- // If a signal interrupted execution, see if we've been asked to close, and try again.
195
- // http://man7.org/linux/man-pages/man7/signal.7.html :
196
- // "Before Linux 3.8, reads from an inotify(7) file descriptor were not restartable"
197
- if errno == syscall.EINTR {
198
- continue
199
- }
200
-
201
- // syscall.Read might have been woken up by Close. If so, we're done.
202
- if w.isClosed() {
203
- return
204
- }
205
-
206
- if n < syscall.SizeofInotifyEvent {
207
- var err error
208
- if n == 0 {
209
- // If EOF is received. This should really never happen.
210
- err = io.EOF
211
- } else if n < 0 {
212
- // If an error occured while reading.
213
- err = errno
214
- } else {
215
- // Read was too short.
216
- err = errors.New("notify: short read in readEvents()")
217
- }
218
- select {
219
- case w.Errors <- err:
220
- case <-w.done:
221
- return
222
- }
223
- continue
224
- }
225
-
226
- var offset uint32
227
- // We don't know how many events we just read into the buffer
228
- // While the offset points to at least one whole event...
229
- for offset <= uint32(n-syscall.SizeofInotifyEvent) {
230
- // Point "raw" to the event in the buffer
231
- raw := (*syscall.InotifyEvent)(unsafe.Pointer(&buf[offset]))
232
-
233
- mask := uint32(raw.Mask)
234
- nameLen := uint32(raw.Len)
235
- // If the event happened to the watched directory or the watched file, the kernel
236
- // doesn't append the filename to the event, but we would like to always fill the
237
- // the "Name" field with a valid filename. We retrieve the path of the watch from
238
- // the "paths" map.
239
- w.mu.Lock()
240
- name := w.paths[int(raw.Wd)]
241
- w.mu.Unlock()
242
- if nameLen > 0 {
243
- // Point "bytes" at the first byte of the filename
244
- bytes := (*[syscall.PathMax]byte)(unsafe.Pointer(&buf[offset+syscall.SizeofInotifyEvent]))
245
- // The filename is padded with NULL bytes. TrimRight() gets rid of those.
246
- name += "/" + strings.TrimRight(string(bytes[0:nameLen]), "\000")
247
- }
248
-
249
- event := newEvent(name, mask)
250
-
251
- // Send the events that are not ignored on the events channel
252
- if !event.ignoreLinux(mask) {
253
- select {
254
- case w.Events <- event:
255
- case <-w.done:
256
- return
257
- }
258
- }
259
-
260
- // Move to the next event in the buffer
261
- offset += syscall.SizeofInotifyEvent + nameLen
262
- }
263
- }
264
-}
265
-
266
-// Certain types of events can be "ignored" and not sent over the Events
267
-// channel. Such as events marked ignore by the kernel, or MODIFY events
268
-// against files that do not exist.
269
-func (e *Event) ignoreLinux(mask uint32) bool {
270
- // Ignore anything the inotify API says to ignore
271
- if mask&syscall.IN_IGNORED == syscall.IN_IGNORED {
272
- return true
273
- }
274
-
275
- // If the event is not a DELETE or RENAME, the file must exist.
276
- // Otherwise the event is ignored.
277
- // *Note*: this was put in place because it was seen that a MODIFY
278
- // event was sent after the DELETE. This ignores that MODIFY and
279
- // assumes a DELETE will come or has come if the file doesn't exist.
280
- if !(e.Op&Remove == Remove || e.Op&Rename == Rename) {
281
- _, statErr := os.Lstat(e.Name)
282
- return os.IsNotExist(statErr)
283
- }
284
- return false
285
-}
286
-
287
-// newEvent returns an platform-independent Event based on an inotify mask.
288
-func newEvent(name string, mask uint32) Event {
289
- e := Event{Name: name}
290
- if mask&syscall.IN_CREATE == syscall.IN_CREATE || mask&syscall.IN_MOVED_TO == syscall.IN_MOVED_TO {
291
- e.Op |= Create
292
- }
293
- if mask&syscall.IN_DELETE_SELF == syscall.IN_DELETE_SELF || mask&syscall.IN_DELETE == syscall.IN_DELETE {
294
- e.Op |= Remove
295
- }
296
- if mask&syscall.IN_MODIFY == syscall.IN_MODIFY {
297
- e.Op |= Write
298
- }
299
- if mask&syscall.IN_MOVE_SELF == syscall.IN_MOVE_SELF || mask&syscall.IN_MOVED_FROM == syscall.IN_MOVED_FROM {
300
- e.Op |= Rename
301
- }
302
- if mask&syscall.IN_ATTRIB == syscall.IN_ATTRIB {
303
- e.Op |= Chmod
304
- }
305
- return e
306
-}
Godeps/_workspace/src/gopkg.in/fsnotify.v1/inotify_poller.go
deleted
-186
@@ -1,186 +0,0 @@
1
-// Copyright 2015 The Go Authors. All rights reserved.
2
-// Use of this source code is governed by a BSD-style
3
-// license that can be found in the LICENSE file.
4
-
5
-// +build linux
6
-
7
-package fsnotify
8
-
9
-import (
10
- "errors"
11
- "syscall"
12
-)
13
-
14
-type fdPoller struct {
15
- fd int // File descriptor (as returned by the inotify_init() syscall)
16
- epfd int // Epoll file descriptor
17
- pipe [2]int // Pipe for waking up
18
-}
19
-
20
-func emptyPoller(fd int) *fdPoller {
21
- poller := new(fdPoller)
22
- poller.fd = fd
23
- poller.epfd = -1
24
- poller.pipe[0] = -1
25
- poller.pipe[1] = -1
26
- return poller
27
-}
28
-
29
-// Create a new inotify poller.
30
-// This creates an inotify handler, and an epoll handler.
31
-func newFdPoller(fd int) (*fdPoller, error) {
32
- var errno error
33
- poller := emptyPoller(fd)
34
- defer func() {
35
- if errno != nil {
36
- poller.close()
37
- }
38
- }()
39
- poller.fd = fd
40
-
41
- // Create epoll fd
42
- poller.epfd, errno = syscall.EpollCreate(1)
43
- if poller.epfd == -1 {
44
- return nil, errno
45
- }
46
- // Create pipe; pipe[0] is the read end, pipe[1] the write end.
47
- errno = syscall.Pipe2(poller.pipe[:], syscall.O_NONBLOCK)
48
- if errno != nil {
49
- return nil, errno
50
- }
51
-
52
- // Register inotify fd with epoll
53
- event := syscall.EpollEvent{
54
- Fd: int32(poller.fd),
55
- Events: syscall.EPOLLIN,
56
- }
57
- errno = syscall.EpollCtl(poller.epfd, syscall.EPOLL_CTL_ADD, poller.fd, &event)
58
- if errno != nil {
59
- return nil, errno
60
- }
61
-
62
- // Register pipe fd with epoll
63
- event = syscall.EpollEvent{
64
- Fd: int32(poller.pipe[0]),
65
- Events: syscall.EPOLLIN,
66
- }
67
- errno = syscall.EpollCtl(poller.epfd, syscall.EPOLL_CTL_ADD, poller.pipe[0], &event)
68
- if errno != nil {
69
- return nil, errno
70
- }
71
-
72
- return poller, nil
73
-}
74
-
75
-// Wait using epoll.
76
-// Returns true if something is ready to be read,
77
-// false if there is not.
78
-func (poller *fdPoller) wait() (bool, error) {
79
- // 3 possible events per fd, and 2 fds, makes a maximum of 6 events.
80
- // I don't know whether epoll_wait returns the number of events returned,
81
- // or the total number of events ready.
82
- // I decided to catch both by making the buffer one larger than the maximum.
83
- events := make([]syscall.EpollEvent, 7)
84
- for {
85
- n, errno := syscall.EpollWait(poller.epfd, events, -1)
86
- if n == -1 {
87
- if errno == syscall.EINTR {
88
- continue
89
- }
90
- return false, errno
91
- }
92
- if n == 0 {
93
- // If there are no events, try again.
94
- continue
95
- }
96
- if n > 6 {
97
- // This should never happen. More events were returned than should be possible.
98
- return false, errors.New("epoll_wait returned more events than I know what to do with")
99
- }
100
- ready := events[:n]
101
- epollhup := false
102
- epollerr := false
103
- epollin := false
104
- for _, event := range ready {
105
- if event.Fd == int32(poller.fd) {
106
- if event.Events&syscall.EPOLLHUP != 0 {
107
- // This should not happen, but if it does, treat it as a wakeup.
108
- epollhup = true
109
- }
110
- if event.Events&syscall.EPOLLERR != 0 {
111
- // If an error is waiting on the file descriptor, we should pretend
112
- // something is ready to read, and let syscall.Read pick up the error.
113
- epollerr = true
114
- }
115
- if event.Events&syscall.EPOLLIN != 0 {
116
- // There is data to read.
117
- epollin = true
118
- }
119
- }
120
- if event.Fd == int32(poller.pipe[0]) {
121
- if event.Events&syscall.EPOLLHUP != 0 {
122
- // Write pipe descriptor was closed, by us. This means we're closing down the
123
- // watcher, and we should wake up.
124
- }
125
- if event.Events&syscall.EPOLLERR != 0 {
126
- // If an error is waiting on the pipe file descriptor.
127
- // This is an absolute mystery, and should never ever happen.
128
- return false, errors.New("Error on the pipe descriptor.")
129
- }
130
- if event.Events&syscall.EPOLLIN != 0 {
131
- // This is a regular wakeup, so we have to clear the buffer.
132
- err := poller.clearWake()
133
- if err != nil {
134
- return false, err
135
- }
136
- }
137
- }
138
- }
139
-
140
- if epollhup || epollerr || epollin {
141
- return true, nil
142
- }
143
- return false, nil
144
- }
145
-}
146
-
147
-// Close the write end of the poller.
148
-func (poller *fdPoller) wake() error {
149
- buf := make([]byte, 1)
150
- n, errno := syscall.Write(poller.pipe[1], buf)
151
- if n == -1 {
152
- if errno == syscall.EAGAIN {
153
- // Buffer is full, poller will wake.
154
- return nil
155
- }
156
- return errno
157
- }
158
- return nil
159
-}
160
-
161
-func (poller *fdPoller) clearWake() error {
162
- // You have to be woken up a LOT in order to get to 100!
163
- buf := make([]byte, 100)
164
- n, errno := syscall.Read(poller.pipe[0], buf)
165
- if n == -1 {
166
- if errno == syscall.EAGAIN {
167
- // Buffer is empty, someone else cleared our wake.
168
- return nil
169
- }
170
- return errno
171
- }
172
- return nil
173
-}
174
-
175
-// Close all poller file descriptors, but not the one passed to it.
176
-func (poller *fdPoller) close() {
177
- if poller.pipe[1] != -1 {
178
- syscall.Close(poller.pipe[1])
179
- }
180
- if poller.pipe[0] != -1 {
181
- syscall.Close(poller.pipe[0])
182
- }
183
- if poller.epfd != -1 {
184
- syscall.Close(poller.epfd)
185
- }
186
-}
Godeps/_workspace/src/gopkg.in/fsnotify.v1/inotify_poller_test.go
deleted
-228
@@ -1,228 +0,0 @@
1
-// Copyright 2015 The Go Authors. All rights reserved.
2
-// Use of this source code is governed by a BSD-style
3
-// license that can be found in the LICENSE file.
4
-
5
-// +build linux
6
-
7
-package fsnotify
8
-
9
-import (
10
- "syscall"
11
- "testing"
12
- "time"
13
-)
14
-
15
-type testFd [2]int
16
-
17
-func makeTestFd(t *testing.T) testFd {
18
- var tfd testFd
19
- errno := syscall.Pipe(tfd[:])
20
- if errno != nil {
21
- t.Fatalf("Failed to create pipe: %v", errno)
22
- }
23
- return tfd
24
-}
25
-
26
-func (tfd testFd) fd() int {
27
- return tfd[0]
28
-}
29
-
30
-func (tfd testFd) closeWrite(t *testing.T) {
31
- errno := syscall.Close(tfd[1])
32
- if errno != nil {
33
- t.Fatalf("Failed to close write end of pipe: %v", errno)
34
- }
35
-}
36
-
37
-func (tfd testFd) put(t *testing.T) {
38
- buf := make([]byte, 10)
39
- _, errno := syscall.Write(tfd[1], buf)
40
- if errno != nil {
41
- t.Fatalf("Failed to write to pipe: %v", errno)
42
- }
43
-}
44
-
45
-func (tfd testFd) get(t *testing.T) {
46
- buf := make([]byte, 10)
47
- _, errno := syscall.Read(tfd[0], buf)
48
- if errno != nil {
49
- t.Fatalf("Failed to read from pipe: %v", errno)
50
- }
51
-}
52
-
53
-func (tfd testFd) close() {
54
- syscall.Close(tfd[1])
55
- syscall.Close(tfd[0])
56
-}
57
-
58
-func makePoller(t *testing.T) (testFd, *fdPoller) {
59
- tfd := makeTestFd(t)
60
- poller, err := newFdPoller(tfd.fd())
61
- if err != nil {
62
- t.Fatalf("Failed to create poller: %v", err)
63
- }
64
- return tfd, poller
65
-}
66
-
67
-func TestPollerWithBadFd(t *testing.T) {
68
- _, err := newFdPoller(-1)
69
- if err != syscall.EBADF {
70
- t.Fatalf("Expected EBADF, got: %v", err)
71
- }
72
-}
73
-
74
-func TestPollerWithData(t *testing.T) {
75
- tfd, poller := makePoller(t)
76
- defer tfd.close()
77
- defer poller.close()
78
-
79
- tfd.put(t)
80
- ok, err := poller.wait()
81
- if err != nil {
82
- t.Fatalf("poller failed: %v", err)
83
- }
84
- if !ok {
85
- t.Fatalf("expected poller to return true")
86
- }
87
- tfd.get(t)
88
-}
89
-
90
-func TestPollerWithWakeup(t *testing.T) {
91
- tfd, poller := makePoller(t)
92
- defer tfd.close()
93
- defer poller.close()
94
-
95
- err := poller.wake()
96
- if err != nil {
97
- t.Fatalf("wake failed: %v", err)
98
- }
99
- ok, err := poller.wait()
100
- if err != nil {
101
- t.Fatalf("poller failed: %v", err)
102
- }
103
- if ok {
104
- t.Fatalf("expected poller to return false")
105
- }
106
-}
107
-
108
-func TestPollerWithClose(t *testing.T) {
109
- tfd, poller := makePoller(t)
110
- defer tfd.close()
111
- defer poller.close()
112
-
113
- tfd.closeWrite(t)
114
- ok, err := poller.wait()
115
- if err != nil {
116
- t.Fatalf("poller failed: %v", err)
117
- }
118
- if !ok {
119
- t.Fatalf("expected poller to return true")
120
- }
121
-}
122
-
123
-func TestPollerWithWakeupAndData(t *testing.T) {
124
- tfd, poller := makePoller(t)
125
- defer tfd.close()
126
- defer poller.close()
127
-
128
- tfd.put(t)
129
- err := poller.wake()
130
- if err != nil {
131
- t.Fatalf("wake failed: %v", err)
132
- }
133
-
134
- // both data and wakeup
135
- ok, err := poller.wait()
136
- if err != nil {
137
- t.Fatalf("poller failed: %v", err)
138
- }
139
- if !ok {
140
- t.Fatalf("expected poller to return true")
141
- }
142
-
143
- // data is still in the buffer, wakeup is cleared
144
- ok, err = poller.wait()
145
- if err != nil {
146
- t.Fatalf("poller failed: %v", err)
147
- }
148
- if !ok {
149
- t.Fatalf("expected poller to return true")
150
- }
151
-
152
- tfd.get(t)
153
- // data is gone, only wakeup now
154
- err = poller.wake()
155
- if err != nil {
156
- t.Fatalf("wake failed: %v", err)
157
- }
158
- ok, err = poller.wait()
159
- if err != nil {
160
- t.Fatalf("poller failed: %v", err)
161
- }
162
- if ok {
163
- t.Fatalf("expected poller to return false")
164
- }
165
-}
166
-
167
-func TestPollerConcurrent(t *testing.T) {
168
- tfd, poller := makePoller(t)
169
- defer tfd.close()
170
- defer poller.close()
171
-
172
- oks := make(chan bool)
173
- live := make(chan bool)
174
- defer close(live)
175
- go func() {
176
- defer close(oks)
177
- for {
178
- ok, err := poller.wait()
179
- if err != nil {
180
- t.Fatalf("poller failed: %v", err)
181
- }
182
- oks <- ok
183
- if !<-live {
184
- return
185
- }
186
- }
187
- }()
188
-
189
- // Try a write
190
- select {
191
- case <-time.After(50 * time.Millisecond):
192
- case <-oks:
193
- t.Fatalf("poller did not wait")
194
- }
195
- tfd.put(t)
196
- if !<-oks {
197
- t.Fatalf("expected true")
198
- }
199
- tfd.get(t)
200
- live <- true
201
-
202
- // Try a wakeup
203
- select {
204
- case <-time.After(50 * time.Millisecond):
205
- case <-oks:
206
- t.Fatalf("poller did not wait")
207
- }
208
- err := poller.wake()
209
- if err != nil {
210
- t.Fatalf("wake failed: %v", err)
211
- }
212
- if <-oks {
213
- t.Fatalf("expected false")
214
- }
215
- live <- true
216
-
217
- // Try a close
218
- select {
219
- case <-time.After(50 * time.Millisecond):
220
- case <-oks:
221
- t.Fatalf("poller did not wait")
222
- }
223
- tfd.closeWrite(t)
224
- if !<-oks {
225
- t.Fatalf("expected true")
226
- }
227
- tfd.get(t)
228
-}
Godeps/_workspace/src/gopkg.in/fsnotify.v1/inotify_test.go
deleted
-292
@@ -1,292 +0,0 @@
1
-// Copyright 2015 The Go Authors. All rights reserved.
2
-// Use of this source code is governed by a BSD-style
3
-// license that can be found in the LICENSE file.
4
-
5
-// +build linux
6
-
7
-package fsnotify
8
-
9
-import (
10
- "os"
11
- "path/filepath"
12
- "syscall"
13
- "testing"
14
- "time"
15
-)
16
-
17
-func TestInotifyCloseRightAway(t *testing.T) {
18
- w, err := NewWatcher()
19
- if err != nil {
20
- t.Fatalf("Failed to create watcher")
21
- }
22
-
23
- // Close immediately; it won't even reach the first syscall.Read.
24
- w.Close()
25
-
26
- // Wait for the close to complete.
27
- <-time.After(50 * time.Millisecond)
28
- isWatcherReallyClosed(t, w)
29
-}
30
-
31
-func TestInotifyCloseSlightlyLater(t *testing.T) {
32
- w, err := NewWatcher()
33
- if err != nil {
34
- t.Fatalf("Failed to create watcher")
35
- }
36
-
37
- // Wait until readEvents has reached syscall.Read, and Close.
38
- <-time.After(50 * time.Millisecond)
39
- w.Close()
40
-
41
- // Wait for the close to complete.
42
- <-time.After(50 * time.Millisecond)
43
- isWatcherReallyClosed(t, w)
44
-}
45
-
46
-func TestInotifyCloseSlightlyLaterWithWatch(t *testing.T) {
47
- testDir := tempMkdir(t)
48
- defer os.RemoveAll(testDir)
49
-
50
- w, err := NewWatcher()
51
- if err != nil {
52
- t.Fatalf("Failed to create watcher")
53
- }
54
- w.Add(testDir)
55
-
56
- // Wait until readEvents has reached syscall.Read, and Close.
57
- <-time.After(50 * time.Millisecond)
58
- w.Close()
59
-
60
- // Wait for the close to complete.
61
- <-time.After(50 * time.Millisecond)
62
- isWatcherReallyClosed(t, w)
63
-}
64
-
65
-func TestInotifyCloseAfterRead(t *testing.T) {
66
- testDir := tempMkdir(t)
67
- defer os.RemoveAll(testDir)
68
-
69
- w, err := NewWatcher()
70
- if err != nil {
71
- t.Fatalf("Failed to create watcher")
72
- }
73
-
74
- err = w.Add(testDir)
75
- if err != nil {
76
- t.Fatalf("Failed to add .")
77
- }
78
-
79
- // Generate an event.
80
- os.Create(filepath.Join(testDir, "somethingSOMETHINGsomethingSOMETHING"))
81
-
82
- // Wait for readEvents to read the event, then close the watcher.
83
- <-time.After(50 * time.Millisecond)
84
- w.Close()
85
-
86
- // Wait for the close to complete.
87
- <-time.After(50 * time.Millisecond)
88
- isWatcherReallyClosed(t, w)
89
-}
90
-
91
-func isWatcherReallyClosed(t *testing.T, w *Watcher) {
92
- select {
93
- case err, ok := <-w.Errors:
94
- if ok {
95
- t.Fatalf("w.Errors is not closed; readEvents is still alive after closing (error: %v)", err)
96
- }
97
- default:
98
- t.Fatalf("w.Errors would have blocked; readEvents is still alive!")
99
- }
100
-
101
- select {
102
- case _, ok := <-w.Events:
103
- if ok {
104
- t.Fatalf("w.Events is not closed; readEvents is still alive after closing")
105
- }
106
- default:
107
- t.Fatalf("w.Events would have blocked; readEvents is still alive!")
108
- }
109
-}
110
-
111
-func TestInotifyCloseCreate(t *testing.T) {
112
- testDir := tempMkdir(t)
113
- defer os.RemoveAll(testDir)
114
-
115
- w, err := NewWatcher()
116
- if err != nil {
117
- t.Fatalf("Failed to create watcher: %v", err)
118
- }
119
- defer w.Close()
120
-
121
- err = w.Add(testDir)
122
- if err != nil {
123
- t.Fatalf("Failed to add testDir: %v", err)
124
- }
125
- h, err := os.Create(filepath.Join(testDir, "testfile"))
126
- if err != nil {
127
- t.Fatalf("Failed to create file in testdir: %v", err)
128
- }
129
- h.Close()
130
- select {
131
- case _ = <-w.Events:
132
- case err := <-w.Errors:
133
- t.Fatalf("Error from watcher: %v", err)
134
- case <-time.After(50 * time.Millisecond):
135
- t.Fatalf("Took too long to wait for event")
136
- }
137
-
138
- // At this point, we've received one event, so the goroutine is ready.
139
- // It's also blocking on syscall.Read.
140
- // Now we try to swap the file descriptor under its nose.
141
- w.Close()
142
- w, err = NewWatcher()
143
- defer w.Close()
144
- if err != nil {
145
- t.Fatalf("Failed to create second watcher: %v", err)
146
- }
147
-
148
- <-time.After(50 * time.Millisecond)
149
- err = w.Add(testDir)
150
- if err != nil {
151
- t.Fatalf("Error adding testDir again: %v", err)
152
- }
153
-}
154
-
155
-func TestInotifyStress(t *testing.T) {
156
- testDir := tempMkdir(t)
157
- defer os.RemoveAll(testDir)
158
- testFile := filepath.Join(testDir, "testfile")
159
-
160
- w, err := NewWatcher()
161
- if err != nil {
162
- t.Fatalf("Failed to create watcher: %v", err)
163
- }
164
- defer w.Close()
165
-
166
- killchan := make(chan struct{})
167
- defer close(killchan)
168
-
169
- err = w.Add(testDir)
170
- if err != nil {
171
- t.Fatalf("Failed to add testDir: %v", err)
172
- }
173
-
174
- proc, err := os.FindProcess(os.Getpid())
175
- if err != nil {
176
- t.Fatalf("Error finding process: %v", err)
177
- }
178
-
179
- go func() {
180
- for {
181
- select {
182
- case <-time.After(5 * time.Millisecond):
183
- err := proc.Signal(syscall.SIGUSR1)
184
- if err != nil {
185
- t.Fatalf("Signal failed: %v", err)
186
- }
187
- case <-killchan:
188
- return
189
- }
190
- }
191
- }()
192
-
193
- go func() {
194
- for {
195
- select {
196
- case <-time.After(11 * time.Millisecond):
197
- err := w.poller.wake()
198
- if err != nil {
199
- t.Fatalf("Wake failed: %v", err)
200
- }
201
- case <-killchan:
202
- return
203
- }
204
- }
205
- }()
206
-
207
- go func() {
208
- for {
209
- select {
210
- case <-killchan:
211
- return
212
- default:
213
- handle, err := os.Create(testFile)
214
- if err != nil {
215
- t.Fatalf("Create failed: %v", err)
216
- }
217
- handle.Close()
218
- time.Sleep(time.Millisecond)
219
- err = os.Remove(testFile)
220
- if err != nil {
221
- t.Fatalf("Remove failed: %v", err)
222
- }
223
- }
224
- }
225
- }()
226
-
227
- creates := 0
228
- removes := 0
229
- after := time.After(5 * time.Second)
230
- for {
231
- select {
232
- case <-after:
233
- if creates-removes > 1 || creates-removes < -1 {
234
- t.Fatalf("Creates and removes should not be off by more than one: %d creates, %d removes", creates, removes)
235
- }
236
- if creates < 50 {
237
- t.Fatalf("Expected at least 50 creates, got %d", creates)
238
- }
239
- return
240
- case err := <-w.Errors:
241
- t.Fatalf("Got an error from watcher: %v", err)
242
- case evt := <-w.Events:
243
- if evt.Name != testFile {
244
- t.Fatalf("Got an event for an unknown file: %s", evt.Name)
245
- }
246
- if evt.Op == Create {
247
- creates++
248
- }
249
- if evt.Op == Remove {
250
- removes++
251
- }
252
- }
253
- }
254
-}
255
-
256
-func TestInotifyRemoveTwice(t *testing.T) {
257
- testDir := tempMkdir(t)
258
- defer os.RemoveAll(testDir)
259
- testFile := filepath.Join(testDir, "testfile")
260
-
261
- handle, err := os.Create(testFile)
262
- if err != nil {
263
- t.Fatalf("Create failed: %v", err)
264
- }
265
- handle.Close()
266
-
267
- w, err := NewWatcher()
268
- if err != nil {
269
- t.Fatalf("Failed to create watcher: %v", err)
270
- }
271
- defer w.Close()
272
-
273
- err = w.Add(testFile)
274
- if err != nil {
275
- t.Fatalf("Failed to add testFile: %v", err)
276
- }
277
-
278
- err = os.Remove(testFile)
279
- if err != nil {
280
- t.Fatalf("Failed to remove testFile: %v", err)
281
- }
282
-
283
- err = w.Remove(testFile)
284
- if err != syscall.EINVAL {
285
- t.Fatalf("Expected EINVAL from Remove, got: %v", err)
286
- }
287
-
288
- err = w.Remove(testFile)
289
- if err == syscall.EINVAL {
290
- t.Fatalf("Got EINVAL again, watch was not removed")
291
- }
292
-}
Godeps/_workspace/src/gopkg.in/fsnotify.v1/integration_test.go
deleted
-1135
@@ -1,1135 +0,0 @@
1
-// Copyright 2010 The Go Authors. All rights reserved.
2
-// Use of this source code is governed by a BSD-style
3
-// license that can be found in the LICENSE file.
4
-
5
-// +build !plan9,!solaris
6
-
7
-package fsnotify
8
-
9
-import (
10
- "io/ioutil"
11
- "os"
12
- "os/exec"
13
- "path/filepath"
14
- "runtime"
15
- "sync/atomic"
16
- "testing"
17
- "time"
18
-)
19
-
20
-// An atomic counter
21
-type counter struct {
22
- val int32
23
-}
24
-
25
-func (c *counter) increment() {
26
- atomic.AddInt32(&c.val, 1)
27
-}
28
-
29
-func (c *counter) value() int32 {
30
- return atomic.LoadInt32(&c.val)
31
-}
32
-
33
-func (c *counter) reset() {
34
- atomic.StoreInt32(&c.val, 0)
35
-}
36
-
37
-// tempMkdir makes a temporary directory
38
-func tempMkdir(t *testing.T) string {
39
- dir, err := ioutil.TempDir("", "fsnotify")
40
- if err != nil {
41
- t.Fatalf("failed to create test directory: %s", err)
42
- }
43
- return dir
44
-}
45
-
46
-// newWatcher initializes an fsnotify Watcher instance.
47
-func newWatcher(t *testing.T) *Watcher {
48
- watcher, err := NewWatcher()
49
- if err != nil {
50
- t.Fatalf("NewWatcher() failed: %s", err)
51
- }
52
- return watcher
53
-}
54
-
55
-// addWatch adds a watch for a directory
56
-func addWatch(t *testing.T, watcher *Watcher, dir string) {
57
- if err := watcher.Add(dir); err != nil {
58
- t.Fatalf("watcher.Add(%q) failed: %s", dir, err)
59
- }
60
-}
61
-
62
-func TestFsnotifyMultipleOperations(t *testing.T) {
63
- watcher := newWatcher(t)
64
-
65
- // Receive errors on the error channel on a separate goroutine
66
- go func() {
67
- for err := range watcher.Errors {
68
- t.Fatalf("error received: %s", err)
69
- }
70
- }()
71
-
72
- // Create directory to watch
73
- testDir := tempMkdir(t)
74
- defer os.RemoveAll(testDir)
75
-
76
- // Create directory that's not watched
77
- testDirToMoveFiles := tempMkdir(t)
78
- defer os.RemoveAll(testDirToMoveFiles)
79
-
80
- testFile := filepath.Join(testDir, "TestFsnotifySeq.testfile")
81
- testFileRenamed := filepath.Join(testDirToMoveFiles, "TestFsnotifySeqRename.testfile")
82
-
83
- addWatch(t, watcher, testDir)
84
-
85
- // Receive events on the event channel on a separate goroutine
86
- eventstream := watcher.Events
87
- var createReceived, modifyReceived, deleteReceived, renameReceived counter
88
- done := make(chan bool)
89
- go func() {
90
- for event := range eventstream {
91
- // Only count relevant events
92
- if event.Name == filepath.Clean(testDir) || event.Name == filepath.Clean(testFile) {
93
- t.Logf("event received: %s", event)
94
- if event.Op&Remove == Remove {
95
- deleteReceived.increment()
96
- }
97
- if event.Op&Write == Write {
98
- modifyReceived.increment()
99
- }
100
- if event.Op&Create == Create {
101
- createReceived.increment()
102
- }
103
- if event.Op&Rename == Rename {
104
- renameReceived.increment()
105
- }
106
- } else {
107
- t.Logf("unexpected event received: %s", event)
108
- }
109
- }
110
- done <- true
111
- }()
112
-
113
- // Create a file
114
- // This should add at least one event to the fsnotify event queue
115
- var f *os.File
116
- f, err := os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
117
- if err != nil {
118
- t.Fatalf("creating test file failed: %s", err)
119
- }
120
- f.Sync()
121
-
122
- time.Sleep(time.Millisecond)
123
- f.WriteString("data")
124
- f.Sync()
125
- f.Close()
126
-
127
- time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
128
-
129
- if err := testRename(testFile, testFileRenamed); err != nil {
130
- t.Fatalf("rename failed: %s", err)
131
- }
132
-
133
- // Modify the file outside of the watched dir
134
- f, err = os.Open(testFileRenamed)
135
- if err != nil {
136
- t.Fatalf("open test renamed file failed: %s", err)
137
- }
138
- f.WriteString("data")
139
- f.Sync()
140
- f.Close()
141
-
142
- time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
143
-
144
- // Recreate the file that was moved
145
- f, err = os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
146
- if err != nil {
147
- t.Fatalf("creating test file failed: %s", err)
148
- }
149
- f.Close()
150
- time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
151
-
152
- // We expect this event to be received almost immediately, but let's wait 500 ms to be sure
153
- time.Sleep(500 * time.Millisecond)
154
- cReceived := createReceived.value()
155
- if cReceived != 2 {
156
- t.Fatalf("incorrect number of create events received after 500 ms (%d vs %d)", cReceived, 2)
157
- }
158
- mReceived := modifyReceived.value()
159
- if mReceived != 1 {
160
- t.Fatalf("incorrect number of modify events received after 500 ms (%d vs %d)", mReceived, 1)
161
- }
162
- dReceived := deleteReceived.value()
163
- rReceived := renameReceived.value()
164
- if dReceived+rReceived != 1 {
165
- t.Fatalf("incorrect number of rename+delete events received after 500 ms (%d vs %d)", rReceived+dReceived, 1)
166
- }
167
-
168
- // Try closing the fsnotify instance
169
- t.Log("calling Close()")
170
- watcher.Close()
171
- t.Log("waiting for the event channel to become closed...")
172
- select {
173
- case <-done:
174
- t.Log("event channel closed")
175
- case <-time.After(2 * time.Second):
176
- t.Fatal("event stream was not closed after 2 seconds")
177
- }
178
-}
179
-
180
-func TestFsnotifyMultipleCreates(t *testing.T) {
181
- watcher := newWatcher(t)
182
-
183
- // Receive errors on the error channel on a separate goroutine
184
- go func() {
185
- for err := range watcher.Errors {
186
- t.Fatalf("error received: %s", err)
187
- }
188
- }()
189
-
190
- // Create directory to watch
191
- testDir := tempMkdir(t)
192
- defer os.RemoveAll(testDir)
193
-
194
- testFile := filepath.Join(testDir, "TestFsnotifySeq.testfile")
195
-
196
- addWatch(t, watcher, testDir)
197
-
198
- // Receive events on the event channel on a separate goroutine
199
- eventstream := watcher.Events
200
- var createReceived, modifyReceived, deleteReceived counter
201
- done := make(chan bool)
202
- go func() {
203
- for event := range eventstream {
204
- // Only count relevant events
205
- if event.Name == filepath.Clean(testDir) || event.Name == filepath.Clean(testFile) {
206
- t.Logf("event received: %s", event)
207
- if event.Op&Remove == Remove {
208
- deleteReceived.increment()
209
- }
210
- if event.Op&Create == Create {
211
- createReceived.increment()
212
- }
213
- if event.Op&Write == Write {
214
- modifyReceived.increment()
215
- }
216
- } else {
217
- t.Logf("unexpected event received: %s", event)
218
- }
219
- }
220
- done <- true
221
- }()
222
-
223
- // Create a file
224
- // This should add at least one event to the fsnotify event queue
225
- var f *os.File
226
- f, err := os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
227
- if err != nil {
228
- t.Fatalf("creating test file failed: %s", err)
229
- }
230
- f.Sync()
231
-
232
- time.Sleep(time.Millisecond)
233
- f.WriteString("data")
234
- f.Sync()
235
- f.Close()
236
-
237
- time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
238
-
239
- os.Remove(testFile)
240
-
241
- time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
242
-
243
- // Recreate the file
244
- f, err = os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
245
- if err != nil {
246
- t.Fatalf("creating test file failed: %s", err)
247
- }
248
- f.Close()
249
- time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
250
-
251
- // Modify
252
- f, err = os.OpenFile(testFile, os.O_WRONLY, 0666)
253
- if err != nil {
254
- t.Fatalf("creating test file failed: %s", err)
255
- }
256
- f.Sync()
257
-
258
- time.Sleep(time.Millisecond)
259
- f.WriteString("data")
260
- f.Sync()
261
- f.Close()
262
-
263
- time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
264
-
265
- // Modify
266
- f, err = os.OpenFile(testFile, os.O_WRONLY, 0666)
267
- if err != nil {
268
- t.Fatalf("creating test file failed: %s", err)
269
- }
270
- f.Sync()
271
-
272
- time.Sleep(time.Millisecond)
273
- f.WriteString("data")
274
- f.Sync()
275
- f.Close()
276
-
277
- time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
278
-
279
- // We expect this event to be received almost immediately, but let's wait 500 ms to be sure
280
- time.Sleep(500 * time.Millisecond)
281
- cReceived := createReceived.value()
282
- if cReceived != 2 {
283
- t.Fatalf("incorrect number of create events received after 500 ms (%d vs %d)", cReceived, 2)
284
- }
285
- mReceived := modifyReceived.value()
286
- if mReceived < 3 {
287
- t.Fatalf("incorrect number of modify events received after 500 ms (%d vs atleast %d)", mReceived, 3)
288
- }
289
- dReceived := deleteReceived.value()
290
- if dReceived != 1 {
291
- t.Fatalf("incorrect number of rename+delete events received after 500 ms (%d vs %d)", dReceived, 1)
292
- }
293
-
294
- // Try closing the fsnotify instance
295
- t.Log("calling Close()")
296
- watcher.Close()
297
- t.Log("waiting for the event channel to become closed...")
298
- select {
299
- case <-done:
300
- t.Log("event channel closed")
301
- case <-time.After(2 * time.Second):
302
- t.Fatal("event stream was not closed after 2 seconds")
303
- }
304
-}
305
-
306
-func TestFsnotifyDirOnly(t *testing.T) {
307
- watcher := newWatcher(t)
308
-
309
- // Create directory to watch
310
- testDir := tempMkdir(t)
311
- defer os.RemoveAll(testDir)
312
-
313
- // Create a file before watching directory
314
- // This should NOT add any events to the fsnotify event queue
315
- testFileAlreadyExists := filepath.Join(testDir, "TestFsnotifyEventsExisting.testfile")
316
- {
317
- var f *os.File
318
- f, err := os.OpenFile(testFileAlreadyExists, os.O_WRONLY|os.O_CREATE, 0666)
319
- if err != nil {
320
- t.Fatalf("creating test file failed: %s", err)
321
- }
322
- f.Sync()
323
- f.Close()
324
- }
325
-
326
- addWatch(t, watcher, testDir)
327
-
328
- // Receive errors on the error channel on a separate goroutine
329
- go func() {
330
- for err := range watcher.Errors {
331
- t.Fatalf("error received: %s", err)
332
- }
333
- }()
334
-
335
- testFile := filepath.Join(testDir, "TestFsnotifyDirOnly.testfile")
336
-
337
- // Receive events on the event channel on a separate goroutine
338
- eventstream := watcher.Events
339
- var createReceived, modifyReceived, deleteReceived counter
340
- done := make(chan bool)
341
- go func() {
342
- for event := range eventstream {
343
- // Only count relevant events
344
- if event.Name == filepath.Clean(testDir) || event.Name == filepath.Clean(testFile) || event.Name == filepath.Clean(testFileAlreadyExists) {
345
- t.Logf("event received: %s", event)
346
- if event.Op&Remove == Remove {
347
- deleteReceived.increment()
348
- }
349
- if event.Op&Write == Write {
350
- modifyReceived.increment()
351
- }
352
- if event.Op&Create == Create {
353
- createReceived.increment()
354
- }
355
- } else {
356
- t.Logf("unexpected event received: %s", event)
357
- }
358
- }
359
- done <- true
360
- }()
361
-
362
- // Create a file
363
- // This should add at least one event to the fsnotify event queue
364
- var f *os.File
365
- f, err := os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
366
- if err != nil {
367
- t.Fatalf("creating test file failed: %s", err)
368
- }
369
- f.Sync()
370
-
371
- time.Sleep(time.Millisecond)
372
- f.WriteString("data")
373
- f.Sync()
374
- f.Close()
375
-
376
- time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
377
-
378
- os.Remove(testFile)
379
- os.Remove(testFileAlreadyExists)
380
-
381
- // We expect this event to be received almost immediately, but let's wait 500 ms to be sure
382
- time.Sleep(500 * time.Millisecond)
383
- cReceived := createReceived.value()
384
- if cReceived != 1 {
385
- t.Fatalf("incorrect number of create events received after 500 ms (%d vs %d)", cReceived, 1)
386
- }
387
- mReceived := modifyReceived.value()
388
- if mReceived != 1 {
389
- t.Fatalf("incorrect number of modify events received after 500 ms (%d vs %d)", mReceived, 1)
390
- }
391
- dReceived := deleteReceived.value()
392
- if dReceived != 2 {
393
- t.Fatalf("incorrect number of delete events received after 500 ms (%d vs %d)", dReceived, 2)
394
- }
395
-
396
- // Try closing the fsnotify instance
397
- t.Log("calling Close()")
398
- watcher.Close()
399
- t.Log("waiting for the event channel to become closed...")
400
- select {
401
- case <-done:
402
- t.Log("event channel closed")
403
- case <-time.After(2 * time.Second):
404
- t.Fatal("event stream was not closed after 2 seconds")
405
- }
406
-}
407
-
408
-func TestFsnotifyDeleteWatchedDir(t *testing.T) {
409
- watcher := newWatcher(t)
410
- defer watcher.Close()
411
-
412
- // Create directory to watch
413
- testDir := tempMkdir(t)
414
- defer os.RemoveAll(testDir)
415
-
416
- // Create a file before watching directory
417
- testFileAlreadyExists := filepath.Join(testDir, "TestFsnotifyEventsExisting.testfile")
418
- {
419
- var f *os.File
420
- f, err := os.OpenFile(testFileAlreadyExists, os.O_WRONLY|os.O_CREATE, 0666)
421
- if err != nil {
422
- t.Fatalf("creating test file failed: %s", err)
423
- }
424
- f.Sync()
425
- f.Close()
426
- }
427
-
428
- addWatch(t, watcher, testDir)
429
-
430
- // Add a watch for testFile
431
- addWatch(t, watcher, testFileAlreadyExists)
432
-
433
- // Receive errors on the error channel on a separate goroutine
434
- go func() {
435
- for err := range watcher.Errors {
436
- t.Fatalf("error received: %s", err)
437
- }
438
- }()
439
-
440
- // Receive events on the event channel on a separate goroutine
441
- eventstream := watcher.Events
442
- var deleteReceived counter
443
- go func() {
444
- for event := range eventstream {
445
- // Only count relevant events
446
- if event.Name == filepath.Clean(testDir) || event.Name == filepath.Clean(testFileAlreadyExists) {
447
- t.Logf("event received: %s", event)
448
- if event.Op&Remove == Remove {
449
- deleteReceived.increment()
450
- }
451
- } else {
452
- t.Logf("unexpected event received: %s", event)
453
- }
454
- }
455
- }()
456
-
457
- os.RemoveAll(testDir)
458
-
459
- // We expect this event to be received almost immediately, but let's wait 500 ms to be sure
460
- time.Sleep(500 * time.Millisecond)
461
- dReceived := deleteReceived.value()
462
- if dReceived < 2 {
463
- t.Fatalf("did not receive at least %d delete events, received %d after 500 ms", 2, dReceived)
464
- }
465
-}
466
-
467
-func TestFsnotifySubDir(t *testing.T) {
468
- watcher := newWatcher(t)
469
-
470
- // Create directory to watch
471
- testDir := tempMkdir(t)
472
- defer os.RemoveAll(testDir)
473
-
474
- testFile1 := filepath.Join(testDir, "TestFsnotifyFile1.testfile")
475
- testSubDir := filepath.Join(testDir, "sub")
476
- testSubDirFile := filepath.Join(testDir, "sub/TestFsnotifyFile1.testfile")
477
-
478
- // Receive errors on the error channel on a separate goroutine
479
- go func() {
480
- for err := range watcher.Errors {
481
- t.Fatalf("error received: %s", err)
482
- }
483
- }()
484
-
485
- // Receive events on the event channel on a separate goroutine
486
- eventstream := watcher.Events
487
- var createReceived, deleteReceived counter
488
- done := make(chan bool)
489
- go func() {
490
- for event := range eventstream {
491
- // Only count relevant events
492
- if event.Name == filepath.Clean(testDir) || event.Name == filepath.Clean(testSubDir) || event.Name == filepath.Clean(testFile1) {
493
- t.Logf("event received: %s", event)
494
- if event.Op&Create == Create {
495
- createReceived.increment()
496
- }
497
- if event.Op&Remove == Remove {
498
- deleteReceived.increment()
499
- }
500
- } else {
501
- t.Logf("unexpected event received: %s", event)
502
- }
503
- }
504
- done <- true
505
- }()
506
-
507
- addWatch(t, watcher, testDir)
508
-
509
- // Create sub-directory
510
- if err := os.Mkdir(testSubDir, 0777); err != nil {
511
- t.Fatalf("failed to create test sub-directory: %s", err)
512
- }
513
-
514
- // Create a file
515
- var f *os.File
516
- f, err := os.OpenFile(testFile1, os.O_WRONLY|os.O_CREATE, 0666)
517
- if err != nil {
518
- t.Fatalf("creating test file failed: %s", err)
519
- }
520
- f.Sync()
521
- f.Close()
522
-
523
- // Create a file (Should not see this! we are not watching subdir)
524
- var fs *os.File
525
- fs, err = os.OpenFile(testSubDirFile, os.O_WRONLY|os.O_CREATE, 0666)
526
- if err != nil {
527
- t.Fatalf("creating test file failed: %s", err)
528
- }
529
- fs.Sync()
530
- fs.Close()
531
-
532
- time.Sleep(200 * time.Millisecond)
533
-
534
- // Make sure receive deletes for both file and sub-directory
535
- os.RemoveAll(testSubDir)
536
- os.Remove(testFile1)
537
-
538
- // We expect this event to be received almost immediately, but let's wait 500 ms to be sure
539
- time.Sleep(500 * time.Millisecond)
540
- cReceived := createReceived.value()
541
- if cReceived != 2 {
542
- t.Fatalf("incorrect number of create events received after 500 ms (%d vs %d)", cReceived, 2)
543
- }
544
- dReceived := deleteReceived.value()
545
- if dReceived != 2 {
546
- t.Fatalf("incorrect number of delete events received after 500 ms (%d vs %d)", dReceived, 2)
547
- }
548
-
549
- // Try closing the fsnotify instance
550
- t.Log("calling Close()")
551
- watcher.Close()
552
- t.Log("waiting for the event channel to become closed...")
553
- select {
554
- case <-done:
555
- t.Log("event channel closed")
556
- case <-time.After(2 * time.Second):
557
- t.Fatal("event stream was not closed after 2 seconds")
558
- }
559
-}
560
-
561
-func TestFsnotifyRename(t *testing.T) {
562
- watcher := newWatcher(t)
563
-
564
- // Create directory to watch
565
- testDir := tempMkdir(t)
566
- defer os.RemoveAll(testDir)
567
-
568
- addWatch(t, watcher, testDir)
569
-
570
- // Receive errors on the error channel on a separate goroutine
571
- go func() {
572
- for err := range watcher.Errors {
573
- t.Fatalf("error received: %s", err)
574
- }
575
- }()
576
-
577
- testFile := filepath.Join(testDir, "TestFsnotifyEvents.testfile")
578
- testFileRenamed := filepath.Join(testDir, "TestFsnotifyEvents.testfileRenamed")
579
-
580
- // Receive events on the event channel on a separate goroutine
581
- eventstream := watcher.Events
582
- var renameReceived counter
583
- done := make(chan bool)
584
- go func() {
585
- for event := range eventstream {
586
- // Only count relevant events
587
- if event.Name == filepath.Clean(testDir) || event.Name == filepath.Clean(testFile) || event.Name == filepath.Clean(testFileRenamed) {
588
- if event.Op&Rename == Rename {
589
- renameReceived.increment()
590
- }
591
- t.Logf("event received: %s", event)
592
- } else {
593
- t.Logf("unexpected event received: %s", event)
594
- }
595
- }
596
- done <- true
597
- }()
598
-
599
- // Create a file
600
- // This should add at least one event to the fsnotify event queue
601
- var f *os.File
602
- f, err := os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
603
- if err != nil {
604
- t.Fatalf("creating test file failed: %s", err)
605
- }
606
- f.Sync()
607
-
608
- f.WriteString("data")
609
- f.Sync()
610
- f.Close()
611
-
612
- // Add a watch for testFile
613
- addWatch(t, watcher, testFile)
614
-
615
- if err := testRename(testFile, testFileRenamed); err != nil {
616
- t.Fatalf("rename failed: %s", err)
617
- }
618
-
619
- // We expect this event to be received almost immediately, but let's wait 500 ms to be sure
620
- time.Sleep(500 * time.Millisecond)
621
- if renameReceived.value() == 0 {
622
- t.Fatal("fsnotify rename events have not been received after 500 ms")
623
- }
624
-
625
- // Try closing the fsnotify instance
626
- t.Log("calling Close()")
627
- watcher.Close()
628
- t.Log("waiting for the event channel to become closed...")
629
- select {
630
- case <-done:
631
- t.Log("event channel closed")
632
- case <-time.After(2 * time.Second):
633
- t.Fatal("event stream was not closed after 2 seconds")
634
- }
635
-
636
- os.Remove(testFileRenamed)
637
-}
638
-
639
-func TestFsnotifyRenameToCreate(t *testing.T) {
640
- watcher := newWatcher(t)
641
-
642
- // Create directory to watch
643
- testDir := tempMkdir(t)
644
- defer os.RemoveAll(testDir)
645
-
646
- // Create directory to get file
647
- testDirFrom := tempMkdir(t)
648
- defer os.RemoveAll(testDirFrom)
649
-
650
- addWatch(t, watcher, testDir)
651
-
652
- // Receive errors on the error channel on a separate goroutine
653
- go func() {
654
- for err := range watcher.Errors {
655
- t.Fatalf("error received: %s", err)
656
- }
657
- }()
658
-
659
- testFile := filepath.Join(testDirFrom, "TestFsnotifyEvents.testfile")
660
- testFileRenamed := filepath.Join(testDir, "TestFsnotifyEvents.testfileRenamed")
661
-
662
- // Receive events on the event channel on a separate goroutine
663
- eventstream := watcher.Events
664
- var createReceived counter
665
- done := make(chan bool)
666
- go func() {
667
- for event := range eventstream {
668
- // Only count relevant events
669
- if event.Name == filepath.Clean(testDir) || event.Name == filepath.Clean(testFile) || event.Name == filepath.Clean(testFileRenamed) {
670
- if event.Op&Create == Create {
671
- createReceived.increment()
672
- }
673
- t.Logf("event received: %s", event)
674
- } else {
675
- t.Logf("unexpected event received: %s", event)
676
- }
677
- }
678
- done <- true
679
- }()
680
-
681
- // Create a file
682
- // This should add at least one event to the fsnotify event queue
683
- var f *os.File
684
- f, err := os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
685
- if err != nil {
686
- t.Fatalf("creating test file failed: %s", err)
687
- }
688
- f.Sync()
689
- f.Close()
690
-
691
- if err := testRename(testFile, testFileRenamed); err != nil {
692
- t.Fatalf("rename failed: %s", err)
693
- }
694
-
695
- // We expect this event to be received almost immediately, but let's wait 500 ms to be sure
696
- time.Sleep(500 * time.Millisecond)
697
- if createReceived.value() == 0 {
698
- t.Fatal("fsnotify create events have not been received after 500 ms")
699
- }
700
-
701
- // Try closing the fsnotify instance
702
- t.Log("calling Close()")
703
- watcher.Close()
704
- t.Log("waiting for the event channel to become closed...")
705
- select {
706
- case <-done:
707
- t.Log("event channel closed")
708
- case <-time.After(2 * time.Second):
709
- t.Fatal("event stream was not closed after 2 seconds")
710
- }
711
-
712
- os.Remove(testFileRenamed)
713
-}
714
-
715
-func TestFsnotifyRenameToOverwrite(t *testing.T) {
716
- switch runtime.GOOS {
717
- case "plan9", "windows":
718
- t.Skipf("skipping test on %q (os.Rename over existing file does not create event).", runtime.GOOS)
719
- }
720
-
721
- watcher := newWatcher(t)
722
-
723
- // Create directory to watch
724
- testDir := tempMkdir(t)
725
- defer os.RemoveAll(testDir)
726
-
727
- // Create directory to get file
728
- testDirFrom := tempMkdir(t)
729
- defer os.RemoveAll(testDirFrom)
730
-
731
- testFile := filepath.Join(testDirFrom, "TestFsnotifyEvents.testfile")
732
- testFileRenamed := filepath.Join(testDir, "TestFsnotifyEvents.testfileRenamed")
733
-
734
- // Create a file
735
- var fr *os.File
736
- fr, err := os.OpenFile(testFileRenamed, os.O_WRONLY|os.O_CREATE, 0666)
737
- if err != nil {
738
- t.Fatalf("creating test file failed: %s", err)
739
- }
740
- fr.Sync()
741
- fr.Close()
742
-
743
- addWatch(t, watcher, testDir)
744
-
745
- // Receive errors on the error channel on a separate goroutine
746
- go func() {
747
- for err := range watcher.Errors {
748
- t.Fatalf("error received: %s", err)
749
- }
750
- }()
751
-
752
- // Receive events on the event channel on a separate goroutine
753
- eventstream := watcher.Events
754
- var eventReceived counter
755
- done := make(chan bool)
756
- go func() {
757
- for event := range eventstream {
758
- // Only count relevant events
759
- if event.Name == filepath.Clean(testFileRenamed) {
760
- eventReceived.increment()
761
- t.Logf("event received: %s", event)
762
- } else {
763
- t.Logf("unexpected event received: %s", event)
764
- }
765
- }
766
- done <- true
767
- }()
768
-
769
- // Create a file
770
- // This should add at least one event to the fsnotify event queue
771
- var f *os.File
772
- f, err = os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
773
- if err != nil {
774
- t.Fatalf("creating test file failed: %s", err)
775
- }
776
- f.Sync()
777
- f.Close()
778
-
779
- if err := testRename(testFile, testFileRenamed); err != nil {
780
- t.Fatalf("rename failed: %s", err)
781
- }
782
-
783
- // We expect this event to be received almost immediately, but let's wait 500 ms to be sure
784
- time.Sleep(500 * time.Millisecond)
785
- if eventReceived.value() == 0 {
786
- t.Fatal("fsnotify events have not been received after 500 ms")
787
- }
788
-
789
- // Try closing the fsnotify instance
790
- t.Log("calling Close()")
791
- watcher.Close()
792
- t.Log("waiting for the event channel to become closed...")
793
- select {
794
- case <-done:
795
- t.Log("event channel closed")
796
- case <-time.After(2 * time.Second):
797
- t.Fatal("event stream was not closed after 2 seconds")
798
- }
799
-
800
- os.Remove(testFileRenamed)
801
-}
802
-
803
-func TestRemovalOfWatch(t *testing.T) {
804
- // Create directory to watch
805
- testDir := tempMkdir(t)
806
- defer os.RemoveAll(testDir)
807
-
808
- // Create a file before watching directory
809
- testFileAlreadyExists := filepath.Join(testDir, "TestFsnotifyEventsExisting.testfile")
810
- {
811
- var f *os.File
812
- f, err := os.OpenFile(testFileAlreadyExists, os.O_WRONLY|os.O_CREATE, 0666)
813
- if err != nil {
814
- t.Fatalf("creating test file failed: %s", err)
815
- }
816
- f.Sync()
817
- f.Close()
818
- }
819
-
820
- watcher := newWatcher(t)
821
- defer watcher.Close()
822
-
823
- addWatch(t, watcher, testDir)
824
- if err := watcher.Remove(testDir); err != nil {
825
- t.Fatalf("Could not remove the watch: %v\n", err)
826
- }
827
-
828
- go func() {
829
- select {
830
- case ev := <-watcher.Events:
831
- t.Fatalf("We received event: %v\n", ev)
832
- case <-time.After(500 * time.Millisecond):
833
- t.Log("No event received, as expected.")
834
- }
835
- }()
836
-
837
- time.Sleep(200 * time.Millisecond)
838
- // Modify the file outside of the watched dir
839
- f, err := os.Open(testFileAlreadyExists)
840
- if err != nil {
841
- t.Fatalf("Open test file failed: %s", err)
842
- }
843
- f.WriteString("data")
844
- f.Sync()
845
- f.Close()
846
- if err := os.Chmod(testFileAlreadyExists, 0700); err != nil {
847
- t.Fatalf("chmod failed: %s", err)
848
- }
849
- time.Sleep(400 * time.Millisecond)
850
-}
851
-
852
-func TestFsnotifyAttrib(t *testing.T) {
853
- if runtime.GOOS == "windows" {
854
- t.Skip("attributes don't work on Windows.")
855
- }
856
-
857
- watcher := newWatcher(t)
858
-
859
- // Create directory to watch
860
- testDir := tempMkdir(t)
861
- defer os.RemoveAll(testDir)
862
-
863
- // Receive errors on the error channel on a separate goroutine
864
- go func() {
865
- for err := range watcher.Errors {
866
- t.Fatalf("error received: %s", err)
867
- }
868
- }()
869
-
870
- testFile := filepath.Join(testDir, "TestFsnotifyAttrib.testfile")
871
-
872
- // Receive events on the event channel on a separate goroutine
873
- eventstream := watcher.Events
874
- // The modifyReceived counter counts IsModify events that are not IsAttrib,
875
- // and the attribReceived counts IsAttrib events (which are also IsModify as
876
- // a consequence).
877
- var modifyReceived counter
878
- var attribReceived counter
879
- done := make(chan bool)
880
- go func() {
881
- for event := range eventstream {
882
- // Only count relevant events
883
- if event.Name == filepath.Clean(testDir) || event.Name == filepath.Clean(testFile) {
884
- if event.Op&Write == Write {
885
- modifyReceived.increment()
886
- }
887
- if event.Op&Chmod == Chmod {
888
- attribReceived.increment()
889
- }
890
- t.Logf("event received: %s", event)
891
- } else {
892
- t.Logf("unexpected event received: %s", event)
893
- }
894
- }
895
- done <- true
896
- }()
897
-
898
- // Create a file
899
- // This should add at least one event to the fsnotify event queue
900
- var f *os.File
901
- f, err := os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
902
- if err != nil {
903
- t.Fatalf("creating test file failed: %s", err)
904
- }
905
- f.Sync()
906
-
907
- f.WriteString("data")
908
- f.Sync()
909
- f.Close()
910
-
911
- // Add a watch for testFile
912
- addWatch(t, watcher, testFile)
913
-
914
- if err := os.Chmod(testFile, 0700); err != nil {
915
- t.Fatalf("chmod failed: %s", err)
916
- }
917
-
918
- // We expect this event to be received almost immediately, but let's wait 500 ms to be sure
919
- // Creating/writing a file changes also the mtime, so IsAttrib should be set to true here
920
- time.Sleep(500 * time.Millisecond)
921
- if modifyReceived.value() != 0 {
922
- t.Fatal("received an unexpected modify event when creating a test file")
923
- }
924
- if attribReceived.value() == 0 {
925
- t.Fatal("fsnotify attribute events have not received after 500 ms")
926
- }
927
-
928
- // Modifying the contents of the file does not set the attrib flag (although eg. the mtime
929
- // might have been modified).
930
- modifyReceived.reset()
931
- attribReceived.reset()
932
-
933
- f, err = os.OpenFile(testFile, os.O_WRONLY, 0)
934
- if err != nil {
935
- t.Fatalf("reopening test file failed: %s", err)
936
- }
937
-
938
- f.WriteString("more data")
939
- f.Sync()
940
- f.Close()
941
-
942
- time.Sleep(500 * time.Millisecond)
943
-
944
- if modifyReceived.value() != 1 {
945
- t.Fatal("didn't receive a modify event after changing test file contents")
946
- }
947
-
948
- if attribReceived.value() != 0 {
949
- t.Fatal("did receive an unexpected attrib event after changing test file contents")
950
- }
951
-
952
- modifyReceived.reset()
953
- attribReceived.reset()
954
-
955
- // Doing a chmod on the file should trigger an event with the "attrib" flag set (the contents
956
- // of the file are not changed though)
957
- if err := os.Chmod(testFile, 0600); err != nil {
958
- t.Fatalf("chmod failed: %s", err)
959
- }
960
-
961
- time.Sleep(500 * time.Millisecond)
962
-
963
- if attribReceived.value() != 1 {
964
- t.Fatal("didn't receive an attribute change after 500ms")
965
- }
966
-
967
- // Try closing the fsnotify instance
968
- t.Log("calling Close()")
969
- watcher.Close()
970
- t.Log("waiting for the event channel to become closed...")
971
- select {
972
- case <-done:
973
- t.Log("event channel closed")
974
- case <-time.After(1e9):
975
- t.Fatal("event stream was not closed after 1 second")
976
- }
977
-
978
- os.Remove(testFile)
979
-}
980
-
981
-func TestFsnotifyClose(t *testing.T) {
982
- watcher := newWatcher(t)
983
- watcher.Close()
984
-
985
- var done int32
986
- go func() {
987
- watcher.Close()
988
- atomic.StoreInt32(&done, 1)
989
- }()
990
-
991
- time.Sleep(50e6) // 50 ms
992
- if atomic.LoadInt32(&done) == 0 {
993
- t.Fatal("double Close() test failed: second Close() call didn't return")
994
- }
995
-
996
- testDir := tempMkdir(t)
997
- defer os.RemoveAll(testDir)
998
-
999
- if err := watcher.Add(testDir); err == nil {
1000
- t.Fatal("expected error on Watch() after Close(), got nil")
1001
- }
1002
-}
1003
-
1004
-func TestFsnotifyFakeSymlink(t *testing.T) {
1005
- if runtime.GOOS == "windows" {
1006
- t.Skip("symlinks don't work on Windows.")
1007
- }
1008
-
1009
- watcher := newWatcher(t)
1010
-
1011
- // Create directory to watch
1012
- testDir := tempMkdir(t)
1013
- defer os.RemoveAll(testDir)
1014
-
1015
- var errorsReceived counter
1016
- // Receive errors on the error channel on a separate goroutine
1017
- go func() {
1018
- for errors := range watcher.Errors {
1019
- t.Logf("Received error: %s", errors)
1020
- errorsReceived.increment()
1021
- }
1022
- }()
1023
-
1024
- // Count the CREATE events received
1025
- var createEventsReceived, otherEventsReceived counter
1026
- go func() {
1027
- for ev := range watcher.Events {
1028
- t.Logf("event received: %s", ev)
1029
- if ev.Op&Create == Create {
1030
- createEventsReceived.increment()
1031
- } else {
1032
- otherEventsReceived.increment()
1033
- }
1034
- }
1035
- }()
1036
-
1037
- addWatch(t, watcher, testDir)
1038
-
1039
- if err := os.Symlink(filepath.Join(testDir, "zzz"), filepath.Join(testDir, "zzznew")); err != nil {
1040
- t.Fatalf("Failed to create bogus symlink: %s", err)
1041
- }
1042
- t.Logf("Created bogus symlink")
1043
-
1044
- // We expect this event to be received almost immediately, but let's wait 500 ms to be sure
1045
- time.Sleep(500 * time.Millisecond)
1046
-
1047
- // Should not be error, just no events for broken links (watching nothing)
1048
- if errorsReceived.value() > 0 {
1049
- t.Fatal("fsnotify errors have been received.")
1050
- }
1051
- if otherEventsReceived.value() > 0 {
1052
- t.Fatal("fsnotify other events received on the broken link")
1053
- }
1054
-
1055
- // Except for 1 create event (for the link itself)
1056
- if createEventsReceived.value() == 0 {
1057
- t.Fatal("fsnotify create events were not received after 500 ms")
1058
- }
1059
- if createEventsReceived.value() > 1 {
1060
- t.Fatal("fsnotify more create events received than expected")
1061
- }
1062
-
1063
- // Try closing the fsnotify instance
1064
- t.Log("calling Close()")
1065
- watcher.Close()
1066
-}
1067
-
1068
-// TestConcurrentRemovalOfWatch tests that concurrent calls to RemoveWatch do not race.
1069
-// See https://codereview.appspot.com/103300045/
1070
-// go test -test.run=TestConcurrentRemovalOfWatch -test.cpu=1,1,1,1,1 -race
1071
-func TestConcurrentRemovalOfWatch(t *testing.T) {
1072
- if runtime.GOOS != "darwin" {
1073
- t.Skip("regression test for race only present on darwin")
1074
- }
1075
-
1076
- // Create directory to watch
1077
- testDir := tempMkdir(t)
1078
- defer os.RemoveAll(testDir)
1079
-
1080
- // Create a file before watching directory
1081
- testFileAlreadyExists := filepath.Join(testDir, "TestFsnotifyEventsExisting.testfile")
1082
- {
1083
- var f *os.File
1084
- f, err := os.OpenFile(testFileAlreadyExists, os.O_WRONLY|os.O_CREATE, 0666)
1085
- if err != nil {
1086
- t.Fatalf("creating test file failed: %s", err)
1087
- }
1088
- f.Sync()
1089
- f.Close()
1090
- }
1091
-
1092
- watcher := newWatcher(t)
1093
- defer watcher.Close()
1094
-
1095
- addWatch(t, watcher, testDir)
1096
-
1097
- // Test that RemoveWatch can be invoked concurrently, with no data races.
1098
- removed1 := make(chan struct{})
1099
- go func() {
1100
- defer close(removed1)
1101
- watcher.Remove(testDir)
1102
- }()
1103
- removed2 := make(chan struct{})
1104
- go func() {
1105
- close(removed2)
1106
- watcher.Remove(testDir)
1107
- }()
1108
- <-removed1
1109
- <-removed2
1110
-}
1111
-
1112
-func TestClose(t *testing.T) {
1113
- // Regression test for #59 bad file descriptor from Close
1114
- testDir := tempMkdir(t)
1115
- defer os.RemoveAll(testDir)
1116
-
1117
- watcher := newWatcher(t)
1118
- if err := watcher.Add(testDir); err != nil {
1119
- t.Fatalf("Expected no error on Add, got %v", err)
1120
- }
1121
- err := watcher.Close()
1122
- if err != nil {
1123
- t.Fatalf("Expected no error on Close, got %v.", err)
1124
- }
1125
-}
1126
-
1127
-func testRename(file1, file2 string) error {
1128
- switch runtime.GOOS {
1129
- case "windows", "plan9":
1130
- return os.Rename(file1, file2)
1131
- default:
1132
- cmd := exec.Command("mv", file1, file2)
1133
- return cmd.Run()
1134
- }
1135
-}
Godeps/_workspace/src/gopkg.in/fsnotify.v1/kqueue.go
deleted
-463
@@ -1,463 +0,0 @@
1
-// Copyright 2010 The Go Authors. All rights reserved.
2
-// Use of this source code is governed by a BSD-style
3
-// license that can be found in the LICENSE file.
4
-
5
-// +build freebsd openbsd netbsd dragonfly darwin
6
-
7
-package fsnotify
8
-
9
-import (
10
- "errors"
11
- "fmt"
12
- "io/ioutil"
13
- "os"
14
- "path/filepath"
15
- "sync"
16
- "syscall"
17
- "time"
18
-)
19
-
20
-// Watcher watches a set of files, delivering events to a channel.
21
-type Watcher struct {
22
- Events chan Event
23
- Errors chan error
24
- done chan bool // Channel for sending a "quit message" to the reader goroutine
25
-
26
- kq int // File descriptor (as returned by the kqueue() syscall).
27
-
28
- mu sync.Mutex // Protects access to watcher data
29
- watches map[string]int // Map of watched file descriptors (key: path).
30
- externalWatches map[string]bool // Map of watches added by user of the library.
31
- dirFlags map[string]uint32 // Map of watched directories to fflags used in kqueue.
32
- paths map[int]pathInfo // Map file descriptors to path names for processing kqueue events.
33
- fileExists map[string]bool // Keep track of if we know this file exists (to stop duplicate create events).
34
- isClosed bool // Set to true when Close() is first called
35
-}
36
-
37
-type pathInfo struct {
38
- name string
39
- isDir bool
40
-}
41
-
42
-// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events.
43
-func NewWatcher() (*Watcher, error) {
44
- kq, err := kqueue()
45
- if err != nil {
46
- return nil, err
47
- }
48
-
49
- w := &Watcher{
50
- kq: kq,
51
- watches: make(map[string]int),
52
- dirFlags: make(map[string]uint32),
53
- paths: make(map[int]pathInfo),
54
- fileExists: make(map[string]bool),
55
- externalWatches: make(map[string]bool),
56
- Events: make(chan Event),
57
- Errors: make(chan error),
58
- done: make(chan bool),
59
- }
60
-
61
- go w.readEvents()
62
- return w, nil
63
-}
64
-
65
-// Close removes all watches and closes the events channel.
66
-func (w *Watcher) Close() error {
67
- w.mu.Lock()
68
- if w.isClosed {
69
- w.mu.Unlock()
70
- return nil
71
- }
72
- w.isClosed = true
73
- w.mu.Unlock()
74
-
75
- w.mu.Lock()
76
- ws := w.watches
77
- w.mu.Unlock()
78
-
79
- var err error
80
- for name := range ws {
81
- if e := w.Remove(name); e != nil && err == nil {
82
- err = e
83
- }
84
- }
85
-
86
- // Send "quit" message to the reader goroutine:
87
- w.done <- true
88
-
89
- return nil
90
-}
91
-
92
-// Add starts watching the named file or directory (non-recursively).
93
-func (w *Watcher) Add(name string) error {
94
- w.mu.Lock()
95
- w.externalWatches[name] = true
96
- w.mu.Unlock()
97
- return w.addWatch(name, noteAllEvents)
98
-}
99
-
100
-// Remove stops watching the the named file or directory (non-recursively).
101
-func (w *Watcher) Remove(name string) error {
102
- name = filepath.Clean(name)
103
- w.mu.Lock()
104
- watchfd, ok := w.watches[name]
105
- w.mu.Unlock()
106
- if !ok {
107
- return fmt.Errorf("can't remove non-existent kevent watch for: %s", name)
108
- }
109
-
110
- const registerRemove = syscall.EV_DELETE
111
- if err := register(w.kq, []int{watchfd}, registerRemove, 0); err != nil {
112
- return err
113
- }
114
-
115
- syscall.Close(watchfd)
116
-
117
- w.mu.Lock()
118
- isDir := w.paths[watchfd].isDir
119
- delete(w.watches, name)
120
- delete(w.paths, watchfd)
121
- delete(w.dirFlags, name)
122
- w.mu.Unlock()
123
-
124
- // Find all watched paths that are in this directory that are not external.
125
- if isDir {
126
- var pathsToRemove []string
127
- w.mu.Lock()
128
- for _, path := range w.paths {
129
- wdir, _ := filepath.Split(path.name)
130
- if filepath.Clean(wdir) == name {
131
- if !w.externalWatches[path.name] {
132
- pathsToRemove = append(pathsToRemove, path.name)
133
- }
134
- }
135
- }
136
- w.mu.Unlock()
137
- for _, name := range pathsToRemove {
138
- // Since these are internal, not much sense in propagating error
139
- // to the user, as that will just confuse them with an error about
140
- // a path they did not explicitly watch themselves.
141
- w.Remove(name)
142
- }
143
- }
144
-
145
- return nil
146
-}
147
-
148
-// Watch all events (except NOTE_EXTEND, NOTE_LINK, NOTE_REVOKE)
149
-const noteAllEvents = syscall.NOTE_DELETE | syscall.NOTE_WRITE | syscall.NOTE_ATTRIB | syscall.NOTE_RENAME
150
-
151
-// keventWaitTime to block on each read from kevent
152
-var keventWaitTime = durationToTimespec(100 * time.Millisecond)
153
-
154
-// addWatch adds name to the watched file set.
155
-// The flags are interpreted as described in kevent(2).
156
-func (w *Watcher) addWatch(name string, flags uint32) error {
157
- var isDir bool
158
- // Make ./name and name equivalent
159
- name = filepath.Clean(name)
160
-
161
- w.mu.Lock()
162
- if w.isClosed {
163
- w.mu.Unlock()
164
- return errors.New("kevent instance already closed")
165
- }
166
- watchfd, alreadyWatching := w.watches[name]
167
- // We already have a watch, but we can still override flags.
168
- if alreadyWatching {
169
- isDir = w.paths[watchfd].isDir
170
- }
171
- w.mu.Unlock()
172
-
173
- if !alreadyWatching {
174
- fi, err := os.Lstat(name)
175
- if err != nil {
176
- return err
177
- }
178
-
179
- // Don't watch sockets.
180
- if fi.Mode()&os.ModeSocket == os.ModeSocket {
181
- return nil
182
- }
183
-
184
- // Follow Symlinks
185
- // Unfortunately, Linux can add bogus symlinks to watch list without
186
- // issue, and Windows can't do symlinks period (AFAIK). To maintain
187
- // consistency, we will act like everything is fine. There will simply
188
- // be no file events for broken symlinks.
189
- // Hence the returns of nil on errors.
190
- if fi.Mode()&os.ModeSymlink == os.ModeSymlink {
191
- name, err = filepath.EvalSymlinks(name)
192
- if err != nil {
193
- return nil
194
- }
195
-
196
- fi, err = os.Lstat(name)
197
- if err != nil {
198
- return nil
199
- }
200
- }
201
-
202
- watchfd, err = syscall.Open(name, openMode, 0700)
203
- if watchfd == -1 {
204
- return err
205
- }
206
-
207
- isDir = fi.IsDir()
208
- }
209
-
210
- const registerAdd = syscall.EV_ADD | syscall.EV_CLEAR | syscall.EV_ENABLE
211
- if err := register(w.kq, []int{watchfd}, registerAdd, flags); err != nil {
212
- syscall.Close(watchfd)
213
- return err
214
- }
215
-
216
- if !alreadyWatching {
217
- w.mu.Lock()
218
- w.watches[name] = watchfd
219
- w.paths[watchfd] = pathInfo{name: name, isDir: isDir}
220
- w.mu.Unlock()
221
- }
222
-
223
- if isDir {
224
- // Watch the directory if it has not been watched before,
225
- // or if it was watched before, but perhaps only a NOTE_DELETE (watchDirectoryFiles)
226
- w.mu.Lock()
227
- watchDir := (flags&syscall.NOTE_WRITE) == syscall.NOTE_WRITE &&
228
- (!alreadyWatching || (w.dirFlags[name]&syscall.NOTE_WRITE) != syscall.NOTE_WRITE)
229
- // Store flags so this watch can be updated later
230
- w.dirFlags[name] = flags
231
- w.mu.Unlock()
232
-
233
- if watchDir {
234
- if err := w.watchDirectoryFiles(name); err != nil {
235
- return err
236
- }
237
- }
238
- }
239
- return nil
240
-}
241
-
242
-// readEvents reads from kqueue and converts the received kevents into
243
-// Event values that it sends down the Events channel.
244
-func (w *Watcher) readEvents() {
245
- eventBuffer := make([]syscall.Kevent_t, 10)
246
-
247
- for {
248
- // See if there is a message on the "done" channel
249
- select {
250
- case <-w.done:
251
- err := syscall.Close(w.kq)
252
- if err != nil {
253
- w.Errors <- err
254
- }
255
- close(w.Events)
256
- close(w.Errors)
257
- return
258
- default:
259
- }
260
-
261
- // Get new events
262
- kevents, err := read(w.kq, eventBuffer, &keventWaitTime)
263
- // EINTR is okay, the syscall was interrupted before timeout expired.
264
- if err != nil && err != syscall.EINTR {
265
- w.Errors <- err
266
- continue
267
- }
268
-
269
- // Flush the events we received to the Events channel
270
- for len(kevents) > 0 {
271
- kevent := &kevents[0]
272
- watchfd := int(kevent.Ident)
273
- mask := uint32(kevent.Fflags)
274
- w.mu.Lock()
275
- path := w.paths[watchfd]
276
- w.mu.Unlock()
277
- event := newEvent(path.name, mask)
278
-
279
- if path.isDir && !(event.Op&Remove == Remove) {
280
- // Double check to make sure the directory exists. This can happen when
281
- // we do a rm -fr on a recursively watched folders and we receive a
282
- // modification event first but the folder has been deleted and later
283
- // receive the delete event
284
- if _, err := os.Lstat(event.Name); os.IsNotExist(err) {
285
- // mark is as delete event
286
- event.Op |= Remove
287
- }
288
- }
289
-
290
- if event.Op&Rename == Rename || event.Op&Remove == Remove {
291
- w.Remove(event.Name)
292
- w.mu.Lock()
293
- delete(w.fileExists, event.Name)
294
- w.mu.Unlock()
295
- }
296
-
297
- if path.isDir && event.Op&Write == Write && !(event.Op&Remove == Remove) {
298
- w.sendDirectoryChangeEvents(event.Name)
299
- } else {
300
- // Send the event on the Events channel
301
- w.Events <- event
302
- }
303
-
304
- if event.Op&Remove == Remove {
305
- // Look for a file that may have overwritten this.
306
- // For example, mv f1 f2 will delete f2, then create f2.
307
- fileDir, _ := filepath.Split(event.Name)
308
- fileDir = filepath.Clean(fileDir)
309
- w.mu.Lock()
310
- _, found := w.watches[fileDir]
311
- w.mu.Unlock()
312
- if found {
313
- // make sure the directory exists before we watch for changes. When we
314
- // do a recursive watch and perform rm -fr, the parent directory might
315
- // have gone missing, ignore the missing directory and let the
316
- // upcoming delete event remove the watch from the parent directory.
317
- if _, err := os.Lstat(fileDir); os.IsExist(err) {
318
- w.sendDirectoryChangeEvents(fileDir)
319
- // FIXME: should this be for events on files or just isDir?
320
- }
321
- }
322
- }
323
-
324
- // Move to next event
325
- kevents = kevents[1:]
326
- }
327
- }
328
-}
329
-
330
-// newEvent returns an platform-independent Event based on kqueue Fflags.
331
-func newEvent(name string, mask uint32) Event {
332
- e := Event{Name: name}
333
- if mask&syscall.NOTE_DELETE == syscall.NOTE_DELETE {
334
- e.Op |= Remove
335
- }
336
- if mask&syscall.NOTE_WRITE == syscall.NOTE_WRITE {
337
- e.Op |= Write
338
- }
339
- if mask&syscall.NOTE_RENAME == syscall.NOTE_RENAME {
340
- e.Op |= Rename
341
- }
342
- if mask&syscall.NOTE_ATTRIB == syscall.NOTE_ATTRIB {
343
- e.Op |= Chmod
344
- }
345
- return e
346
-}
347
-
348
-func newCreateEvent(name string) Event {
349
- return Event{Name: name, Op: Create}
350
-}
351
-
352
-// watchDirectoryFiles to mimic inotify when adding a watch on a directory
353
-func (w *Watcher) watchDirectoryFiles(dirPath string) error {
354
- // Get all files
355
- files, err := ioutil.ReadDir(dirPath)
356
- if err != nil {
357
- return err
358
- }
359
-
360
- for _, fileInfo := range files {
361
- filePath := filepath.Join(dirPath, fileInfo.Name())
362
- if err := w.internalWatch(filePath, fileInfo); err != nil {
363
- return err
364
- }
365
-
366
- w.mu.Lock()
367
- w.fileExists[filePath] = true
368
- w.mu.Unlock()
369
- }
370
-
371
- return nil
372
-}
373
-
374
-// sendDirectoryEvents searches the directory for newly created files
375
-// and sends them over the event channel. This functionality is to have
376
-// the BSD version of fsnotify match Linux inotify which provides a
377
-// create event for files created in a watched directory.
378
-func (w *Watcher) sendDirectoryChangeEvents(dirPath string) {
379
- // Get all files
380
- files, err := ioutil.ReadDir(dirPath)
381
- if err != nil {
382
- w.Errors <- err
383
- }
384
-
385
- // Search for new files
386
- for _, fileInfo := range files {
387
- filePath := filepath.Join(dirPath, fileInfo.Name())
388
- w.mu.Lock()
389
- _, doesExist := w.fileExists[filePath]
390
- w.mu.Unlock()
391
- if !doesExist {
392
- // Send create event
393
- w.Events <- newCreateEvent(filePath)
394
- }
395
-
396
- // like watchDirectoryFiles (but without doing another ReadDir)
397
- if err := w.internalWatch(filePath, fileInfo); err != nil {
398
- return
399
- }
400
-
401
- w.mu.Lock()
402
- w.fileExists[filePath] = true
403
- w.mu.Unlock()
404
- }
405
-}
406
-
407
-func (w *Watcher) internalWatch(name string, fileInfo os.FileInfo) error {
408
- if fileInfo.IsDir() {
409
- // mimic Linux providing delete events for subdirectories
410
- // but preserve the flags used if currently watching subdirectory
411
- w.mu.Lock()
412
- flags := w.dirFlags[name]
413
- w.mu.Unlock()
414
-
415
- flags |= syscall.NOTE_DELETE
416
- return w.addWatch(name, flags)
417
- }
418
-
419
- // watch file to mimic Linux inotify
420
- return w.addWatch(name, noteAllEvents)
421
-}
422
-
423
-// kqueue creates a new kernel event queue and returns a descriptor.
424
-func kqueue() (kq int, err error) {
425
- kq, err = syscall.Kqueue()
426
- if kq == -1 {
427
- return kq, err
428
- }
429
- return kq, nil
430
-}
431
-
432
-// register events with the queue
433
-func register(kq int, fds []int, flags int, fflags uint32) error {
434
- changes := make([]syscall.Kevent_t, len(fds))
435
-
436
- for i, fd := range fds {
437
- // SetKevent converts int to the platform-specific types:
438
- syscall.SetKevent(&changes[i], fd, syscall.EVFILT_VNODE, flags)
439
- changes[i].Fflags = fflags
440
- }
441
-
442
- // register the events
443
- success, err := syscall.Kevent(kq, changes, nil, nil)
444
- if success == -1 {
445
- return err
446
- }
447
- return nil
448
-}
449
-
450
-// read retrieves pending events, or waits until an event occurs.
451
-// A timeout of nil blocks indefinitely, while 0 polls the queue.
452
-func read(kq int, events []syscall.Kevent_t, timeout *syscall.Timespec) ([]syscall.Kevent_t, error) {
453
- n, err := syscall.Kevent(kq, nil, events, timeout)
454
- if err != nil {
455
- return nil, err
456
- }
457
- return events[0:n], nil
458
-}
459
-
460
-// durationToTimespec prepares a timeout value
461
-func durationToTimespec(d time.Duration) syscall.Timespec {
462
- return syscall.NsecToTimespec(d.Nanoseconds())
463
-}
Godeps/_workspace/src/gopkg.in/fsnotify.v1/open_mode_bsd.go
deleted
-11
@@ -1,11 +0,0 @@
1
-// Copyright 2013 The Go Authors. All rights reserved.
2
-// Use of this source code is governed by a BSD-style
3
-// license that can be found in the LICENSE file.
4
-
5
-// +build freebsd openbsd netbsd dragonfly
6
-
7
-package fsnotify
8
-
9
-import "syscall"
10
-
11
-const openMode = syscall.O_NONBLOCK | syscall.O_RDONLY
Godeps/_workspace/src/gopkg.in/fsnotify.v1/open_mode_darwin.go
deleted
-12
@@ -1,12 +0,0 @@
1
-// Copyright 2013 The Go Authors. All rights reserved.
2
-// Use of this source code is governed by a BSD-style
3
-// license that can be found in the LICENSE file.
4
-
5
-// +build darwin
6
-
7
-package fsnotify
8
-
9
-import "syscall"
10
-
11
-// note: This constant is not defined on BSD
12
-const openMode = syscall.O_EVTONLY
Godeps/_workspace/src/gopkg.in/fsnotify.v1/windows.go
deleted
-561
@@ -1,561 +0,0 @@
1
-// Copyright 2011 The Go Authors. All rights reserved.
2
-// Use of this source code is governed by a BSD-style
3
-// license that can be found in the LICENSE file.
4
-
5
-// +build windows
6
-
7
-package fsnotify
8
-
9
-import (
10
- "errors"
11
- "fmt"
12
- "os"
13
- "path/filepath"
14
- "runtime"
15
- "sync"
16
- "syscall"
17
- "unsafe"
18
-)
19
-
20
-// Watcher watches a set of files, delivering events to a channel.
21
-type Watcher struct {
22
- Events chan Event
23
- Errors chan error
24
- isClosed bool // Set to true when Close() is first called
25
- mu sync.Mutex // Map access
26
- port syscall.Handle // Handle to completion port
27
- watches watchMap // Map of watches (key: i-number)
28
- input chan *input // Inputs to the reader are sent on this channel
29
- quit chan chan<- error
30
-}
31
-
32
-// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events.
33
-func NewWatcher() (*Watcher, error) {
34
- port, e := syscall.CreateIoCompletionPort(syscall.InvalidHandle, 0, 0, 0)
35
- if e != nil {
36
- return nil, os.NewSyscallError("CreateIoCompletionPort", e)
37
- }
38
- w := &Watcher{
39
- port: port,
40
- watches: make(watchMap),
41
- input: make(chan *input, 1),
42
- Events: make(chan Event, 50),
43
- Errors: make(chan error),
44
- quit: make(chan chan<- error, 1),
45
- }
46
- go w.readEvents()
47
- return w, nil
48
-}
49
-
50
-// Close removes all watches and closes the events channel.
51
-func (w *Watcher) Close() error {
52
- if w.isClosed {
53
- return nil
54
- }
55
- w.isClosed = true
56
-
57
- // Send "quit" message to the reader goroutine
58
- ch := make(chan error)
59
- w.quit <- ch
60
- if err := w.wakeupReader(); err != nil {
61
- return err
62
- }
63
- return <-ch
64
-}
65
-
66
-// Add starts watching the named file or directory (non-recursively).
67
-func (w *Watcher) Add(name string) error {
68
- if w.isClosed {
69
- return errors.New("watcher already closed")
70
- }
71
- in := &input{
72
- op: opAddWatch,
73
- path: filepath.Clean(name),
74
- flags: sys_FS_ALL_EVENTS,
75
- reply: make(chan error),
76
- }
77
- w.input <- in
78
- if err := w.wakeupReader(); err != nil {
79
- return err
80
- }
81
- return <-in.reply
82
-}
83
-
84
-// Remove stops watching the the named file or directory (non-recursively).
85
-func (w *Watcher) Remove(name string) error {
86
- in := &input{
87
- op: opRemoveWatch,
88
- path: filepath.Clean(name),
89
- reply: make(chan error),
90
- }
91
- w.input <- in
92
- if err := w.wakeupReader(); err != nil {
93
- return err
94
- }
95
- return <-in.reply
96
-}
97
-
98
-const (
99
- // Options for AddWatch
100
- sys_FS_ONESHOT = 0x80000000
101
- sys_FS_ONLYDIR = 0x1000000
102
-
103
- // Events
104
- sys_FS_ACCESS = 0x1
105
- sys_FS_ALL_EVENTS = 0xfff
106
- sys_FS_ATTRIB = 0x4
107
- sys_FS_CLOSE = 0x18
108
- sys_FS_CREATE = 0x100
109
- sys_FS_DELETE = 0x200
110
- sys_FS_DELETE_SELF = 0x400
111
- sys_FS_MODIFY = 0x2
112
- sys_FS_MOVE = 0xc0
113
- sys_FS_MOVED_FROM = 0x40
114
- sys_FS_MOVED_TO = 0x80
115
- sys_FS_MOVE_SELF = 0x800
116
-
117
- // Special events
118
- sys_FS_IGNORED = 0x8000
119
- sys_FS_Q_OVERFLOW = 0x4000
120
-)
121
-
122
-func newEvent(name string, mask uint32) Event {
123
- e := Event{Name: name}
124
- if mask&sys_FS_CREATE == sys_FS_CREATE || mask&sys_FS_MOVED_TO == sys_FS_MOVED_TO {
125
- e.Op |= Create
126
- }
127
- if mask&sys_FS_DELETE == sys_FS_DELETE || mask&sys_FS_DELETE_SELF == sys_FS_DELETE_SELF {
128
- e.Op |= Remove
129
- }
130
- if mask&sys_FS_MODIFY == sys_FS_MODIFY {
131
- e.Op |= Write
132
- }
133
- if mask&sys_FS_MOVE == sys_FS_MOVE || mask&sys_FS_MOVE_SELF == sys_FS_MOVE_SELF || mask&sys_FS_MOVED_FROM == sys_FS_MOVED_FROM {
134
- e.Op |= Rename
135
- }
136
- if mask&sys_FS_ATTRIB == sys_FS_ATTRIB {
137
- e.Op |= Chmod
138
- }
139
- return e
140
-}
141
-
142
-const (
143
- opAddWatch = iota
144
- opRemoveWatch
145
-)
146
-
147
-const (
148
- provisional uint64 = 1 << (32 + iota)
149
-)
150
-
151
-type input struct {
152
- op int
153
- path string
154
- flags uint32
155
- reply chan error
156
-}
157
-
158
-type inode struct {
159
- handle syscall.Handle
160
- volume uint32
161
- index uint64
162
-}
163
-
164
-type watch struct {
165
- ov syscall.Overlapped
166
- ino *inode // i-number
167
- path string // Directory path
168
- mask uint64 // Directory itself is being watched with these notify flags
169
- names map[string]uint64 // Map of names being watched and their notify flags
170
- rename string // Remembers the old name while renaming a file
171
- buf [4096]byte
172
-}
173
-
174
-type indexMap map[uint64]*watch
175
-type watchMap map[uint32]indexMap
176
-
177
-func (w *Watcher) wakeupReader() error {
178
- e := syscall.PostQueuedCompletionStatus(w.port, 0, 0, nil)
179
- if e != nil {
180
- return os.NewSyscallError("PostQueuedCompletionStatus", e)
181
- }
182
- return nil
183
-}
184
-
185
-func getDir(pathname string) (dir string, err error) {
186
- attr, e := syscall.GetFileAttributes(syscall.StringToUTF16Ptr(pathname))
187
- if e != nil {
188
- return "", os.NewSyscallError("GetFileAttributes", e)
189
- }
190
- if attr&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 {
191
- dir = pathname
192
- } else {
193
- dir, _ = filepath.Split(pathname)
194
- dir = filepath.Clean(dir)
195
- }
196
- return
197
-}
198
-
199
-func getIno(path string) (ino *inode, err error) {
200
- h, e := syscall.CreateFile(syscall.StringToUTF16Ptr(path),
201
- syscall.FILE_LIST_DIRECTORY,
202
- syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE,
203
- nil, syscall.OPEN_EXISTING,
204
- syscall.FILE_FLAG_BACKUP_SEMANTICS|syscall.FILE_FLAG_OVERLAPPED, 0)
205
- if e != nil {
206
- return nil, os.NewSyscallError("CreateFile", e)
207
- }
208
- var fi syscall.ByHandleFileInformation
209
- if e = syscall.GetFileInformationByHandle(h, &fi); e != nil {
210
- syscall.CloseHandle(h)
211
- return nil, os.NewSyscallError("GetFileInformationByHandle", e)
212
- }
213
- ino = &inode{
214
- handle: h,
215
- volume: fi.VolumeSerialNumber,
216
- index: uint64(fi.FileIndexHigh)<<32 | uint64(fi.FileIndexLow),
217
- }
218
- return ino, nil
219
-}
220
-
221
-// Must run within the I/O thread.
222
-func (m watchMap) get(ino *inode) *watch {
223
- if i := m[ino.volume]; i != nil {
224
- return i[ino.index]
225
- }
226
- return nil
227
-}
228
-
229
-// Must run within the I/O thread.
230
-func (m watchMap) set(ino *inode, watch *watch) {
231
- i := m[ino.volume]
232
- if i == nil {
233
- i = make(indexMap)
234
- m[ino.volume] = i
235
- }
236
- i[ino.index] = watch
237
-}
238
-
239
-// Must run within the I/O thread.
240
-func (w *Watcher) addWatch(pathname string, flags uint64) error {
241
- dir, err := getDir(pathname)
242
- if err != nil {
243
- return err
244
- }
245
- if flags&sys_FS_ONLYDIR != 0 && pathname != dir {
246
- return nil
247
- }
248
- ino, err := getIno(dir)
249
- if err != nil {
250
- return err
251
- }
252
- w.mu.Lock()
253
- watchEntry := w.watches.get(ino)
254
- w.mu.Unlock()
255
- if watchEntry == nil {
256
- if _, e := syscall.CreateIoCompletionPort(ino.handle, w.port, 0, 0); e != nil {
257
- syscall.CloseHandle(ino.handle)
258
- return os.NewSyscallError("CreateIoCompletionPort", e)
259
- }
260
- watchEntry = &watch{
261
- ino: ino,
262
- path: dir,
263
- names: make(map[string]uint64),
264
- }
265
- w.mu.Lock()
266
- w.watches.set(ino, watchEntry)
267
- w.mu.Unlock()
268
- flags |= provisional
269
- } else {
270
- syscall.CloseHandle(ino.handle)
271
- }
272
- if pathname == dir {
273
- watchEntry.mask |= flags
274
- } else {
275
- watchEntry.names[filepath.Base(pathname)] |= flags
276
- }
277
- if err = w.startRead(watchEntry); err != nil {
278
- return err
279
- }
280
- if pathname == dir {
281
- watchEntry.mask &= ^provisional
282
- } else {
283
- watchEntry.names[filepath.Base(pathname)] &= ^provisional
284
- }
285
- return nil
286
-}
287
-
288
-// Must run within the I/O thread.
289
-func (w *Watcher) remWatch(pathname string) error {
290
- dir, err := getDir(pathname)
291
- if err != nil {
292
- return err
293
- }
294
- ino, err := getIno(dir)
295
- if err != nil {
296
- return err
297
- }
298
- w.mu.Lock()
299
- watch := w.watches.get(ino)
300
- w.mu.Unlock()
301
- if watch == nil {
302
- return fmt.Errorf("can't remove non-existent watch for: %s", pathname)
303
- }
304
- if pathname == dir {
305
- w.sendEvent(watch.path, watch.mask&sys_FS_IGNORED)
306
- watch.mask = 0
307
- } else {
308
- name := filepath.Base(pathname)
309
- w.sendEvent(watch.path+"\\"+name, watch.names[name]&sys_FS_IGNORED)
310
- delete(watch.names, name)
311
- }
312
- return w.startRead(watch)
313
-}
314
-
315
-// Must run within the I/O thread.
316
-func (w *Watcher) deleteWatch(watch *watch) {
317
- for name, mask := range watch.names {
318
- if mask&provisional == 0 {
319
- w.sendEvent(watch.path+"\\"+name, mask&sys_FS_IGNORED)
320
- }
321
- delete(watch.names, name)
322
- }
323
- if watch.mask != 0 {
324
- if watch.mask&provisional == 0 {
325
- w.sendEvent(watch.path, watch.mask&sys_FS_IGNORED)
326
- }
327
- watch.mask = 0
328
- }
329
-}
330
-
331
-// Must run within the I/O thread.
332
-func (w *Watcher) startRead(watch *watch) error {
333
- if e := syscall.CancelIo(watch.ino.handle); e != nil {
334
- w.Errors <- os.NewSyscallError("CancelIo", e)
335
- w.deleteWatch(watch)
336
- }
337
- mask := toWindowsFlags(watch.mask)
338
- for _, m := range watch.names {
339
- mask |= toWindowsFlags(m)
340
- }
341
- if mask == 0 {
342
- if e := syscall.CloseHandle(watch.ino.handle); e != nil {
343
- w.Errors <- os.NewSyscallError("CloseHandle", e)
344
- }
345
- w.mu.Lock()
346
- delete(w.watches[watch.ino.volume], watch.ino.index)
347
- w.mu.Unlock()
348
- return nil
349
- }
350
- e := syscall.ReadDirectoryChanges(watch.ino.handle, &watch.buf[0],
351
- uint32(unsafe.Sizeof(watch.buf)), false, mask, nil, &watch.ov, 0)
352
- if e != nil {
353
- err := os.NewSyscallError("ReadDirectoryChanges", e)
354
- if e == syscall.ERROR_ACCESS_DENIED && watch.mask&provisional == 0 {
355
- // Watched directory was probably removed
356
- if w.sendEvent(watch.path, watch.mask&sys_FS_DELETE_SELF) {
357
- if watch.mask&sys_FS_ONESHOT != 0 {
358
- watch.mask = 0
359
- }
360
- }
361
- err = nil
362
- }
363
- w.deleteWatch(watch)
364
- w.startRead(watch)
365
- return err
366
- }
367
- return nil
368
-}
369
-
370
-// readEvents reads from the I/O completion port, converts the
371
-// received events into Event objects and sends them via the Events channel.
372
-// Entry point to the I/O thread.
373
-func (w *Watcher) readEvents() {
374
- var (
375
- n, key uint32
376
- ov *syscall.Overlapped
377
- )
378
- runtime.LockOSThread()
379
-
380
- for {
381
- e := syscall.GetQueuedCompletionStatus(w.port, &n, &key, &ov, syscall.INFINITE)
382
- watch := (*watch)(unsafe.Pointer(ov))
383
-
384
- if watch == nil {
385
- select {
386
- case ch := <-w.quit:
387
- w.mu.Lock()
388
- var indexes []indexMap
389
- for _, index := range w.watches {
390
- indexes = append(indexes, index)
391
- }
392
- w.mu.Unlock()
393
- for _, index := range indexes {
394
- for _, watch := range index {
395
- w.deleteWatch(watch)
396
- w.startRead(watch)
397
- }
398
- }
399
- var err error
400
- if e := syscall.CloseHandle(w.port); e != nil {
401
- err = os.NewSyscallError("CloseHandle", e)
402
- }
403
- close(w.Events)
404
- close(w.Errors)
405
- ch <- err
406
- return
407
- case in := <-w.input:
408
- switch in.op {
409
- case opAddWatch:
410
- in.reply <- w.addWatch(in.path, uint64(in.flags))
411
- case opRemoveWatch:
412
- in.reply <- w.remWatch(in.path)
413
- }
414
- default:
415
- }
416
- continue
417
- }
418
-
419
- switch e {
420
- case syscall.ERROR_MORE_DATA:
421
- if watch == nil {
422
- w.Errors <- errors.New("ERROR_MORE_DATA has unexpectedly null lpOverlapped buffer")
423
- } else {
424
- // The i/o succeeded but the buffer is full.
425
- // In theory we should be building up a full packet.
426
- // In practice we can get away with just carrying on.
427
- n = uint32(unsafe.Sizeof(watch.buf))
428
- }
429
- case syscall.ERROR_ACCESS_DENIED:
430
- // Watched directory was probably removed
431
- w.sendEvent(watch.path, watch.mask&sys_FS_DELETE_SELF)
432
- w.deleteWatch(watch)
433
- w.startRead(watch)
434
- continue
435
- case syscall.ERROR_OPERATION_ABORTED:
436
- // CancelIo was called on this handle
437
- continue
438
- default:
439
- w.Errors <- os.NewSyscallError("GetQueuedCompletionPort", e)
440
- continue
441
- case nil:
442
- }
443
-
444
- var offset uint32
445
- for {
446
- if n == 0 {
447
- w.Events <- newEvent("", sys_FS_Q_OVERFLOW)
448
- w.Errors <- errors.New("short read in readEvents()")
449
- break
450
- }
451
-
452
- // Point "raw" to the event in the buffer
453
- raw := (*syscall.FileNotifyInformation)(unsafe.Pointer(&watch.buf[offset]))
454
- buf := (*[syscall.MAX_PATH]uint16)(unsafe.Pointer(&raw.FileName))
455
- name := syscall.UTF16ToString(buf[:raw.FileNameLength/2])
456
- fullname := watch.path + "\\" + name
457
-
458
- var mask uint64
459
- switch raw.Action {
460
- case syscall.FILE_ACTION_REMOVED:
461
- mask = sys_FS_DELETE_SELF
462
- case syscall.FILE_ACTION_MODIFIED:
463
- mask = sys_FS_MODIFY
464
- case syscall.FILE_ACTION_RENAMED_OLD_NAME:
465
- watch.rename = name
466
- case syscall.FILE_ACTION_RENAMED_NEW_NAME:
467
- if watch.names[watch.rename] != 0 {
468
- watch.names[name] |= watch.names[watch.rename]
469
- delete(watch.names, watch.rename)
470
- mask = sys_FS_MOVE_SELF
471
- }
472
- }
473
-
474
- sendNameEvent := func() {
475
- if w.sendEvent(fullname, watch.names[name]&mask) {
476
- if watch.names[name]&sys_FS_ONESHOT != 0 {
477
- delete(watch.names, name)
478
- }
479
- }
480
- }
481
- if raw.Action != syscall.FILE_ACTION_RENAMED_NEW_NAME {
482
- sendNameEvent()
483
- }
484
- if raw.Action == syscall.FILE_ACTION_REMOVED {
485
- w.sendEvent(fullname, watch.names[name]&sys_FS_IGNORED)
486
- delete(watch.names, name)
487
- }
488
- if w.sendEvent(fullname, watch.mask&toFSnotifyFlags(raw.Action)) {
489
- if watch.mask&sys_FS_ONESHOT != 0 {
490
- watch.mask = 0
491
- }
492
- }
493
- if raw.Action == syscall.FILE_ACTION_RENAMED_NEW_NAME {
494
- fullname = watch.path + "\\" + watch.rename
495
- sendNameEvent()
496
- }
497
-
498
- // Move to the next event in the buffer
499
- if raw.NextEntryOffset == 0 {
500
- break
501
- }
502
- offset += raw.NextEntryOffset
503
-
504
- // Error!
505
- if offset >= n {
506
- w.Errors <- errors.New("Windows system assumed buffer larger than it is, events have likely been missed.")
507
- break
508
- }
509
- }
510
-
511
- if err := w.startRead(watch); err != nil {
512
- w.Errors <- err
513
- }
514
- }
515
-}
516
-
517
-func (w *Watcher) sendEvent(name string, mask uint64) bool {
518
- if mask == 0 {
519
- return false
520
- }
521
- event := newEvent(name, uint32(mask))
522
- select {
523
- case ch := <-w.quit:
524
- w.quit <- ch
525
- case w.Events <- event:
526
- }
527
- return true
528
-}
529
-
530
-func toWindowsFlags(mask uint64) uint32 {
531
- var m uint32
532
- if mask&sys_FS_ACCESS != 0 {
533
- m |= syscall.FILE_NOTIFY_CHANGE_LAST_ACCESS
534
- }
535
- if mask&sys_FS_MODIFY != 0 {
536
- m |= syscall.FILE_NOTIFY_CHANGE_LAST_WRITE
537
- }
538
- if mask&sys_FS_ATTRIB != 0 {
539
- m |= syscall.FILE_NOTIFY_CHANGE_ATTRIBUTES
540
- }
541
- if mask&(sys_FS_MOVE|sys_FS_CREATE|sys_FS_DELETE) != 0 {
542
- m |= syscall.FILE_NOTIFY_CHANGE_FILE_NAME | syscall.FILE_NOTIFY_CHANGE_DIR_NAME
543
- }
544
- return m
545
-}
546
-
547
-func toFSnotifyFlags(action uint32) uint64 {
548
- switch action {
549
- case syscall.FILE_ACTION_ADDED:
550
- return sys_FS_CREATE
551
- case syscall.FILE_ACTION_REMOVED:
552
- return sys_FS_DELETE
553
- case syscall.FILE_ACTION_MODIFIED:
554
- return sys_FS_MODIFY
555
- case syscall.FILE_ACTION_RENAMED_OLD_NAME:
556
- return sys_FS_MOVED_FROM
557
- case syscall.FILE_ACTION_RENAMED_NEW_NAME:
558
- return sys_FS_MOVED_TO
559
- }
560
- return 0
561
-}
cmd/ipfswatch/main.go
+1
-1
@@ -8,7 +8,6 @@ import (
8
"path/filepath"
9
10
homedir "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/mitchellh/go-homedir"
11
- fsnotify "github.com/ipfs/go-ipfs/Godeps/_workspace/src/gopkg.in/fsnotify.v1"
11
commands "github.com/ipfs/go-ipfs/commands"
12
core "github.com/ipfs/go-ipfs/core"
13
corehttp "github.com/ipfs/go-ipfs/core/corehttp"
@@ -17,6 +16,7 @@ import (
16
fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo"
17
process "gx/ipfs/QmQopLATEYMNg7dVqZRNDfeE2S1yKy8zrRh5xnYiuqeZBn/goprocess"
18
context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
19
+ fsnotify "gx/ipfs/QmczzCMvJ3HV57WBKDy8b4ucp7quT325JjDbixYRS5Pwvv/fsnotify.v1"
20
)
21
22
var http = flag.Bool("http", false, "expose IPFS HTTP API")
package.json
+6
@@ -135,6 +135,12 @@
135
"hash": "QmZRjKbHa6DenStpQJFiaPcEwkZqrx7TH6xTf342LDU3qM",
136
"name": "go-sysinfo",
137
"version": "0.0.0"
138
+ },
139
+ {
140
+ "author": "kubuxu",
141
+ "hash": "QmczzCMvJ3HV57WBKDy8b4ucp7quT325JjDbixYRS5Pwvv",
142
+ "name": "fsnotify.v1",
143
+ "version": "1.3.0"
144
}
145
],
146
"gxVersion": "0.4.0",