Skip to content

Commit 0bd000f

Browse files
authored
fsevents: improve documentation (#52)
This PR adds comprehensive doc comments to all exported constants, mostly derived from the Apple documentation but with changes to make them directly relevant to this package's API. It also uses C constants directly rather than relying on an implicit association between `1<<iota` and the actual enum values. It also unexports `GetStreamRefPaths`, `GetStreamRefDescription` and `GetStreamRefDeviceID` because none of them are usable with this package's API because there is no way to get an `FSEventStreamRef` value because it's hidden inside an unexported field inside the `EventStream` struct. Also unexport the `CFRunLoopRef` because it's similarly not useful or usable. Other than the above unexports, the API remains identical. Unfortunately I am unable to get the tests to pass, which makes me think that something is wrong somewhere, but that applies to the original code too, not just the code with these changes applied.
1 parent 66dfb65 commit 0bd000f

4 files changed

Lines changed: 278 additions & 94 deletions

File tree

fsevents.go

Lines changed: 61 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -10,74 +10,29 @@ import (
1010
"time"
1111
)
1212

13-
// CreateFlags for creating a New stream.
14-
type CreateFlags uint32
15-
16-
// kFSEventStreamCreateFlag...
17-
const (
18-
// use CoreFoundation types instead of raw C types (disabled)
19-
useCFTypes CreateFlags = 1 << iota
20-
21-
// NoDefer sends events on the leading edge (for interactive applications).
22-
// By default events are delivered after latency seconds (for background tasks).
23-
NoDefer
24-
25-
// WatchRoot for a change to occur to a directory along the path being watched.
26-
WatchRoot
27-
28-
// IgnoreSelf doesn't send events triggered by the current process (macOS 10.6+).
29-
IgnoreSelf
30-
31-
// FileEvents sends events about individual files, generating significantly
32-
// more events (macOS 10.7+) than directory level notifications.
33-
FileEvents
34-
)
35-
36-
// EventFlags passed to the FSEventStreamCallback function.
37-
type EventFlags uint32
38-
39-
// kFSEventStreamEventFlag...
40-
const (
41-
// MustScanSubDirs indicates that events were coalesced hierarchically.
42-
MustScanSubDirs EventFlags = 1 << iota
43-
// UserDropped or KernelDropped is set alongside MustScanSubDirs
44-
// to help diagnose the problem.
45-
UserDropped
46-
KernelDropped
47-
48-
// EventIDsWrapped indicates the 64-bit event ID counter wrapped around.
49-
EventIDsWrapped
50-
51-
// HistoryDone is a sentinel event when retrieving events sinceWhen.
52-
HistoryDone
53-
54-
// RootChanged indicates a change to a directory along the path being watched.
55-
RootChanged
56-
57-
// Mount for a volume mounted underneath the path being monitored.
58-
Mount
59-
// Unmount event occurs after a volume is unmounted.
60-
Unmount
61-
62-
// The following flags are only set when using FileEvents.
63-
64-
ItemCreated
65-
ItemRemoved
66-
ItemInodeMetaMod
67-
ItemRenamed
68-
ItemModified
69-
ItemFinderInfoMod
70-
ItemChangeOwner
71-
ItemXattrMod
72-
ItemIsFile
73-
ItemIsDir
74-
ItemIsSymlink
75-
)
76-
7713
// Event represents a single file system notification.
7814
type Event struct {
15+
// Path holds the path to the item that's changed, relative
16+
// to its device's root.
17+
// Use DeviceForPath to determine the absolute path that's
18+
// being referred to.
7919
Path string
20+
21+
// Flags holds details what has happened.
8022
Flags EventFlags
23+
24+
// ID holds the event ID.
25+
//
26+
// Each event ID comes from the most recent event being reported
27+
// in the corresponding directory named in the EventStream.Paths field
28+
// Event IDs all come from a single global source.
29+
// They are guaranteed to always be increasing, usually in leaps
30+
// and bounds, even across system reboots and moving drives from
31+
// one machine to another. If you were to
32+
// stop processing events from this stream after this event
33+
// and resume processing them later from a newly-created
34+
// EventStream, this is the value you would pass for the
35+
// EventStream.EventID along with Resume=true.
8136
ID uint64
8237
}
8338

@@ -99,19 +54,49 @@ func DeviceForPath(path string) (int32, error) {
9954
// es.Stop()
10055
// ...
10156
type EventStream struct {
102-
stream FSEventStreamRef
103-
rlref CFRunLoopRef
57+
stream fsEventStreamRef
58+
rlref cfRunLoopRef
10459
hasFinalizer bool
10560
registryID uintptr
10661
uuid string
10762

63+
// Events holds the channel on which events will be sent.
64+
// It's initialized by EventStream.Start if nil.
10865
Events chan []Event
66+
67+
// Paths holds the set of paths to watch, each
68+
// specifying the root of a filesystem hierarchy to be
69+
// watched for modifications.
10970
Paths []string
71+
72+
// Flags specifies what events to receive on the stream.
11073
Flags CreateFlags
111-
EventID uint64
74+
75+
// Resume specifies that watching should resume from the event
76+
// specified by EventID.
11277
Resume bool
78+
79+
// EventID holds the most recent event ID.
80+
//
81+
// NOTE: this is updated asynchronously by the
82+
// watcher and should not be accessed while
83+
// the stream has been started.
84+
EventID uint64
85+
86+
// Latency holds the number of seconds the service should wait after hearing
87+
// about an event from the kernel before passing it along to the
88+
// client via its callback. Specifying a larger value may result
89+
// in more effective temporal coalescing, resulting in fewer
90+
// callbacks and greater overall efficiency.
11391
Latency time.Duration
114-
// syscall represents this with an int32
92+
93+
// When Device is non-zero, the watcher will watch events on the
94+
// device with this ID, and the paths in the Paths field are
95+
// interpreted relative to the device's root.
96+
//
97+
// The device ID is the same as the st_dev field from a stat
98+
// structure of a file on that device or the f_fsid[0] field of
99+
// a statfs structure.
115100
Device int32
116101
}
117102

@@ -149,7 +134,8 @@ func (r *eventStreamRegistry) Delete(i uintptr) {
149134
delete(r.m, i)
150135
}
151136

152-
// Start listening to an event stream.
137+
// Start listening to an event stream. This creates es.Events if it's not already
138+
// a valid channel.
153139
func (es *EventStream) Start() {
154140
if es.Events == nil {
155141
es.Events = make(chan []Event)
@@ -163,12 +149,14 @@ func (es *EventStream) Start() {
163149
es.start(es.Paths, cbInfo)
164150
}
165151

166-
// Flush events that have occurred but haven't been delivered.
152+
// Flush flushes events that have occurred but haven't been delivered.
153+
// If sync is true, it will block until all the events have been delivered,
154+
// otherwise it will return immediately.
167155
func (es *EventStream) Flush(sync bool) {
168156
flush(es.stream, sync)
169157
}
170158

171-
// Stop listening to the event stream.
159+
// Stop stops listening to the event stream.
172160
func (es *EventStream) Stop() {
173161
if es.stream != nil {
174162
stop(es.stream, es.rlref)
@@ -180,7 +168,8 @@ func (es *EventStream) Stop() {
180168
es.registryID = 0
181169
}
182170

183-
// Restart listening.
171+
// Restart restarts the event listener. This
172+
// can be used to change the current watch flags.
184173
func (es *EventStream) Restart() {
185174
es.Stop()
186175
es.Resume = true

fsevents_test.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ func TestBasicExample(t *testing.T) {
5252
if err != nil {
5353
t.Fatal(err)
5454
}
55-
56-
<-wait
55+
select{
56+
case <-wait:
57+
case <-time.After(5 * time.Second):
58+
t.Fatal("timed out waiting for event")
59+
}
5760
}

0 commit comments

Comments
 (0)