@cryptotaxi247 / kubo / commits / fb0aa6358

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 -[![Coverage](http://gocover.io/_badge/github.com/go-fsnotify/fsnotify)](http://gocover.io/github.com/go-fsnotify/fsnotify) [![GoDoc](https://godoc.org/gopkg.in/fsnotify.v1?status.svg)](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 [![Build Status](https://travis-ci.org/go-fsnotify/fsnotify.svg?branch=master)](https://travis-ci.org/go-fsnotify/fsnotify)|
12 -|kqueue |BSD, OS X, iOS\*|Supported [![Circle CI](https://circleci.com/gh/go-fsnotify/fsnotify.svg?style=svg)](https://circleci.com/gh/go-fsnotify/fsnotify)|
13 -|ReadDirectoryChangesW|Windows|Supported [![Build status](https://ci.appveyor.com/api/projects/status/ivwjubaih4r0udeh/branch/master?svg=true)](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",