Improve documentation for exported identifiers.
closes #30
# Changelog
+## v0.14.3 / 2014-08-15
+
+* Improve documentation for exported identifiers. [#30](https://github.com/go-fsnotify/fsnotify/issues/30)
+* Minor updates based on feedback from golint.
+
## v0.14.2 / 2014-07-09
* Moved to [github.com/go-fsnotify/fsnotify](https://github.com/go-fsnotify/fsnotify).
## v0.13.0 / 2014-06-21
* Events channel of type Event rather than *Event.
-* Add/Remove accept a name rather than a path (same behavior).
* [API] Remove AddWatch on Windows, use Add.
* [internal] use syscall constants directly for inotify and kqueue.
* [internal] kqueue: rename events to kevents and fileEvent to event.
// +build !plan9,!solaris
-// Package fsnotify implements file system notification.
+// Package fsnotify provides a platform-independent interface for file system notifications.
package fsnotify
import "fmt"
-// Event represents a single file system event.
+// Event represents a single file system notification.
type Event struct {
- Name string // Relative path to the file/directory.
- Op Op // Platform-independent bitmask.
+ Name string // Relative path to the file or directory.
+ Op Op // File operation that triggered the event.
}
// Op describes a set of file operations.
Chmod
)
-// String formats the event e in the form
-// "filename: REMOVE|WRITE|..."
+// String returns a string representation of the event in the form
+// "file: REMOVE|WRITE|..."
func (e Event) String() string {
events := ""
if e.Op&Create == Create {
- events += "|" + "CREATE"
+ events += "|CREATE"
}
-
if e.Op&Remove == Remove {
- events += "|" + "REMOVE"
+ events += "|REMOVE"
}
-
if e.Op&Write == Write {
- events += "|" + "WRITE"
+ events += "|WRITE"
}
-
if e.Op&Rename == Rename {
- events += "|" + "RENAME"
+ events += "|RENAME"
}
-
if e.Op&Chmod == Chmod {
- events += "|" + "CHMOD"
+ events += "|CHMOD"
}
if len(events) > 0 {
)
const (
- // Watch all events
- sys_NOTE_ALLEVENTS = syscall.NOTE_DELETE | syscall.NOTE_WRITE | syscall.NOTE_ATTRIB | syscall.NOTE_RENAME
+ // Watch all events (except NOTE_EXTEND, NOTE_LINK, NOTE_REVOKE)
+ noteAllEvents = syscall.NOTE_DELETE | syscall.NOTE_WRITE | syscall.NOTE_ATTRIB | syscall.NOTE_RENAME
// Block for 100 ms on each call to kevent
keventWaitTime = 100e6
)
+// newEvent returns an platform-independent Event based on kqueue Fflags.
func newEvent(name string, mask uint32, create bool) Event {
e := Event{Name: name}
if create {
return e
}
+// Watcher watches a set of files, delivering events to a channel.
type Watcher struct {
+ Events chan Event
+ Errors chan error
mu sync.Mutex // Mutex for the Watcher itself.
- kq int // File descriptor (as returned by the kqueue() syscall)
- watches map[string]int // Map of watched file descriptors (key: path)
+ kq int // File descriptor (as returned by the kqueue() syscall).
+ watches map[string]int // Map of watched file descriptors (key: path).
wmut sync.Mutex // Protects access to watches.
- enFlags map[string]uint32 // Map of watched files to evfilt note flags used in kqueue
+ enFlags map[string]uint32 // Map of watched files to evfilt note flags used in kqueue.
enmut sync.Mutex // Protects access to enFlags.
- paths map[int]string // Map of watched paths (key: watch descriptor)
- finfo map[int]os.FileInfo // Map of file information (isDir, isReg; key: watch descriptor)
+ paths map[int]string // Map of watched paths (key: watch descriptor).
+ finfo map[int]os.FileInfo // Map of file information (isDir, isReg; key: watch descriptor).
pmut sync.Mutex // Protects access to paths and finfo.
- fileExists map[string]bool // Keep track of if we know this file exists (to stop duplicate create events)
+ fileExists map[string]bool // Keep track of if we know this file exists (to stop duplicate create events).
femut sync.Mutex // Protects access to fileExists.
externalWatches map[string]bool // Map of watches added by user of the library.
ewmut sync.Mutex // Protects access to externalWatches.
- Errors chan error // Errors are sent on this channel
- Events chan Event // Events are returned on this channel
done chan bool // Channel for sending a "quit message" to the reader goroutine
isClosed bool // Set to true when Close() is first called
}
-// NewWatcher creates and returns a new kevent instance using kqueue(2)
+// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events.
func NewWatcher() (*Watcher, error) {
fd, errno := syscall.Kqueue()
if fd == -1 {
return w, nil
}
-// Close closes a kevent watcher instance
-// It sends a message to the reader goroutine to quit and removes all watches
-// associated with the kevent instance
+// Close removes all watches and closes the events channel.
func (w *Watcher) Close() error {
w.mu.Lock()
if w.isClosed {
w.isClosed = true
w.mu.Unlock()
- // Send "quit" message to the reader goroutine
+ // Send "quit" message to the reader goroutine:
w.done <- true
w.wmut.Lock()
ws := w.watches
return nil
}
-// AddWatch adds path to the watched file set.
+// addWatch adds path to the watched file set.
// The flags are interpreted as described in kevent(2).
func (w *Watcher) addWatch(path string, flags uint32) error {
w.mu.Lock()
}
}
- fd, errno := syscall.Open(path, open_FLAGS, 0700)
+ fd, errno := syscall.Open(path, openMode, 0700)
if fd == -1 {
return os.NewSyscallError("Open", errno)
}
return nil
}
-// Add starts watching on the named file.
+// Add starts watching the named file or directory (non-recursively).
func (w *Watcher) Add(name string) error {
w.ewmut.Lock()
w.externalWatches[name] = true
w.ewmut.Unlock()
- return w.addWatch(name, sys_NOTE_ALLEVENTS)
+ return w.addWatch(name, noteAllEvents)
}
-// Remove stops watching on the named file.
+// Remove stops watching the the named file or directory (non-recursively).
func (w *Watcher) Remove(name string) error {
w.wmut.Lock()
watchfd, ok := w.watches[name]
w.wmut.Unlock()
if !ok {
- return errors.New(fmt.Sprintf("can't remove non-existent kevent watch for: %s", name))
+ return fmt.Errorf("can't remove non-existent kevent watch for: %s", name)
}
var kbuf [1]syscall.Kevent_t
watchEntry := &kbuf[0]
if fileInfo.IsDir() == false {
// Watch file to mimic linux fsnotify
- e := w.addWatch(filePath, sys_NOTE_ALLEVENTS)
+ e := w.addWatch(filePath, noteAllEvents)
if e != nil {
return e
}
)
const (
- sys_AGNOSTIC_EVENTS = syscall.IN_MOVED_TO | syscall.IN_MOVED_FROM |
+ agnosticEvents = syscall.IN_MOVED_TO | syscall.IN_MOVED_FROM |
syscall.IN_CREATE | syscall.IN_ATTRIB | syscall.IN_MODIFY |
syscall.IN_MOVE_SELF | syscall.IN_DELETE | syscall.IN_DELETE_SELF
)
+// newEvent returns an platform-independent Event based on an inotify mask.
func newEvent(name string, mask uint32) Event {
e := Event{Name: name}
if mask&syscall.IN_CREATE == syscall.IN_CREATE || mask&syscall.IN_MOVED_TO == syscall.IN_MOVED_TO {
flags uint32 // inotify flags of this watch (see inotify(7) for the list of valid flags)
}
+// Watcher watches a set of files, delivering events to a channel.
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)
watches map[string]*watch // Map of inotify watches (key: path)
paths map[int]string // Map of watched paths (key: watch descriptor)
- Errors chan error // Errors are sent on this channel
- Events chan Event // Events are returned on this channel
done chan bool // Channel for sending a "quit message" to the reader goroutine
isClosed bool // Set to true when Close() is first called
}
-// NewWatcher creates and returns a new inotify instance using inotify_init(2)
+// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events.
func NewWatcher() (*Watcher, error) {
fd, errno := syscall.InotifyInit()
if fd == -1 {
return w, nil
}
-// Close closes an inotify watcher instance
-// It sends a message to the reader goroutine to quit and removes all watches
-// associated with the inotify instance
+// Close removes all watches and closes the events channel.
func (w *Watcher) Close() error {
if w.isClosed {
return nil
return nil
}
-// Add starts watching on the named file.
+// Add starts watching the named file or directory (non-recursively).
func (w *Watcher) Add(name string) error {
if w.isClosed {
return errors.New("inotify instance already closed")
}
- var flags uint32 = sys_AGNOSTIC_EVENTS
+ var flags uint32 = agnosticEvents
w.mu.Lock()
watchEntry, found := w.watches[name]
return nil
}
-// Remove stops watching on the named file.
+// Remove stops watching the the named file or directory (non-recursively).
func (w *Watcher) Remove(name string) error {
w.mu.Lock()
defer w.mu.Unlock()
watch, ok := w.watches[name]
if !ok {
- return errors.New(fmt.Sprintf("can't remove non-existent inotify watch for: %s", name))
+ return fmt.Errorf("can't remove non-existent inotify watch for: %s", name)
}
success, errno := syscall.InotifyRmWatch(w.fd, watch.wd)
if success == -1 {
continue
}
- var offset uint32 = 0
+ var offset uint32
// We don't know how many events we just read into the buffer
// While the offset points to at least one whole event...
for offset <= uint32(n-syscall.SizeofInotifyEvent) {
import "syscall"
-const open_FLAGS = syscall.O_NONBLOCK | syscall.O_RDONLY
+const openMode = syscall.O_NONBLOCK | syscall.O_RDONLY
import "syscall"
-const open_FLAGS = syscall.O_EVTONLY
+const openMode = syscall.O_EVTONLY
type indexMap map[uint64]*watch
type watchMap map[uint32]indexMap
-// A Watcher waits for and receives event notifications
-// for a specific set of files and directories.
+// Watcher watches a set of files, delivering events to a channel.
type Watcher struct {
+ Events chan Event
+ Errors chan error
+ isClosed bool // Set to true when Close() is first called
mu sync.Mutex // Map access
port syscall.Handle // Handle to completion port
watches watchMap // Map of watches (key: i-number)
input chan *input // Inputs to the reader are sent on this channel
- Events chan Event // Events are returned on this channel
- Errors chan error // Errors are sent on this channel
- isClosed bool // Set to true when Close() is first called
quit chan chan<- error
}
-// NewWatcher creates and returns a Watcher.
+// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events.
func NewWatcher() (*Watcher, error) {
port, e := syscall.CreateIoCompletionPort(syscall.InvalidHandle, 0, 0, 0)
if e != nil {
return w, nil
}
-// Close closes a Watcher.
-// It sends a message to the reader goroutine to quit and removes all watches
-// associated with the watcher.
+// Close removes all watches and closes the events channel.
func (w *Watcher) Close() error {
if w.isClosed {
return nil
return <-in.reply
}
-// Add starts watching on the named file.
+// Add starts watching the named file or directory (non-recursively).
func (w *Watcher) Add(name string) error {
return w.AddWatch(name, sys_FS_ALL_EVENTS)
}
-// Remove stops watching on the named file.
+// Remove stops watching the the named file or directory (non-recursively).
func (w *Watcher) Remove(name string) error {
in := &input{
op: opRemoveWatch,