fsevents 2.0.3 → 2.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/fsevents.js +1 -1
- package/fsevents.node +0 -0
- package/package.json +3 -3
- package/ISSUE_TEMPLATE.md +0 -8
- package/binding.gyp +0 -23
- package/src/constants.h +0 -112
- package/src/fsevents.c +0 -145
- package/src/rawfsevents.c +0 -149
- package/src/rawfsevents.h +0 -23
- package/test/01_native.js +0 -34
- package/test/02_interleaved.js +0 -40
- package/test/02_structure.js +0 -30
- package/test/03_simple.js +0 -61
- package/test/03_waiting.js +0 -28
- package/test/utils/fs.js +0 -51
- package/test/utils/misc.js +0 -21
- package/test.sh +0 -29
package/LICENSE
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
MIT License
|
2
2
|
-----------
|
3
3
|
|
4
|
-
Copyright (C) 2010-
|
4
|
+
Copyright (C) 2010-2019 by Philipp Dunkel, Ben Noordhuis, Elan Shankar
|
5
5
|
|
6
6
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
7
7
|
of this software and associated documentation files (the "Software"), to deal
|
package/fsevents.js
CHANGED
@@ -17,8 +17,8 @@ function watch(path, handler) {
|
|
17
17
|
if ('string' !== typeof path) throw new TypeError(`argument 1 must be a string and not a ${typeof path}`);
|
18
18
|
if ('function' !== typeof handler) throw new TypeError(`argument 2 must be a function and not a ${typeof handler}`);
|
19
19
|
|
20
|
-
|
21
20
|
let instance = Native.start(path, handler);
|
21
|
+
if (!instance) throw new Error(`could not watch: ${path}`);
|
22
22
|
return () => {
|
23
23
|
const result = instance ? Promise.resolve(instance).then(Native.stop) : null;
|
24
24
|
instance = null;
|
package/fsevents.node
CHANGED
Binary file
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "fsevents",
|
3
|
-
"version": "2.0.
|
3
|
+
"version": "2.0.7",
|
4
4
|
"description": "Native Access to Mac OS-X FSEvents",
|
5
5
|
"main": "fsevents.js",
|
6
6
|
"os": [
|
@@ -11,9 +11,9 @@
|
|
11
11
|
},
|
12
12
|
"scripts": {
|
13
13
|
"clean": "node-gyp clean && rm -f fsevents.node",
|
14
|
-
"
|
14
|
+
"build": "node-gyp clean && rm -f fsevents.node && node-gyp rebuild && node-gyp clean",
|
15
15
|
"test": "/bin/bash ./test.sh 2>/dev/null",
|
16
|
-
"prepublishOnly": "
|
16
|
+
"prepublishOnly": "npm run build"
|
17
17
|
},
|
18
18
|
"repository": {
|
19
19
|
"type": "git",
|
package/ISSUE_TEMPLATE.md
DELETED
@@ -1,8 +0,0 @@
|
|
1
|
-
If you are NOT on OS X and have come here to file an issue about compatibility problems,
|
2
|
-
please stop and go to #115 for your answer.
|
3
|
-
|
4
|
-
You can look through many other similar closed issues as well if you're interested:
|
5
|
-
https://github.com/strongloop/fsevents/search?utf8=%E2%9C%93&q=%22notsup%22+OR+%22EBADPLATFORM%22&type=Issues.
|
6
|
-
|
7
|
-
If you are here to report an issue observed while using this module on OS X, please delete
|
8
|
-
all this pre-filled text then go ahead and submit your report.
|
package/binding.gyp
DELETED
@@ -1,23 +0,0 @@
|
|
1
|
-
{
|
2
|
-
"conditions": [
|
3
|
-
['OS=="mac"', {
|
4
|
-
"targets": [{
|
5
|
-
"target_name": "fsevents",
|
6
|
-
"sources": [ "src/fsevents.c", "src/rawfsevents.c" ],
|
7
|
-
"xcode_settings": {
|
8
|
-
"OTHER_LDFLAGS": [
|
9
|
-
"-framework CoreFoundation -framework CoreServices"
|
10
|
-
]
|
11
|
-
}
|
12
|
-
}, {
|
13
|
-
"target_name": "action_after_build",
|
14
|
-
"type": "none",
|
15
|
-
"dependencies": ["fsevents"],
|
16
|
-
"copies": [{
|
17
|
-
"files": ["<(PRODUCT_DIR)/fsevents.node"],
|
18
|
-
"destination": "./"
|
19
|
-
}]
|
20
|
-
}]
|
21
|
-
}]
|
22
|
-
]
|
23
|
-
}
|
package/src/constants.h
DELETED
@@ -1,112 +0,0 @@
|
|
1
|
-
#ifndef __constants_h
|
2
|
-
#define __constants_h
|
3
|
-
|
4
|
-
#include "CoreFoundation/CoreFoundation.h"
|
5
|
-
|
6
|
-
// constants from https://developer.apple.com/library/mac/documentation/Darwin/Reference/FSEvents_Ref/index.html#//apple_ref/doc/constant_group/FSEventStreamEventFlags
|
7
|
-
#ifndef kFSEventStreamEventFlagNone
|
8
|
-
#define kFSEventStreamEventFlagNone 0x00000000
|
9
|
-
#endif
|
10
|
-
|
11
|
-
#ifndef kFSEventStreamEventFlagMustScanSubDirs
|
12
|
-
#define kFSEventStreamEventFlagMustScanSubDirs 0x00000001
|
13
|
-
#endif
|
14
|
-
|
15
|
-
#ifndef kFSEventStreamEventFlagUserDropped
|
16
|
-
#define kFSEventStreamEventFlagUserDropped 0x00000002
|
17
|
-
#endif
|
18
|
-
|
19
|
-
#ifndef kFSEventStreamEventFlagKernelDropped
|
20
|
-
#define kFSEventStreamEventFlagKernelDropped 0x00000004
|
21
|
-
#endif
|
22
|
-
|
23
|
-
#ifndef kFSEventStreamEventFlagEventIdsWrapped
|
24
|
-
#define kFSEventStreamEventFlagEventIdsWrapped 0x00000008
|
25
|
-
#endif
|
26
|
-
|
27
|
-
#ifndef kFSEventStreamEventFlagHistoryDone
|
28
|
-
#define kFSEventStreamEventFlagHistoryDone 0x00000010
|
29
|
-
#endif
|
30
|
-
|
31
|
-
#ifndef kFSEventStreamEventFlagRootChanged
|
32
|
-
#define kFSEventStreamEventFlagRootChanged 0x00000020
|
33
|
-
#endif
|
34
|
-
|
35
|
-
#ifndef kFSEventStreamEventFlagMount
|
36
|
-
#define kFSEventStreamEventFlagMount 0x00000040
|
37
|
-
#endif
|
38
|
-
|
39
|
-
#ifndef kFSEventStreamEventFlagUnmount
|
40
|
-
#define kFSEventStreamEventFlagUnmount 0x00000080
|
41
|
-
#endif
|
42
|
-
|
43
|
-
#ifndef kFSEventStreamEventFlagItemCreated
|
44
|
-
#define kFSEventStreamEventFlagItemCreated 0x00000100
|
45
|
-
#endif
|
46
|
-
|
47
|
-
#ifndef kFSEventStreamEventFlagItemRemoved
|
48
|
-
#define kFSEventStreamEventFlagItemRemoved 0x00000200
|
49
|
-
#endif
|
50
|
-
|
51
|
-
#ifndef kFSEventStreamEventFlagItemInodeMetaMod
|
52
|
-
#define kFSEventStreamEventFlagItemInodeMetaMod 0x00000400
|
53
|
-
#endif
|
54
|
-
|
55
|
-
#ifndef kFSEventStreamEventFlagItemRenamed
|
56
|
-
#define kFSEventStreamEventFlagItemRenamed 0x00000800
|
57
|
-
#endif
|
58
|
-
|
59
|
-
#ifndef kFSEventStreamEventFlagItemModified
|
60
|
-
#define kFSEventStreamEventFlagItemModified 0x00001000
|
61
|
-
#endif
|
62
|
-
|
63
|
-
#ifndef kFSEventStreamEventFlagItemFinderInfoMod
|
64
|
-
#define kFSEventStreamEventFlagItemFinderInfoMod 0x00002000
|
65
|
-
#endif
|
66
|
-
|
67
|
-
#ifndef kFSEventStreamEventFlagItemChangeOwner
|
68
|
-
#define kFSEventStreamEventFlagItemChangeOwner 0x00004000
|
69
|
-
#endif
|
70
|
-
|
71
|
-
#ifndef kFSEventStreamEventFlagItemXattrMod
|
72
|
-
#define kFSEventStreamEventFlagItemXattrMod 0x00008000
|
73
|
-
#endif
|
74
|
-
|
75
|
-
#ifndef kFSEventStreamEventFlagItemIsFile
|
76
|
-
#define kFSEventStreamEventFlagItemIsFile 0x00010000
|
77
|
-
#endif
|
78
|
-
|
79
|
-
#ifndef kFSEventStreamEventFlagItemIsDir
|
80
|
-
#define kFSEventStreamEventFlagItemIsDir 0x00020000
|
81
|
-
#endif
|
82
|
-
|
83
|
-
#ifndef kFSEventStreamEventFlagItemIsSymlink
|
84
|
-
#define kFSEventStreamEventFlagItemIsSymlink 0x00040000
|
85
|
-
#endif
|
86
|
-
|
87
|
-
// constants from https://developer.apple.com/library/mac/documentation/Darwin/Reference/FSEvents_Ref/index.html#//apple_ref/doc/constant_group/FSEventStreamCreateFlags
|
88
|
-
#ifndef kFSEventStreamCreateFlagNone
|
89
|
-
#define kFSEventStreamCreateFlagNone 0x00000000
|
90
|
-
#endif
|
91
|
-
|
92
|
-
#ifndef kFSEventStreamCreateFlagUseCFTypes
|
93
|
-
#define kFSEventStreamCreateFlagUseCFTypes 0x00000001
|
94
|
-
#endif
|
95
|
-
|
96
|
-
#ifndef kFSEventStreamCreateFlagNoDefer
|
97
|
-
#define kFSEventStreamCreateFlagNoDefer 0x00000002
|
98
|
-
#endif
|
99
|
-
|
100
|
-
#ifndef kFSEventStreamCreateFlagWatchRoot
|
101
|
-
#define kFSEventStreamCreateFlagWatchRoot 0x00000004
|
102
|
-
#endif
|
103
|
-
|
104
|
-
#ifndef kFSEventStreamCreateFlagIgnoreSelf
|
105
|
-
#define kFSEventStreamCreateFlagIgnoreSelf 0x00000008
|
106
|
-
#endif
|
107
|
-
|
108
|
-
#ifndef kFSEventStreamCreateFlagFileEvents
|
109
|
-
#define kFSEventStreamCreateFlagFileEvents 0x00000010
|
110
|
-
#endif
|
111
|
-
|
112
|
-
#endif
|
package/src/fsevents.c
DELETED
@@ -1,145 +0,0 @@
|
|
1
|
-
/*
|
2
|
-
** © 2018 by Philipp Dunkel, Ben Noordhuis, Elan Shankar
|
3
|
-
** Licensed under MIT License.
|
4
|
-
*/
|
5
|
-
|
6
|
-
#include <assert.h>
|
7
|
-
|
8
|
-
#define NAPI_VERSION 4
|
9
|
-
#include <node_api.h>
|
10
|
-
|
11
|
-
#include "rawfsevents.h"
|
12
|
-
#include "constants.h"
|
13
|
-
|
14
|
-
#ifndef CHECK
|
15
|
-
#ifdef NDEBUG
|
16
|
-
#define CHECK(x) do { if (!(x)) abort(); } while (0)
|
17
|
-
#else
|
18
|
-
#define CHECK assert
|
19
|
-
#endif
|
20
|
-
#endif
|
21
|
-
|
22
|
-
|
23
|
-
typedef struct {
|
24
|
-
size_t count;
|
25
|
-
fse_event_t *events;
|
26
|
-
} fse_js_event;
|
27
|
-
|
28
|
-
void fse_propagate_event(void *callback, size_t numevents, fse_event_t *events) {
|
29
|
-
fse_js_event *event = malloc(sizeof(*event));
|
30
|
-
CHECK(event);
|
31
|
-
event->count = numevents;
|
32
|
-
event->events = events;
|
33
|
-
CHECK(napi_call_threadsafe_function((napi_threadsafe_function)callback, event, napi_tsfn_blocking) == napi_ok);
|
34
|
-
}
|
35
|
-
|
36
|
-
void fse_dispatch_events(napi_env env, napi_value callback, void* context, void* data) {
|
37
|
-
fse_js_event *event = data;
|
38
|
-
napi_value recv, args[3];
|
39
|
-
size_t idx;
|
40
|
-
CHECK(napi_get_null(env, &recv) == napi_ok);
|
41
|
-
|
42
|
-
for (idx = 0; idx < event->count; idx++) {
|
43
|
-
CHECK(napi_create_string_utf8(env, event->events[idx].path, NAPI_AUTO_LENGTH, &args[0]) == napi_ok);
|
44
|
-
CHECK(napi_create_uint32(env, event->events[idx].flags, &args[1]) == napi_ok);
|
45
|
-
CHECK(napi_create_int64(env, event->events[idx].id, &args[2]) == napi_ok);
|
46
|
-
CHECK(napi_call_function(env, recv, callback, 3, args, &recv) == napi_ok);
|
47
|
-
}
|
48
|
-
|
49
|
-
free(event->events);
|
50
|
-
free(event);
|
51
|
-
}
|
52
|
-
|
53
|
-
void fse_free_watcher(napi_env env, void* watcher, void* callback) {
|
54
|
-
fse_free(watcher);
|
55
|
-
}
|
56
|
-
|
57
|
-
void fse_watcher_started(void *context) {
|
58
|
-
napi_threadsafe_function callback = (napi_threadsafe_function)context;
|
59
|
-
CHECK(napi_acquire_threadsafe_function(callback) == napi_ok);
|
60
|
-
}
|
61
|
-
void fse_watcher_ended(void *context) {
|
62
|
-
napi_threadsafe_function callback = (napi_threadsafe_function)context;
|
63
|
-
CHECK(napi_release_threadsafe_function(callback, napi_tsfn_abort) == napi_ok);
|
64
|
-
}
|
65
|
-
|
66
|
-
static napi_value FSEStart(napi_env env, napi_callback_info info) {
|
67
|
-
size_t argc = 2;
|
68
|
-
napi_value argv[argc];
|
69
|
-
char path[PATH_MAX];
|
70
|
-
napi_threadsafe_function callback;
|
71
|
-
napi_value asyncResource, asyncName;
|
72
|
-
|
73
|
-
CHECK(napi_get_cb_info(env, info, &argc, argv, NULL, NULL) == napi_ok);
|
74
|
-
CHECK(napi_get_value_string_utf8(env, argv[0], path, PATH_MAX, &argc) == napi_ok);
|
75
|
-
CHECK(napi_create_object(env, &asyncResource) == napi_ok);
|
76
|
-
CHECK(napi_create_string_utf8(env, "fsevents", NAPI_AUTO_LENGTH, &asyncName) == napi_ok);
|
77
|
-
CHECK(napi_create_threadsafe_function(env, argv[1], asyncResource, asyncName, 0, 1, NULL, NULL, NULL, fse_dispatch_events, &callback) == napi_ok);
|
78
|
-
CHECK(napi_ref_threadsafe_function(env, callback) == napi_ok);
|
79
|
-
|
80
|
-
fse_watcher_t watcher = fse_alloc();
|
81
|
-
CHECK(watcher);
|
82
|
-
fse_watch(path, fse_propagate_event, callback, fse_watcher_started, fse_watcher_ended, watcher);
|
83
|
-
|
84
|
-
napi_value result;
|
85
|
-
CHECK(napi_create_external(env, watcher, fse_free_watcher, callback, &result) == napi_ok);
|
86
|
-
return result;
|
87
|
-
}
|
88
|
-
static napi_value FSEStop(napi_env env, napi_callback_info info) {
|
89
|
-
size_t argc = 1;
|
90
|
-
napi_value external;
|
91
|
-
fse_watcher_t watcher;
|
92
|
-
CHECK(napi_get_cb_info(env, info, &argc, &external, NULL, NULL) == napi_ok);
|
93
|
-
CHECK(napi_get_value_external(env, external, (void**)&watcher) == napi_ok);
|
94
|
-
napi_threadsafe_function callback = (napi_threadsafe_function)fse_context_of(watcher);
|
95
|
-
if (callback) {
|
96
|
-
CHECK(napi_unref_threadsafe_function(env, callback) == napi_ok);
|
97
|
-
}
|
98
|
-
fse_unwatch(watcher);
|
99
|
-
napi_value result;
|
100
|
-
CHECK(napi_get_undefined(env, &result) == napi_ok);
|
101
|
-
return result;
|
102
|
-
}
|
103
|
-
|
104
|
-
#define CONSTANT(name) do {\
|
105
|
-
CHECK(napi_create_int32(env, name, &value) == napi_ok);\
|
106
|
-
CHECK(napi_set_named_property(env, constants, #name, value) == napi_ok);\
|
107
|
-
} while (0)
|
108
|
-
|
109
|
-
napi_value Init(napi_env env, napi_value exports) {
|
110
|
-
fse_init();
|
111
|
-
napi_value value, constants;
|
112
|
-
|
113
|
-
CHECK(napi_create_object(env, &constants) == napi_ok);
|
114
|
-
napi_property_descriptor descriptors[] = {
|
115
|
-
{ "start", NULL, FSEStart, NULL, NULL, NULL, napi_default, NULL },
|
116
|
-
{ "stop", NULL, FSEStop, NULL, NULL, NULL, napi_default, NULL },
|
117
|
-
{ "constants", NULL, NULL, NULL, NULL, constants, napi_default, NULL }
|
118
|
-
};
|
119
|
-
CHECK(napi_define_properties(env, exports, 3, descriptors) == napi_ok);
|
120
|
-
|
121
|
-
CONSTANT(kFSEventStreamEventFlagNone);
|
122
|
-
CONSTANT(kFSEventStreamEventFlagMustScanSubDirs);
|
123
|
-
CONSTANT(kFSEventStreamEventFlagUserDropped);
|
124
|
-
CONSTANT(kFSEventStreamEventFlagKernelDropped);
|
125
|
-
CONSTANT(kFSEventStreamEventFlagEventIdsWrapped);
|
126
|
-
CONSTANT(kFSEventStreamEventFlagHistoryDone);
|
127
|
-
CONSTANT(kFSEventStreamEventFlagRootChanged);
|
128
|
-
CONSTANT(kFSEventStreamEventFlagMount);
|
129
|
-
CONSTANT(kFSEventStreamEventFlagUnmount);
|
130
|
-
CONSTANT(kFSEventStreamEventFlagItemCreated);
|
131
|
-
CONSTANT(kFSEventStreamEventFlagItemRemoved);
|
132
|
-
CONSTANT(kFSEventStreamEventFlagItemInodeMetaMod);
|
133
|
-
CONSTANT(kFSEventStreamEventFlagItemRenamed);
|
134
|
-
CONSTANT(kFSEventStreamEventFlagItemModified);
|
135
|
-
CONSTANT(kFSEventStreamEventFlagItemFinderInfoMod);
|
136
|
-
CONSTANT(kFSEventStreamEventFlagItemChangeOwner);
|
137
|
-
CONSTANT(kFSEventStreamEventFlagItemXattrMod);
|
138
|
-
CONSTANT(kFSEventStreamEventFlagItemIsFile);
|
139
|
-
CONSTANT(kFSEventStreamEventFlagItemIsDir);
|
140
|
-
CONSTANT(kFSEventStreamEventFlagItemIsSymlink);
|
141
|
-
|
142
|
-
return exports;
|
143
|
-
}
|
144
|
-
|
145
|
-
NAPI_MODULE(NODE_GYP_MODULE_NAME, Init)
|
package/src/rawfsevents.c
DELETED
@@ -1,149 +0,0 @@
|
|
1
|
-
#include "rawfsevents.h"
|
2
|
-
#include "CoreFoundation/CoreFoundation.h"
|
3
|
-
#include "CoreServices/CoreServices.h"
|
4
|
-
#include <pthread.h>
|
5
|
-
#include <assert.h>
|
6
|
-
|
7
|
-
#ifndef CHECK
|
8
|
-
#ifdef NDEBUG
|
9
|
-
#define CHECK(x) do { if (!(x)) abort(); } while (0)
|
10
|
-
#else
|
11
|
-
#define CHECK assert
|
12
|
-
#endif
|
13
|
-
#endif
|
14
|
-
|
15
|
-
typedef struct {
|
16
|
-
pthread_t thread;
|
17
|
-
CFRunLoopRef loop;
|
18
|
-
pthread_mutex_t lock;
|
19
|
-
pthread_cond_t init;
|
20
|
-
} fse_loop_t;
|
21
|
-
|
22
|
-
struct fse_watcher_s {
|
23
|
-
char path[PATH_MAX];
|
24
|
-
FSEventStreamRef stream;
|
25
|
-
fse_event_handler_t handler;
|
26
|
-
fse_thread_hook_t hookend;
|
27
|
-
void *context;
|
28
|
-
};
|
29
|
-
|
30
|
-
static fse_loop_t fsevents;
|
31
|
-
|
32
|
-
void fse_init() {
|
33
|
-
fsevents.thread = NULL;
|
34
|
-
fsevents.loop = NULL;
|
35
|
-
pthread_mutex_init(&fsevents.lock, NULL);
|
36
|
-
pthread_cond_init(&fsevents.init, NULL);
|
37
|
-
}
|
38
|
-
|
39
|
-
void *fse_run_loop(void *data) {
|
40
|
-
|
41
|
-
fsevents.loop = CFRunLoopGetCurrent();
|
42
|
-
pthread_mutex_unlock(&fsevents.lock);
|
43
|
-
|
44
|
-
pthread_cond_signal(&fsevents.init);
|
45
|
-
pthread_mutex_lock(&fsevents.lock);
|
46
|
-
CFRunLoopPerformBlock(fsevents.loop, kCFRunLoopDefaultMode, ^(void){
|
47
|
-
pthread_mutex_unlock(&fsevents.lock);
|
48
|
-
});
|
49
|
-
CFRunLoopRun();
|
50
|
-
|
51
|
-
pthread_mutex_lock(&fsevents.lock);
|
52
|
-
fsevents.loop = NULL;
|
53
|
-
pthread_mutex_unlock(&fsevents.lock);
|
54
|
-
|
55
|
-
return NULL;
|
56
|
-
}
|
57
|
-
|
58
|
-
void fse_handle_events(
|
59
|
-
ConstFSEventStreamRef stream,
|
60
|
-
void *data,
|
61
|
-
size_t numEvents,
|
62
|
-
void *eventPaths,
|
63
|
-
const FSEventStreamEventFlags eventFlags[],
|
64
|
-
const FSEventStreamEventId eventIds[]
|
65
|
-
) {
|
66
|
-
fse_watcher_t watcher = data;
|
67
|
-
if (!watcher->handler) return;
|
68
|
-
fse_event_t *events = malloc(sizeof(*events) * numEvents);
|
69
|
-
CHECK(events);
|
70
|
-
size_t idx;
|
71
|
-
for (idx=0; idx < numEvents; idx++) {
|
72
|
-
fse_event_t *event = &events[idx];
|
73
|
-
CFStringRef path = (CFStringRef)CFArrayGetValueAtIndex((CFArrayRef)eventPaths, idx);
|
74
|
-
strncpy(event->path, CFStringGetCStringPtr(path, kCFStringEncodingUTF8), sizeof(event->path));
|
75
|
-
event->id = eventIds[idx];
|
76
|
-
event->flags = eventFlags[idx];
|
77
|
-
}
|
78
|
-
if (!watcher->handler) {
|
79
|
-
free(events);
|
80
|
-
} else {
|
81
|
-
watcher->handler(watcher->context, numEvents, events);
|
82
|
-
}
|
83
|
-
}
|
84
|
-
|
85
|
-
void fse_clear(fse_watcher_t watcher) {
|
86
|
-
watcher->path[0] = 0;
|
87
|
-
watcher->handler = NULL;
|
88
|
-
watcher->stream = NULL;
|
89
|
-
watcher->context = NULL;
|
90
|
-
watcher->hookend = NULL;
|
91
|
-
}
|
92
|
-
|
93
|
-
fse_watcher_t fse_alloc() {
|
94
|
-
fse_watcher_t watcher = malloc(sizeof(*watcher));
|
95
|
-
CHECK(watcher);
|
96
|
-
fse_clear(watcher);
|
97
|
-
return watcher;
|
98
|
-
}
|
99
|
-
|
100
|
-
void fse_free(fse_watcher_t watcher) {
|
101
|
-
fse_unwatch(watcher);
|
102
|
-
free(watcher);
|
103
|
-
}
|
104
|
-
|
105
|
-
void fse_watch(const char *path, fse_event_handler_t handler, void *context, fse_thread_hook_t hookstart, fse_thread_hook_t hookend, fse_watcher_t watcher) {
|
106
|
-
pthread_mutex_lock(&fsevents.lock);
|
107
|
-
if (!fsevents.loop) {
|
108
|
-
pthread_create(&fsevents.thread, NULL, fse_run_loop, NULL);
|
109
|
-
pthread_mutex_unlock(&fsevents.lock);
|
110
|
-
pthread_cond_wait(&fsevents.init, &fsevents.lock);
|
111
|
-
}
|
112
|
-
|
113
|
-
strncpy(watcher->path, path, PATH_MAX);
|
114
|
-
watcher->handler = handler;
|
115
|
-
watcher->context = context;
|
116
|
-
FSEventStreamContext streamcontext = { 0, watcher, NULL, NULL, NULL };
|
117
|
-
CFStringRef dirs[] = { CFStringCreateWithCString(NULL, watcher->path, kCFStringEncodingUTF8) };
|
118
|
-
watcher->stream = FSEventStreamCreate(NULL, &fse_handle_events, &streamcontext, CFArrayCreate(NULL, (const void **)&dirs, 1, NULL), kFSEventStreamEventIdSinceNow, (CFAbsoluteTime) 0.1, kFSEventStreamCreateFlagNone | kFSEventStreamCreateFlagWatchRoot | kFSEventStreamCreateFlagFileEvents | kFSEventStreamCreateFlagUseCFTypes);
|
119
|
-
CFRunLoopPerformBlock(fsevents.loop, kCFRunLoopDefaultMode, ^(void){
|
120
|
-
if (hookstart) hookstart(watcher->context);
|
121
|
-
FSEventStreamScheduleWithRunLoop(watcher->stream, fsevents.loop, kCFRunLoopDefaultMode);
|
122
|
-
FSEventStreamStart(watcher->stream);
|
123
|
-
});
|
124
|
-
CFRunLoopWakeUp(fsevents.loop);
|
125
|
-
pthread_mutex_unlock(&fsevents.lock);
|
126
|
-
}
|
127
|
-
|
128
|
-
void fse_unwatch(fse_watcher_t watcher) {
|
129
|
-
FSEventStreamRef stream = watcher->stream;
|
130
|
-
fse_thread_hook_t hookend = watcher->hookend;
|
131
|
-
void *context = watcher->context;
|
132
|
-
fse_clear(watcher);
|
133
|
-
|
134
|
-
pthread_mutex_lock(&fsevents.lock);
|
135
|
-
if (fsevents.loop && stream) {
|
136
|
-
CFRunLoopPerformBlock(fsevents.loop, kCFRunLoopDefaultMode, ^(void){
|
137
|
-
FSEventStreamStop(stream);
|
138
|
-
FSEventStreamUnscheduleFromRunLoop(stream, fsevents.loop, kCFRunLoopDefaultMode);
|
139
|
-
FSEventStreamInvalidate(stream);
|
140
|
-
FSEventStreamRelease(stream);
|
141
|
-
if (hookend) hookend(context);
|
142
|
-
});
|
143
|
-
}
|
144
|
-
pthread_mutex_unlock(&fsevents.lock);
|
145
|
-
}
|
146
|
-
|
147
|
-
void *fse_context_of(fse_watcher_t watcher) {
|
148
|
-
return watcher->context;
|
149
|
-
}
|
package/src/rawfsevents.h
DELETED
@@ -1,23 +0,0 @@
|
|
1
|
-
#ifndef __loop_h
|
2
|
-
#define __loop_h
|
3
|
-
|
4
|
-
#include <stdlib.h>
|
5
|
-
#include <limits.h>
|
6
|
-
|
7
|
-
typedef struct {
|
8
|
-
unsigned long long id;
|
9
|
-
char path[PATH_MAX];
|
10
|
-
unsigned int flags;
|
11
|
-
} fse_event_t;
|
12
|
-
|
13
|
-
typedef void (*fse_event_handler_t)(void *context, size_t numevents, fse_event_t *events);
|
14
|
-
typedef void (*fse_thread_hook_t)(void *context);
|
15
|
-
typedef struct fse_watcher_s* fse_watcher_t;
|
16
|
-
|
17
|
-
void fse_init();
|
18
|
-
fse_watcher_t fse_alloc();
|
19
|
-
void fse_free(fse_watcher_t watcherp);
|
20
|
-
void fse_watch(const char *path, fse_event_handler_t handler, void *context, fse_thread_hook_t hookstart, fse_thread_hook_t hookend, fse_watcher_t watcher_p);
|
21
|
-
void fse_unwatch(fse_watcher_t watcher);
|
22
|
-
void *fse_context_of(fse_watcher_t watcher);
|
23
|
-
#endif
|
package/test/01_native.js
DELETED
@@ -1,34 +0,0 @@
|
|
1
|
-
const native = require('../fsevents.node');
|
2
|
-
const { rm, touch, rename } = require('./utils/fs.js');
|
3
|
-
const { run, sleep } = require('./utils/misc.js');
|
4
|
-
const path = require('path');
|
5
|
-
const assert = require('assert');
|
6
|
-
|
7
|
-
const DIR = process.argv[2];
|
8
|
-
|
9
|
-
run(async () => {
|
10
|
-
const events = [];
|
11
|
-
const listener = native.start(DIR, (...args) => events.push(args));
|
12
|
-
|
13
|
-
await touch(path.join(DIR, 'created'));
|
14
|
-
await sleep(250);
|
15
|
-
await rename(path.join(DIR, 'created'), path.join(DIR, 'renamed'));
|
16
|
-
await sleep(250);
|
17
|
-
await rm(path.join(DIR, 'renamed'));
|
18
|
-
await sleep(500);
|
19
|
-
|
20
|
-
native.stop(listener);
|
21
|
-
|
22
|
-
const expected = [
|
23
|
-
[path.join(DIR, 'created'), 66816, 80865],
|
24
|
-
[path.join(DIR, 'created'), 68864, 80887],
|
25
|
-
[path.join(DIR, 'renamed'), 67584, 80888],
|
26
|
-
[path.join(DIR, 'renamed'), 68096, 80910]
|
27
|
-
];
|
28
|
-
assert.equal(events.length, expected.length);
|
29
|
-
for (let idx = 0; idx < events.length; idx++) {
|
30
|
-
assert.equal(events[idx].length, expected[idx].length);
|
31
|
-
assert.equal(events[idx][0], expected[idx][0]);
|
32
|
-
assert.equal(events[idx][1], expected[idx][1]);
|
33
|
-
}
|
34
|
-
});
|
package/test/02_interleaved.js
DELETED
@@ -1,40 +0,0 @@
|
|
1
|
-
const native = require('../fsevents.node');
|
2
|
-
const { mkdir, rm, touch, rename } = require('./utils/fs.js');
|
3
|
-
const { run, sleep } = require('./utils/misc.js');
|
4
|
-
const path = require('path');
|
5
|
-
const assert = require('assert');
|
6
|
-
|
7
|
-
const DIR = process.argv[2];
|
8
|
-
|
9
|
-
run(async () => {
|
10
|
-
await mkdir(`${DIR}/A`);
|
11
|
-
await mkdir(`${DIR}/B`);
|
12
|
-
await sleep(500);
|
13
|
-
const events = [];
|
14
|
-
|
15
|
-
const listenerA = native.start(`${DIR}/A`, (...args) => events.push(args));
|
16
|
-
|
17
|
-
await touch(path.join(`${DIR}/A`, 'created'));
|
18
|
-
await sleep(500);
|
19
|
-
const listenerB = native.start(`${DIR}/B`, (...args) => events.push(args));
|
20
|
-
await sleep(500);
|
21
|
-
native.stop(listenerA);
|
22
|
-
await rename(path.join(`${DIR}/A`, 'created'), path.join(`${DIR}/B`, 'renamed'));
|
23
|
-
await sleep(500);
|
24
|
-
await rm(path.join(`${DIR}/B`, 'renamed'));
|
25
|
-
await sleep(500);
|
26
|
-
|
27
|
-
native.stop(listenerB);
|
28
|
-
|
29
|
-
const expected = [
|
30
|
-
[path.join(`${DIR}/A`, 'created'), 66816, 80865],
|
31
|
-
[path.join(`${DIR}/B`, 'renamed'), 67584, 80888],
|
32
|
-
[path.join(`${DIR}/B`, 'renamed'), 68096, 80910]
|
33
|
-
];
|
34
|
-
assert.equal(events.length, expected.length);
|
35
|
-
for (let idx = 0; idx < events.length; idx++) {
|
36
|
-
assert.equal(events[idx].length, expected[idx].length);
|
37
|
-
assert.equal(events[idx][0], expected[idx][0]);
|
38
|
-
assert.equal(events[idx][1], expected[idx][1]);
|
39
|
-
}
|
40
|
-
});
|
package/test/02_structure.js
DELETED
@@ -1,30 +0,0 @@
|
|
1
|
-
/*
|
2
|
-
** © 2018 by Philipp Dunkel, Ben Noordhuis, Elan Shankar
|
3
|
-
** Licensed under MIT License.
|
4
|
-
*/
|
5
|
-
|
6
|
-
/* jshint node:true */
|
7
|
-
'use strict';
|
8
|
-
|
9
|
-
const assert = require('assert');
|
10
|
-
const fsevents = require('../fsevents');
|
11
|
-
const { run } = require('./utils/misc.js');
|
12
|
-
|
13
|
-
run(async ()=>{
|
14
|
-
assert.equal('object', typeof fsevents);
|
15
|
-
assert.equal('function', typeof fsevents.watch);
|
16
|
-
assert.equal('function', typeof fsevents.getInfo);
|
17
|
-
assert.equal('object', typeof fsevents.constants);
|
18
|
-
|
19
|
-
assert.equal('file', fsevents.getInfo('path', fsevents.constants.kFSEventStreamEventFlagItemIsFile).type);
|
20
|
-
assert.equal('directory', fsevents.getInfo('path', fsevents.constants.kFSEventStreamEventFlagItemIsDir).type);
|
21
|
-
assert.equal('symlink', fsevents.getInfo('path', fsevents.constants.kFSEventStreamEventFlagItemIsSymlink).type);
|
22
|
-
|
23
|
-
assert.equal('deleted', fsevents.getInfo('path', fsevents.constants.kFSEventStreamEventFlagItemRemoved).event);
|
24
|
-
assert.equal('moved', fsevents.getInfo('path', fsevents.constants.kFSEventStreamEventFlagItemRenamed).event);
|
25
|
-
assert.equal('created', fsevents.getInfo('path', fsevents.constants.kFSEventStreamEventFlagItemCreated).event);
|
26
|
-
assert.equal('modified', fsevents.getInfo('path', fsevents.constants.kFSEventStreamEventFlagItemModified).event);
|
27
|
-
assert.equal('root-changed', fsevents.getInfo('path', fsevents.constants.kFSEventStreamEventFlagRootChanged).event);
|
28
|
-
|
29
|
-
assert.deepEqual()
|
30
|
-
});
|
package/test/03_simple.js
DELETED
@@ -1,61 +0,0 @@
|
|
1
|
-
/*
|
2
|
-
** © 2018 by Philipp Dunkel, Ben Noordhuis, Elan Shankar
|
3
|
-
** Licensed under MIT License.
|
4
|
-
*/
|
5
|
-
|
6
|
-
/* jshint node:true */
|
7
|
-
'use strict';
|
8
|
-
|
9
|
-
const { rm, touch, rename } = require('./utils/fs.js');
|
10
|
-
const { sleep, capture, run } = require('./utils/misc.js');
|
11
|
-
|
12
|
-
const path = require('path');
|
13
|
-
const assert = require('assert');
|
14
|
-
const fsevents = require('../fsevents');
|
15
|
-
|
16
|
-
const DIR = process.argv[2];
|
17
|
-
|
18
|
-
run(async ()=>{
|
19
|
-
const events = capture();
|
20
|
-
const stop = fsevents.watch(DIR, events.callback);
|
21
|
-
|
22
|
-
await touch(path.join(DIR, 'created'));
|
23
|
-
await sleep(250);
|
24
|
-
await rename(path.join(DIR, 'created'), path.join(DIR, 'renamed'));
|
25
|
-
await sleep(250);
|
26
|
-
await rm(path.join(DIR, 'renamed'));
|
27
|
-
await sleep(1500);
|
28
|
-
|
29
|
-
await stop();
|
30
|
-
|
31
|
-
const expected = [
|
32
|
-
{
|
33
|
-
path: path.join(DIR, 'created'),
|
34
|
-
event: 'created',
|
35
|
-
type: 'file'
|
36
|
-
},
|
37
|
-
{
|
38
|
-
path: path.join(DIR, 'created'),
|
39
|
-
event: 'moved',
|
40
|
-
type: 'file'
|
41
|
-
},
|
42
|
-
{
|
43
|
-
path: path.join(DIR, 'renamed'),
|
44
|
-
event: 'moved',
|
45
|
-
type: 'file'
|
46
|
-
},
|
47
|
-
{
|
48
|
-
path: path.join(DIR, 'renamed'),
|
49
|
-
event: 'deleted',
|
50
|
-
type: 'file'
|
51
|
-
}
|
52
|
-
];
|
53
|
-
|
54
|
-
const parsed = events.map((args) => fsevents.getInfo(...args));
|
55
|
-
parsed.forEach((actual, idx)=>{
|
56
|
-
const expect = expected[idx];
|
57
|
-
assert.equal(actual.path, expect.path);
|
58
|
-
assert.equal(actual.type, expect.type);
|
59
|
-
assert.equal(actual.event, expect.event);
|
60
|
-
})
|
61
|
-
});
|
package/test/03_waiting.js
DELETED
@@ -1,28 +0,0 @@
|
|
1
|
-
/*
|
2
|
-
** © 2018 by Philipp Dunkel, Ben Noordhuis, Elan Shankar
|
3
|
-
** Licensed under MIT License.
|
4
|
-
*/
|
5
|
-
|
6
|
-
/* jshint node:true */
|
7
|
-
'use strict';
|
8
|
-
|
9
|
-
const path = require('path');
|
10
|
-
const assert = require('assert');
|
11
|
-
const fsevents = require('../fsevents');
|
12
|
-
const { run, sleep } = require('./utils/misc.js');
|
13
|
-
const { touch } = require('./utils/fs.js');
|
14
|
-
|
15
|
-
const DIR = process.argv[2];
|
16
|
-
|
17
|
-
run(async ()=>{
|
18
|
-
const events = [];
|
19
|
-
const stopWatching = fsevents.watch(DIR, (...args)=>events.push(args));
|
20
|
-
await sleep(500);
|
21
|
-
for (let idx = 0; idx < 10; idx++) {
|
22
|
-
await touch(path.join(DIR, `${idx + 1}.touch`));
|
23
|
-
await sleep(250);
|
24
|
-
}
|
25
|
-
await sleep(500);
|
26
|
-
assert.equal(events.length, 10)
|
27
|
-
await stopWatching();
|
28
|
-
});
|
package/test/utils/fs.js
DELETED
@@ -1,51 +0,0 @@
|
|
1
|
-
const fs = require('fs');
|
2
|
-
const path = require('path');
|
3
|
-
|
4
|
-
exports.rmrf = async (file) => {
|
5
|
-
let stat;
|
6
|
-
try {
|
7
|
-
stat = await exports.stat(file);
|
8
|
-
} catch(err) {
|
9
|
-
//ignore
|
10
|
-
}
|
11
|
-
if (!stat) return;
|
12
|
-
if (stat.isDirectory()) {
|
13
|
-
const files = await exports.readdir(file);
|
14
|
-
await Promise.all(files.map(exports.rmrf));
|
15
|
-
}
|
16
|
-
await exports.rm(file, stat);
|
17
|
-
}
|
18
|
-
|
19
|
-
exports.rm = async (file, stat) => {
|
20
|
-
stat = stat || await exports.stat(file);
|
21
|
-
return await new Promise((resolve, reject) => {
|
22
|
-
fs[stat.isDirectory() ? 'rmdir' : 'unlink'](file, (err) => {
|
23
|
-
if (err) return reject(err);
|
24
|
-
resolve();
|
25
|
-
});
|
26
|
-
});
|
27
|
-
};
|
28
|
-
exports.readdir = async (dir) => {
|
29
|
-
const files = await fs.promises.readdir(dir);
|
30
|
-
return files.map((child) => path.join(file, child));
|
31
|
-
};
|
32
|
-
exports.stat = fs.promises.stat;
|
33
|
-
exports.mkdir = fs.promises.mkdir;
|
34
|
-
exports.write = fs.promises.writeFile;
|
35
|
-
exports.read = fs.promises.readFile;
|
36
|
-
exports.chmod = fs.promises.chmod
|
37
|
-
exports.touch = async (file) => {
|
38
|
-
try {
|
39
|
-
await exports.stat(file);
|
40
|
-
} catch(err) {
|
41
|
-
await exports.write(file, '');
|
42
|
-
}
|
43
|
-
|
44
|
-
return await new Promise((resolve, reject) => {
|
45
|
-
fs.utimes(file, Date.now(), Date.now(), (err) => {
|
46
|
-
if (err) return reject(err);
|
47
|
-
resolve();
|
48
|
-
});
|
49
|
-
});
|
50
|
-
};
|
51
|
-
exports.rename = fs.promises.rename;
|
package/test/utils/misc.js
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
exports.sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
2
|
-
exports.capture = () => {
|
3
|
-
const events = [];
|
4
|
-
events.callback = (...args) => events.push(args);
|
5
|
-
return events;
|
6
|
-
};
|
7
|
-
|
8
|
-
exports.run = async (test) => {
|
9
|
-
try {
|
10
|
-
await test();
|
11
|
-
process.exit(0);
|
12
|
-
} catch(err) {
|
13
|
-
console.log(' ---');
|
14
|
-
console.log(` message: ${err.message}`);
|
15
|
-
console.log(` actual: ${JSON.stringify(err.actual)}`);
|
16
|
-
console.log(` expected: ${JSON.stringify(err.expected)}`);
|
17
|
-
console.log(` source: ${err.stack.split(/\r?\n/)[1].trim()}`);
|
18
|
-
console.log(' ...');
|
19
|
-
process.exit(1);
|
20
|
-
}
|
21
|
-
};
|
package/test.sh
DELETED
@@ -1,29 +0,0 @@
|
|
1
|
-
#!/bin/bash
|
2
|
-
|
3
|
-
N=0
|
4
|
-
F=0
|
5
|
-
T="$(pwd)/temp"
|
6
|
-
V=$(node -v)
|
7
|
-
D=$(date +%F_%T)
|
8
|
-
|
9
|
-
echo "TAP version 13"
|
10
|
-
echo "# Node Version: $V"
|
11
|
-
for FILE in $(ls test/*.js); do
|
12
|
-
DIR="$T/$D/$N"
|
13
|
-
rm -rf "$DIR"
|
14
|
-
mkdir -p "$DIR"
|
15
|
-
N=$(($N + 1))
|
16
|
-
echo "# File: $FILE" 1>&2
|
17
|
-
echo "# Directory: $DIR" 1>&2
|
18
|
-
node "$FILE" "$DIR"
|
19
|
-
if [ $? = 0 ]; then
|
20
|
-
echo "ok $N $FILE"
|
21
|
-
else
|
22
|
-
F=$(($F + 1))
|
23
|
-
echo "not ok $N $FILE"
|
24
|
-
fi
|
25
|
-
done
|
26
|
-
echo "1..$N"
|
27
|
-
rm -rf "$T"
|
28
|
-
|
29
|
-
exit $F
|