adamh-rinotify 0.9.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +25 -0
- data/examples/watch_file.rb +58 -0
- data/examples/watch_file_threaded.rb +63 -0
- data/ext/rinotify.c +289 -0
- data/ext/rinotify.h +163 -0
- data/ext/rinotify_event.c +55 -0
- data/ext/rinotify_event.h +60 -0
- data/extconf.rb +3 -0
- metadata +58 -0
data/README.rdoc
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
Example usage:
|
2
|
+
|
3
|
+
rinotify = RInotify.new
|
4
|
+
rinotify.add_watch(ARGV[0], RInotify::MODIFY | RInotify::DELETE_SELF)
|
5
|
+
|
6
|
+
has_events = rinotify.wait_for_events(5)
|
7
|
+
if has_events
|
8
|
+
# iterate through events
|
9
|
+
rinotify.each_event {|revent|
|
10
|
+
|
11
|
+
# check if the event we received was MODIFY or DELETE_SELF
|
12
|
+
if revent.check_mask(RInotify::MODIFY)
|
13
|
+
puts "file was modified"
|
14
|
+
elsif revent.check_mask(RInotify::DELETE_SELF)
|
15
|
+
puts "file was deleted"
|
16
|
+
end
|
17
|
+
}
|
18
|
+
|
19
|
+
else
|
20
|
+
# no events were received in the number of seconds specified in wait_for_events above
|
21
|
+
puts "Timed out"
|
22
|
+
end
|
23
|
+
|
24
|
+
# close and clean up
|
25
|
+
rinotify.close
|
@@ -0,0 +1,58 @@
|
|
1
|
+
#######################################################
|
2
|
+
# copyright (C) 2007 by Rob Merrell
|
3
|
+
# rob@migrob.com
|
4
|
+
#
|
5
|
+
#
|
6
|
+
# This example shows the very basics of how to use RInotify with regular files.
|
7
|
+
# It is recomended that this example be used to see the uses of different methods
|
8
|
+
# and not in actual production code. The method wait_for_events really does wait for
|
9
|
+
# events until one is received or it times out, meaning it blocks. Long story short,
|
10
|
+
# use threads as is shown in the example: watch_file_threaded.rb.
|
11
|
+
#
|
12
|
+
#######################################################
|
13
|
+
|
14
|
+
# require the file and rubygems if necessary
|
15
|
+
begin
|
16
|
+
require 'rinotify'
|
17
|
+
rescue LoadError
|
18
|
+
require 'rubygems'
|
19
|
+
require 'rinotify'
|
20
|
+
end
|
21
|
+
|
22
|
+
# make sure we have a file name
|
23
|
+
if !ARGV[0]
|
24
|
+
raise("Please pass in a file name")
|
25
|
+
end
|
26
|
+
|
27
|
+
# make sure that it is indeed a file
|
28
|
+
if !File.file?(ARGV[0])
|
29
|
+
raise("Nice try, but no cigar. I can't read this, because it isn't a regular file.")
|
30
|
+
end
|
31
|
+
|
32
|
+
# create the object and add a watch on the file
|
33
|
+
rinotify = RInotify.new
|
34
|
+
rinotify.add_watch(ARGV[0], RInotify::MODIFY | RInotify::DELETE_SELF)
|
35
|
+
|
36
|
+
# timeout after five seconds
|
37
|
+
has_events = rinotify.wait_for_events(5)
|
38
|
+
if has_events
|
39
|
+
|
40
|
+
# iterate through events
|
41
|
+
rinotify.each_event {|revent|
|
42
|
+
|
43
|
+
# check if the event we received was MODIFY or DELETE_SELF
|
44
|
+
if revent.check_mask(RInotify::MODIFY)
|
45
|
+
puts "file was modified"
|
46
|
+
elsif revent.check_mask(RInotify::DELETE_SELF)
|
47
|
+
puts "file was deleted"
|
48
|
+
end
|
49
|
+
}
|
50
|
+
|
51
|
+
else
|
52
|
+
# no events were received in the number of seconds specified in wait_for_events above
|
53
|
+
puts "Timed out"
|
54
|
+
end
|
55
|
+
|
56
|
+
# close and clean up
|
57
|
+
rinotify.close
|
58
|
+
|
@@ -0,0 +1,63 @@
|
|
1
|
+
#######################################################
|
2
|
+
# copyright (C) 2007 by Rob Merrell
|
3
|
+
# rob@migrob.com
|
4
|
+
#
|
5
|
+
#
|
6
|
+
# This example shows how to use RInotify using threads. And should
|
7
|
+
# look very similar to watch_file.rb
|
8
|
+
#
|
9
|
+
#######################################################
|
10
|
+
|
11
|
+
# require the file and rubygems if necessary
|
12
|
+
begin
|
13
|
+
require 'rinotify'
|
14
|
+
rescue LoadError
|
15
|
+
require 'rubygems'
|
16
|
+
require 'rinotify'
|
17
|
+
end
|
18
|
+
|
19
|
+
# make sure we have a file name
|
20
|
+
if !ARGV[0]
|
21
|
+
raise("Please pass in a file name")
|
22
|
+
end
|
23
|
+
|
24
|
+
# make sure that it is indeed a file
|
25
|
+
if !File.file?(ARGV[0])
|
26
|
+
raise("Nice try, but no cigar. I can't read this, because it isn't a regular file.")
|
27
|
+
end
|
28
|
+
|
29
|
+
# create the object and add a watch on the file
|
30
|
+
rinotify = RInotify.new
|
31
|
+
rinotify.add_watch(ARGV[0], RInotify::MODIFY | RInotify::DELETE_SELF)
|
32
|
+
|
33
|
+
# catch ctrl-c and clean up the RInotify object
|
34
|
+
trap("INT") do
|
35
|
+
rinotify.close
|
36
|
+
exit
|
37
|
+
end
|
38
|
+
|
39
|
+
# sit and watch the file. Time out after 5 seconds.
|
40
|
+
event_thread = Thread.new do
|
41
|
+
while (1)
|
42
|
+
has_events = rinotify.wait_for_events(2)
|
43
|
+
if has_events
|
44
|
+
|
45
|
+
# iterate through events
|
46
|
+
rinotify.each_event {|revent|
|
47
|
+
|
48
|
+
# check if the event we received was MODIFY or DELETE_SELF
|
49
|
+
if revent.check_mask(RInotify::MODIFY)
|
50
|
+
print "file was modified\n"
|
51
|
+
elsif revent.check_mask(RInotify::DELETE_SELF)
|
52
|
+
print "file was deleted\n"
|
53
|
+
end
|
54
|
+
}
|
55
|
+
|
56
|
+
else
|
57
|
+
# no events were received in the number of seconds specified in wait_for_events above
|
58
|
+
print "Timed out\n"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
event_thread.join
|
data/ext/rinotify.c
ADDED
@@ -0,0 +1,289 @@
|
|
1
|
+
/*****************************************************
|
2
|
+
* copyright (C) 2007 by Rob Merrell
|
3
|
+
* rob@migrob.com
|
4
|
+
*
|
5
|
+
* ***************************************************/
|
6
|
+
|
7
|
+
#include "ruby.h"
|
8
|
+
#include "rinotify.h"
|
9
|
+
#include "rinotify_event.h"
|
10
|
+
|
11
|
+
#include <sys/inotify.h>
|
12
|
+
#include <sys/time.h>
|
13
|
+
#include <sys/ioctl.h>
|
14
|
+
#include <unistd.h>
|
15
|
+
|
16
|
+
// extension entry point
|
17
|
+
void Init_rinotify() {
|
18
|
+
rb_cRInotify = rb_define_class("RInotify", rb_cObject);
|
19
|
+
rb_cRInotifyEvent = rb_define_class("RInotifyEvent", rb_cObject);
|
20
|
+
|
21
|
+
// initialize all of the events
|
22
|
+
rinotify_declare_events(rb_cRInotify);
|
23
|
+
|
24
|
+
|
25
|
+
// RInotify.new
|
26
|
+
rb_define_alloc_func(rb_cRInotify, rb_rinotify_new);
|
27
|
+
|
28
|
+
// RInotify.version
|
29
|
+
rb_define_method(rb_cRInotify, "version", rb_rinotify_version, 0);
|
30
|
+
|
31
|
+
// RInotify.close
|
32
|
+
rb_define_method(rb_cRInotify, "close", rb_rinotify_close, 0);
|
33
|
+
|
34
|
+
// RInotify.add_watch
|
35
|
+
rb_define_method(rb_cRInotify, "add_watch", rb_rinotify_add_watch, 2);
|
36
|
+
|
37
|
+
// RInotify.rm_watch
|
38
|
+
rb_define_method(rb_cRInotify, "rm_watch", rb_rinotify_rm_watch, 1);
|
39
|
+
|
40
|
+
// RInotify.wait_for_events
|
41
|
+
rb_define_method(rb_cRInotify, "wait_for_events", rb_rinotify_wait_for_events, 1);
|
42
|
+
|
43
|
+
// RInotify.each_event
|
44
|
+
rb_define_method(rb_cRInotify, "each_event", rb_rinotify_each_event, 0);
|
45
|
+
|
46
|
+
// RInotify.watch_descriptors
|
47
|
+
rb_define_method(rb_cRInotify, "watch_descriptors", rb_rinotify_watch_descriptors, 0);
|
48
|
+
|
49
|
+
// RInotify.event_queue_size
|
50
|
+
rb_define_method(rb_cRInotify, "event_queue_size", rb_rinotify_queue_size, 0);
|
51
|
+
|
52
|
+
|
53
|
+
/* The following methods are implemented in rinotify_event.c */
|
54
|
+
|
55
|
+
// RInotifyEvent.name
|
56
|
+
rb_define_method(rb_cRInotifyEvent, "name", rb_rinotify_event_name, 0);
|
57
|
+
|
58
|
+
// RInotifyEvent.watch_descriptor
|
59
|
+
rb_define_method(rb_cRInotifyEvent, "watch_descriptor", rb_rinotify_event_watch_descriptor, 0);
|
60
|
+
|
61
|
+
// RInotifyEvent.check_mask
|
62
|
+
rb_define_method(rb_cRInotifyEvent, "check_mask", rb_rinotify_event_check_mask, 1);
|
63
|
+
}
|
64
|
+
|
65
|
+
|
66
|
+
static VALUE rb_rinotify_new(VALUE klass) {
|
67
|
+
VALUE initialized_class;
|
68
|
+
|
69
|
+
// initialize inotify
|
70
|
+
int *inotify = NULL;
|
71
|
+
inotify = malloc(sizeof(int));
|
72
|
+
*inotify = inotify_init();
|
73
|
+
|
74
|
+
if (*inotify < 0)
|
75
|
+
rb_sys_fail("inotify_init");
|
76
|
+
|
77
|
+
// make sure free is called because we malloc'd above
|
78
|
+
initialized_class = Data_Wrap_Struct(klass, NULL, free, inotify);
|
79
|
+
|
80
|
+
// initialize all of the instance variables for this class
|
81
|
+
rinotify_declare_instance_vars(initialized_class);
|
82
|
+
|
83
|
+
return initialized_class;
|
84
|
+
}
|
85
|
+
|
86
|
+
|
87
|
+
static VALUE rb_rinotify_version(VALUE self) {
|
88
|
+
return rb_str_new2(CURRENT_VERSION);
|
89
|
+
}
|
90
|
+
|
91
|
+
|
92
|
+
static VALUE rb_rinotify_close(VALUE self) {
|
93
|
+
int *inotify = NULL, close_return;
|
94
|
+
Data_Get_Struct(self, int, inotify);
|
95
|
+
|
96
|
+
// close and clean up inotify
|
97
|
+
close_return = close(*inotify);
|
98
|
+
if (close_return)
|
99
|
+
rb_sys_fail("close");
|
100
|
+
|
101
|
+
return Qnil;
|
102
|
+
}
|
103
|
+
|
104
|
+
|
105
|
+
static VALUE rb_rinotify_add_watch(VALUE self, VALUE filename, VALUE event_masks) {
|
106
|
+
int *inotify = NULL, watch_desc;
|
107
|
+
VALUE watch_desc_id, watch_descriptor_list;
|
108
|
+
Data_Get_Struct(self, int, inotify);
|
109
|
+
|
110
|
+
// add the watch
|
111
|
+
watch_desc = inotify_add_watch(*inotify, RSTRING(filename)->ptr, NUM2INT(event_masks));
|
112
|
+
if (watch_desc < 0)
|
113
|
+
rb_sys_fail("add_watch");
|
114
|
+
|
115
|
+
watch_desc_id = INT2NUM(watch_desc);
|
116
|
+
|
117
|
+
// add the watch descriptor to our list
|
118
|
+
watch_descriptor_list = rb_iv_get(self, "@watch_descriptors");
|
119
|
+
rb_hash_aset(watch_descriptor_list, watch_desc_id, filename);
|
120
|
+
|
121
|
+
return watch_desc_id;
|
122
|
+
}
|
123
|
+
|
124
|
+
|
125
|
+
static VALUE rb_rinotify_rm_watch(VALUE self, VALUE watch_desc) {
|
126
|
+
int *inotify = NULL, rm_return;
|
127
|
+
Data_Get_Struct(self, int, inotify);
|
128
|
+
|
129
|
+
// remove the watch
|
130
|
+
rm_return = inotify_rm_watch(*inotify, NUM2INT(watch_desc));
|
131
|
+
if (rm_return < 0)
|
132
|
+
rb_sys_fail("rm_watch");
|
133
|
+
|
134
|
+
return INT2NUM(rm_return);
|
135
|
+
}
|
136
|
+
|
137
|
+
|
138
|
+
static VALUE rb_rinotify_wait_for_events(VALUE self, VALUE time_value) {
|
139
|
+
struct timeval time;
|
140
|
+
fd_set rfds;
|
141
|
+
int select_ret, *inotify = NULL;
|
142
|
+
|
143
|
+
Data_Get_Struct(self, int, inotify);
|
144
|
+
|
145
|
+
// set the timout value
|
146
|
+
time.tv_sec = NUM2INT(time_value);
|
147
|
+
time.tv_usec = 0;
|
148
|
+
|
149
|
+
// add inotify to the file descriptor set
|
150
|
+
FD_ZERO(&rfds);
|
151
|
+
FD_SET(*inotify, &rfds);
|
152
|
+
|
153
|
+
select_ret = rb_thread_select(*inotify + 1, &rfds, NULL, NULL, &time);
|
154
|
+
|
155
|
+
if (select_ret < 0)
|
156
|
+
rb_sys_fail("select");
|
157
|
+
|
158
|
+
// no events are available and we have timed out
|
159
|
+
else if (!select_ret)
|
160
|
+
return Qfalse;
|
161
|
+
|
162
|
+
// events are available
|
163
|
+
else if (FD_ISSET(*inotify, &rfds))
|
164
|
+
return Qtrue;
|
165
|
+
|
166
|
+
// to keep the compiler happy...
|
167
|
+
return Qfalse;
|
168
|
+
}
|
169
|
+
|
170
|
+
|
171
|
+
static VALUE rb_rinotify_each_event(VALUE self) {
|
172
|
+
struct inotify_event *event = NULL, *tmp_event = NULL;
|
173
|
+
int *inotify = NULL, i = 0, len;
|
174
|
+
char buffer[BUFFER_SIZE];
|
175
|
+
|
176
|
+
Data_Get_Struct(self, int, inotify);
|
177
|
+
|
178
|
+
len = read(*inotify, buffer, BUFFER_SIZE);
|
179
|
+
|
180
|
+
// read each event
|
181
|
+
while (i < len) {
|
182
|
+
tmp_event = (struct inotify_event *) &buffer[i];
|
183
|
+
|
184
|
+
// copy the tmp_event into our malloc'd event so that it doesn't
|
185
|
+
// go out of scope after we yield the object
|
186
|
+
event = malloc(EVENT_SIZE + tmp_event->len);
|
187
|
+
memmove(event, tmp_event, EVENT_SIZE + tmp_event->len);
|
188
|
+
|
189
|
+
// construct the RInotifyEvent object
|
190
|
+
rb_yield(rb_rinotify_event_new(event));
|
191
|
+
|
192
|
+
i += EVENT_SIZE + event->len;
|
193
|
+
}
|
194
|
+
|
195
|
+
return Qnil;
|
196
|
+
}
|
197
|
+
|
198
|
+
|
199
|
+
static VALUE rb_rinotify_watch_descriptors(VALUE self) {
|
200
|
+
return rb_iv_get(self, "@watch_descriptors");
|
201
|
+
}
|
202
|
+
|
203
|
+
|
204
|
+
static VALUE rb_rinotify_queue_size(VALUE self) {
|
205
|
+
int *inotify = NULL, return_val;
|
206
|
+
unsigned int queue_size;
|
207
|
+
|
208
|
+
Data_Get_Struct(self, int, inotify);
|
209
|
+
|
210
|
+
// get the queue size
|
211
|
+
return_val = ioctl(*inotify, FIONREAD, &queue_size);
|
212
|
+
|
213
|
+
if (return_val < 0)
|
214
|
+
rb_sys_fail("event_queue_size");
|
215
|
+
|
216
|
+
return UINT2NUM(queue_size);
|
217
|
+
}
|
218
|
+
|
219
|
+
|
220
|
+
static void rinotify_declare_events(VALUE klass) {
|
221
|
+
// watch events
|
222
|
+
rb_const_set(klass, rb_intern("IN_ACCESS"), INT2NUM(IN_ACCESS));
|
223
|
+
rb_const_set(klass, rb_intern("ACCESS"), INT2NUM(IN_ACCESS));
|
224
|
+
|
225
|
+
rb_const_set(klass, rb_intern("IN_MODIFY"), INT2NUM(IN_MODIFY));
|
226
|
+
rb_const_set(klass, rb_intern("MODIFY"), INT2NUM(IN_MODIFY));
|
227
|
+
|
228
|
+
rb_const_set(klass, rb_intern("IN_ATTRIB"), INT2NUM(IN_ATTRIB));
|
229
|
+
rb_const_set(klass, rb_intern("ATTRIB"), INT2NUM(IN_ATTRIB));
|
230
|
+
|
231
|
+
rb_const_set(klass, rb_intern("IN_CLOSE_WRITE"), INT2NUM(IN_CLOSE_WRITE));
|
232
|
+
rb_const_set(klass, rb_intern("CLOSE_WRITE"), INT2NUM(IN_CLOSE_WRITE));
|
233
|
+
|
234
|
+
rb_const_set(klass, rb_intern("IN_CLOSE_NOWRITE"), INT2NUM(IN_CLOSE_NOWRITE));
|
235
|
+
rb_const_set(klass, rb_intern("CLOSE_NOWRITE"), INT2NUM(IN_CLOSE_NOWRITE));
|
236
|
+
|
237
|
+
rb_const_set(klass, rb_intern("IN_OPEN"), INT2NUM(IN_OPEN));
|
238
|
+
rb_const_set(klass, rb_intern("OPEN"), INT2NUM(IN_OPEN));
|
239
|
+
|
240
|
+
rb_const_set(klass, rb_intern("IN_MOVED_FROM"), INT2NUM(IN_MOVED_FROM));
|
241
|
+
rb_const_set(klass, rb_intern("MOVED_FROM"), INT2NUM(IN_MOVED_FROM));
|
242
|
+
|
243
|
+
rb_const_set(klass, rb_intern("IN_MOVED_TO"), INT2NUM(IN_MOVED_TO));
|
244
|
+
rb_const_set(klass, rb_intern("MOVED_TO"), INT2NUM(IN_MOVED_TO));
|
245
|
+
|
246
|
+
rb_const_set(klass, rb_intern("IN_CREATE"), INT2NUM(IN_CREATE));
|
247
|
+
rb_const_set(klass, rb_intern("CREATE"), INT2NUM(IN_CREATE));
|
248
|
+
|
249
|
+
rb_const_set(klass, rb_intern("IN_DELETE"), INT2NUM(IN_DELETE));
|
250
|
+
rb_const_set(klass, rb_intern("DELETE"), INT2NUM(IN_DELETE));
|
251
|
+
|
252
|
+
rb_const_set(klass, rb_intern("IN_DELETE_SELF"), INT2NUM(IN_DELETE_SELF));
|
253
|
+
rb_const_set(klass, rb_intern("DELETE_SELF"), INT2NUM(IN_DELETE_SELF));
|
254
|
+
|
255
|
+
// sent by any watch
|
256
|
+
rb_const_set(klass, rb_intern("IN_UNMOUNT"), INT2NUM(IN_UNMOUNT));
|
257
|
+
rb_const_set(klass, rb_intern("UNMOUNT"), INT2NUM(IN_UNMOUNT));
|
258
|
+
|
259
|
+
rb_const_set(klass, rb_intern("IN_Q_OVERFLOW"), INT2NUM(IN_Q_OVERFLOW));
|
260
|
+
rb_const_set(klass, rb_intern("Q_OVERFLOW"), INT2NUM(IN_Q_OVERFLOW));
|
261
|
+
|
262
|
+
rb_const_set(klass, rb_intern("IN_IGNORED"), INT2NUM(IN_IGNORED));
|
263
|
+
rb_const_set(klass, rb_intern("IGNORED"), INT2NUM(IN_IGNORED));
|
264
|
+
|
265
|
+
// helper events
|
266
|
+
rb_const_set(klass, rb_intern("IN_CLOSE"), INT2NUM(IN_CLOSE));
|
267
|
+
rb_const_set(klass, rb_intern("CLOSE"), INT2NUM(IN_CLOSE));
|
268
|
+
|
269
|
+
rb_const_set(klass, rb_intern("IN_MOVE"), INT2NUM(IN_MOVE));
|
270
|
+
rb_const_set(klass, rb_intern("MOVE"), INT2NUM(IN_MOVE));
|
271
|
+
|
272
|
+
// special flags
|
273
|
+
rb_const_set(klass, rb_intern("IN_ISDIR"), INT2NUM(IN_ISDIR));
|
274
|
+
rb_const_set(klass, rb_intern("ISDIR"), INT2NUM(IN_ISDIR));
|
275
|
+
|
276
|
+
rb_const_set(klass, rb_intern("IN_ONESHOT"), INT2NUM(IN_ONESHOT));
|
277
|
+
rb_const_set(klass, rb_intern("ONESHOT"), INT2NUM(IN_ONESHOT));
|
278
|
+
|
279
|
+
rb_const_set(klass, rb_intern("IN_ALL_EVENTS"), INT2NUM(IN_ALL_EVENTS));
|
280
|
+
rb_const_set(klass, rb_intern("ALL_EVENTS"), INT2NUM(IN_ALL_EVENTS));
|
281
|
+
}
|
282
|
+
|
283
|
+
|
284
|
+
static void rinotify_declare_instance_vars(VALUE klass) {
|
285
|
+
// Array: holds a listing of all watch descriptors and the filename or directory name
|
286
|
+
// that they happen to be watching
|
287
|
+
VALUE watch_descriptors = rb_hash_new();
|
288
|
+
rb_iv_set(klass, "@watch_descriptors", watch_descriptors);
|
289
|
+
}
|
data/ext/rinotify.h
ADDED
@@ -0,0 +1,163 @@
|
|
1
|
+
/*****************************************************
|
2
|
+
* copyright (C) 2007 by Rob Merrell
|
3
|
+
* rob@migrob.com
|
4
|
+
*
|
5
|
+
* ***************************************************/
|
6
|
+
|
7
|
+
#ifndef RINOTIFY_H
|
8
|
+
#define RINOTIFY_H
|
9
|
+
|
10
|
+
#include "ruby.h"
|
11
|
+
#include <sys/inotify.h>
|
12
|
+
|
13
|
+
#define CURRENT_VERSION "0.9"
|
14
|
+
#define EVENT_SIZE sizeof(struct inotify_event)
|
15
|
+
#define BUFFER_SIZE 16384
|
16
|
+
|
17
|
+
// RInotify class
|
18
|
+
static VALUE rb_cRInotify;
|
19
|
+
|
20
|
+
/* Non Ruby-implimented Prototypes */
|
21
|
+
|
22
|
+
// declare the inotify events as constants
|
23
|
+
static void rinotify_declare_events(VALUE);
|
24
|
+
|
25
|
+
// declare any instance variables we will need
|
26
|
+
static void rinotify_declare_instance_vars(VALUE);
|
27
|
+
|
28
|
+
|
29
|
+
|
30
|
+
/* Ruby Prototypes */
|
31
|
+
|
32
|
+
/*
|
33
|
+
* call-seq:
|
34
|
+
* RInotify.new -> RInotify
|
35
|
+
*
|
36
|
+
* Returns a new RInotify object.
|
37
|
+
*
|
38
|
+
* Example Usage:
|
39
|
+
* @rinotify = RInotify.new
|
40
|
+
*/
|
41
|
+
static VALUE rb_rinotify_new(VALUE);
|
42
|
+
|
43
|
+
|
44
|
+
/*
|
45
|
+
* call-seq:
|
46
|
+
* RInotify.version -> String
|
47
|
+
*
|
48
|
+
* Returns the current version.
|
49
|
+
*
|
50
|
+
* Example Usage:
|
51
|
+
* @rinotify.version => "0.1.0"
|
52
|
+
*/
|
53
|
+
static VALUE rb_rinotify_version(VALUE);
|
54
|
+
|
55
|
+
|
56
|
+
/*
|
57
|
+
* call-seq:
|
58
|
+
* RInotify.close -> nil
|
59
|
+
*
|
60
|
+
* Clean up and close inotify.
|
61
|
+
*
|
62
|
+
* Example Usage:
|
63
|
+
* @rinotify.close
|
64
|
+
*/
|
65
|
+
static VALUE rb_rinotify_close(VALUE);
|
66
|
+
|
67
|
+
|
68
|
+
/*
|
69
|
+
* call-seq:
|
70
|
+
* RInotify.add_watch(filename, event masks) -> watch descriptor
|
71
|
+
*
|
72
|
+
* Adds a watch on a file or directory.
|
73
|
+
*
|
74
|
+
* The event masks are simple a bitmask and should be joined like:
|
75
|
+
* RInotify::OPEN | RInotify::MODIFY
|
76
|
+
*
|
77
|
+
* Example Usage:
|
78
|
+
* @rinotify = RInotify.new
|
79
|
+
* @rinotify.add_watch("/home/rob/Desktop/my_file.txt", RInotify::MODIFY | RInotify::DELETE_SELF | RInotify::OPEN)
|
80
|
+
*/
|
81
|
+
static VALUE rb_rinotify_add_watch(VALUE, VALUE, VALUE);
|
82
|
+
|
83
|
+
|
84
|
+
/*
|
85
|
+
* call-seq:
|
86
|
+
* RInotify.rm_watch(watch descriptor) -> closed watch descriptor
|
87
|
+
*
|
88
|
+
* Remove a watch descriptor. Note that this is not a necessary step
|
89
|
+
* when closing inotify.
|
90
|
+
*
|
91
|
+
* Example Usage:
|
92
|
+
* @rinotify = RInotify.new
|
93
|
+
* wd = @rinotify.add_watch("/home/rob/Desktop/my_file.txt", RInotify::MODIFY | RInotify::DELETE_SELF | RInotify::OPEN)
|
94
|
+
* @rinotify.rm_watch(wd)
|
95
|
+
*/
|
96
|
+
static VALUE rb_rinotify_rm_watch(VALUE, VALUE);
|
97
|
+
|
98
|
+
|
99
|
+
/*
|
100
|
+
* call-seq:
|
101
|
+
* RInotify.wait_for_events(seconds to time out) -> true or false
|
102
|
+
*
|
103
|
+
* Waits for events to be received from inotify.
|
104
|
+
* Returns true when there are events waiting in the queue
|
105
|
+
* and false if not.
|
106
|
+
*
|
107
|
+
* Example Usage:
|
108
|
+
* @rinotify = RInotify.new
|
109
|
+
* @rinotify.add_watch("/home/rob/Desktop/my_file.txt", RInotify::MODIFY | RInotify::DELETE_SELF | RInotify::OPEN)
|
110
|
+
*
|
111
|
+
* # set time out at 5 seconds
|
112
|
+
* has_events = @rinotify.wait_for_events(5)
|
113
|
+
*/
|
114
|
+
static VALUE rb_rinotify_wait_for_events(VALUE, VALUE);
|
115
|
+
|
116
|
+
|
117
|
+
/*
|
118
|
+
* call-seq:
|
119
|
+
* RInotify.each_event -> RInotifyEvent
|
120
|
+
*
|
121
|
+
* Yields an RInotifyEvent object in a block
|
122
|
+
*
|
123
|
+
* Example Usage:
|
124
|
+
* has_events = @rinotify.wait_for_events(5)
|
125
|
+
* if has_events
|
126
|
+
* @rinotify.each_event {|revent|
|
127
|
+
* ...
|
128
|
+
* }
|
129
|
+
* end
|
130
|
+
*/
|
131
|
+
static VALUE rb_rinotify_each_event(VALUE);
|
132
|
+
|
133
|
+
|
134
|
+
/*
|
135
|
+
* call-seq:
|
136
|
+
* RInotify.watch_descriptors -> Hash(watch descriptor, file name)
|
137
|
+
*
|
138
|
+
* Returns a hash of all watch_descriptors and file name of each file or directory
|
139
|
+
* being watched.
|
140
|
+
*
|
141
|
+
* Example Usage:
|
142
|
+
* @rinotify.watch_descriptors => [1, "/home/rob/Desktop/my_file.txt"]
|
143
|
+
*/
|
144
|
+
static VALUE rb_rinotify_watch_descriptors(VALUE);
|
145
|
+
|
146
|
+
|
147
|
+
/*
|
148
|
+
* call-seq:
|
149
|
+
* RInotify.event_queue_size -> Fixnum
|
150
|
+
*
|
151
|
+
* Returns the current size of the event queue. This is useful if you want to throttle
|
152
|
+
* your event checks
|
153
|
+
*
|
154
|
+
* Example Usage:
|
155
|
+
* while (queue_size < 128)
|
156
|
+
* if @rinotify.wait_for_events(5)
|
157
|
+
* queue_size = @rinotify.event_queue_size
|
158
|
+
* end
|
159
|
+
* end
|
160
|
+
*/
|
161
|
+
static VALUE rb_rinotify_queue_size(VALUE);
|
162
|
+
|
163
|
+
#endif
|
@@ -0,0 +1,55 @@
|
|
1
|
+
#include "ruby.h"
|
2
|
+
#include "rinotify_event.h"
|
3
|
+
|
4
|
+
#include <sys/inotify.h>
|
5
|
+
|
6
|
+
VALUE rb_rinotify_event_new(struct inotify_event *event) {
|
7
|
+
VALUE rinotify_event;
|
8
|
+
|
9
|
+
// initialize the object
|
10
|
+
rinotify_event = Data_Wrap_Struct(rb_cRInotifyEvent, NULL, free, event);
|
11
|
+
rb_obj_call_init(rinotify_event, 0, NULL);
|
12
|
+
|
13
|
+
return rinotify_event;
|
14
|
+
}
|
15
|
+
|
16
|
+
|
17
|
+
VALUE rb_rinotify_event_name(VALUE self) {
|
18
|
+
VALUE name;
|
19
|
+
struct inotify_event *event;
|
20
|
+
Data_Get_Struct(self, struct inotify_event, event);
|
21
|
+
|
22
|
+
// if watching for events in a directory inotify will tell us the name
|
23
|
+
if (event->len) {
|
24
|
+
name = rb_str_new2(event->name);
|
25
|
+
} else {
|
26
|
+
// watching a single file doesn't waste space with a filename so return nil
|
27
|
+
name = Qnil;
|
28
|
+
}
|
29
|
+
|
30
|
+
return name;
|
31
|
+
}
|
32
|
+
|
33
|
+
|
34
|
+
VALUE rb_rinotify_event_watch_descriptor(VALUE self) {
|
35
|
+
struct inotify_event *event;
|
36
|
+
Data_Get_Struct(self, struct inotify_event, event);
|
37
|
+
|
38
|
+
return INT2NUM(event->wd);
|
39
|
+
}
|
40
|
+
|
41
|
+
|
42
|
+
VALUE rb_rinotify_event_check_mask(VALUE self, VALUE masks) {
|
43
|
+
VALUE return_val;
|
44
|
+
struct inotify_event *event;
|
45
|
+
Data_Get_Struct(self, struct inotify_event, event);
|
46
|
+
|
47
|
+
// check if the mask is part of the event
|
48
|
+
if (event->mask & NUM2INT(masks))
|
49
|
+
return_val = Qtrue;
|
50
|
+
else
|
51
|
+
return_val = Qfalse;
|
52
|
+
|
53
|
+
return return_val;
|
54
|
+
}
|
55
|
+
|
@@ -0,0 +1,60 @@
|
|
1
|
+
/*****************************************************
|
2
|
+
* copyright (C) 2007 by Rob Merrell
|
3
|
+
* rob@migrob.com
|
4
|
+
*
|
5
|
+
* ***************************************************/
|
6
|
+
|
7
|
+
#ifndef RINOTIFY_EVENT_H
|
8
|
+
#define RINOTIFY_EVENT_H
|
9
|
+
|
10
|
+
#include "ruby.h"
|
11
|
+
#include <sys/inotify.h>
|
12
|
+
|
13
|
+
// RInotifyEvent class
|
14
|
+
VALUE rb_cRInotifyEvent;
|
15
|
+
|
16
|
+
/* Ruby Prototypes */
|
17
|
+
|
18
|
+
// returns a new RInotifyEvent object. This method should only be called by RInotify.each_event
|
19
|
+
VALUE rb_rinotify_event_new(struct inotify_event*);
|
20
|
+
|
21
|
+
|
22
|
+
/*
|
23
|
+
* call-seq:
|
24
|
+
* RInotifyEvent.name -> event name
|
25
|
+
*
|
26
|
+
* Returns the name of the event if the watched file is a directory. If it is a file
|
27
|
+
* nil is returned. In this case the event name can be found by looking the watch descriptor
|
28
|
+
* up using RInotify.watch_descriptors.
|
29
|
+
*
|
30
|
+
* Example Usage:
|
31
|
+
* rinotify_event.name -> "/home/rob/desktop/tmp/test"
|
32
|
+
*/
|
33
|
+
VALUE rb_rinotify_event_name(VALUE);
|
34
|
+
|
35
|
+
|
36
|
+
/*
|
37
|
+
* call-seq:
|
38
|
+
* RInotifyEvent.watch_descriptor -> event watch descriptor
|
39
|
+
*
|
40
|
+
* Returns the watch descriptor that the event belongs to.
|
41
|
+
*
|
42
|
+
* Example Usage:
|
43
|
+
* rinotify_event.watch_descriptor -> 1
|
44
|
+
*/
|
45
|
+
VALUE rb_rinotify_event_watch_descriptor(VALUE);
|
46
|
+
|
47
|
+
|
48
|
+
/*
|
49
|
+
* call-seq:
|
50
|
+
* RInotifyEvent.check_mask(mask) -> boolean
|
51
|
+
*
|
52
|
+
* Returns true or false if the current event contains the mask(s)
|
53
|
+
*
|
54
|
+
* Example Usage:
|
55
|
+
* rinotify_event->check_mask(RInotify::MODIFY) -> true
|
56
|
+
* rinotify_event->check_mask(RInotify::DELETE_SELF) -> false
|
57
|
+
*/
|
58
|
+
VALUE rb_rinotify_event_check_mask(VALUE, VALUE);
|
59
|
+
|
60
|
+
#endif
|
data/extconf.rb
ADDED
metadata
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: adamh-rinotify
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.9.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Rob Merrell
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-07-06 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description:
|
17
|
+
email: rob@migrob.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions:
|
21
|
+
- extconf.rb
|
22
|
+
extra_rdoc_files:
|
23
|
+
- README.rdoc
|
24
|
+
files:
|
25
|
+
- ext/rinotify.c
|
26
|
+
- ext/rinotify.h
|
27
|
+
- ext/rinotify_event.c
|
28
|
+
- ext/rinotify_event.h
|
29
|
+
- README.rdoc
|
30
|
+
has_rdoc: false
|
31
|
+
homepage: http://rinotify.migrob.com
|
32
|
+
post_install_message:
|
33
|
+
rdoc_options:
|
34
|
+
- --charset=UTF-8
|
35
|
+
require_paths:
|
36
|
+
- .
|
37
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: "0"
|
42
|
+
version:
|
43
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: "0"
|
48
|
+
version:
|
49
|
+
requirements: []
|
50
|
+
|
51
|
+
rubyforge_project:
|
52
|
+
rubygems_version: 1.2.0
|
53
|
+
signing_key:
|
54
|
+
specification_version: 2
|
55
|
+
summary: A Ruby wrapper for Linux's inotify
|
56
|
+
test_files:
|
57
|
+
- examples/watch_file.rb
|
58
|
+
- examples/watch_file_threaded.rb
|