io-watch 0.6.1 → 0.6.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/bin/io-watch +1 -0
- data/ext/configure +2 -2
- data/ext/io/watch/fsevent.c +2 -1
- data/ext/io/watch/inotify.c +99 -6
- data/lib/io/watch/monitor.rb +1 -0
- data/lib/io/watch/version.rb +1 -1
- data/lib/io/watch.rb +3 -0
- data/license.md +1 -0
- data/readme.md +4 -0
- data.tar.gz.sig +0 -0
- metadata +3 -2
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 14f3ccb0d7a3066e70e3ab6e25221c585f1a17034e0e9731fe85637e6797b4d8
|
4
|
+
data.tar.gz: 35d7f43fd20d2ef7cf68558c787344cc49c614498e98e8ccfc25bfca08d5b5d6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 045d52cf0bc46fcc1410af1eb75362b21584561350996baa58c0b87a8b0216d24013d18ed97542d9c987f4b457b828b115f10f0ad5848734842194b45f2b09a0
|
7
|
+
data.tar.gz: 1d1a110f3d8f85e1d4f74fd2b55d927d4c91a3b02bbf506ce4b1f20272b67ba6c8830d3e265fa4948feac4de1ee5d2531ca76c8f2211255b21cc9d5cab33644f
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data/bin/io-watch
CHANGED
data/ext/configure
CHANGED
@@ -43,7 +43,7 @@ esac
|
|
43
43
|
cat > Makefile <<EOF
|
44
44
|
TARGET = io-watch
|
45
45
|
CC = $CC
|
46
|
-
CFLAGS = -Wall -Wextra
|
46
|
+
CFLAGS = -Wall -Wextra -Werror
|
47
47
|
LDFLAGS = $LDFLAGS
|
48
48
|
SOURCES = $SOURCES
|
49
49
|
OBJECTS = \$(SOURCES:.c=.o)
|
@@ -74,4 +74,4 @@ uninstall:
|
|
74
74
|
.PHONY: all clean install uninstall
|
75
75
|
EOF
|
76
76
|
|
77
|
-
echo "Configuration complete. Run 'make' to build the project."
|
77
|
+
echo "Configuration complete. Run 'make' to build the project."
|
data/ext/io/watch/fsevent.c
CHANGED
@@ -44,6 +44,7 @@ void IO_Watch_FSEvent_callback(
|
|
44
44
|
const FSEventStreamEventFlags eventFlags[],
|
45
45
|
const FSEventStreamEventId eventIds[]) {
|
46
46
|
|
47
|
+
(void)streamRef; // unused
|
47
48
|
const char **eventPaths = (const char**)eventData;
|
48
49
|
struct IO_Watch *watch = context;
|
49
50
|
|
@@ -104,4 +105,4 @@ void IO_Watch_run(struct IO_Watch *watch) {
|
|
104
105
|
}
|
105
106
|
free(pathsToWatch);
|
106
107
|
CFRelease(pathsToWatchArray);
|
107
|
-
}
|
108
|
+
}
|
data/ext/io/watch/inotify.c
CHANGED
@@ -9,6 +9,8 @@
|
|
9
9
|
#include <dirent.h>
|
10
10
|
#include <string.h>
|
11
11
|
#include <sys/stat.h>
|
12
|
+
#include <time.h>
|
13
|
+
#include <poll.h>
|
12
14
|
|
13
15
|
enum {
|
14
16
|
DEBUG = 0,
|
@@ -18,11 +20,16 @@ struct IO_Watch_Watch {
|
|
18
20
|
int watch_descriptor;
|
19
21
|
char *path;
|
20
22
|
int index;
|
23
|
+
|
24
|
+
int modified;
|
21
25
|
};
|
22
26
|
|
23
27
|
struct IO_Watch_Watch_Array {
|
24
28
|
size_t size;
|
25
29
|
size_t capacity;
|
30
|
+
|
31
|
+
size_t pending;
|
32
|
+
|
26
33
|
struct IO_Watch_Watch *watches;
|
27
34
|
};
|
28
35
|
|
@@ -31,6 +38,7 @@ struct IO_Watch_Watch_Array {
|
|
31
38
|
void IO_Watch_Watch_Array_initialize(struct IO_Watch_Watch_Array *array) {
|
32
39
|
array->size = 0;
|
33
40
|
array->capacity = 16;
|
41
|
+
array->pending = 0;
|
34
42
|
array->watches = malloc(array->capacity * sizeof(struct IO_Watch_Watch));
|
35
43
|
if (!array->watches) {
|
36
44
|
perror("io-watch:IO_Watch_Watch_Array_initialize:malloc");
|
@@ -176,6 +184,46 @@ void IO_Watch_INotify_print_event(struct inotify_event *event) {
|
|
176
184
|
fprintf(stderr, "\n");
|
177
185
|
}
|
178
186
|
|
187
|
+
static size_t IO_Watch_INotify_flush_events(struct IO_Watch_Watch_Array watch_array) {
|
188
|
+
size_t count = 0;
|
189
|
+
|
190
|
+
if (watch_array.pending == 0) {
|
191
|
+
return 0;
|
192
|
+
}
|
193
|
+
|
194
|
+
for (size_t i = 0; i < watch_array.size; i++) {
|
195
|
+
int modified = watch_array.watches[i].modified;
|
196
|
+
if (modified) {
|
197
|
+
count++;
|
198
|
+
|
199
|
+
printf("{\"index\":%d,\"mask\":%u}\n", watch_array.watches[i].index, modified);
|
200
|
+
watch_array.watches[i].modified = 0;
|
201
|
+
}
|
202
|
+
}
|
203
|
+
|
204
|
+
watch_array.pending = 0;
|
205
|
+
|
206
|
+
fflush(stdout);
|
207
|
+
|
208
|
+
if (DEBUG) fprintf(stderr, "io-watch:IO_Watch_INotify_flush_events: Flushed %zu events\n", count);
|
209
|
+
|
210
|
+
return count;
|
211
|
+
}
|
212
|
+
|
213
|
+
static float IO_Watch_handle_timeout(float latency, struct timespec *start_time) {
|
214
|
+
if (start_time) {
|
215
|
+
struct timespec current_time;
|
216
|
+
clock_gettime(CLOCK_MONOTONIC, ¤t_time);
|
217
|
+
|
218
|
+
float delta = current_time.tv_sec - start_time->tv_sec;
|
219
|
+
delta += (current_time.tv_nsec - start_time->tv_nsec) / 1e9;
|
220
|
+
|
221
|
+
return latency - delta;
|
222
|
+
} else {
|
223
|
+
return 0.0;
|
224
|
+
}
|
225
|
+
}
|
226
|
+
|
179
227
|
void IO_Watch_run(struct IO_Watch *watch) {
|
180
228
|
int fd = inotify_init1(IN_NONBLOCK);
|
181
229
|
if (fd == -1) {
|
@@ -193,16 +241,60 @@ void IO_Watch_run(struct IO_Watch *watch) {
|
|
193
241
|
IO_Watch_Watch_Array_scan(fd, &watch_array, path, i);
|
194
242
|
}
|
195
243
|
|
244
|
+
float latency = watch->latency;
|
245
|
+
|
246
|
+
// If start_time is non-null, it means we are now coallescing events, up to the specified latency:
|
247
|
+
struct timespec start_time_buffer, *start_time = NULL;
|
248
|
+
|
196
249
|
printf("{\"status\":\"started\"}\n");
|
197
250
|
fflush(stdout);
|
198
251
|
|
199
252
|
char buffer[BUFFER_SIZE] __attribute__ ((aligned(8)));
|
200
253
|
|
201
254
|
while (1) {
|
255
|
+
// Check for any events:
|
202
256
|
ssize_t result = read(fd, buffer, BUFFER_SIZE);
|
203
|
-
|
204
|
-
|
205
|
-
|
257
|
+
|
258
|
+
// Calculate the timeout, if any:
|
259
|
+
float timeout = IO_Watch_handle_timeout(latency, start_time);
|
260
|
+
|
261
|
+
// We need to check if the timeout has expired:
|
262
|
+
if (timeout < 0.0) {
|
263
|
+
if (DEBUG) fprintf(stderr, "io-watch:IO_Watch_run: Timeout expired\n");
|
264
|
+
|
265
|
+
start_time = NULL;
|
266
|
+
// Flush any pending events:
|
267
|
+
IO_Watch_INotify_flush_events(watch_array);
|
268
|
+
}
|
269
|
+
|
270
|
+
// If no events are available, we have to wait for the timeout:
|
271
|
+
if (result == -1) {
|
272
|
+
if (errno != EAGAIN && errno != EWOULDBLOCK) {
|
273
|
+
perror("(io-watch:IO_Watch_run:read)");
|
274
|
+
exit(EXIT_FAILURE);
|
275
|
+
}
|
276
|
+
|
277
|
+
if (DEBUG) fprintf(stderr, "io-watch:IO_Watch_run: No events available, waiting for %0.4f seconds\n", timeout);
|
278
|
+
|
279
|
+
// Wait until the file descriptor becomes readable:
|
280
|
+
struct pollfd poll_fd = {fd, POLLIN, 0};
|
281
|
+
int poll_timeout = start_time ? (int) (timeout * 1e3) : -1;
|
282
|
+
|
283
|
+
// If we have a timeout of 0.0, we have to poll for at least 1 ms:
|
284
|
+
if (poll_timeout == 0 && timeout > 0.0) {
|
285
|
+
poll_timeout = 1;
|
286
|
+
}
|
287
|
+
|
288
|
+
if (DEBUG) fprintf(stderr, "io-watch:IO_Watch_run:poll: Polling for %d ms\n", poll_timeout);
|
289
|
+
poll(&poll_fd, 1, poll_timeout);
|
290
|
+
continue;
|
291
|
+
}
|
292
|
+
|
293
|
+
// If we have received events, we have to set the start_time if it is not set:
|
294
|
+
if (!start_time) {
|
295
|
+
if (DEBUG) fprintf(stderr, "io-watch:IO_Watch_run: Setting start_time\n");
|
296
|
+
start_time = &start_time_buffer;
|
297
|
+
clock_gettime(CLOCK_MONOTONIC, start_time);
|
206
298
|
}
|
207
299
|
|
208
300
|
for (ssize_t offset = 0; offset < result;) {
|
@@ -225,7 +317,9 @@ void IO_Watch_run(struct IO_Watch *watch) {
|
|
225
317
|
ssize_t index = IO_Watch_Watch_Array_find(&watch_array, event->wd);
|
226
318
|
|
227
319
|
if (index != -1) {
|
228
|
-
|
320
|
+
if (DEBUG) fprintf(stderr, "io-watch:IO_Watch_run: Modified path %s mask=%d\n", watch_array.watches[index].path, event->mask);
|
321
|
+
watch_array.watches[index].modified |= event->mask;
|
322
|
+
watch_array.pending += 1;
|
229
323
|
|
230
324
|
// If a new directory is created, add a watch for it
|
231
325
|
if (event->mask & IN_CREATE && event->mask & IN_ISDIR) {
|
@@ -239,9 +333,8 @@ void IO_Watch_run(struct IO_Watch *watch) {
|
|
239
333
|
|
240
334
|
offset += sizeof(struct inotify_event) + event->len;
|
241
335
|
}
|
242
|
-
fflush(stdout);
|
243
336
|
}
|
244
|
-
|
337
|
+
|
245
338
|
for (size_t i = 0; i < watch_array.size; i++) {
|
246
339
|
inotify_rm_watch(fd, watch_array.watches[i].watch_descriptor);
|
247
340
|
free(watch_array.watches[i].path);
|
data/lib/io/watch/monitor.rb
CHANGED
@@ -9,6 +9,7 @@ class IO
|
|
9
9
|
module Watch
|
10
10
|
# Represents a list of roots to watch for changes.
|
11
11
|
class Monitor
|
12
|
+
# The path to the compiled `io-watch` command.
|
12
13
|
def self.command_path
|
13
14
|
if extension_path = Gem.loaded_specs['io-watch']&.extension_dir
|
14
15
|
if File.exist?(extension_path)
|
data/lib/io/watch/version.rb
CHANGED
data/lib/io/watch.rb
CHANGED
data/license.md
CHANGED
data/readme.md
CHANGED
@@ -4,6 +4,10 @@ Monitor the file-system for changes.
|
|
4
4
|
|
5
5
|
[![Development Status](https://github.com/socketry/io-watch/workflows/Test/badge.svg)](https://github.com/socketry/io-watch/actions?workflow=Test)
|
6
6
|
|
7
|
+
## Motivation
|
8
|
+
|
9
|
+
Previously, I was using the `listen` gem in combination with `rb-inotify` or `rb-fsevent` to watch for file-system changes. However, those libraries have been around for an extremely long time and have accumulated a lot of cruft. In addition, I don't like having to multiplex in application code depending on the underlying platform. I created this library to provide a simple, unified interface for watching directories for changes. This is the most consistently supported behaviour across all platforms, and fits the needs of most applications without a huge amount of complexity.
|
10
|
+
|
7
11
|
## Usage
|
8
12
|
|
9
13
|
Please see the [project documentation](https://socketry.github.io/io-watch/) for more details.
|
data.tar.gz.sig
CHANGED
Binary file
|
metadata
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: io-watch
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.
|
4
|
+
version: 0.6.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Samuel Williams
|
8
|
+
- Étienne Barrié
|
8
9
|
autorequire:
|
9
10
|
bindir: bin
|
10
11
|
cert_chain:
|
@@ -37,7 +38,7 @@ cert_chain:
|
|
37
38
|
Q2K9NVun/S785AP05vKkXZEFYxqG6EW012U4oLcFl5MySFajYXRYbuUpH6AY+HP8
|
38
39
|
voD0MPg1DssDLKwXyt1eKD/+Fq0bFWhwVM/1XiAXL7lyYUyOq24KHgQ2Csg=
|
39
40
|
-----END CERTIFICATE-----
|
40
|
-
date: 2024-08-
|
41
|
+
date: 2024-08-12 00:00:00.000000000 Z
|
41
42
|
dependencies: []
|
42
43
|
description:
|
43
44
|
email:
|
metadata.gz.sig
CHANGED
Binary file
|