mirror of
https://github.com/ipfs/kubo.git
synced 2025-06-30 18:13:54 +08:00
godeps: update fsnotify to v1.2.0
This commit is contained in:
4
Godeps/Godeps.json
generated
4
Godeps/Godeps.json
generated
@ -237,8 +237,8 @@
|
||||
},
|
||||
{
|
||||
"ImportPath": "gopkg.in/fsnotify.v1",
|
||||
"Comment": "v1.1.0",
|
||||
"Rev": "f582d920d11386e8ae15227bb5933a8f9b4c3dec"
|
||||
"Comment": "v1.2.0",
|
||||
"Rev": "96c060f6a6b7e0d6f75fddd10efeaca3e5d1bcb0"
|
||||
},
|
||||
{
|
||||
"ImportPath": "gopkg.in/natefinch/lumberjack.v2",
|
||||
|
8
Godeps/_workspace/src/gopkg.in/fsnotify.v1/.travis.yml
generated
vendored
8
Godeps/_workspace/src/gopkg.in/fsnotify.v1/.travis.yml
generated
vendored
@ -1,10 +1,12 @@
|
||||
sudo: false
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.2
|
||||
- tip
|
||||
- 1.4.1
|
||||
|
||||
before_script:
|
||||
- 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
|
||||
|
||||
# not yet https://github.com/travis-ci/travis-ci/issues/2318
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
|
1
Godeps/_workspace/src/gopkg.in/fsnotify.v1/AUTHORS
generated
vendored
1
Godeps/_workspace/src/gopkg.in/fsnotify.v1/AUTHORS
generated
vendored
@ -21,6 +21,7 @@ Kelvin Fo <vmirage@gmail.com>
|
||||
Matt Layher <mdlayher@gmail.com>
|
||||
Nathan Youngman <git@nathany.com>
|
||||
Paul Hammond <paul@paulhammond.org>
|
||||
Pieter Droogendijk <pieter@binky.org.uk>
|
||||
Pursuit92 <JoshChase@techpursuit.net>
|
||||
Rob Figueiredo <robfig@gmail.com>
|
||||
Soge Zhang <zhssoge@gmail.com>
|
||||
|
16
Godeps/_workspace/src/gopkg.in/fsnotify.v1/CHANGELOG.md
generated
vendored
16
Godeps/_workspace/src/gopkg.in/fsnotify.v1/CHANGELOG.md
generated
vendored
@ -1,5 +1,15 @@
|
||||
# Changelog
|
||||
|
||||
## v1.2.0 / 2015-02-08
|
||||
|
||||
* inotify: use epoll to wake up readEvents [#66](https://github.com/go-fsnotify/fsnotify/pull/66) (thanks @PieterD)
|
||||
* inotify: closing watcher should now always shut down goroutine [#63](https://github.com/go-fsnotify/fsnotify/pull/63) (thanks @PieterD)
|
||||
* kqueue: close kqueue after removing watches, fixes [#59](https://github.com/go-fsnotify/fsnotify/issues/59)
|
||||
|
||||
## v1.1.1 / 2015-02-05
|
||||
|
||||
* inotify: Retry read on EINTR [#61](https://github.com/go-fsnotify/fsnotify/issues/61) (thanks @PieterD)
|
||||
|
||||
## v1.1.0 / 2014-12-12
|
||||
|
||||
* kqueue: rework internals [#43](https://github.com/go-fsnotify/fsnotify/pull/43)
|
||||
@ -10,7 +20,7 @@
|
||||
* remove calls to os.NewSyscallError
|
||||
* More efficient string concatenation for Event.String() [#52](https://github.com/go-fsnotify/fsnotify/pull/52) (thanks @mdlayher)
|
||||
* kqueue: fix regression in rework causing subdirectories to be watched [#48](https://github.com/go-fsnotify/fsnotify/issues/48)
|
||||
* kqueue: cleanup internal watch before sending remove event [#51](https://github.com/go-fsnotify/fsnotify/issues/48)
|
||||
* kqueue: cleanup internal watch before sending remove event [#51](https://github.com/go-fsnotify/fsnotify/issues/51)
|
||||
|
||||
## v1.0.4 / 2014-09-07
|
||||
|
||||
@ -81,6 +91,10 @@
|
||||
* no tests for the current implementation
|
||||
* not fully implemented on Windows [#93](https://github.com/howeyc/fsnotify/issues/93#issuecomment-39285195)
|
||||
|
||||
## v0.9.3 / 2014-12-31
|
||||
|
||||
* kqueue: cleanup internal watch before sending remove event [#51](https://github.com/go-fsnotify/fsnotify/issues/51)
|
||||
|
||||
## v0.9.2 / 2014-08-17
|
||||
|
||||
* [Backport] Fix missing create events on OS X. [#14](https://github.com/go-fsnotify/fsnotify/issues/14) (thanks @zhsso)
|
||||
|
45
Godeps/_workspace/src/gopkg.in/fsnotify.v1/CONTRIBUTING.md
generated
vendored
45
Godeps/_workspace/src/gopkg.in/fsnotify.v1/CONTRIBUTING.md
generated
vendored
@ -1,21 +1,34 @@
|
||||
# Contributing
|
||||
|
||||
* Send questions to [golang-dev@googlegroups.com](mailto:golang-dev@googlegroups.com).
|
||||
|
||||
### Issues
|
||||
## Issues
|
||||
|
||||
* Request features and report bugs using the [GitHub Issue Tracker](https://github.com/go-fsnotify/fsnotify/issues).
|
||||
* Please indicate the platform you are running on.
|
||||
* Please indicate the platform you are using fsnotify on.
|
||||
* A code example to reproduce the problem is appreciated.
|
||||
|
||||
### Pull Requests
|
||||
## Pull Requests
|
||||
|
||||
### Contributor License Agreement
|
||||
|
||||
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).
|
||||
|
||||
Please indicate that you have signed the CLA in your pull request.
|
||||
|
||||
To hack on fsnotify, please use [the workflow outlined by Katrina Owen](https://blog.splice.com/contributing-open-source-git-repositories-go/), in short:
|
||||
### How fsnotify is Developed
|
||||
|
||||
1. Install as usual (`go get -u github.com/go-fsnotify/fsnotify`)
|
||||
* Development is done on feature branches.
|
||||
* Tests are run on BSD, Linux, OS X and Windows.
|
||||
* Pull requests are reviewed and [applied to master][am] using [hub][].
|
||||
* Maintainers may modify or squash commits rather than asking contributors to.
|
||||
* To issue a new release, the maintainers will:
|
||||
* Update the CHANGELOG
|
||||
* Tag a version, which will become available through gopkg.in.
|
||||
|
||||
### How to Fork
|
||||
|
||||
For smooth sailing, always use the original import path. Installing with `go get` makes this easy.
|
||||
|
||||
1. Install from GitHub (`go get -u github.com/go-fsnotify/fsnotify`)
|
||||
2. Create your feature branch (`git checkout -b my-new-feature`)
|
||||
3. Ensure everything works and the tests pass (see below)
|
||||
4. Commit your changes (`git commit -am 'Add some feature'`)
|
||||
@ -27,15 +40,7 @@ Contribute upstream:
|
||||
3. Push to the branch (`git push fork my-new-feature`)
|
||||
4. Create a new Pull Request on GitHub
|
||||
|
||||
If other team members need your patch before it is merged:
|
||||
|
||||
1. Install as usual (`go get -u github.com/go-fsnotify/fsnotify`)
|
||||
2. Add your remote (`git remote add fork git@github.com:mycompany/repo.git`)
|
||||
3. Pull your revisions (`git fetch fork; git checkout -b my-new-feature fork/my-new-feature`)
|
||||
|
||||
Notice: For smooth sailing, always use the original import path. Installing with `go get` makes this easy.
|
||||
|
||||
Note: The maintainers will update the CHANGELOG on your behalf. Please don't modify it in your pull request.
|
||||
This workflow is [thoroughly explained by Katrina Owen](https://blog.splice.com/contributing-open-source-git-repositories-go/).
|
||||
|
||||
### Testing
|
||||
|
||||
@ -62,11 +67,11 @@ Help maintaining fsnotify is welcome. To be a maintainer:
|
||||
* Submit a pull request and sign the CLA as above.
|
||||
* You must be able to run the test suite on Mac, Windows, Linux and BSD.
|
||||
|
||||
To keep master clean, the fsnotify project uses the "apply mail" workflow outlined in Nathaniel Talbott's post ["Merge pull request" Considered Harmful](http://blog.spreedly.com/2014/06/24/merge-pull-request-considered-harmful/#.VGa5yZPF_Zs).
|
||||
|
||||
This requires installing [hub](https://github.com/github/hub). Both version 1 and 2 support `hub am -3`.
|
||||
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][].
|
||||
|
||||
All code changes should be internal pull requests.
|
||||
|
||||
Releases are tagged using [Semantic Versioning](http://semver.org/), which makes them available through gopkg.in.
|
||||
Releases are tagged using [Semantic Versioning](http://semver.org/).
|
||||
|
||||
[hub]: https://github.com/github/hub
|
||||
[am]: http://blog.spreedly.com/2014/06/24/merge-pull-request-considered-harmful/#.VGa5yZPF_Zs
|
||||
|
0
Godeps/_workspace/src/gopkg.in/fsnotify.v1/NotUsed.xcworkspace
generated
vendored
Normal file
0
Godeps/_workspace/src/gopkg.in/fsnotify.v1/NotUsed.xcworkspace
generated
vendored
Normal file
21
Godeps/_workspace/src/gopkg.in/fsnotify.v1/README.md
generated
vendored
21
Godeps/_workspace/src/gopkg.in/fsnotify.v1/README.md
generated
vendored
@ -8,14 +8,14 @@ Cross platform: Windows, Linux, BSD and OS X.
|
||||
|
||||
|Adapter |OS |Status |
|
||||
|----------|----------|----------|
|
||||
|inotify |Linux, Android\*|Supported|
|
||||
|kqueue |BSD, OS X, iOS\*|Supported|
|
||||
|ReadDirectoryChangesW|Windows|Supported|
|
||||
|inotify |Linux, Android\*|Supported [](https://travis-ci.org/go-fsnotify/fsnotify)|
|
||||
|kqueue |BSD, OS X, iOS\*|Supported [](https://circleci.com/gh/go-fsnotify/fsnotify)|
|
||||
|ReadDirectoryChangesW|Windows|Supported [](https://ci.appveyor.com/project/NathanYoungman/fsnotify/branch/master)|
|
||||
|FSEvents |OS X |[Planned](https://github.com/go-fsnotify/fsnotify/issues/11)|
|
||||
|FEN |Solaris 11 |[Planned](https://github.com/go-fsnotify/fsnotify/issues/12)|
|
||||
|fanotify |Linux 2.6.37+ | |
|
||||
|USN Journals |Windows |[Maybe](https://github.com/go-fsnotify/fsnotify/issues/53)|
|
||||
|Polling |*All* |[Maybe](https://github.com/go-fsnotify/fsnotify/issues/9)|
|
||||
| |Plan 9 | |
|
||||
|
||||
\* Android and iOS are untested.
|
||||
|
||||
@ -41,8 +41,7 @@ import "gopkg.in/fsnotify.v1"
|
||||
|
||||
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.
|
||||
|
||||
**master** may have untagged changes. Use it to test the very latest code,
|
||||
but don't expect it to remain API-compatible:
|
||||
**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:
|
||||
|
||||
```go
|
||||
import "github.com/go-fsnotify/fsnotify"
|
||||
@ -50,13 +49,11 @@ import "github.com/go-fsnotify/fsnotify"
|
||||
|
||||
## Contributing
|
||||
|
||||
* Send questions to [golang-dev@googlegroups.com](mailto:golang-dev@googlegroups.com).
|
||||
* Request features and report bugs using the [GitHub Issue Tracker](https://github.com/go-fsnotify/fsnotify/issues). Please indicate the platform you are running on.
|
||||
|
||||
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).
|
||||
|
||||
Please read [CONTRIBUTING](https://github.com/go-fsnotify/fsnotify/blob/master/CONTRIBUTING.md) before opening a pull request.
|
||||
Please refer to [CONTRIBUTING][] before opening an issue or pull request.
|
||||
|
||||
## Example
|
||||
|
||||
See [example_test.go](https://github.com/go-fsnotify/fsnotify/blob/master/example_test.go).
|
||||
|
||||
|
||||
[contributing]: https://github.com/go-fsnotify/fsnotify/blob/master/CONTRIBUTING.md
|
||||
|
26
Godeps/_workspace/src/gopkg.in/fsnotify.v1/circle.yml
generated
vendored
Normal file
26
Godeps/_workspace/src/gopkg.in/fsnotify.v1/circle.yml
generated
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
## OS X build (CircleCI iOS beta)
|
||||
|
||||
# Pretend like it's an Xcode project, at least to get it running.
|
||||
machine:
|
||||
environment:
|
||||
XCODE_WORKSPACE: NotUsed.xcworkspace
|
||||
XCODE_SCHEME: NotUsed
|
||||
# This is where the go project is actually checked out to:
|
||||
CIRCLE_BUILD_DIR: $HOME/.go_project/src/github.com/go-fsnotify/fsnotify
|
||||
|
||||
dependencies:
|
||||
pre:
|
||||
- brew upgrade go
|
||||
|
||||
test:
|
||||
override:
|
||||
- go test ./...
|
||||
|
||||
# Idealized future config, eventually with cross-platform build matrix :-)
|
||||
|
||||
# machine:
|
||||
# go:
|
||||
# version: 1.4
|
||||
# os:
|
||||
# - osx
|
||||
# - linux
|
2
Godeps/_workspace/src/gopkg.in/fsnotify.v1/example_test.go
generated
vendored
2
Godeps/_workspace/src/gopkg.in/fsnotify.v1/example_test.go
generated
vendored
@ -9,7 +9,7 @@ package fsnotify_test
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/jbenet/go-ipfs/Godeps/_workspace/src/gopkg.in/fsnotify.v1"
|
||||
"github.com/go-fsnotify/fsnotify"
|
||||
)
|
||||
|
||||
func ExampleNewWatcher() {
|
||||
|
139
Godeps/_workspace/src/gopkg.in/fsnotify.v1/inotify.go
generated
vendored
139
Godeps/_workspace/src/gopkg.in/fsnotify.v1/inotify.go
generated
vendored
@ -9,6 +9,7 @@ package fsnotify
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
@ -22,46 +23,65 @@ type Watcher struct {
|
||||
Events chan Event
|
||||
Errors chan error
|
||||
mu sync.Mutex // Map access
|
||||
fd int // File descriptor (as returned by the inotify_init() syscall)
|
||||
fd int
|
||||
poller *fdPoller
|
||||
watches map[string]*watch // Map of inotify watches (key: path)
|
||||
paths map[int]string // Map of watched paths (key: watch descriptor)
|
||||
done chan bool // Channel for sending a "quit message" to the reader goroutine
|
||||
isClosed bool // Set to true when Close() is first called
|
||||
done chan struct{} // Channel for sending a "quit message" to the reader goroutine
|
||||
doneResp chan struct{} // Channel to respond to Close
|
||||
}
|
||||
|
||||
// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events.
|
||||
func NewWatcher() (*Watcher, error) {
|
||||
// Create inotify fd
|
||||
fd, errno := syscall.InotifyInit()
|
||||
if fd == -1 {
|
||||
return nil, os.NewSyscallError("inotify_init", errno)
|
||||
return nil, errno
|
||||
}
|
||||
// Create epoll
|
||||
poller, err := newFdPoller(fd)
|
||||
if err != nil {
|
||||
syscall.Close(fd)
|
||||
return nil, err
|
||||
}
|
||||
w := &Watcher{
|
||||
fd: fd,
|
||||
poller: poller,
|
||||
watches: make(map[string]*watch),
|
||||
paths: make(map[int]string),
|
||||
Events: make(chan Event),
|
||||
Errors: make(chan error),
|
||||
done: make(chan bool, 1),
|
||||
done: make(chan struct{}),
|
||||
doneResp: make(chan struct{}),
|
||||
}
|
||||
|
||||
go w.readEvents()
|
||||
return w, nil
|
||||
}
|
||||
|
||||
func (w *Watcher) isClosed() bool {
|
||||
select {
|
||||
case <-w.done:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// Close removes all watches and closes the events channel.
|
||||
func (w *Watcher) Close() error {
|
||||
if w.isClosed {
|
||||
if w.isClosed() {
|
||||
return nil
|
||||
}
|
||||
w.isClosed = true
|
||||
|
||||
// Remove all watches
|
||||
for name := range w.watches {
|
||||
w.Remove(name)
|
||||
}
|
||||
// Send 'close' signal to goroutine, and set the Watcher to closed.
|
||||
close(w.done)
|
||||
|
||||
// Send "quit" message to the reader goroutine
|
||||
w.done <- true
|
||||
// Wake up goroutine
|
||||
w.poller.wake()
|
||||
|
||||
// Wait for goroutine to close
|
||||
<-w.doneResp
|
||||
|
||||
return nil
|
||||
}
|
||||
@ -69,7 +89,7 @@ func (w *Watcher) Close() error {
|
||||
// Add starts watching the named file or directory (non-recursively).
|
||||
func (w *Watcher) Add(name string) error {
|
||||
name = filepath.Clean(name)
|
||||
if w.isClosed {
|
||||
if w.isClosed() {
|
||||
return errors.New("inotify instance already closed")
|
||||
}
|
||||
|
||||
@ -88,7 +108,7 @@ func (w *Watcher) Add(name string) error {
|
||||
}
|
||||
wd, errno := syscall.InotifyAddWatch(w.fd, name, flags)
|
||||
if wd == -1 {
|
||||
return os.NewSyscallError("inotify_add_watch", errno)
|
||||
return errno
|
||||
}
|
||||
|
||||
w.mu.Lock()
|
||||
@ -99,20 +119,33 @@ func (w *Watcher) Add(name string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Remove stops watching the the named file or directory (non-recursively).
|
||||
// Remove stops watching the named file or directory (non-recursively).
|
||||
func (w *Watcher) Remove(name string) error {
|
||||
name = filepath.Clean(name)
|
||||
|
||||
// Fetch the watch.
|
||||
w.mu.Lock()
|
||||
defer w.mu.Unlock()
|
||||
watch, ok := w.watches[name]
|
||||
|
||||
// Remove it from inotify.
|
||||
if !ok {
|
||||
return fmt.Errorf("can't remove non-existent inotify watch for: %s", name)
|
||||
}
|
||||
// inotify_rm_watch will return EINVAL if the file has been deleted;
|
||||
// the inotify will already have been removed.
|
||||
// That means we can safely delete it from our watches, whatever inotify_rm_watch does.
|
||||
delete(w.watches, name)
|
||||
success, errno := syscall.InotifyRmWatch(w.fd, watch.wd)
|
||||
if success == -1 {
|
||||
return os.NewSyscallError("inotify_rm_watch", errno)
|
||||
// TODO: Perhaps it's not helpful to return an error here in every case.
|
||||
// the only two possible errors are:
|
||||
// EBADF, which happens when w.fd is not a valid file descriptor of any kind.
|
||||
// EINVAL, which is when fd is not an inotify descriptor or wd is not a valid watch descriptor.
|
||||
// Watch descriptors are invalidated when they are removed explicitly or implicitly;
|
||||
// explicitly by inotify_rm_watch, implicitly when the file they are watching is deleted.
|
||||
return errno
|
||||
}
|
||||
delete(w.watches, name)
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -128,35 +161,65 @@ func (w *Watcher) readEvents() {
|
||||
buf [syscall.SizeofInotifyEvent * 4096]byte // Buffer for a maximum of 4096 raw events
|
||||
n int // Number of bytes read with read()
|
||||
errno error // Syscall errno
|
||||
ok bool // For poller.wait
|
||||
)
|
||||
|
||||
defer close(w.doneResp)
|
||||
defer close(w.Errors)
|
||||
defer close(w.Events)
|
||||
defer syscall.Close(w.fd)
|
||||
defer w.poller.close()
|
||||
|
||||
for {
|
||||
// See if there is a message on the "done" channel
|
||||
select {
|
||||
case <-w.done:
|
||||
syscall.Close(w.fd)
|
||||
close(w.Events)
|
||||
close(w.Errors)
|
||||
// See if we have been closed.
|
||||
if w.isClosed() {
|
||||
return
|
||||
default:
|
||||
}
|
||||
|
||||
ok, errno = w.poller.wait()
|
||||
if errno != nil {
|
||||
select {
|
||||
case w.Errors <- errno:
|
||||
case <-w.done:
|
||||
return
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
n, errno = syscall.Read(w.fd, buf[:])
|
||||
// If a signal interrupted execution, see if we've been asked to close, and try again.
|
||||
// http://man7.org/linux/man-pages/man7/signal.7.html :
|
||||
// "Before Linux 3.8, reads from an inotify(7) file descriptor were not restartable"
|
||||
if errno == syscall.EINTR {
|
||||
continue
|
||||
}
|
||||
|
||||
// If EOF is received
|
||||
if n == 0 {
|
||||
syscall.Close(w.fd)
|
||||
close(w.Events)
|
||||
close(w.Errors)
|
||||
// syscall.Read might have been woken up by Close. If so, we're done.
|
||||
if w.isClosed() {
|
||||
return
|
||||
}
|
||||
|
||||
if n < 0 {
|
||||
w.Errors <- os.NewSyscallError("read", errno)
|
||||
continue
|
||||
}
|
||||
if n < syscall.SizeofInotifyEvent {
|
||||
w.Errors <- errors.New("inotify: short read in readEvents()")
|
||||
var err error
|
||||
if n == 0 {
|
||||
// If EOF is received. This should really never happen.
|
||||
err = io.EOF
|
||||
} else if n < 0 {
|
||||
// If an error occured while reading.
|
||||
err = errno
|
||||
} else {
|
||||
// Read was too short.
|
||||
err = errors.New("notify: short read in readEvents()")
|
||||
}
|
||||
select {
|
||||
case w.Errors <- err:
|
||||
case <-w.done:
|
||||
return
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
@ -187,7 +250,11 @@ func (w *Watcher) readEvents() {
|
||||
|
||||
// Send the events that are not ignored on the events channel
|
||||
if !event.ignoreLinux(mask) {
|
||||
w.Events <- event
|
||||
select {
|
||||
case w.Events <- event:
|
||||
case <-w.done:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Move to the next event in the buffer
|
||||
|
186
Godeps/_workspace/src/gopkg.in/fsnotify.v1/inotify_poller.go
generated
vendored
Normal file
186
Godeps/_workspace/src/gopkg.in/fsnotify.v1/inotify_poller.go
generated
vendored
Normal file
@ -0,0 +1,186 @@
|
||||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build linux
|
||||
|
||||
package fsnotify
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
type fdPoller struct {
|
||||
fd int // File descriptor (as returned by the inotify_init() syscall)
|
||||
epfd int // Epoll file descriptor
|
||||
pipe [2]int // Pipe for waking up
|
||||
}
|
||||
|
||||
func emptyPoller(fd int) *fdPoller {
|
||||
poller := new(fdPoller)
|
||||
poller.fd = fd
|
||||
poller.epfd = -1
|
||||
poller.pipe[0] = -1
|
||||
poller.pipe[1] = -1
|
||||
return poller
|
||||
}
|
||||
|
||||
// Create a new inotify poller.
|
||||
// This creates an inotify handler, and an epoll handler.
|
||||
func newFdPoller(fd int) (*fdPoller, error) {
|
||||
var errno error
|
||||
poller := emptyPoller(fd)
|
||||
defer func() {
|
||||
if errno != nil {
|
||||
poller.close()
|
||||
}
|
||||
}()
|
||||
poller.fd = fd
|
||||
|
||||
// Create epoll fd
|
||||
poller.epfd, errno = syscall.EpollCreate(1)
|
||||
if poller.epfd == -1 {
|
||||
return nil, errno
|
||||
}
|
||||
// Create pipe; pipe[0] is the read end, pipe[1] the write end.
|
||||
errno = syscall.Pipe2(poller.pipe[:], syscall.O_NONBLOCK)
|
||||
if errno != nil {
|
||||
return nil, errno
|
||||
}
|
||||
|
||||
// Register inotify fd with epoll
|
||||
event := syscall.EpollEvent{
|
||||
Fd: int32(poller.fd),
|
||||
Events: syscall.EPOLLIN,
|
||||
}
|
||||
errno = syscall.EpollCtl(poller.epfd, syscall.EPOLL_CTL_ADD, poller.fd, &event)
|
||||
if errno != nil {
|
||||
return nil, errno
|
||||
}
|
||||
|
||||
// Register pipe fd with epoll
|
||||
event = syscall.EpollEvent{
|
||||
Fd: int32(poller.pipe[0]),
|
||||
Events: syscall.EPOLLIN,
|
||||
}
|
||||
errno = syscall.EpollCtl(poller.epfd, syscall.EPOLL_CTL_ADD, poller.pipe[0], &event)
|
||||
if errno != nil {
|
||||
return nil, errno
|
||||
}
|
||||
|
||||
return poller, nil
|
||||
}
|
||||
|
||||
// Wait using epoll.
|
||||
// Returns true if something is ready to be read,
|
||||
// false if there is not.
|
||||
func (poller *fdPoller) wait() (bool, error) {
|
||||
// 3 possible events per fd, and 2 fds, makes a maximum of 6 events.
|
||||
// I don't know whether epoll_wait returns the number of events returned,
|
||||
// or the total number of events ready.
|
||||
// I decided to catch both by making the buffer one larger than the maximum.
|
||||
events := make([]syscall.EpollEvent, 7)
|
||||
for {
|
||||
n, errno := syscall.EpollWait(poller.epfd, events, -1)
|
||||
if n == -1 {
|
||||
if errno == syscall.EINTR {
|
||||
continue
|
||||
}
|
||||
return false, errno
|
||||
}
|
||||
if n == 0 {
|
||||
// If there are no events, try again.
|
||||
continue
|
||||
}
|
||||
if n > 6 {
|
||||
// This should never happen. More events were returned than should be possible.
|
||||
return false, errors.New("epoll_wait returned more events than I know what to do with")
|
||||
}
|
||||
ready := events[:n]
|
||||
epollhup := false
|
||||
epollerr := false
|
||||
epollin := false
|
||||
for _, event := range ready {
|
||||
if event.Fd == int32(poller.fd) {
|
||||
if event.Events&syscall.EPOLLHUP != 0 {
|
||||
// This should not happen, but if it does, treat it as a wakeup.
|
||||
epollhup = true
|
||||
}
|
||||
if event.Events&syscall.EPOLLERR != 0 {
|
||||
// If an error is waiting on the file descriptor, we should pretend
|
||||
// something is ready to read, and let syscall.Read pick up the error.
|
||||
epollerr = true
|
||||
}
|
||||
if event.Events&syscall.EPOLLIN != 0 {
|
||||
// There is data to read.
|
||||
epollin = true
|
||||
}
|
||||
}
|
||||
if event.Fd == int32(poller.pipe[0]) {
|
||||
if event.Events&syscall.EPOLLHUP != 0 {
|
||||
// Write pipe descriptor was closed, by us. This means we're closing down the
|
||||
// watcher, and we should wake up.
|
||||
}
|
||||
if event.Events&syscall.EPOLLERR != 0 {
|
||||
// If an error is waiting on the pipe file descriptor.
|
||||
// This is an absolute mystery, and should never ever happen.
|
||||
return false, errors.New("Error on the pipe descriptor.")
|
||||
}
|
||||
if event.Events&syscall.EPOLLIN != 0 {
|
||||
// This is a regular wakeup, so we have to clear the buffer.
|
||||
err := poller.clearWake()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if epollhup || epollerr || epollin {
|
||||
return true, nil
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Close the write end of the poller.
|
||||
func (poller *fdPoller) wake() error {
|
||||
buf := make([]byte, 1)
|
||||
n, errno := syscall.Write(poller.pipe[1], buf)
|
||||
if n == -1 {
|
||||
if errno == syscall.EAGAIN {
|
||||
// Buffer is full, poller will wake.
|
||||
return nil
|
||||
}
|
||||
return errno
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (poller *fdPoller) clearWake() error {
|
||||
// You have to be woken up a LOT in order to get to 100!
|
||||
buf := make([]byte, 100)
|
||||
n, errno := syscall.Read(poller.pipe[0], buf)
|
||||
if n == -1 {
|
||||
if errno == syscall.EAGAIN {
|
||||
// Buffer is empty, someone else cleared our wake.
|
||||
return nil
|
||||
}
|
||||
return errno
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close all poller file descriptors, but not the one passed to it.
|
||||
func (poller *fdPoller) close() {
|
||||
if poller.pipe[1] != -1 {
|
||||
syscall.Close(poller.pipe[1])
|
||||
}
|
||||
if poller.pipe[0] != -1 {
|
||||
syscall.Close(poller.pipe[0])
|
||||
}
|
||||
if poller.epfd != -1 {
|
||||
syscall.Close(poller.epfd)
|
||||
}
|
||||
}
|
228
Godeps/_workspace/src/gopkg.in/fsnotify.v1/inotify_poller_test.go
generated
vendored
Normal file
228
Godeps/_workspace/src/gopkg.in/fsnotify.v1/inotify_poller_test.go
generated
vendored
Normal file
@ -0,0 +1,228 @@
|
||||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build linux
|
||||
|
||||
package fsnotify
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
type testFd [2]int
|
||||
|
||||
func makeTestFd(t *testing.T) testFd {
|
||||
var tfd testFd
|
||||
errno := syscall.Pipe(tfd[:])
|
||||
if errno != nil {
|
||||
t.Fatalf("Failed to create pipe: %v", errno)
|
||||
}
|
||||
return tfd
|
||||
}
|
||||
|
||||
func (tfd testFd) fd() int {
|
||||
return tfd[0]
|
||||
}
|
||||
|
||||
func (tfd testFd) closeWrite(t *testing.T) {
|
||||
errno := syscall.Close(tfd[1])
|
||||
if errno != nil {
|
||||
t.Fatalf("Failed to close write end of pipe: %v", errno)
|
||||
}
|
||||
}
|
||||
|
||||
func (tfd testFd) put(t *testing.T) {
|
||||
buf := make([]byte, 10)
|
||||
_, errno := syscall.Write(tfd[1], buf)
|
||||
if errno != nil {
|
||||
t.Fatalf("Failed to write to pipe: %v", errno)
|
||||
}
|
||||
}
|
||||
|
||||
func (tfd testFd) get(t *testing.T) {
|
||||
buf := make([]byte, 10)
|
||||
_, errno := syscall.Read(tfd[0], buf)
|
||||
if errno != nil {
|
||||
t.Fatalf("Failed to read from pipe: %v", errno)
|
||||
}
|
||||
}
|
||||
|
||||
func (tfd testFd) close() {
|
||||
syscall.Close(tfd[1])
|
||||
syscall.Close(tfd[0])
|
||||
}
|
||||
|
||||
func makePoller(t *testing.T) (testFd, *fdPoller) {
|
||||
tfd := makeTestFd(t)
|
||||
poller, err := newFdPoller(tfd.fd())
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create poller: %v", err)
|
||||
}
|
||||
return tfd, poller
|
||||
}
|
||||
|
||||
func TestPollerWithBadFd(t *testing.T) {
|
||||
_, err := newFdPoller(-1)
|
||||
if err != syscall.EBADF {
|
||||
t.Fatalf("Expected EBADF, got: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPollerWithData(t *testing.T) {
|
||||
tfd, poller := makePoller(t)
|
||||
defer tfd.close()
|
||||
defer poller.close()
|
||||
|
||||
tfd.put(t)
|
||||
ok, err := poller.wait()
|
||||
if err != nil {
|
||||
t.Fatalf("poller failed: %v", err)
|
||||
}
|
||||
if !ok {
|
||||
t.Fatalf("expected poller to return true")
|
||||
}
|
||||
tfd.get(t)
|
||||
}
|
||||
|
||||
func TestPollerWithWakeup(t *testing.T) {
|
||||
tfd, poller := makePoller(t)
|
||||
defer tfd.close()
|
||||
defer poller.close()
|
||||
|
||||
err := poller.wake()
|
||||
if err != nil {
|
||||
t.Fatalf("wake failed: %v", err)
|
||||
}
|
||||
ok, err := poller.wait()
|
||||
if err != nil {
|
||||
t.Fatalf("poller failed: %v", err)
|
||||
}
|
||||
if ok {
|
||||
t.Fatalf("expected poller to return false")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPollerWithClose(t *testing.T) {
|
||||
tfd, poller := makePoller(t)
|
||||
defer tfd.close()
|
||||
defer poller.close()
|
||||
|
||||
tfd.closeWrite(t)
|
||||
ok, err := poller.wait()
|
||||
if err != nil {
|
||||
t.Fatalf("poller failed: %v", err)
|
||||
}
|
||||
if !ok {
|
||||
t.Fatalf("expected poller to return true")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPollerWithWakeupAndData(t *testing.T) {
|
||||
tfd, poller := makePoller(t)
|
||||
defer tfd.close()
|
||||
defer poller.close()
|
||||
|
||||
tfd.put(t)
|
||||
err := poller.wake()
|
||||
if err != nil {
|
||||
t.Fatalf("wake failed: %v", err)
|
||||
}
|
||||
|
||||
// both data and wakeup
|
||||
ok, err := poller.wait()
|
||||
if err != nil {
|
||||
t.Fatalf("poller failed: %v", err)
|
||||
}
|
||||
if !ok {
|
||||
t.Fatalf("expected poller to return true")
|
||||
}
|
||||
|
||||
// data is still in the buffer, wakeup is cleared
|
||||
ok, err = poller.wait()
|
||||
if err != nil {
|
||||
t.Fatalf("poller failed: %v", err)
|
||||
}
|
||||
if !ok {
|
||||
t.Fatalf("expected poller to return true")
|
||||
}
|
||||
|
||||
tfd.get(t)
|
||||
// data is gone, only wakeup now
|
||||
err = poller.wake()
|
||||
if err != nil {
|
||||
t.Fatalf("wake failed: %v", err)
|
||||
}
|
||||
ok, err = poller.wait()
|
||||
if err != nil {
|
||||
t.Fatalf("poller failed: %v", err)
|
||||
}
|
||||
if ok {
|
||||
t.Fatalf("expected poller to return false")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPollerConcurrent(t *testing.T) {
|
||||
tfd, poller := makePoller(t)
|
||||
defer tfd.close()
|
||||
defer poller.close()
|
||||
|
||||
oks := make(chan bool)
|
||||
live := make(chan bool)
|
||||
defer close(live)
|
||||
go func() {
|
||||
defer close(oks)
|
||||
for {
|
||||
ok, err := poller.wait()
|
||||
if err != nil {
|
||||
t.Fatalf("poller failed: %v", err)
|
||||
}
|
||||
oks <- ok
|
||||
if !<-live {
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// Try a write
|
||||
select {
|
||||
case <-time.After(50 * time.Millisecond):
|
||||
case <-oks:
|
||||
t.Fatalf("poller did not wait")
|
||||
}
|
||||
tfd.put(t)
|
||||
if !<-oks {
|
||||
t.Fatalf("expected true")
|
||||
}
|
||||
tfd.get(t)
|
||||
live <- true
|
||||
|
||||
// Try a wakeup
|
||||
select {
|
||||
case <-time.After(50 * time.Millisecond):
|
||||
case <-oks:
|
||||
t.Fatalf("poller did not wait")
|
||||
}
|
||||
err := poller.wake()
|
||||
if err != nil {
|
||||
t.Fatalf("wake failed: %v", err)
|
||||
}
|
||||
if <-oks {
|
||||
t.Fatalf("expected false")
|
||||
}
|
||||
live <- true
|
||||
|
||||
// Try a close
|
||||
select {
|
||||
case <-time.After(50 * time.Millisecond):
|
||||
case <-oks:
|
||||
t.Fatalf("poller did not wait")
|
||||
}
|
||||
tfd.closeWrite(t)
|
||||
if !<-oks {
|
||||
t.Fatalf("expected true")
|
||||
}
|
||||
tfd.get(t)
|
||||
}
|
292
Godeps/_workspace/src/gopkg.in/fsnotify.v1/inotify_test.go
generated
vendored
Normal file
292
Godeps/_workspace/src/gopkg.in/fsnotify.v1/inotify_test.go
generated
vendored
Normal file
@ -0,0 +1,292 @@
|
||||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build linux
|
||||
|
||||
package fsnotify
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestInotifyCloseRightAway(t *testing.T) {
|
||||
w, err := NewWatcher()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create watcher")
|
||||
}
|
||||
|
||||
// Close immediately; it won't even reach the first syscall.Read.
|
||||
w.Close()
|
||||
|
||||
// Wait for the close to complete.
|
||||
<-time.After(50 * time.Millisecond)
|
||||
isWatcherReallyClosed(t, w)
|
||||
}
|
||||
|
||||
func TestInotifyCloseSlightlyLater(t *testing.T) {
|
||||
w, err := NewWatcher()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create watcher")
|
||||
}
|
||||
|
||||
// Wait until readEvents has reached syscall.Read, and Close.
|
||||
<-time.After(50 * time.Millisecond)
|
||||
w.Close()
|
||||
|
||||
// Wait for the close to complete.
|
||||
<-time.After(50 * time.Millisecond)
|
||||
isWatcherReallyClosed(t, w)
|
||||
}
|
||||
|
||||
func TestInotifyCloseSlightlyLaterWithWatch(t *testing.T) {
|
||||
testDir := tempMkdir(t)
|
||||
defer os.RemoveAll(testDir)
|
||||
|
||||
w, err := NewWatcher()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create watcher")
|
||||
}
|
||||
w.Add(testDir)
|
||||
|
||||
// Wait until readEvents has reached syscall.Read, and Close.
|
||||
<-time.After(50 * time.Millisecond)
|
||||
w.Close()
|
||||
|
||||
// Wait for the close to complete.
|
||||
<-time.After(50 * time.Millisecond)
|
||||
isWatcherReallyClosed(t, w)
|
||||
}
|
||||
|
||||
func TestInotifyCloseAfterRead(t *testing.T) {
|
||||
testDir := tempMkdir(t)
|
||||
defer os.RemoveAll(testDir)
|
||||
|
||||
w, err := NewWatcher()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create watcher")
|
||||
}
|
||||
|
||||
err = w.Add(testDir)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to add .")
|
||||
}
|
||||
|
||||
// Generate an event.
|
||||
os.Create(filepath.Join(testDir, "somethingSOMETHINGsomethingSOMETHING"))
|
||||
|
||||
// Wait for readEvents to read the event, then close the watcher.
|
||||
<-time.After(50 * time.Millisecond)
|
||||
w.Close()
|
||||
|
||||
// Wait for the close to complete.
|
||||
<-time.After(50 * time.Millisecond)
|
||||
isWatcherReallyClosed(t, w)
|
||||
}
|
||||
|
||||
func isWatcherReallyClosed(t *testing.T, w *Watcher) {
|
||||
select {
|
||||
case err, ok := <-w.Errors:
|
||||
if ok {
|
||||
t.Fatalf("w.Errors is not closed; readEvents is still alive after closing (error: %v)", err)
|
||||
}
|
||||
default:
|
||||
t.Fatalf("w.Errors would have blocked; readEvents is still alive!")
|
||||
}
|
||||
|
||||
select {
|
||||
case _, ok := <-w.Events:
|
||||
if ok {
|
||||
t.Fatalf("w.Events is not closed; readEvents is still alive after closing")
|
||||
}
|
||||
default:
|
||||
t.Fatalf("w.Events would have blocked; readEvents is still alive!")
|
||||
}
|
||||
}
|
||||
|
||||
func TestInotifyCloseCreate(t *testing.T) {
|
||||
testDir := tempMkdir(t)
|
||||
defer os.RemoveAll(testDir)
|
||||
|
||||
w, err := NewWatcher()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create watcher: %v", err)
|
||||
}
|
||||
defer w.Close()
|
||||
|
||||
err = w.Add(testDir)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to add testDir: %v", err)
|
||||
}
|
||||
h, err := os.Create(filepath.Join(testDir, "testfile"))
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create file in testdir: %v", err)
|
||||
}
|
||||
h.Close()
|
||||
select {
|
||||
case _ = <-w.Events:
|
||||
case err := <-w.Errors:
|
||||
t.Fatalf("Error from watcher: %v", err)
|
||||
case <-time.After(50 * time.Millisecond):
|
||||
t.Fatalf("Took too long to wait for event")
|
||||
}
|
||||
|
||||
// At this point, we've received one event, so the goroutine is ready.
|
||||
// It's also blocking on syscall.Read.
|
||||
// Now we try to swap the file descriptor under its nose.
|
||||
w.Close()
|
||||
w, err = NewWatcher()
|
||||
defer w.Close()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create second watcher: %v", err)
|
||||
}
|
||||
|
||||
<-time.After(50 * time.Millisecond)
|
||||
err = w.Add(testDir)
|
||||
if err != nil {
|
||||
t.Fatalf("Error adding testDir again: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInotifyStress(t *testing.T) {
|
||||
testDir := tempMkdir(t)
|
||||
defer os.RemoveAll(testDir)
|
||||
testFile := filepath.Join(testDir, "testfile")
|
||||
|
||||
w, err := NewWatcher()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create watcher: %v", err)
|
||||
}
|
||||
defer w.Close()
|
||||
|
||||
killchan := make(chan struct{})
|
||||
defer close(killchan)
|
||||
|
||||
err = w.Add(testDir)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to add testDir: %v", err)
|
||||
}
|
||||
|
||||
proc, err := os.FindProcess(os.Getpid())
|
||||
if err != nil {
|
||||
t.Fatalf("Error finding process: %v", err)
|
||||
}
|
||||
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case <-time.After(5 * time.Millisecond):
|
||||
err := proc.Signal(syscall.SIGUSR1)
|
||||
if err != nil {
|
||||
t.Fatalf("Signal failed: %v", err)
|
||||
}
|
||||
case <-killchan:
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case <-time.After(11 * time.Millisecond):
|
||||
err := w.poller.wake()
|
||||
if err != nil {
|
||||
t.Fatalf("Wake failed: %v", err)
|
||||
}
|
||||
case <-killchan:
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case <-killchan:
|
||||
return
|
||||
default:
|
||||
handle, err := os.Create(testFile)
|
||||
if err != nil {
|
||||
t.Fatalf("Create failed: %v", err)
|
||||
}
|
||||
handle.Close()
|
||||
time.Sleep(time.Millisecond)
|
||||
err = os.Remove(testFile)
|
||||
if err != nil {
|
||||
t.Fatalf("Remove failed: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
creates := 0
|
||||
removes := 0
|
||||
after := time.After(5 * time.Second)
|
||||
for {
|
||||
select {
|
||||
case <-after:
|
||||
if creates-removes > 1 || creates-removes < -1 {
|
||||
t.Fatalf("Creates and removes should not be off by more than one: %d creates, %d removes", creates, removes)
|
||||
}
|
||||
if creates < 50 {
|
||||
t.Fatalf("Expected at least 50 creates, got %d", creates)
|
||||
}
|
||||
return
|
||||
case err := <-w.Errors:
|
||||
t.Fatalf("Got an error from watcher: %v", err)
|
||||
case evt := <-w.Events:
|
||||
if evt.Name != testFile {
|
||||
t.Fatalf("Got an event for an unknown file: %s", evt.Name)
|
||||
}
|
||||
if evt.Op == Create {
|
||||
creates++
|
||||
}
|
||||
if evt.Op == Remove {
|
||||
removes++
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestInotifyRemoveTwice(t *testing.T) {
|
||||
testDir := tempMkdir(t)
|
||||
defer os.RemoveAll(testDir)
|
||||
testFile := filepath.Join(testDir, "testfile")
|
||||
|
||||
handle, err := os.Create(testFile)
|
||||
if err != nil {
|
||||
t.Fatalf("Create failed: %v", err)
|
||||
}
|
||||
handle.Close()
|
||||
|
||||
w, err := NewWatcher()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create watcher: %v", err)
|
||||
}
|
||||
defer w.Close()
|
||||
|
||||
err = w.Add(testFile)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to add testFile: %v", err)
|
||||
}
|
||||
|
||||
err = os.Remove(testFile)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to remove testFile: %v", err)
|
||||
}
|
||||
|
||||
err = w.Remove(testFile)
|
||||
if err != syscall.EINVAL {
|
||||
t.Fatalf("Expected EINVAL from Remove, got: %v", err)
|
||||
}
|
||||
|
||||
err = w.Remove(testFile)
|
||||
if err == syscall.EINVAL {
|
||||
t.Fatalf("Got EINVAL again, watch was not removed")
|
||||
}
|
||||
}
|
15
Godeps/_workspace/src/gopkg.in/fsnotify.v1/integration_test.go
generated
vendored
15
Godeps/_workspace/src/gopkg.in/fsnotify.v1/integration_test.go
generated
vendored
@ -1109,6 +1109,21 @@ func TestConcurrentRemovalOfWatch(t *testing.T) {
|
||||
<-removed2
|
||||
}
|
||||
|
||||
func TestClose(t *testing.T) {
|
||||
// Regression test for #59 bad file descriptor from Close
|
||||
testDir := tempMkdir(t)
|
||||
defer os.RemoveAll(testDir)
|
||||
|
||||
watcher := newWatcher(t)
|
||||
if err := watcher.Add(testDir); err != nil {
|
||||
t.Fatalf("Expected no error on Add, got %v", err)
|
||||
}
|
||||
err := watcher.Close()
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error on Close, got %v.", err)
|
||||
}
|
||||
}
|
||||
|
||||
func testRename(file1, file2 string) error {
|
||||
switch runtime.GOOS {
|
||||
case "windows", "plan9":
|
||||
|
12
Godeps/_workspace/src/gopkg.in/fsnotify.v1/kqueue.go
generated
vendored
12
Godeps/_workspace/src/gopkg.in/fsnotify.v1/kqueue.go
generated
vendored
@ -72,15 +72,19 @@ func (w *Watcher) Close() error {
|
||||
w.isClosed = true
|
||||
w.mu.Unlock()
|
||||
|
||||
// Send "quit" message to the reader goroutine:
|
||||
w.done <- true
|
||||
|
||||
w.mu.Lock()
|
||||
ws := w.watches
|
||||
w.mu.Unlock()
|
||||
|
||||
var err error
|
||||
for name := range ws {
|
||||
w.Remove(name)
|
||||
if e := w.Remove(name); e != nil && err == nil {
|
||||
err = e
|
||||
}
|
||||
}
|
||||
|
||||
// Send "quit" message to the reader goroutine:
|
||||
w.done <- true
|
||||
|
||||
return nil
|
||||
}
|
||||
|
Reference in New Issue
Block a user