swerling-sinotify 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +5 -0
- data/History.txt +3 -0
- data/README.rdoc +139 -0
- data/README.txt +139 -0
- data/Rakefile +50 -0
- data/examples/watcher.rb +30 -0
- data/ext/extconf.rb +12 -0
- data/ext/src/inotify-syscalls.h +24 -0
- data/ext/src/inotify.h +113 -0
- data/ext/src/sinotify.c +205 -0
- data/lib/sinotify.rb +18 -0
- data/lib/sinotify/event.rb +185 -0
- data/lib/sinotify/notifier.rb +308 -0
- data/lib/sinotify/prim_event.rb +118 -0
- data/lib/sinotify/watch.rb +21 -0
- data/lib/sinotify_info.rb +47 -0
- data/sinotify.gemspec +79 -0
- data/spec/prim_notify_spec.rb +98 -0
- data/spec/sinotify_spec.rb +247 -0
- data/spec/spec_helper.rb +14 -0
- metadata +95 -0
data/.gitignore
ADDED
data/History.txt
ADDED
data/README.rdoc
ADDED
@@ -0,0 +1,139 @@
|
|
1
|
+
sinotify
|
2
|
+
by Steven Swerling
|
3
|
+
http://tab-a.slot-z.net
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
ALPHA Alert -- just uploaded initial release.
|
8
|
+
|
9
|
+
|
10
|
+
Linux inotify is a means to receive events describing file system activity (create, modify, delete, close, etc).
|
11
|
+
|
12
|
+
Sinotify was derived from aredridel's package (http://raa.ruby-lang.org/project/ruby-inotify/), with the addition of
|
13
|
+
Paul Boon's tweak for making the event_check thread more polite (see
|
14
|
+
http://www.mindbucket.com/2009/02/24/ruby-daemons-verifying-good-behavior/)
|
15
|
+
|
16
|
+
In sinotify, the classes Sinotify::PrimNotifier and Sinotify::PrimEvent provide a low level wrapper to inotify, with
|
17
|
+
the ability to establish 'watches' and then listen for inotify events using one of inotify's synchronous event loops,
|
18
|
+
and providing access to the events' masks (see 'man inotify' for details). Sinotify::PrimEvent class adds a little semantic sugar
|
19
|
+
to the event in to the form of 'etypes', which are just ruby symbols that describe the event mask. If the event has a
|
20
|
+
raw mask of (DELETE_SELF & IS_DIR), then the etypes array would be [:delete_self, :is_dir].
|
21
|
+
|
22
|
+
In addition to the 'straight' wrapper in inotify, sinotify provides an asynchronous implementation of the 'observer
|
23
|
+
pattern' for notification. In other words, Sinotify::Notifier listens in the background for inotify events, adapting
|
24
|
+
them into instances of Sinotify::Event as they come in and immediately placing them in a concurrent queue, from which
|
25
|
+
they are 'announced' to 'subscribers' of the event. [Sinotify uses the 'cosell' implementation of the Announcements
|
26
|
+
event notification framework, hence the terminology 'subscribe' and 'announce' rather then 'listen' and 'trigger' used
|
27
|
+
in the standard event observer pattern. See the 'cosell' package on github for details.]
|
28
|
+
|
29
|
+
A variety of 'knobs' are provided for controlling the behavior of the notifier: whether a watch should apply to a
|
30
|
+
single directory or should recurse into subdirectores, how fast it should broadcast queued events, etc (see
|
31
|
+
Sinotify::Notifier, and the example in the synopsis section below). An event 'spy' can also be setup to log all
|
32
|
+
Sinotify::PrimEvents and Sinotify::Events.
|
33
|
+
|
34
|
+
Sinotify::Event simplifies inotify's muddled event model, sending events only for those files/directories that have
|
35
|
+
changed. That's not to say you can't setup a notifier that recurses into subdirectories, just that any individual
|
36
|
+
event will apply to a single file, and not to its children. Also, event types are identified using words (in the form
|
37
|
+
of ruby :symbols) instead of inotify's event masks. See Sinotify::Event for more explanation.
|
38
|
+
|
39
|
+
The README for inotify:
|
40
|
+
|
41
|
+
http://www.kernel.org/pub/linux/kernel/people/rml/inotify/README
|
42
|
+
|
43
|
+
Selected quotes from the README for inotify:
|
44
|
+
|
45
|
+
* "Rumor is that the 'd' in 'dnotify' does not stand for 'directory' but for 'suck.'"
|
46
|
+
|
47
|
+
* "The 'i' in inotify does not stand for 'suck' but for 'inode' -- the logical
|
48
|
+
choice since inotify is inode-based."
|
49
|
+
|
50
|
+
(The 's' in 'sinotify' does in fact stand for 'suck.')
|
51
|
+
|
52
|
+
|
53
|
+
== FEATURES/PROBLEMS:
|
54
|
+
|
55
|
+
* None known. But it's still early.
|
56
|
+
|
57
|
+
== SYNOPSIS:
|
58
|
+
|
59
|
+
Try this:
|
60
|
+
|
61
|
+
$ mkdir /tmp/sinotify_test
|
62
|
+
$ irb
|
63
|
+
require 'sinotify'
|
64
|
+
notifier = Sinotify::Notifier.new('/tmp/sinotify_test', :recurse => true, :etypes => [:create, :modify, :delete])
|
65
|
+
notifier.spy!(:logger => Logger.new('/tmp/inotify_spy.log')) # optional event spy
|
66
|
+
notifier.when_announcing(Sinotify::Event) do |sinotify_event|
|
67
|
+
puts "Event happened at #{sinotify_event.timestamp} on #{sinotify_event.path}, etypes => #{sinotify_event.etypes.inspect}"
|
68
|
+
end
|
69
|
+
notifier.when_announcing(Sinotify::Event) do |sinotify_event|
|
70
|
+
puts " --> demonstrate that multiple subscribers can be setup: #{sinotify_event.etypes.inspect}"
|
71
|
+
end
|
72
|
+
notifier.watch! # don't forget to start the watch
|
73
|
+
|
74
|
+
Then in another linux console:
|
75
|
+
|
76
|
+
$ touch /tmp/sinotify_test/hi && sleep 1 && echo 'hello' >> /tmp/sinotify_test/hi && sleep 1 && rm -r /tmp/sinotify_test
|
77
|
+
|
78
|
+
Back in irb you will see:
|
79
|
+
|
80
|
+
Event happened at Sat Jul 11 12:29:18 -0400 2009 on /tmp/sinotify_test/hi, etypes => [:create]
|
81
|
+
--> demonstrate that multiple subscribers can be setup: [:create]
|
82
|
+
Event happened at Sat Jul 11 12:29:19 -0400 2009 on /tmp/sinotify_test/hi, etypes => [:modify]
|
83
|
+
--> demonstrate that multiple subscribers can be setup: [:modify]
|
84
|
+
Event happened at Sat Jul 11 12:29:20 -0400 2009 on /tmp/sinotify_test/hi, etypes => [:delete]
|
85
|
+
--> demonstrate that multiple subscribers can be setup: [:delete]
|
86
|
+
Event happened at Sat Jul 11 12:29:20 -0400 2009 on /tmp/sinotify_test, etypes => [:delete]
|
87
|
+
--> demonstrate that multiple subscribers can be setup: [:delete]
|
88
|
+
|
89
|
+
|
90
|
+
tail -n 50 -f /tmp/inotify_spy.log:
|
91
|
+
|
92
|
+
...
|
93
|
+
... INFO -- : Sinotify::Notifier Prim Event Spy: <Sinotify::PrimEvent :name => 'hi', :etypes => [:create], :mask => 100 ...
|
94
|
+
... INFO -- : Sinotify::Notifier Event Spy <Sinotify::Event :path => '/tmp/sinotify_test/hi', dir? => false, :etypes => ...
|
95
|
+
... INFO -- : Sinotify::Notifier Prim Event Spy: <Sinotify::PrimEvent :name => 'hi', :etypes => [:modify], :mask => 2 ...
|
96
|
+
... INFO -- : Sinotify::Notifier Event Spy <Sinotify::Event :path => '/tmp/sinotify_test/hi', dir? => false, :etypes => ...
|
97
|
+
... INFO -- : Sinotify::Notifier Prim Event Spy: <Sinotify::PrimEvent :name => 'hi', :etypes => [:delete], :mask => 200 ...
|
98
|
+
... INFO -- : Sinotify::Notifier Event Spy <Sinotify::Event :path => '/tmp/sinotify_test/hi', dir? => false, :etypes => ...
|
99
|
+
... INFO -- : Sinotify::Notifier Prim Event Spy: <Sinotify::PrimEvent :name => '', :etypes => [:delete_self], :mask => 400 ...
|
100
|
+
... INFO -- : Sinotify::Notifier Event Spy <Sinotify::Event :path => '/tmp/sinotify_test', dir? => true, :etypes => [:delete]...
|
101
|
+
etc.
|
102
|
+
|
103
|
+
|
104
|
+
|
105
|
+
== REQUIREMENTS:
|
106
|
+
|
107
|
+
* linux inotify dev libs
|
108
|
+
* cosell announcements framework gem
|
109
|
+
|
110
|
+
== INSTALL:
|
111
|
+
|
112
|
+
* Todo: install instruction
|
113
|
+
* sudo gem install cosell...
|
114
|
+
* sudo gem install sinotify...
|
115
|
+
|
116
|
+
== LICENSE:
|
117
|
+
|
118
|
+
(The MIT License)
|
119
|
+
|
120
|
+
Copyright (c) 2008 FIXME (different license?)
|
121
|
+
|
122
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
123
|
+
a copy of this software and associated documentation files (the
|
124
|
+
'Software'), to deal in the Software without restriction, including
|
125
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
126
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
127
|
+
permit persons to whom the Software is furnished to do so, subject to
|
128
|
+
the following conditions:
|
129
|
+
|
130
|
+
The above copyright notice and this permission notice shall be
|
131
|
+
included in all copies or substantial portions of the Software.
|
132
|
+
|
133
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
134
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
135
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
136
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
137
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
138
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
139
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.txt
ADDED
@@ -0,0 +1,139 @@
|
|
1
|
+
sinotify
|
2
|
+
by Steven Swerling
|
3
|
+
http://tab-a.slot-z.net
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
ALPHA Alert -- just uploaded initial release.
|
8
|
+
|
9
|
+
|
10
|
+
Linux inotify is a means to receive events describing file system activity (create, modify, delete, close, etc).
|
11
|
+
|
12
|
+
Sinotify was derived from aredridel's package (http://raa.ruby-lang.org/project/ruby-inotify/), with the addition of
|
13
|
+
Paul Boon's tweak for making the event_check thread more polite (see
|
14
|
+
http://www.mindbucket.com/2009/02/24/ruby-daemons-verifying-good-behavior/)
|
15
|
+
|
16
|
+
In sinotify, the classes Sinotify::PrimNotifier and Sinotify::PrimEvent provide a low level wrapper to inotify, with
|
17
|
+
the ability to establish 'watches' and then listen for inotify events using one of inotify's synchronous event loops,
|
18
|
+
and providing access to the events' masks (see 'man inotify' for details). Sinotify::PrimEvent class adds a little semantic sugar
|
19
|
+
to the event in to the form of 'etypes', which are just ruby symbols that describe the event mask. If the event has a
|
20
|
+
raw mask of (DELETE_SELF & IS_DIR), then the etypes array would be [:delete_self, :is_dir].
|
21
|
+
|
22
|
+
In addition to the 'straight' wrapper in inotify, sinotify provides an asynchronous implementation of the 'observer
|
23
|
+
pattern' for notification. In other words, Sinotify::Notifier listens in the background for inotify events, adapting
|
24
|
+
them into instances of Sinotify::Event as they come in and immediately placing them in a concurrent queue, from which
|
25
|
+
they are 'announced' to 'subscribers' of the event. [Sinotify uses the 'cosell' implementation of the Announcements
|
26
|
+
event notification framework, hence the terminology 'subscribe' and 'announce' rather then 'listen' and 'trigger' used
|
27
|
+
in the standard event observer pattern. See the 'cosell' package on github for details.]
|
28
|
+
|
29
|
+
A variety of 'knobs' are provided for controlling the behavior of the notifier: whether a watch should apply to a
|
30
|
+
single directory or should recurse into subdirectores, how fast it should broadcast queued events, etc (see
|
31
|
+
Sinotify::Notifier, and the example in the synopsis section below). An event 'spy' can also be setup to log all
|
32
|
+
Sinotify::PrimEvents and Sinotify::Events.
|
33
|
+
|
34
|
+
Sinotify::Event simplifies inotify's muddled event model, sending events only for those files/directories that have
|
35
|
+
changed. That's not to say you can't setup a notifier that recurses into subdirectories, just that any individual
|
36
|
+
event will apply to a single file, and not to its children. Also, event types are identified using words (in the form
|
37
|
+
of ruby :symbols) instead of inotify's event masks. See Sinotify::Event for more explanation.
|
38
|
+
|
39
|
+
The README for inotify:
|
40
|
+
|
41
|
+
http://www.kernel.org/pub/linux/kernel/people/rml/inotify/README
|
42
|
+
|
43
|
+
Selected quotes from the README for inotify:
|
44
|
+
|
45
|
+
* "Rumor is that the 'd' in 'dnotify' does not stand for 'directory' but for 'suck.'"
|
46
|
+
|
47
|
+
* "The 'i' in inotify does not stand for 'suck' but for 'inode' -- the logical
|
48
|
+
choice since inotify is inode-based."
|
49
|
+
|
50
|
+
(The 's' in 'sinotify' does in fact stand for 'suck.')
|
51
|
+
|
52
|
+
|
53
|
+
== FEATURES/PROBLEMS:
|
54
|
+
|
55
|
+
* None known. But it's still early.
|
56
|
+
|
57
|
+
== SYNOPSIS:
|
58
|
+
|
59
|
+
Try this:
|
60
|
+
|
61
|
+
$ mkdir /tmp/sinotify_test
|
62
|
+
$ irb
|
63
|
+
require 'sinotify'
|
64
|
+
notifier = Sinotify::Notifier.new('/tmp/sinotify_test', :recurse => true, :etypes => [:create, :modify, :delete])
|
65
|
+
notifier.spy!(:logger => Logger.new('/tmp/inotify_spy.log')) # optional event spy
|
66
|
+
notifier.when_announcing(Sinotify::Event) do |sinotify_event|
|
67
|
+
puts "Event happened at #{sinotify_event.timestamp} on #{sinotify_event.path}, etypes => #{sinotify_event.etypes.inspect}"
|
68
|
+
end
|
69
|
+
notifier.when_announcing(Sinotify::Event) do |sinotify_event|
|
70
|
+
puts " --> demonstrate that multiple subscribers can be setup: #{sinotify_event.etypes.inspect}"
|
71
|
+
end
|
72
|
+
notifier.watch! # don't forget to start the watch
|
73
|
+
|
74
|
+
Then in another linux console:
|
75
|
+
|
76
|
+
$ touch /tmp/sinotify_test/hi && sleep 1 && echo 'hello' >> /tmp/sinotify_test/hi && sleep 1 && rm -r /tmp/sinotify_test
|
77
|
+
|
78
|
+
Back in irb you will see:
|
79
|
+
|
80
|
+
Event happened at Sat Jul 11 12:29:18 -0400 2009 on /tmp/sinotify_test/hi, etypes => [:create]
|
81
|
+
--> demonstrate that multiple subscribers can be setup: [:create]
|
82
|
+
Event happened at Sat Jul 11 12:29:19 -0400 2009 on /tmp/sinotify_test/hi, etypes => [:modify]
|
83
|
+
--> demonstrate that multiple subscribers can be setup: [:modify]
|
84
|
+
Event happened at Sat Jul 11 12:29:20 -0400 2009 on /tmp/sinotify_test/hi, etypes => [:delete]
|
85
|
+
--> demonstrate that multiple subscribers can be setup: [:delete]
|
86
|
+
Event happened at Sat Jul 11 12:29:20 -0400 2009 on /tmp/sinotify_test, etypes => [:delete]
|
87
|
+
--> demonstrate that multiple subscribers can be setup: [:delete]
|
88
|
+
|
89
|
+
|
90
|
+
tail -n 50 -f /tmp/inotify_spy.log:
|
91
|
+
|
92
|
+
...
|
93
|
+
... INFO -- : Sinotify::Notifier Prim Event Spy: <Sinotify::PrimEvent :name => 'hi', :etypes => [:create], :mask => 100 ...
|
94
|
+
... INFO -- : Sinotify::Notifier Event Spy <Sinotify::Event :path => '/tmp/sinotify_test/hi', dir? => false, :etypes => ...
|
95
|
+
... INFO -- : Sinotify::Notifier Prim Event Spy: <Sinotify::PrimEvent :name => 'hi', :etypes => [:modify], :mask => 2 ...
|
96
|
+
... INFO -- : Sinotify::Notifier Event Spy <Sinotify::Event :path => '/tmp/sinotify_test/hi', dir? => false, :etypes => ...
|
97
|
+
... INFO -- : Sinotify::Notifier Prim Event Spy: <Sinotify::PrimEvent :name => 'hi', :etypes => [:delete], :mask => 200 ...
|
98
|
+
... INFO -- : Sinotify::Notifier Event Spy <Sinotify::Event :path => '/tmp/sinotify_test/hi', dir? => false, :etypes => ...
|
99
|
+
... INFO -- : Sinotify::Notifier Prim Event Spy: <Sinotify::PrimEvent :name => '', :etypes => [:delete_self], :mask => 400 ...
|
100
|
+
... INFO -- : Sinotify::Notifier Event Spy <Sinotify::Event :path => '/tmp/sinotify_test', dir? => true, :etypes => [:delete]...
|
101
|
+
etc.
|
102
|
+
|
103
|
+
|
104
|
+
|
105
|
+
== REQUIREMENTS:
|
106
|
+
|
107
|
+
* linux inotify dev libs
|
108
|
+
* cosell announcements framework gem
|
109
|
+
|
110
|
+
== INSTALL:
|
111
|
+
|
112
|
+
* Todo: install instruction
|
113
|
+
* sudo gem install cosell...
|
114
|
+
* sudo gem install sinotify...
|
115
|
+
|
116
|
+
== LICENSE:
|
117
|
+
|
118
|
+
(The MIT License)
|
119
|
+
|
120
|
+
Copyright (c) 2008 FIXME (different license?)
|
121
|
+
|
122
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
123
|
+
a copy of this software and associated documentation files (the
|
124
|
+
'Software'), to deal in the Software without restriction, including
|
125
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
126
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
127
|
+
permit persons to whom the Software is furnished to do so, subject to
|
128
|
+
the following conditions:
|
129
|
+
|
130
|
+
The above copyright notice and this permission notice shall be
|
131
|
+
included in all copies or substantial portions of the Software.
|
132
|
+
|
133
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
134
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
135
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
136
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
137
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
138
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
139
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
# Look in the tasks/setup.rb file for the various options that can be
|
2
|
+
# configured in this Rakefile. The .rake files in the tasks directory
|
3
|
+
# are where the options are used.
|
4
|
+
|
5
|
+
begin
|
6
|
+
require 'bones'
|
7
|
+
Bones.setup
|
8
|
+
rescue LoadError
|
9
|
+
begin
|
10
|
+
load 'tasks/setup.rb'
|
11
|
+
rescue LoadError
|
12
|
+
raise RuntimeError, '### please install the "bones" gem ###'
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
#ensure_in_path 'lib'
|
17
|
+
|
18
|
+
require File.join(File.dirname(__FILE__), 'lib/sinotify_info')
|
19
|
+
|
20
|
+
# bones gem settings
|
21
|
+
PROJ.name = 'sinotify'
|
22
|
+
PROJ.authors = 'Steven Swerling'
|
23
|
+
PROJ.email = 'sswerling@yahoo.com'
|
24
|
+
PROJ.url = 'http://tab-a.slot-z.net'
|
25
|
+
PROJ.version = Sinotify::VERSION
|
26
|
+
PROJ.rubyforge.name = 'sinotify'
|
27
|
+
PROJ.gem.extentions = FileList['ext/**/extconf.rb']
|
28
|
+
PROJ.gem.dependencies = ['cosell']
|
29
|
+
PROJ.spec.opts << '--color'
|
30
|
+
PROJ.rdoc.opts = ["--inline-source"]
|
31
|
+
PROJ.rdoc.exclude = ["^tasks/setup\.rb$", "\.[ch]$"]
|
32
|
+
|
33
|
+
task :default => 'spec:run'
|
34
|
+
task :myclobber => [:clobber] do
|
35
|
+
sh "rm -rf #{File.join(File.dirname(__FILE__), 'pkg')}"
|
36
|
+
sh "rm -rf #{File.join(File.dirname(__FILE__), 'doc')}"
|
37
|
+
sh "rm -rf #{File.join(File.dirname(__FILE__), 'ext/*.log')}"
|
38
|
+
sh "rm -rf #{File.join(File.dirname(__FILE__), 'ext/*.o')}"
|
39
|
+
sh "rm -rf #{File.join(File.dirname(__FILE__), 'ext/*.so')}"
|
40
|
+
sh "rm -rf #{File.join(File.dirname(__FILE__), 'ext/Makefile')}"
|
41
|
+
end
|
42
|
+
task :mypackage => [:myclobber] do
|
43
|
+
sh "rm -rf #{File.join(File.dirname(__FILE__), 'pkg')}"
|
44
|
+
sh "rm -rf #{File.join(File.dirname(__FILE__), 'doc')}"
|
45
|
+
sh "rm -rf #{File.join(File.dirname(__FILE__), 'ext/*.log')}"
|
46
|
+
sh "rm -rf #{File.join(File.dirname(__FILE__), 'ext/*.o')}"
|
47
|
+
sh "rm -rf #{File.join(File.dirname(__FILE__), 'ext/*.so')}"
|
48
|
+
Rake::Task['gem:package'].invoke
|
49
|
+
end
|
50
|
+
|
data/examples/watcher.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
#!usr/bin/ruby
|
2
|
+
|
3
|
+
require 'sinotify'
|
4
|
+
require 'find'
|
5
|
+
|
6
|
+
i = Inotify.new
|
7
|
+
|
8
|
+
t = Thread.new do
|
9
|
+
i.each_event do |ev|
|
10
|
+
p ev.name
|
11
|
+
p ev.mask
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
raise("Specify a directory") if !ARGV[0]
|
16
|
+
|
17
|
+
Find.find(ARGV[0]) do |e|
|
18
|
+
if ['.svn', 'CVS', 'RCS'].include? File.basename(e) or !File.directory? e
|
19
|
+
Find.prune
|
20
|
+
else
|
21
|
+
begin
|
22
|
+
puts "Adding #{e}"
|
23
|
+
i.add_watch(e, Inotify::CREATE | Inotify::DELETE | Inotify::MOVE | Inotify::MODIFY)
|
24
|
+
rescue
|
25
|
+
puts "Skipping #{e}: #{$!}"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
t.join
|
data/ext/extconf.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'mkmf'
|
2
|
+
|
3
|
+
dir = File.join(File.dirname(__FILE__))
|
4
|
+
|
5
|
+
if RUBY_VERSION =~ /1.9/ then
|
6
|
+
$CPPFLAGS += " -DRUBY_19"
|
7
|
+
end
|
8
|
+
|
9
|
+
have_header('linux/inotify.h')
|
10
|
+
# this was in the original inotify, but I don't know what it is for:
|
11
|
+
# have_header("version.h")
|
12
|
+
create_makefile('sinotify', 'src')
|
@@ -0,0 +1,24 @@
|
|
1
|
+
#ifndef _LINUX_INOTIFY_SYSCALLS_H
|
2
|
+
#define _LINUX_INOTIFY_SYSCALLS_H
|
3
|
+
|
4
|
+
#if defined(__i386__)
|
5
|
+
# define __NR_inotify_init 291
|
6
|
+
# define __NR_inotify_add_watch 292
|
7
|
+
# define __NR_inotify_rm_watch 293
|
8
|
+
#elif defined(__x86_64__)
|
9
|
+
# define __NR_inotify_init 253
|
10
|
+
# define __NR_inotify_add_watch 254
|
11
|
+
# define __NR_inotify_rm_watch 255
|
12
|
+
#elif defined(__ppc__)
|
13
|
+
# define __NR_inotify_init 275
|
14
|
+
# define __NR_inotify_add_watch 276
|
15
|
+
# define __NR_inotify_rm_watch 277
|
16
|
+
#elif defined (__ia64__)
|
17
|
+
# define __NR_inotify_init 1277
|
18
|
+
# define __NR_inotify_add_watch 1278
|
19
|
+
# define __NR_inotify_rm_watch 1279
|
20
|
+
#else
|
21
|
+
# error "Unsupported architecture!"
|
22
|
+
#endif
|
23
|
+
|
24
|
+
#endif /* _LINUX_INOTIFY_SYSCALLS_H */
|
data/ext/src/inotify.h
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
/*
|
2
|
+
* Inode based directory notification for Linux
|
3
|
+
*
|
4
|
+
* Copyright (C) 2005 John McCutchan
|
5
|
+
*/
|
6
|
+
|
7
|
+
#ifndef _LINUX_INOTIFY_H
|
8
|
+
#define _LINUX_INOTIFY_H
|
9
|
+
|
10
|
+
#include <linux/types.h>
|
11
|
+
|
12
|
+
/*
|
13
|
+
* struct inotify_event - structure read from the inotify device for each event
|
14
|
+
*
|
15
|
+
* When you are watching a directory, you will receive the filename for events
|
16
|
+
* such as IN_CREATE, IN_DELETE, IN_OPEN, IN_CLOSE, ..., relative to the wd.
|
17
|
+
*/
|
18
|
+
struct inotify_event {
|
19
|
+
__s32 wd; /* watch descriptor */
|
20
|
+
__u32 mask; /* watch mask */
|
21
|
+
__u32 cookie; /* cookie to synchronize two events */
|
22
|
+
__u32 len; /* length (including nulls) of name */
|
23
|
+
char name[0]; /* stub for possible name */
|
24
|
+
};
|
25
|
+
|
26
|
+
/* the following are legal, implemented events that user-space can watch for */
|
27
|
+
#define IN_ACCESS 0x00000001 /* File was accessed */
|
28
|
+
#define IN_MODIFY 0x00000002 /* File was modified */
|
29
|
+
#define IN_ATTRIB 0x00000004 /* Metadata changed */
|
30
|
+
#define IN_CLOSE_WRITE 0x00000008 /* Writtable file was closed */
|
31
|
+
#define IN_CLOSE_NOWRITE 0x00000010 /* Unwrittable file closed */
|
32
|
+
#define IN_OPEN 0x00000020 /* File was opened */
|
33
|
+
#define IN_MOVED_FROM 0x00000040 /* File was moved from X */
|
34
|
+
#define IN_MOVED_TO 0x00000080 /* File was moved to Y */
|
35
|
+
#define IN_CREATE 0x00000100 /* Subfile was created */
|
36
|
+
#define IN_DELETE 0x00000200 /* Subfile was deleted */
|
37
|
+
#define IN_DELETE_SELF 0x00000400 /* Self was deleted */
|
38
|
+
#define IN_MOVE_SELF 0x00000800 /* Self was moved */
|
39
|
+
|
40
|
+
/* the following are legal events. they are sent as needed to any watch */
|
41
|
+
#define IN_UNMOUNT 0x00002000 /* Backing fs was unmounted */
|
42
|
+
#define IN_Q_OVERFLOW 0x00004000 /* Event queued overflowed */
|
43
|
+
#define IN_IGNORED 0x00008000 /* File was ignored */
|
44
|
+
|
45
|
+
/* helper events */
|
46
|
+
#define IN_CLOSE (IN_CLOSE_WRITE | IN_CLOSE_NOWRITE) /* close */
|
47
|
+
#define IN_MOVE (IN_MOVED_FROM | IN_MOVED_TO) /* moves */
|
48
|
+
|
49
|
+
/* special flags */
|
50
|
+
#define IN_ONLYDIR 0x01000000 /* only watch the path if it is a directory */
|
51
|
+
#define IN_DONT_FOLLOW 0x02000000 /* don't follow a sym link */
|
52
|
+
#define IN_MASK_ADD 0x20000000 /* add to the mask of an already existing watch */
|
53
|
+
#define IN_ISDIR 0x40000000 /* event occurred against dir */
|
54
|
+
#define IN_ONESHOT 0x80000000 /* only send event once */
|
55
|
+
|
56
|
+
/*
|
57
|
+
* All of the events - we build the list by hand so that we can add flags in
|
58
|
+
* the future and not break backward compatibility. Apps will get only the
|
59
|
+
* events that they originally wanted. Be sure to add new events here!
|
60
|
+
*/
|
61
|
+
#define IN_ALL_EVENTS (IN_ACCESS | IN_MODIFY | IN_ATTRIB | IN_CLOSE_WRITE | \
|
62
|
+
IN_CLOSE_NOWRITE | IN_OPEN | IN_MOVED_FROM | \
|
63
|
+
IN_MOVED_TO | IN_DELETE | IN_CREATE | IN_DELETE_SELF | \
|
64
|
+
IN_MOVE_SELF)
|
65
|
+
|
66
|
+
#ifdef __KERNEL__
|
67
|
+
|
68
|
+
#include <linux/dcache.h>
|
69
|
+
#include <linux/fs.h>
|
70
|
+
#include <linux/config.h>
|
71
|
+
|
72
|
+
#ifdef CONFIG_INOTIFY
|
73
|
+
|
74
|
+
extern void inotify_inode_queue_event(struct inode *, __u32, __u32,
|
75
|
+
const char *);
|
76
|
+
extern void inotify_dentry_parent_queue_event(struct dentry *, __u32, __u32,
|
77
|
+
const char *);
|
78
|
+
extern void inotify_unmount_inodes(struct list_head *);
|
79
|
+
extern void inotify_inode_is_dead(struct inode *);
|
80
|
+
extern u32 inotify_get_cookie(void);
|
81
|
+
|
82
|
+
#else
|
83
|
+
|
84
|
+
static inline void inotify_inode_queue_event(struct inode *inode,
|
85
|
+
__u32 mask, __u32 cookie,
|
86
|
+
const char *filename)
|
87
|
+
{
|
88
|
+
}
|
89
|
+
|
90
|
+
static inline void inotify_dentry_parent_queue_event(struct dentry *dentry,
|
91
|
+
__u32 mask, __u32 cookie,
|
92
|
+
const char *filename)
|
93
|
+
{
|
94
|
+
}
|
95
|
+
|
96
|
+
static inline void inotify_unmount_inodes(struct list_head *list)
|
97
|
+
{
|
98
|
+
}
|
99
|
+
|
100
|
+
static inline void inotify_inode_is_dead(struct inode *inode)
|
101
|
+
{
|
102
|
+
}
|
103
|
+
|
104
|
+
static inline u32 inotify_get_cookie(void)
|
105
|
+
{
|
106
|
+
return 0;
|
107
|
+
}
|
108
|
+
|
109
|
+
#endif /* CONFIG_INOTIFY */
|
110
|
+
|
111
|
+
#endif /* __KERNEL __ */
|
112
|
+
|
113
|
+
#endif /* _LINUX_INOTIFY_H */
|