io-watch 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 28d2d87eebbc0c7ba0750330239bdd1d00c8195ff8a93121ba13a8368b681730
4
+ data.tar.gz: 8528b998df129ca0da1f4ff7cbf3627721608bf4491ac7da41fb3a8b381d65cf
5
+ SHA512:
6
+ metadata.gz: 7896b82cab31023f395aeb3bf9a588e31291b8d5ed2030f818377977e15dfb431a7ec80af2717ee252bff134816aea367c2099084747c09af16af62c58c174fe
7
+ data.tar.gz: e9f8f8a987490ace634ddd18eea1514657e12b0f945219063442750c16e53dc1f59e95b91c0ecb356e06ec863d2661a601069e611fe6ad3503a739737a01a2bf
checksums.yaml.gz.sig ADDED
Binary file
data/ext/Makefile ADDED
@@ -0,0 +1,31 @@
1
+ TARGET = io-watch
2
+ CC = cc
3
+ CFLAGS = -Wall -Wextra
4
+ LDFLAGS = -framework CoreServices
5
+ SOURCES = io/watch.c io/watch/fsevent.c
6
+ OBJECTS = $(SOURCES:.c=.o)
7
+ PREFIX = /Users/samuel/Developer/socketry/io-watch/ext
8
+
9
+ all: $(TARGET)
10
+
11
+ $(TARGET): $(OBJECTS)
12
+ $(CC) $(LDFLAGS) -o $@ $^
13
+
14
+ # To create object files
15
+ %.o: %.c
16
+ $(CC) $(CFLAGS) -c $< -o $@
17
+
18
+ # Clean Target
19
+ clean:
20
+ rm -f $(TARGET) $(OBJECTS)
21
+
22
+ install: $(TARGET)
23
+ @echo "Installing $(TARGET) to $(PREFIX)/bin"
24
+ mkdir -p $(PREFIX)/bin
25
+ install -m 755 $(TARGET) $(PREFIX)/bin
26
+
27
+ uninstall:
28
+ @echo "Removing $(TARGET) from $(PREFIX)/bin"
29
+ rm -f $(PREFIX)/bin/$(TARGET)
30
+
31
+ .PHONY: all clean install uninstall
data/ext/bin/io-watch ADDED
Binary file
data/ext/configure ADDED
@@ -0,0 +1,77 @@
1
+ #!/bin/sh
2
+
3
+ PREFIX=$(pwd)
4
+ LDFLAGS=""
5
+ SOURCES=""
6
+ CC="${CC:-cc}"
7
+
8
+ # Parse command line arguments
9
+ for arg in "$@"; do
10
+ case $arg in
11
+ --prefix=*)
12
+ PREFIX="${arg#*=}"
13
+ shift
14
+ ;;
15
+ *)
16
+ echo "Unknown option: $arg"
17
+ exit 1
18
+ ;;
19
+ esac
20
+ done
21
+
22
+ OS="$(uname)"
23
+ echo "Detected OS: $OS"
24
+
25
+ # Generate Makefile based on the platform
26
+ case "$OS" in
27
+ Darwin)
28
+ echo "Using FSEvents (macOS)"
29
+ LDFLAGS="-framework CoreServices"
30
+ SOURCES="io/watch.c io/watch/fsevent.c"
31
+ ;;
32
+ Linux)
33
+ echo "Using inotify (Linux)"
34
+ SOURCES="io/watch.c io/watch/inotify.c"
35
+ ;;
36
+ *)
37
+ echo "Unsupported platform: $OS"
38
+ exit 1
39
+ ;;
40
+ esac
41
+
42
+ # Create the Makefile
43
+ cat > Makefile <<EOF
44
+ TARGET = io-watch
45
+ CC = $CC
46
+ CFLAGS = -Wall -Wextra
47
+ LDFLAGS = $LDFLAGS
48
+ SOURCES = $SOURCES
49
+ OBJECTS = \$(SOURCES:.c=.o)
50
+ PREFIX = $PREFIX
51
+
52
+ all: \$(TARGET)
53
+
54
+ \$(TARGET): \$(OBJECTS)
55
+ \$(CC) \$(LDFLAGS) -o \$@ \$^
56
+
57
+ # To create object files
58
+ %.o: %.c
59
+ \$(CC) \$(CFLAGS) -c \$< -o \$@
60
+
61
+ # Clean Target
62
+ clean:
63
+ rm -f \$(TARGET) \$(OBJECTS)
64
+
65
+ install: \$(TARGET)
66
+ @echo "Installing \$(TARGET) to \$(PREFIX)/bin"
67
+ mkdir -p \$(PREFIX)/bin
68
+ install -m 755 \$(TARGET) \$(PREFIX)/bin
69
+
70
+ uninstall:
71
+ @echo "Removing \$(TARGET) from \$(PREFIX)/bin"
72
+ rm -f \$(PREFIX)/bin/\$(TARGET)
73
+
74
+ .PHONY: all clean install uninstall
75
+ EOF
76
+
77
+ echo "Configuration complete. Run 'make' to build the project."
@@ -0,0 +1,107 @@
1
+ #include "watch.h"
2
+
3
+ #include <CoreServices/CoreServices.h>
4
+ #include <dispatch/dispatch.h>
5
+ #include <stdio.h>
6
+
7
+ enum {
8
+ DEBUG = 0,
9
+ };
10
+
11
+ static
12
+ int IO_Watch_path_prefix(const char *path, const char *prefix) {
13
+ size_t path_size = strlen(path);
14
+ size_t prefix_size = strlen(prefix);
15
+
16
+ if (path_size < prefix_size) {
17
+ return 0;
18
+ }
19
+
20
+ return strncmp(path, prefix, prefix_size) == 0;
21
+ }
22
+
23
+ static
24
+ ssize_t IO_Watch_find_path(struct IO_Watch *watch, const char *path) {
25
+ size_t index = 0;
26
+
27
+ while (index < watch->size) {
28
+ if (IO_Watch_path_prefix(path, watch->paths[index])) {
29
+ return index;
30
+ }
31
+
32
+ index += 1;
33
+ }
34
+
35
+ return -1;
36
+ }
37
+
38
+ // Function to handle filesystem events
39
+ void IO_Watch_FSEvent_callback(
40
+ ConstFSEventStreamRef streamRef,
41
+ void *context,
42
+ size_t numberOfEvents,
43
+ void *eventData,
44
+ const FSEventStreamEventFlags eventFlags[],
45
+ const FSEventStreamEventId eventIds[]) {
46
+
47
+ const char **eventPaths = (const char**)eventData;
48
+ struct IO_Watch *watch = context;
49
+
50
+ for (size_t i = 0; i < numberOfEvents; i++) {
51
+ if (DEBUG) fprintf(stderr, "Event: %s\n", eventPaths[i]);
52
+
53
+ // Find the index of the path in the paths array
54
+ ssize_t index = IO_Watch_find_path(watch, eventPaths[i]);
55
+
56
+ if (index != -1) {
57
+ // Output event data as newline-delimited JSON
58
+ printf("{\"index\":%zu,\"flags\":%u,\"id\":%llu}\n", index, eventFlags[i], eventIds[i]);
59
+ } else {
60
+ fprintf(stderr, "Path not found in paths array: %s\n", eventPaths[i]);
61
+ }
62
+ }
63
+
64
+ fflush(stdout);
65
+ }
66
+
67
+ void IO_Watch_run(struct IO_Watch *watch) {
68
+ CFStringRef *pathsToWatch = malloc(sizeof(CFStringRef) * watch->size);
69
+ for (size_t i = 0; i < watch->size; i++) {
70
+ pathsToWatch[i] = CFStringCreateWithCString(NULL, watch->paths[i], kCFStringEncodingUTF8);
71
+ }
72
+
73
+ CFArrayRef pathsToWatchArray = CFArrayCreate(NULL, (const void **)pathsToWatch, watch->size, &kCFTypeArrayCallBacks);
74
+
75
+ FSEventStreamContext context = {0, watch, NULL, NULL, NULL};
76
+
77
+ FSEventStreamRef stream;
78
+ CFAbsoluteTime latency = watch->latency;
79
+
80
+ stream = FSEventStreamCreate(
81
+ NULL,
82
+ &IO_Watch_FSEvent_callback,
83
+ &context,
84
+ pathsToWatchArray,
85
+ kFSEventStreamEventIdSinceNow,
86
+ latency,
87
+ kFSEventStreamCreateFlagNone
88
+ );
89
+
90
+ dispatch_queue_t queue = dispatch_queue_create("com.example.fsevents.queue", NULL);
91
+ FSEventStreamSetDispatchQueue(stream, queue);
92
+ FSEventStreamStart(stream);
93
+
94
+ printf("{\"status\":\"started\"}\n");
95
+ fflush(stdout);
96
+
97
+ dispatch_main();
98
+
99
+ FSEventStreamStop(stream);
100
+ FSEventStreamInvalidate(stream);
101
+ FSEventStreamRelease(stream);
102
+ for (size_t i = 0; i < watch->size; i++) {
103
+ CFRelease(pathsToWatch[i]);
104
+ }
105
+ free(pathsToWatch);
106
+ CFRelease(pathsToWatchArray);
107
+ }
Binary file
@@ -0,0 +1,229 @@
1
+ #include "watch.h"
2
+
3
+ #include <sys/inotify.h>
4
+ #include <limits.h>
5
+ #include <stdio.h>
6
+ #include <stdlib.h>
7
+ #include <unistd.h>
8
+ #include <errno.h>
9
+ #include <dirent.h>
10
+ #include <string.h>
11
+ #include <sys/stat.h>
12
+
13
+ enum {
14
+ DEBUG = 0,
15
+ };
16
+
17
+ struct IO_Watch_Watch {
18
+ int watch_descriptor;
19
+ char *path;
20
+ int index;
21
+ };
22
+
23
+ struct IO_Watch_Watch_Array {
24
+ size_t size;
25
+ size_t capacity;
26
+ struct IO_Watch_Watch *watches;
27
+ };
28
+
29
+ #define BUFFER_SIZE (10 * (sizeof(struct inotify_event) + NAME_MAX + 1))
30
+
31
+ void IO_Watch_Watch_Array_initialize(struct IO_Watch_Watch_Array *array) {
32
+ array->size = 0;
33
+ array->capacity = 16;
34
+ array->watches = malloc(array->capacity * sizeof(struct IO_Watch_Watch));
35
+ if (!array->watches) {
36
+ perror("malloc");
37
+ exit(EXIT_FAILURE);
38
+ }
39
+ }
40
+
41
+ void IO_Watch_Watch_Array_resize(struct IO_Watch_Watch_Array *array) {
42
+ array->capacity *= 2;
43
+ array->watches = realloc(array->watches, array->capacity * sizeof(struct IO_Watch_Watch));
44
+ if (!array->watches) {
45
+ perror("realloc");
46
+ exit(EXIT_FAILURE);
47
+ }
48
+ }
49
+
50
+ void IO_Watch_Watch_Array_add(struct IO_Watch_Watch_Array *array, int watch_descriptor, char *path, int index) {
51
+ if (array->size == array->capacity) {
52
+ IO_Watch_Watch_Array_resize(array);
53
+ }
54
+ array->watches[array->size].watch_descriptor = watch_descriptor;
55
+ array->watches[array->size].path = path;
56
+ array->watches[array->size].index = index;
57
+ array->size++;
58
+ }
59
+
60
+ ssize_t IO_Watch_Watch_Array_find(struct IO_Watch_Watch_Array *array, int watch_descriptor) {
61
+ for (size_t i = 0; i < array->size; i++) {
62
+ if (array->watches[i].watch_descriptor == watch_descriptor) {
63
+ return i;
64
+ }
65
+ }
66
+ return -1;
67
+ }
68
+
69
+ void IO_Watch_Watch_Array_watch(int fd, struct IO_Watch_Watch_Array *watch_array, char *path, int index) {
70
+ int watch_descriptor = inotify_add_watch(fd, path, IN_ALL_EVENTS);
71
+ if (watch_descriptor == -1) {
72
+ perror("inotify_add_watch");
73
+ exit(EXIT_FAILURE);
74
+ }
75
+
76
+ IO_Watch_Watch_Array_add(watch_array, watch_descriptor, path, index);
77
+
78
+ if (DEBUG) fprintf(stderr, "Added watch: %s\n", path);
79
+ }
80
+
81
+ void IO_Watch_Watch_Array_scan(int fd, struct IO_Watch_Watch_Array *watch_array, const char *root, int index) {
82
+ DIR *dir = opendir(root);
83
+ if (!dir) {
84
+ perror("opendir");
85
+ return;
86
+ }
87
+
88
+ struct dirent *entry;
89
+ while ((entry = readdir(dir)) != NULL) {
90
+ if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
91
+ continue;
92
+ }
93
+
94
+ size_t size = strlen(root) + 1 + strlen(entry->d_name) + 1;
95
+ char *path = malloc(size);
96
+ snprintf(path, size, "%s/%s", root, entry->d_name);
97
+
98
+ struct stat statbuf;
99
+ if (stat(path, &statbuf) == -1) {
100
+ perror("stat");
101
+ continue;
102
+ }
103
+
104
+ if (S_ISDIR(statbuf.st_mode)) {
105
+ IO_Watch_Watch_Array_watch(fd, watch_array, path, index);
106
+ IO_Watch_Watch_Array_scan(fd, watch_array, path, index);
107
+ } else {
108
+ free(path);
109
+ }
110
+ }
111
+
112
+ closedir(dir);
113
+ }
114
+
115
+ void IO_Watch_Watch_Array_add_subdirectory(int fd, struct IO_Watch_Watch_Array *watch_array, struct IO_Watch_Watch watch, const char *name) {
116
+ size_t size = strlen(watch.path) + 1 + strlen(name) + 1;
117
+ char *path = malloc(size);
118
+ snprintf(path, size, "%s/%s", watch.path, name);
119
+
120
+ IO_Watch_Watch_Array_watch(fd, watch_array, path, watch.index);
121
+ IO_Watch_Watch_Array_scan(fd, watch_array, path, watch.index);
122
+ }
123
+
124
+ void IO_Watch_Watch_Array_remove(int fd, struct IO_Watch_Watch_Array *watch_array, size_t index) {
125
+ struct IO_Watch_Watch watch = watch_array->watches[index];
126
+
127
+ if (DEBUG) fprintf(stderr, "Removing watch: %s\n", watch.path);
128
+
129
+ inotify_rm_watch(fd, watch.watch_descriptor);
130
+ free(watch.path);
131
+
132
+ // Replace the removed item with the last one.
133
+ watch_array->size--;
134
+ if (index < watch_array->size) {
135
+ watch_array->watches[index] = watch_array->watches[watch_array->size];
136
+ }
137
+ }
138
+
139
+ static
140
+ void IO_Watch_INotify_print_event(struct inotify_event *event) {
141
+ fprintf(stderr, "Event: wd=%d", event->wd);
142
+
143
+ uint32_t mask = event->mask;
144
+ if (mask & IN_ACCESS) fprintf(stderr, " ACCESS");
145
+ if (mask & IN_MODIFY) fprintf(stderr, " MODIFY");
146
+ if (mask & IN_ATTRIB) fprintf(stderr, " ATTRIB");
147
+ if (mask & IN_CLOSE_WRITE) fprintf(stderr, " CLOSE_WRITE");
148
+ if (mask & IN_CLOSE_NOWRITE) fprintf(stderr, " CLOSE_NOWRITE");
149
+ if (mask & IN_OPEN) fprintf(stderr, " OPEN");
150
+ if (mask & IN_MOVED_FROM) fprintf(stderr, " MOVED_FROM");
151
+ if (mask & IN_MOVED_TO) fprintf(stderr, " MOVED_TO");
152
+ if (mask & IN_CREATE) fprintf(stderr, " CREATE");
153
+ if (mask & IN_DELETE) fprintf(stderr, " DELETE");
154
+ if (mask & IN_DELETE_SELF) fprintf(stderr, " DELETE_SELF");
155
+ if (mask & IN_MOVE_SELF) fprintf(stderr, " MOVE_SELF");
156
+ if (mask & IN_UNMOUNT) fprintf(stderr, " UNMOUNT");
157
+ if (mask & IN_Q_OVERFLOW) fprintf(stderr, " Q_OVERFLOW");
158
+ if (mask & IN_IGNORED) fprintf(stderr, " IGNORED");
159
+ if (mask & IN_ISDIR) fprintf(stderr, " ISDIR");
160
+ if (mask & IN_ONESHOT) fprintf(stderr, " ONESHOT");
161
+ if (mask & IN_ALL_EVENTS) fprintf(stderr, " ALL_EVENTS");
162
+
163
+ if (event->len > 0) {
164
+ fprintf(stderr, " name=%s", event->name);
165
+ }
166
+
167
+ fprintf(stderr, "\n");
168
+ }
169
+
170
+ void IO_Watch_run(struct IO_Watch *watch) {
171
+ int fd = inotify_init1(IN_NONBLOCK);
172
+ if (fd == -1) {
173
+ perror("inotify_init1");
174
+ exit(EXIT_FAILURE);
175
+ }
176
+
177
+ struct IO_Watch_Watch_Array watch_array;
178
+ IO_Watch_Watch_Array_initialize(&watch_array);
179
+
180
+ for (size_t i = 0; i < watch->size; i++) {
181
+ char *path = strdup(watch->paths[i]);
182
+
183
+ IO_Watch_Watch_Array_watch(fd, &watch_array, path, i);
184
+ IO_Watch_Watch_Array_scan(fd, &watch_array, path, i);
185
+ }
186
+
187
+ printf("{\"status\":\"started\"}\n");
188
+ fflush(stdout);
189
+
190
+ char buffer[BUFFER_SIZE] __attribute__ ((aligned(8)));
191
+
192
+ while (1) {
193
+ ssize_t result = read(fd, buffer, BUFFER_SIZE);
194
+ if (result == -1 && errno != EAGAIN) {
195
+ perror("read");
196
+ exit(EXIT_FAILURE);
197
+ }
198
+
199
+ for (ssize_t offset = 0; offset < result;) {
200
+ struct inotify_event *event = (struct inotify_event *) &buffer[offset];
201
+ if (DEBUG) IO_Watch_INotify_print_event(event);
202
+
203
+ ssize_t index = IO_Watch_Watch_Array_find(&watch_array, event->wd);
204
+
205
+ if (index != -1) {
206
+ printf("{\"index\":%d,\"mask\":%u}\n", watch_array.watches[index].index, event->mask);
207
+
208
+ // If a new directory is created, add a watch for it
209
+ if (event->mask & IN_CREATE && event->mask & IN_ISDIR) {
210
+ IO_Watch_Watch_Array_add_subdirectory(fd, &watch_array, watch_array.watches[index], event->name);
211
+ } else if (event->mask & IN_IGNORED) {
212
+ IO_Watch_Watch_Array_remove(fd, &watch_array, index);
213
+ }
214
+ } else {
215
+ fprintf(stderr, "Watch descriptor not found: %d\n", event->wd);
216
+ }
217
+
218
+ offset += sizeof(struct inotify_event) + event->len;
219
+ }
220
+ fflush(stdout);
221
+ }
222
+
223
+ for (size_t i = 0; i < watch_array.size; i++) {
224
+ inotify_rm_watch(fd, watch_array.watches[i].watch_descriptor);
225
+ free(watch_array.watches[i].path);
226
+ }
227
+ close(fd);
228
+ free(watch_array.watches);
229
+ }
@@ -0,0 +1,13 @@
1
+ #pragma once
2
+
3
+ #include <stddef.h>
4
+ #include <sys/types.h>
5
+
6
+ struct IO_Watch {
7
+ float latency;
8
+
9
+ size_t size;
10
+ const char **paths;
11
+ };
12
+
13
+ void IO_Watch_run(struct IO_Watch *watch);
data/ext/io/watch.c ADDED
@@ -0,0 +1,45 @@
1
+ #include "watch/watch.h"
2
+
3
+ #include <stdio.h>
4
+ #include <stdlib.h>
5
+ #include <string.h>
6
+
7
+ enum {
8
+ DEBUG = 0,
9
+ };
10
+
11
+ int main(int argc, char **argv) {
12
+ if (argc < 2) {
13
+ fprintf(stderr, "Usage: %s <directory_to_watch> [<directory_to_watch> ...]\n", argv[0]);
14
+ return 1;
15
+ }
16
+
17
+ struct IO_Watch watch;
18
+ watch.latency = 0.1;
19
+ watch.size = argc - 1;
20
+ watch.paths = (const char **) &argv[1];
21
+
22
+ char * latency = getenv("IO_WATCH_LATENCY");
23
+ if (latency != NULL) {
24
+ watch.latency = atof(latency);
25
+ }
26
+
27
+ for (size_t i = 0; i < watch.size; i++) {
28
+ char *real_path = realpath(watch.paths[i], NULL);
29
+ if (real_path == NULL) {
30
+ fprintf(stderr, "Error: realpath failed for %s\n", watch.paths[i]);
31
+ return 1;
32
+ } else {
33
+ if (DEBUG) fprintf(stderr, "Watching: %s\n", real_path);
34
+ watch.paths[i] = real_path;
35
+ }
36
+ }
37
+
38
+ IO_Watch_run(&watch);
39
+
40
+ for (size_t i = 0; i < watch.size; i++) {
41
+ free((void *) watch.paths[i]);
42
+ }
43
+
44
+ return 0;
45
+ }
data/ext/io/watch.o ADDED
Binary file
data/ext/io-watch ADDED
Binary file
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2024, by Samuel Williams.
5
+
6
+ require 'json'
7
+
8
+ class IO
9
+ module Watch
10
+ # Represents a list of roots to watch for changes.
11
+ class Monitor
12
+ def self.command_path
13
+ if extensions_path = Gem.loaded_specs['io-watch']&.extensions_dir
14
+ if File.exist?(extensions_path)
15
+ return File.join(extensions_path, 'io-watch')
16
+ end
17
+ end
18
+
19
+ return File.join(__dir__, '../../../ext/bin/io-watch')
20
+ end
21
+
22
+ COMMAND_PATH = self.command_path
23
+
24
+ # Initialize the monitor with a list of roots to watch.
25
+ #
26
+ # The roots are the paths that will be watched for changes, recursively.
27
+ #
28
+ # @parameter roots [Array(String)] The list of root directories to watch. Changes to these directories, and their children, recursively, will be reported.
29
+ # @parameter latency [Float] The latency to use when watching the filesystem.
30
+ def initialize(roots, latency = 0.1)
31
+ @roots = roots
32
+ @latency = latency
33
+ end
34
+
35
+ # Run the monitor and yield events as they occur.
36
+ #
37
+ # The values yielded are hashes with at least the following:
38
+ # - `:root` - The root path that the event occurred in.
39
+ #
40
+ # There may be other platform specific keys present.
41
+ #
42
+ # @yields {|event| ...} Yielded for each event that occurs.
43
+ # @parameter event [Hash] The event that occurred.
44
+ def run
45
+ environment = {'IO_WATCH_LATENCY' => @latency.to_s}
46
+ IO.pipe do |input, output|
47
+ pid = Process.spawn(environment, self.class.command_path, *@roots, out: output)
48
+ output.close
49
+
50
+ input.each_line do |line|
51
+ event = JSON.parse(line, symbolize_names: true)
52
+
53
+ if index = event[:index]
54
+ event[:root] = @roots[index]
55
+ end
56
+
57
+ yield event
58
+ end
59
+ ensure
60
+ Process.kill('TERM', pid) if pid
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2024, by Samuel Williams.
5
+
6
+ class IO
7
+ module Watch
8
+ VERSION = '0.1.0'
9
+ end
10
+ end
data/lib/io/watch.rb ADDED
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2024, by Samuel Williams.
5
+
6
+ require_relative 'watch/version'
7
+ require_relative 'watch/monitor'
8
+
9
+ class IO
10
+ module Watch
11
+ def self.new(...)
12
+ Monitor.new(...)
13
+ end
14
+ end
15
+ end
data/license.md ADDED
@@ -0,0 +1,21 @@
1
+ # MIT License
2
+
3
+ Copyright, 2024, by Samuel Williams.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/readme.md ADDED
@@ -0,0 +1,29 @@
1
+ # IO::Watch
2
+
3
+ Monitor the file-system for changes.
4
+
5
+ [![Development Status](https://github.com/socketry/io-watch/workflows/Test/badge.svg)](https://github.com/socketry/io-watch/actions?workflow=Test)
6
+
7
+ ## Usage
8
+
9
+ Please see the [project documentation](https://socketry.github.io/io-watch/) for more details.
10
+
11
+ - [Getting Started](https://socketry.github.io/io-watch/guides/getting-started/index) - This guide explains how to use the `io-watch` gem for watching files and directories for changes.
12
+
13
+ ## Contributing
14
+
15
+ We welcome contributions to this project.
16
+
17
+ 1. Fork it.
18
+ 2. Create your feature branch (`git checkout -b my-new-feature`).
19
+ 3. Commit your changes (`git commit -am 'Add some feature'`).
20
+ 4. Push to the branch (`git push origin my-new-feature`).
21
+ 5. Create new Pull Request.
22
+
23
+ ### Developer Certificate of Origin
24
+
25
+ In order to protect users of this project, we require all contributions to comply with the [Developer Certificate of Origin](https://developercertificate.org/). This ensures that all contributions are properly licensed and attributed. All contributors must agree to this document for their contributions to be accepted.
26
+
27
+ ### Community Guidelines
28
+
29
+ This project is best served by a collaborative and respectful environment. Treat each other professionally, respect differing viewpoints, and engage constructively. Harassment, discrimination, or harmful behavior is not tolerated. Communicate clearly, listen actively, and support one another. If any issues arise, please inform the project maintainers.
data.tar.gz.sig ADDED
Binary file
metadata ADDED
@@ -0,0 +1,89 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: io-watch
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Samuel Williams
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain:
11
+ - |
12
+ -----BEGIN CERTIFICATE-----
13
+ MIIE2DCCA0CgAwIBAgIBATANBgkqhkiG9w0BAQsFADBhMRgwFgYDVQQDDA9zYW11
14
+ ZWwud2lsbGlhbXMxHTAbBgoJkiaJk/IsZAEZFg1vcmlvbnRyYW5zZmVyMRIwEAYK
15
+ CZImiZPyLGQBGRYCY28xEjAQBgoJkiaJk/IsZAEZFgJuejAeFw0yMjA4MDYwNDUz
16
+ MjRaFw0zMjA4MDMwNDUzMjRaMGExGDAWBgNVBAMMD3NhbXVlbC53aWxsaWFtczEd
17
+ MBsGCgmSJomT8ixkARkWDW9yaW9udHJhbnNmZXIxEjAQBgoJkiaJk/IsZAEZFgJj
18
+ bzESMBAGCgmSJomT8ixkARkWAm56MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIB
19
+ igKCAYEAomvSopQXQ24+9DBB6I6jxRI2auu3VVb4nOjmmHq7XWM4u3HL+pni63X2
20
+ 9qZdoq9xt7H+RPbwL28LDpDNflYQXoOhoVhQ37Pjn9YDjl8/4/9xa9+NUpl9XDIW
21
+ sGkaOY0eqsQm1pEWkHJr3zn/fxoKPZPfaJOglovdxf7dgsHz67Xgd/ka+Wo1YqoE
22
+ e5AUKRwUuvaUaumAKgPH+4E4oiLXI4T1Ff5Q7xxv6yXvHuYtlMHhYfgNn8iiW8WN
23
+ XibYXPNP7NtieSQqwR/xM6IRSoyXKuS+ZNGDPUUGk8RoiV/xvVN4LrVm9upSc0ss
24
+ RZ6qwOQmXCo/lLcDUxJAgG95cPw//sI00tZan75VgsGzSWAOdjQpFM0l4dxvKwHn
25
+ tUeT3ZsAgt0JnGqNm2Bkz81kG4A2hSyFZTFA8vZGhp+hz+8Q573tAR89y9YJBdYM
26
+ zp0FM4zwMNEUwgfRzv1tEVVUEXmoFCyhzonUUw4nE4CFu/sE3ffhjKcXcY//qiSW
27
+ xm4erY3XAgMBAAGjgZowgZcwCQYDVR0TBAIwADALBgNVHQ8EBAMCBLAwHQYDVR0O
28
+ BBYEFO9t7XWuFf2SKLmuijgqR4sGDlRsMC4GA1UdEQQnMCWBI3NhbXVlbC53aWxs
29
+ aWFtc0BvcmlvbnRyYW5zZmVyLmNvLm56MC4GA1UdEgQnMCWBI3NhbXVlbC53aWxs
30
+ aWFtc0BvcmlvbnRyYW5zZmVyLmNvLm56MA0GCSqGSIb3DQEBCwUAA4IBgQB5sxkE
31
+ cBsSYwK6fYpM+hA5B5yZY2+L0Z+27jF1pWGgbhPH8/FjjBLVn+VFok3CDpRqwXCl
32
+ xCO40JEkKdznNy2avOMra6PFiQyOE74kCtv7P+Fdc+FhgqI5lMon6tt9rNeXmnW/
33
+ c1NaMRdxy999hmRGzUSFjozcCwxpy/LwabxtdXwXgSay4mQ32EDjqR1TixS1+smp
34
+ 8C/NCWgpIfzpHGJsjvmH2wAfKtTTqB9CVKLCWEnCHyCaRVuKkrKjqhYCdmMBqCws
35
+ JkxfQWC+jBVeG9ZtPhQgZpfhvh+6hMhraUYRQ6XGyvBqEUe+yo6DKIT3MtGE2+CP
36
+ eX9i9ZWBydWb8/rvmwmX2kkcBbX0hZS1rcR593hGc61JR6lvkGYQ2MYskBveyaxt
37
+ Q2K9NVun/S785AP05vKkXZEFYxqG6EW012U4oLcFl5MySFajYXRYbuUpH6AY+HP8
38
+ voD0MPg1DssDLKwXyt1eKD/+Fq0bFWhwVM/1XiAXL7lyYUyOq24KHgQ2Csg=
39
+ -----END CERTIFICATE-----
40
+ date: 2024-06-28 00:00:00.000000000 Z
41
+ dependencies: []
42
+ description:
43
+ email:
44
+ executables: []
45
+ extensions:
46
+ - ext/configure
47
+ extra_rdoc_files: []
48
+ files:
49
+ - ext/Makefile
50
+ - ext/bin/io-watch
51
+ - ext/configure
52
+ - ext/io-watch
53
+ - ext/io/watch.c
54
+ - ext/io/watch.o
55
+ - ext/io/watch/fsevent.c
56
+ - ext/io/watch/fsevent.o
57
+ - ext/io/watch/inotify.c
58
+ - ext/io/watch/watch.h
59
+ - lib/io/watch.rb
60
+ - lib/io/watch/monitor.rb
61
+ - lib/io/watch/version.rb
62
+ - license.md
63
+ - readme.md
64
+ homepage: https://github.com/socketry/io-watch
65
+ licenses:
66
+ - MIT
67
+ metadata:
68
+ documentation_uri: https://socketry.github.io/io-watch/
69
+ source_code_uri: https://github.com/socketry/io-watch.git
70
+ post_install_message:
71
+ rdoc_options: []
72
+ require_paths:
73
+ - lib
74
+ required_ruby_version: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: '3.1'
79
+ required_rubygems_version: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ requirements: []
85
+ rubygems_version: 3.5.11
86
+ signing_key:
87
+ specification_version: 4
88
+ summary: A tool for watching changes to the filesystem.
89
+ test_files: []
metadata.gz.sig ADDED
Binary file