rb-inotify 0.8.8 → 0.10.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +21 -0
- data/.travis.yml +19 -0
- data/Gemfile +16 -0
- data/LICENSE.md +10 -0
- data/README.md +48 -1
- data/Rakefile +10 -50
- data/lib/rb-inotify/errors.rb +3 -0
- data/lib/rb-inotify/event.rb +10 -3
- data/lib/rb-inotify/native/flags.rb +5 -0
- data/lib/rb-inotify/native.rb +6 -4
- data/lib/rb-inotify/notifier.rb +77 -59
- data/lib/rb-inotify/version.rb +24 -0
- data/lib/rb-inotify/watcher.rb +7 -2
- data/lib/rb-inotify.rb +2 -4
- data/rb-inotify.gemspec +23 -48
- data/spec/inotify_spec.rb +9 -0
- data/spec/notifier_spec.rb +180 -0
- data/spec/spec_helper.rb +29 -0
- metadata +108 -75
- data/MIT-LICENSE +0 -20
- data/VERSION +0 -1
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 803cf77fe31e9334147381cbc2fcdc911f5c8c060582af70afb80ba00caa4967
|
4
|
+
data.tar.gz: dc13bce654e7a7c20d17722db4a62d4a091a6f21918e8133702306d90d5e0ccb
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 8b798f26a05bb0757e2bb29c49bdc07b694659c9bfd1a007be3fec48acbfccb59c049bbf17881c739f80f66fc63b03df15fb70574aaae73ce2f457667e726eec
|
7
|
+
data.tar.gz: c29ccd96375401b43d52ca09345ab235e11b044706ef4995525372961b126d4b845ac468c422c40dd77eec36995ac19855dccab85706a6458f34505bec5ac02b
|
data/.gitignore
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
Gemfile.lock
|
7
|
+
InstalledFiles
|
8
|
+
_yardoc
|
9
|
+
coverage
|
10
|
+
doc/
|
11
|
+
lib/bundler/man
|
12
|
+
pkg
|
13
|
+
rdoc
|
14
|
+
spec/reports
|
15
|
+
test/tmp
|
16
|
+
test/version_tmp
|
17
|
+
tmp
|
18
|
+
.tags*
|
19
|
+
.rspec_status
|
20
|
+
/guard/
|
21
|
+
/listen/
|
data/.travis.yml
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
language: ruby
|
2
|
+
cache: bundler
|
3
|
+
|
4
|
+
matrix:
|
5
|
+
include:
|
6
|
+
- rvm: 2.3
|
7
|
+
- rvm: 2.4
|
8
|
+
- rvm: 2.5
|
9
|
+
- rvm: 2.6
|
10
|
+
- rvm: jruby
|
11
|
+
- rvm: truffleruby
|
12
|
+
- rvm: jruby-head
|
13
|
+
- rvm: ruby-head
|
14
|
+
allow_failures:
|
15
|
+
- rvm: truffleruby
|
16
|
+
- rvm: jruby
|
17
|
+
- rvm: ruby-head
|
18
|
+
- rvm: jruby-head
|
19
|
+
fast_finish: true
|
data/Gemfile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
# Specify your gem's dependencies in utopia.gemspec
|
4
|
+
gemspec
|
5
|
+
|
6
|
+
group :development do
|
7
|
+
gem 'pry'
|
8
|
+
gem 'pry-coolline'
|
9
|
+
|
10
|
+
gem 'tty-prompt'
|
11
|
+
end
|
12
|
+
|
13
|
+
group :test do
|
14
|
+
gem 'simplecov'
|
15
|
+
gem 'coveralls', require: false
|
16
|
+
end
|
data/LICENSE.md
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
# The MIT License
|
2
|
+
|
3
|
+
Copyright, 2009, by [Natalie Weizenbaum](https://github.com/nex3).
|
4
|
+
Copyright, 2017, by [Samuel G. D. Williams](http://www.codeotaku.com).
|
5
|
+
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
7
|
+
|
8
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
9
|
+
|
10
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
CHANGED
@@ -6,7 +6,11 @@ It uses the [FFI](http://wiki.github.com/ffi/ffi) gem to avoid having to compile
|
|
6
6
|
|
7
7
|
[API documentation is available on rdoc.info](http://rdoc.info/projects/nex3/rb-inotify).
|
8
8
|
|
9
|
-
|
9
|
+
[![Build Status](https://secure.travis-ci.org/guard/rb-inotify.svg)](http://travis-ci.org/guard/rb-inotify)
|
10
|
+
[![Code Climate](https://codeclimate.com/github/guard/rb-inotify.svg)](https://codeclimate.com/github/guard/rb-inotify)
|
11
|
+
[![Coverage Status](https://coveralls.io/repos/guard/rb-inotify/badge.svg)](https://coveralls.io/r/guard/rb-inotify)
|
12
|
+
|
13
|
+
## Usage
|
10
14
|
|
11
15
|
The API is similar to the inotify C API, but with a more Rubyish feel.
|
12
16
|
First, create a notifier:
|
@@ -64,3 +68,46 @@ It can even be used with EventMachine:
|
|
64
68
|
Unfortunately, this currently doesn't work under JRuby.
|
65
69
|
JRuby currently doesn't use native file descriptors for the IO object,
|
66
70
|
so we can't use the notifier's file descriptor as a stand-in.
|
71
|
+
|
72
|
+
### Resource Limits
|
73
|
+
|
74
|
+
If you get an error like `inotify event queue has overflowed` you might be running into system limits. You can add the following to your `/etc/sysctl.conf` to increase the number of files that can be monitored:
|
75
|
+
|
76
|
+
```
|
77
|
+
fs.inotify.max_user_watches = 100000
|
78
|
+
fs.inotify.max_queued_events = 100000
|
79
|
+
fs.inotify.max_user_instances = 100000
|
80
|
+
```
|
81
|
+
|
82
|
+
## Contributing
|
83
|
+
|
84
|
+
1. Fork it
|
85
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
86
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
87
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
88
|
+
5. Create new Pull Request
|
89
|
+
|
90
|
+
## License
|
91
|
+
|
92
|
+
Released under the MIT license.
|
93
|
+
|
94
|
+
Copyright, 2009, by [Natalie Weizenbaum](https://github.com/nex3).
|
95
|
+
Copyright, 2017, by [Samuel G. D. Williams](http://www.codeotaku.com/samuel-williams).
|
96
|
+
|
97
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
98
|
+
of this software and associated documentation files (the "Software"), to deal
|
99
|
+
in the Software without restriction, including without limitation the rights
|
100
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
101
|
+
copies of the Software, and to permit persons to whom the Software is
|
102
|
+
furnished to do so, subject to the following conditions:
|
103
|
+
|
104
|
+
The above copyright notice and this permission notice shall be included in
|
105
|
+
all copies or substantial portions of the Software.
|
106
|
+
|
107
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
108
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
109
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
110
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
111
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
112
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
113
|
+
THE SOFTWARE.
|
data/Rakefile
CHANGED
@@ -1,54 +1,14 @@
|
|
1
|
-
require
|
2
|
-
require '
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require 'rspec/core/rake_task'
|
3
3
|
|
4
|
-
|
5
|
-
require 'jeweler'
|
6
|
-
Jeweler::Tasks.new do |gem|
|
7
|
-
gem.name = "rb-inotify"
|
8
|
-
gem.summary = "A Ruby wrapper for Linux's inotify, using FFI"
|
9
|
-
gem.description = gem.summary
|
10
|
-
gem.email = "nex342@gmail.com"
|
11
|
-
gem.homepage = "http://github.com/nex3/rb-inotify"
|
12
|
-
gem.authors = ["Nathan Weizenbaum"]
|
13
|
-
gem.add_dependency "ffi", ">= 0.5.0"
|
14
|
-
gem.add_development_dependency "yard", ">= 0.4.0"
|
15
|
-
end
|
16
|
-
Jeweler::GemcutterTasks.new
|
17
|
-
rescue LoadError
|
18
|
-
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
19
|
-
end
|
20
|
-
|
21
|
-
task(:permissions) {sh %{chmod -R a+r .}}
|
22
|
-
Rake::Task[:build].prerequisites.unshift('permissions')
|
4
|
+
RSpec::Core::RakeTask.new(:spec)
|
23
5
|
|
24
|
-
|
25
|
-
|
26
|
-
write_without_inotify
|
27
|
-
filename = File.join(File.dirname(__FILE__), "lib/rb-inotify.rb")
|
28
|
-
text = File.read(filename)
|
29
|
-
File.open(filename, 'w') do |f|
|
30
|
-
f.write text.gsub(/^( VERSION = ).*/, '\1' + [major, minor, patch].inspect)
|
31
|
-
end
|
32
|
-
end
|
33
|
-
alias_method :write_without_inotify, :write
|
34
|
-
alias_method :write, :write_with_inotify
|
35
|
-
end
|
36
|
-
|
37
|
-
class Jeweler::Commands::Version::Base
|
38
|
-
def commit_version_with_inotify
|
39
|
-
return unless self.repo
|
40
|
-
self.repo.add(File.join(File.dirname(__FILE__), "lib/rb-inotify.rb"))
|
41
|
-
commit_version_without_inotify
|
42
|
-
end
|
43
|
-
alias_method :commit_version_without_inotify, :commit_version
|
44
|
-
alias_method :commit_version, :commit_version_with_inotify
|
45
|
-
end
|
6
|
+
desc "Run tests"
|
7
|
+
task :default => :spec
|
46
8
|
|
47
|
-
|
48
|
-
require '
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
abort "YARD is not available. In order to run yardoc, you must: sudo gem install yard"
|
53
|
-
end
|
9
|
+
task :console do
|
10
|
+
require 'rb-inotify'
|
11
|
+
require 'pry'
|
12
|
+
|
13
|
+
binding.pry
|
54
14
|
end
|
data/lib/rb-inotify/event.rb
CHANGED
@@ -113,11 +113,11 @@ module INotify
|
|
113
113
|
@native = Native::Event.new(ptr)
|
114
114
|
@related = []
|
115
115
|
@cookie = @native[:cookie]
|
116
|
-
@name = data[@native.size, @native[:len]].gsub(/\0+$/, '')
|
116
|
+
@name = fix_encoding(data[@native.size, @native[:len]].gsub(/\0+$/, ''))
|
117
117
|
@notifier = notifier
|
118
118
|
@watcher_id = @native[:wd]
|
119
119
|
|
120
|
-
raise
|
120
|
+
raise QueueOverflowError.new("inotify event queue has overflowed.") if @native[:mask] & Native::Flags::IN_Q_OVERFLOW != 0
|
121
121
|
end
|
122
122
|
|
123
123
|
# Calls the callback of the watcher that fired this event,
|
@@ -125,7 +125,7 @@ module INotify
|
|
125
125
|
#
|
126
126
|
# @private
|
127
127
|
def callback!
|
128
|
-
watcher.callback!(self)
|
128
|
+
watcher && watcher.callback!(self)
|
129
129
|
end
|
130
130
|
|
131
131
|
# Returns the size of this event object in bytes,
|
@@ -135,5 +135,12 @@ module INotify
|
|
135
135
|
def size
|
136
136
|
@native.size + @native[:len]
|
137
137
|
end
|
138
|
+
|
139
|
+
private
|
140
|
+
|
141
|
+
def fix_encoding(name)
|
142
|
+
name.force_encoding('filesystem') if name.respond_to?(:force_encoding)
|
143
|
+
name
|
144
|
+
end
|
138
145
|
end
|
139
146
|
end
|
@@ -65,6 +65,11 @@ module INotify
|
|
65
65
|
# Event occurred against dir.
|
66
66
|
IN_ISDIR = 0x40000000
|
67
67
|
|
68
|
+
## fpathconf Macros
|
69
|
+
|
70
|
+
# returns the maximum length of a filename in the directory path or fd that the process is allowed to create. The corresponding macro is _POSIX_NAME_MAX.
|
71
|
+
PC_NAME_MAX = 3
|
72
|
+
|
68
73
|
# Converts a list of flags to the bitmask that the C API expects.
|
69
74
|
#
|
70
75
|
# @param flags [Array<Symbol>]
|
data/lib/rb-inotify/native.rb
CHANGED
@@ -8,7 +8,11 @@ module INotify
|
|
8
8
|
# @private
|
9
9
|
module Native
|
10
10
|
extend FFI::Library
|
11
|
-
ffi_lib
|
11
|
+
ffi_lib FFI::Library::LIBC
|
12
|
+
begin
|
13
|
+
ffi_lib 'inotify'
|
14
|
+
rescue LoadError
|
15
|
+
end
|
12
16
|
|
13
17
|
# The C struct describing an inotify event.
|
14
18
|
#
|
@@ -24,8 +28,6 @@ module INotify
|
|
24
28
|
attach_function :inotify_init, [], :int
|
25
29
|
attach_function :inotify_add_watch, [:int, :string, :uint32], :int
|
26
30
|
attach_function :inotify_rm_watch, [:int, :uint32], :int
|
27
|
-
|
28
|
-
attach_function :read, [:int, :pointer, :size_t], :ssize_t
|
29
|
-
attach_function :close, [:int], :int
|
31
|
+
attach_function :fpathconf, [:int, :int], :long
|
30
32
|
end
|
31
33
|
end
|
data/lib/rb-inotify/notifier.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'thread'
|
2
|
+
|
1
3
|
module INotify
|
2
4
|
# Notifier wraps a single instance of inotify.
|
3
5
|
# It's possible to have more than one instance,
|
@@ -38,12 +40,8 @@ module INotify
|
|
38
40
|
# (except under JRuby -- see \{#to\_io}).
|
39
41
|
#
|
40
42
|
# @return [Fixnum]
|
41
|
-
|
42
|
-
|
43
|
-
# @return [Boolean] Whether or not this Ruby implementation supports
|
44
|
-
# wrapping the native file descriptor in a Ruby IO wrapper.
|
45
|
-
def self.supports_ruby_io?
|
46
|
-
RUBY_PLATFORM !~ /java/
|
43
|
+
def fd
|
44
|
+
@handle.fileno
|
47
45
|
end
|
48
46
|
|
49
47
|
# Creates a new {Notifier}.
|
@@ -51,9 +49,22 @@ module INotify
|
|
51
49
|
# @return [Notifier]
|
52
50
|
# @raise [SystemCallError] if inotify failed to initialize for some reason
|
53
51
|
def initialize
|
54
|
-
@
|
52
|
+
@running = Mutex.new
|
53
|
+
@pipe = IO.pipe
|
54
|
+
# JRuby shutdown sometimes runs IO finalizers before all threads finish.
|
55
|
+
if RUBY_ENGINE == 'jruby'
|
56
|
+
@pipe[0].autoclose = false
|
57
|
+
@pipe[1].autoclose = false
|
58
|
+
end
|
59
|
+
|
55
60
|
@watchers = {}
|
56
|
-
|
61
|
+
|
62
|
+
fd = Native.inotify_init
|
63
|
+
unless fd < 0
|
64
|
+
@handle = IO.new(fd)
|
65
|
+
@handle.autoclose = false if RUBY_ENGINE == 'jruby'
|
66
|
+
return
|
67
|
+
end
|
57
68
|
|
58
69
|
raise SystemCallError.new(
|
59
70
|
"Failed to initialize inotify" +
|
@@ -82,10 +93,7 @@ module INotify
|
|
82
93
|
# @return [IO] An IO object wrapping the file descriptor
|
83
94
|
# @raise [NotImplementedError] if this is being called in JRuby
|
84
95
|
def to_io
|
85
|
-
|
86
|
-
raise NotImplementedError.new("INotify::Notifier#to_io is not supported under JRuby")
|
87
|
-
end
|
88
|
-
@io ||= IO.new(@fd)
|
96
|
+
@handle
|
89
97
|
end
|
90
98
|
|
91
99
|
# Watches a file or directory for changes,
|
@@ -189,12 +197,21 @@ module INotify
|
|
189
197
|
def watch(path, *flags, &callback)
|
190
198
|
return Watcher.new(self, path, *flags, &callback) unless flags.include?(:recursive)
|
191
199
|
|
192
|
-
Dir.
|
200
|
+
dir = Dir.new(path)
|
201
|
+
|
202
|
+
dir.each do |base|
|
203
|
+
d = File.join(path, base)
|
193
204
|
binary_d = d.respond_to?(:force_encoding) ? d.dup.force_encoding('BINARY') : d
|
194
205
|
next if binary_d =~ /\/\.\.?$/ # Current or parent directory
|
195
|
-
|
206
|
+
next if RECURSIVE_BLACKLIST.include?(d)
|
207
|
+
next if flags.include?(:dont_follow) && File.symlink?(d)
|
208
|
+
next if !File.directory?(d)
|
209
|
+
|
210
|
+
watch(d, *flags, &callback)
|
196
211
|
end
|
197
212
|
|
213
|
+
dir.close
|
214
|
+
|
198
215
|
rec_flags = [:create, :moved_to]
|
199
216
|
return watch(path, *((flags - [:recursive]) | rec_flags)) do |event|
|
200
217
|
callback.call(event) if flags.include?(:all_events) || !(flags & event.flags).empty?
|
@@ -212,8 +229,14 @@ module INotify
|
|
212
229
|
#
|
213
230
|
# @see #process
|
214
231
|
def run
|
215
|
-
@
|
216
|
-
|
232
|
+
@running.synchronize do
|
233
|
+
Thread.current[:INOTIFY_RUN_THREAD] = true
|
234
|
+
@stop = false
|
235
|
+
|
236
|
+
process until @stop
|
237
|
+
end
|
238
|
+
ensure
|
239
|
+
Thread.current[:INOTIFY_RUN_THREAD] = false
|
217
240
|
end
|
218
241
|
|
219
242
|
# Stop watching for filesystem events.
|
@@ -221,6 +244,13 @@ module INotify
|
|
221
244
|
# exit out as soon as we finish handling the events.
|
222
245
|
def stop
|
223
246
|
@stop = true
|
247
|
+
@pipe.last.write "."
|
248
|
+
|
249
|
+
unless Thread.current[:INOTIFY_RUN_THREAD]
|
250
|
+
@running.synchronize do
|
251
|
+
# no-op: we just needed to wait until the lock was available
|
252
|
+
end
|
253
|
+
end
|
224
254
|
end
|
225
255
|
|
226
256
|
# Blocks until there are one or more filesystem events
|
@@ -230,30 +260,30 @@ module INotify
|
|
230
260
|
#
|
231
261
|
# @see #run
|
232
262
|
def process
|
233
|
-
read_events.each
|
263
|
+
read_events.each do |event|
|
264
|
+
event.callback!
|
265
|
+
event.flags.include?(:ignored) && event.notifier.watchers.delete(event.watcher_id)
|
266
|
+
end
|
234
267
|
end
|
235
268
|
|
236
269
|
# Close the notifier.
|
237
270
|
#
|
238
271
|
# @raise [SystemCallError] if closing the underlying file descriptor fails.
|
239
272
|
def close
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
case FFI.errno
|
244
|
-
when Errno::EBADF::Errno; ": invalid or closed file descriptior"
|
245
|
-
when Errno::EIO::Errno; ": an I/O error occured"
|
246
|
-
end,
|
247
|
-
FFI.errno)
|
273
|
+
stop
|
274
|
+
@handle.close
|
275
|
+
@watchers.clear
|
248
276
|
end
|
249
277
|
|
250
|
-
|
251
|
-
|
252
|
-
#
|
253
|
-
#
|
254
|
-
#
|
278
|
+
# Blocks until there are one or more filesystem events that this notifier
|
279
|
+
# has watchers registered for. Once there are events, returns their {Event}
|
280
|
+
# objects.
|
281
|
+
#
|
282
|
+
# This can return an empty list if the watcher was closed elsewhere.
|
283
|
+
#
|
284
|
+
# {#run} or {#process} are ususally preferable to calling this directly.
|
255
285
|
def read_events
|
256
|
-
size =
|
286
|
+
size = Native::Event.size + Native.fpathconf(fd, Native::Flags::PC_NAME_MAX) + 1
|
257
287
|
tries = 1
|
258
288
|
|
259
289
|
begin
|
@@ -261,48 +291,36 @@ module INotify
|
|
261
291
|
rescue SystemCallError => er
|
262
292
|
# EINVAL means that there's more data to be read
|
263
293
|
# than will fit in the buffer size
|
264
|
-
raise er unless er.errno == Errno::EINVAL::Errno
|
294
|
+
raise er unless er.errno == Errno::EINVAL::Errno && tries < 5
|
265
295
|
size *= 2
|
266
296
|
tries += 1
|
267
297
|
retry
|
268
298
|
end
|
299
|
+
return [] if data.nil?
|
269
300
|
|
270
301
|
events = []
|
271
302
|
cookies = {}
|
272
|
-
while
|
273
|
-
events <<
|
274
|
-
next if
|
275
|
-
cookies[
|
276
|
-
cookies[
|
303
|
+
while event = Event.consume(data, self)
|
304
|
+
events << event
|
305
|
+
next if event.cookie == 0
|
306
|
+
cookies[event.cookie] ||= []
|
307
|
+
cookies[event.cookie] << event
|
277
308
|
end
|
278
309
|
cookies.each {|c, evs| evs.each {|ev| ev.related.replace(evs - [ev]).freeze}}
|
279
310
|
events
|
280
311
|
end
|
281
312
|
|
313
|
+
private
|
314
|
+
|
282
315
|
# Same as IO#readpartial, or as close as we need.
|
283
316
|
def readpartial(size)
|
284
|
-
|
285
|
-
return
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
size_read = Native.read(fd, buffer, size)
|
292
|
-
return buffer.read_string(size_read) if size_read >= 0
|
293
|
-
end while FFI.errno == Errno::EINTR::Errno && tries <= 5
|
294
|
-
|
295
|
-
raise SystemCallError.new("Error reading inotify events" +
|
296
|
-
case FFI.errno
|
297
|
-
when Errno::EAGAIN::Errno; ": no data available for non-blocking I/O"
|
298
|
-
when Errno::EBADF::Errno; ": invalid or closed file descriptor"
|
299
|
-
when Errno::EFAULT::Errno; ": invalid buffer"
|
300
|
-
when Errno::EINVAL::Errno; ": invalid file descriptor"
|
301
|
-
when Errno::EIO::Errno; ": I/O error"
|
302
|
-
when Errno::EISDIR::Errno; ": file descriptor is a directory"
|
303
|
-
else; ""
|
304
|
-
end,
|
305
|
-
FFI.errno)
|
317
|
+
readable, = select([@handle, @pipe.first])
|
318
|
+
return nil if readable.include?(@pipe.first)
|
319
|
+
@handle.readpartial(size)
|
320
|
+
rescue Errno::EBADF
|
321
|
+
# If the IO has already been closed, reading from it will cause
|
322
|
+
# Errno::EBADF.
|
323
|
+
nil
|
306
324
|
end
|
307
325
|
end
|
308
326
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# Copyright, 2012, by Natalie Weizenbaum.
|
2
|
+
# Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
|
+
# of this software and associated documentation files (the "Software"), to deal
|
6
|
+
# in the Software without restriction, including without limitation the rights
|
7
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
# copies of the Software, and to permit persons to whom the Software is
|
9
|
+
# furnished to do so, subject to the following conditions:
|
10
|
+
#
|
11
|
+
# The above copyright notice and this permission notice shall be included in
|
12
|
+
# all copies or substantial portions of the Software.
|
13
|
+
#
|
14
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
16
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
17
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
18
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
19
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
20
|
+
# THE SOFTWARE.
|
21
|
+
|
22
|
+
module INotify
|
23
|
+
VERSION = '0.10.1'
|
24
|
+
end
|
data/lib/rb-inotify/watcher.rb
CHANGED
@@ -45,8 +45,13 @@ module INotify
|
|
45
45
|
#
|
46
46
|
# @raise [SystemCallError] if the watch fails to be disabled for some reason
|
47
47
|
def close
|
48
|
-
|
49
|
-
|
48
|
+
if Native.inotify_rm_watch(@notifier.fd, @id) == 0
|
49
|
+
@notifier.watchers.delete(@id)
|
50
|
+
return
|
51
|
+
end
|
52
|
+
|
53
|
+
raise SystemCallError.new("Failed to stop watching #{path.inspect}",
|
54
|
+
FFI.errno)
|
50
55
|
end
|
51
56
|
|
52
57
|
# Creates a new {Watcher}.
|
data/lib/rb-inotify.rb
CHANGED
@@ -1,8 +1,10 @@
|
|
1
|
+
require 'rb-inotify/version'
|
1
2
|
require 'rb-inotify/native'
|
2
3
|
require 'rb-inotify/native/flags'
|
3
4
|
require 'rb-inotify/notifier'
|
4
5
|
require 'rb-inotify/watcher'
|
5
6
|
require 'rb-inotify/event'
|
7
|
+
require 'rb-inotify/errors'
|
6
8
|
|
7
9
|
# The root module of the library, which is laid out as so:
|
8
10
|
#
|
@@ -10,8 +12,4 @@ require 'rb-inotify/event'
|
|
10
12
|
# * {Watcher} -- A watcher for a single file or directory
|
11
13
|
# * {Event} -- An filesystem event notification
|
12
14
|
module INotify
|
13
|
-
# An array containing the version number of rb-inotify.
|
14
|
-
# The numbers in the array are the major, minor, and patch versions,
|
15
|
-
# respectively.
|
16
|
-
VERSION = [0, 8, 8]
|
17
15
|
end
|
data/rb-inotify.gemspec
CHANGED
@@ -1,53 +1,28 @@
|
|
1
|
-
# Generated by jeweler
|
2
|
-
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
-
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
1
|
# -*- encoding: utf-8 -*-
|
2
|
+
require_relative 'lib/rb-inotify/version'
|
5
3
|
|
6
|
-
Gem::Specification.new do |
|
7
|
-
|
8
|
-
|
4
|
+
Gem::Specification.new do |spec|
|
5
|
+
spec.name = 'rb-inotify'
|
6
|
+
spec.version = INotify::VERSION
|
7
|
+
spec.platform = Gem::Platform::RUBY
|
9
8
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
s.extra_rdoc_files = [
|
16
|
-
"README.md"
|
17
|
-
]
|
18
|
-
s.files = [
|
19
|
-
".yardopts",
|
20
|
-
"MIT-LICENSE",
|
21
|
-
"README.md",
|
22
|
-
"Rakefile",
|
23
|
-
"VERSION",
|
24
|
-
"lib/rb-inotify.rb",
|
25
|
-
"lib/rb-inotify/event.rb",
|
26
|
-
"lib/rb-inotify/native.rb",
|
27
|
-
"lib/rb-inotify/native/flags.rb",
|
28
|
-
"lib/rb-inotify/notifier.rb",
|
29
|
-
"lib/rb-inotify/watcher.rb",
|
30
|
-
"rb-inotify.gemspec"
|
31
|
-
]
|
32
|
-
s.homepage = %q{http://github.com/nex3/rb-inotify}
|
33
|
-
s.require_paths = ["lib"]
|
34
|
-
s.rubygems_version = %q{1.3.7}
|
35
|
-
s.summary = %q{A Ruby wrapper for Linux's inotify, using FFI}
|
9
|
+
spec.summary = 'A Ruby wrapper for Linux inotify, using FFI'
|
10
|
+
spec.authors = ['Natalie Weizenbaum', 'Samuel Williams']
|
11
|
+
spec.email = ['nex342@gmail.com', 'samuel.williams@oriontransfer.co.nz']
|
12
|
+
spec.homepage = 'https://github.com/guard/rb-inotify'
|
13
|
+
spec.licenses = ['MIT']
|
36
14
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
s.add_dependency(%q<yard>, [">= 0.4.0"])
|
51
|
-
end
|
15
|
+
spec.files = `git ls-files`.split($/)
|
16
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
spec.required_ruby_version = '>= 2.2'
|
21
|
+
|
22
|
+
spec.add_dependency "ffi", "~> 1.0"
|
23
|
+
|
24
|
+
spec.add_development_dependency "rspec", "~> 3.6"
|
25
|
+
spec.add_development_dependency "bundler"
|
26
|
+
spec.add_development_dependency "rake"
|
27
|
+
spec.add_development_dependency "concurrent-ruby"
|
52
28
|
end
|
53
|
-
|
@@ -0,0 +1,180 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'tmpdir'
|
3
|
+
require 'concurrent'
|
4
|
+
|
5
|
+
describe INotify::Notifier do
|
6
|
+
describe "instance" do
|
7
|
+
around do |block|
|
8
|
+
Dir.mktmpdir do |dir|
|
9
|
+
@root = Pathname.new(dir)
|
10
|
+
@notifier = INotify::Notifier.new
|
11
|
+
|
12
|
+
begin
|
13
|
+
block.call
|
14
|
+
ensure
|
15
|
+
@notifier.close
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
let(:dir) do
|
21
|
+
@root.join("foo").tap(&:mkdir)
|
22
|
+
end
|
23
|
+
|
24
|
+
let(:another_dir) do
|
25
|
+
@root.join("bar").tap(&:mkdir)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "stops" do
|
29
|
+
@notifier.stop
|
30
|
+
end
|
31
|
+
|
32
|
+
describe :process do
|
33
|
+
it "gets events" do
|
34
|
+
events = recording(dir, :create)
|
35
|
+
dir.join("test.txt").write("hello world")
|
36
|
+
|
37
|
+
@notifier.process
|
38
|
+
|
39
|
+
expect(events.size).to eq(1)
|
40
|
+
expect(events.first.name).to eq("test.txt")
|
41
|
+
expect(events.first.absolute_name).to eq(dir.join("test.txt").to_s)
|
42
|
+
end
|
43
|
+
|
44
|
+
it "gets simultaneous events" do
|
45
|
+
events = recording(dir, :create)
|
46
|
+
|
47
|
+
dir.join("one.txt").write("hello world")
|
48
|
+
dir.join("two.txt").write("hello world")
|
49
|
+
|
50
|
+
@notifier.process
|
51
|
+
|
52
|
+
expect(events.map(&:name)).to match_array(%w(one.txt two.txt))
|
53
|
+
end
|
54
|
+
|
55
|
+
it "separates events between watches" do
|
56
|
+
bar_events = nil
|
57
|
+
|
58
|
+
foo_events = recording(dir, :create)
|
59
|
+
bar_events = recording(another_dir, :create)
|
60
|
+
|
61
|
+
dir.join("test.txt").write("hello world")
|
62
|
+
another_dir.join("test_two.txt").write("hello world")
|
63
|
+
|
64
|
+
@notifier.process
|
65
|
+
|
66
|
+
expect(foo_events.size).to eq(1)
|
67
|
+
expect(foo_events.first.name).to eq("test.txt")
|
68
|
+
expect(foo_events.first.absolute_name).to eq(dir.join("test.txt").to_s)
|
69
|
+
|
70
|
+
expect(bar_events.size).to eq(1)
|
71
|
+
expect(bar_events.first.name).to eq("test_two.txt")
|
72
|
+
expect(bar_events.first.absolute_name).to eq(another_dir.join("test_two.txt").to_s)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
describe :run do
|
77
|
+
it "processes repeatedly until stopped" do
|
78
|
+
barriers = Array.new(3) { Concurrent::Event.new }
|
79
|
+
barrier_queue = barriers.dup
|
80
|
+
events = recording(dir, :create) { barrier_queue.shift.set }
|
81
|
+
|
82
|
+
run_thread = Thread.new { @notifier.run }
|
83
|
+
|
84
|
+
dir.join("one.txt").write("hello world")
|
85
|
+
barriers.shift.wait(1) or raise "timeout"
|
86
|
+
|
87
|
+
expect(events.map(&:name)).to match_array(%w(one.txt))
|
88
|
+
|
89
|
+
dir.join("two.txt").write("hello world")
|
90
|
+
barriers.shift.wait(1) or raise "timeout"
|
91
|
+
|
92
|
+
expect(events.map(&:name)).to match_array(%w(one.txt two.txt))
|
93
|
+
|
94
|
+
@notifier.stop
|
95
|
+
|
96
|
+
dir.join("three.txt").write("hello world")
|
97
|
+
barriers.shift.wait(1)
|
98
|
+
|
99
|
+
dir.join("four.txt").write("hello world")
|
100
|
+
run_thread.join
|
101
|
+
|
102
|
+
expect(events.map(&:name)).to match_array(%w(one.txt two.txt))
|
103
|
+
end
|
104
|
+
|
105
|
+
it "can be stopped from within a callback" do
|
106
|
+
barriers = Array.new(3) { Concurrent::Event.new }
|
107
|
+
barrier_queue = barriers.dup
|
108
|
+
events = recording(dir, :create) { @notifier.stop }
|
109
|
+
|
110
|
+
run_thread = Thread.new { @notifier.run }
|
111
|
+
dir.join("one.txt").write("hello world")
|
112
|
+
run_thread.join
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
describe :fd do
|
117
|
+
it "returns an integer" do
|
118
|
+
expect(@notifier.fd).to be_an(Integer)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
describe :to_io do
|
123
|
+
it "returns a ruby IO" do
|
124
|
+
expect(@notifier.to_io).to be_an(::IO)
|
125
|
+
end
|
126
|
+
|
127
|
+
it "matches the fd" do
|
128
|
+
expect(@notifier.to_io.fileno).to eq(@notifier.fd)
|
129
|
+
end
|
130
|
+
|
131
|
+
it "caches its result" do
|
132
|
+
expect(@notifier.to_io).to be(@notifier.to_io)
|
133
|
+
end
|
134
|
+
|
135
|
+
it "is selectable" do
|
136
|
+
events = recording(dir, :create)
|
137
|
+
expect(select([@notifier.to_io], nil, nil, 0.2)).to be_nil
|
138
|
+
|
139
|
+
dir.join("test.txt").write("hello world")
|
140
|
+
expect(select([@notifier.to_io], nil, nil, 0.2)).to eq([[@notifier.to_io], [], []])
|
141
|
+
|
142
|
+
@notifier.process
|
143
|
+
expect(select([@notifier.to_io], nil, nil, 0.2)).to be_nil
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
private
|
148
|
+
|
149
|
+
def recording(dir, *flags, callback: nil)
|
150
|
+
events = []
|
151
|
+
@notifier.watch(dir.to_s, *flags) do |event|
|
152
|
+
events << event
|
153
|
+
yield if block_given?
|
154
|
+
end
|
155
|
+
|
156
|
+
events
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
describe "mixed instances" do
|
161
|
+
it "doesn't tangle fds" do
|
162
|
+
notifiers = Array.new(30) { INotify::Notifier.new }
|
163
|
+
notifiers.each(&:to_io)
|
164
|
+
|
165
|
+
one = Array.new(10) { IO.pipe.last }
|
166
|
+
notifiers.each(&:close)
|
167
|
+
|
168
|
+
two = Array.new(10) { IO.pipe.last }
|
169
|
+
|
170
|
+
notifiers = nil
|
171
|
+
GC.start
|
172
|
+
|
173
|
+
_, writable, _ = select(nil, one, nil, 1)
|
174
|
+
expect(writable).to match_array(one)
|
175
|
+
|
176
|
+
_, writable, _ = select(nil, two, nil, 1)
|
177
|
+
expect(writable).to match_array(two)
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
|
2
|
+
if ENV['COVERAGE'] || ENV['TRAVIS']
|
3
|
+
begin
|
4
|
+
require 'simplecov'
|
5
|
+
|
6
|
+
SimpleCov.start do
|
7
|
+
add_filter "/spec/"
|
8
|
+
end
|
9
|
+
|
10
|
+
if ENV['TRAVIS']
|
11
|
+
require 'coveralls'
|
12
|
+
Coveralls.wear!
|
13
|
+
end
|
14
|
+
rescue LoadError
|
15
|
+
warn "Could not load simplecov: #{$!}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
require "bundler/setup"
|
20
|
+
require "rb-inotify"
|
21
|
+
|
22
|
+
RSpec.configure do |config|
|
23
|
+
# Enable flags like --only-failures and --next-failure
|
24
|
+
config.example_status_persistence_file_path = ".rspec_status"
|
25
|
+
|
26
|
+
config.expect_with :rspec do |c|
|
27
|
+
c.syntax = :expect
|
28
|
+
end
|
29
|
+
end
|
metadata
CHANGED
@@ -1,104 +1,137 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: rb-inotify
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
segments:
|
6
|
-
- 0
|
7
|
-
- 8
|
8
|
-
- 8
|
9
|
-
version: 0.8.8
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.10.1
|
10
5
|
platform: ruby
|
11
|
-
authors:
|
12
|
-
-
|
6
|
+
authors:
|
7
|
+
- Natalie Weizenbaum
|
8
|
+
- Samuel Williams
|
13
9
|
autorequire:
|
14
10
|
bindir: bin
|
15
11
|
cert_chain: []
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
dependencies:
|
20
|
-
- !ruby/object:Gem::Dependency
|
12
|
+
date: 2019-12-24 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
21
15
|
name: ffi
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - "~>"
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '1.0'
|
21
|
+
type: :runtime
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - "~>"
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: '1.0'
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: rspec
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - "~>"
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '3.6'
|
35
|
+
type: :development
|
22
36
|
prerelease: false
|
23
|
-
|
24
|
-
|
25
|
-
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - "~>"
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '3.6'
|
42
|
+
- !ruby/object:Gem::Dependency
|
43
|
+
name: bundler
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
26
46
|
- - ">="
|
27
|
-
- !ruby/object:Gem::Version
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '0'
|
49
|
+
type: :development
|
50
|
+
prerelease: false
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
56
|
+
- !ruby/object:Gem::Dependency
|
57
|
+
name: rake
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
type: :development
|
37
64
|
prerelease: false
|
38
|
-
|
39
|
-
|
40
|
-
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: concurrent-ruby
|
72
|
+
requirement: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
41
74
|
- - ">="
|
42
|
-
- !ruby/object:Gem::Version
|
43
|
-
|
44
|
-
- 0
|
45
|
-
- 4
|
46
|
-
- 0
|
47
|
-
version: 0.4.0
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
48
77
|
type: :development
|
49
|
-
|
50
|
-
|
51
|
-
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0'
|
84
|
+
description:
|
85
|
+
email:
|
86
|
+
- nex342@gmail.com
|
87
|
+
- samuel.williams@oriontransfer.co.nz
|
52
88
|
executables: []
|
53
|
-
|
54
89
|
extensions: []
|
55
|
-
|
56
|
-
|
57
|
-
-
|
58
|
-
|
59
|
-
- .yardopts
|
60
|
-
-
|
90
|
+
extra_rdoc_files: []
|
91
|
+
files:
|
92
|
+
- ".gitignore"
|
93
|
+
- ".travis.yml"
|
94
|
+
- ".yardopts"
|
95
|
+
- Gemfile
|
96
|
+
- LICENSE.md
|
61
97
|
- README.md
|
62
98
|
- Rakefile
|
63
|
-
- VERSION
|
64
99
|
- lib/rb-inotify.rb
|
100
|
+
- lib/rb-inotify/errors.rb
|
65
101
|
- lib/rb-inotify/event.rb
|
66
102
|
- lib/rb-inotify/native.rb
|
67
103
|
- lib/rb-inotify/native/flags.rb
|
68
104
|
- lib/rb-inotify/notifier.rb
|
105
|
+
- lib/rb-inotify/version.rb
|
69
106
|
- lib/rb-inotify/watcher.rb
|
70
107
|
- rb-inotify.gemspec
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
108
|
+
- spec/inotify_spec.rb
|
109
|
+
- spec/notifier_spec.rb
|
110
|
+
- spec/spec_helper.rb
|
111
|
+
homepage: https://github.com/guard/rb-inotify
|
112
|
+
licenses:
|
113
|
+
- MIT
|
114
|
+
metadata: {}
|
75
115
|
post_install_message:
|
76
116
|
rdoc_options: []
|
77
|
-
|
78
|
-
require_paths:
|
117
|
+
require_paths:
|
79
118
|
- lib
|
80
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
81
|
-
|
82
|
-
requirements:
|
119
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
120
|
+
requirements:
|
83
121
|
- - ">="
|
84
|
-
- !ruby/object:Gem::Version
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
89
|
-
none: false
|
90
|
-
requirements:
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: '2.2'
|
124
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
125
|
+
requirements:
|
91
126
|
- - ">="
|
92
|
-
- !ruby/object:Gem::Version
|
93
|
-
|
94
|
-
- 0
|
95
|
-
version: "0"
|
127
|
+
- !ruby/object:Gem::Version
|
128
|
+
version: '0'
|
96
129
|
requirements: []
|
97
|
-
|
98
|
-
rubyforge_project:
|
99
|
-
rubygems_version: 1.3.7
|
130
|
+
rubygems_version: 3.0.4
|
100
131
|
signing_key:
|
101
|
-
specification_version:
|
102
|
-
summary: A Ruby wrapper for Linux
|
103
|
-
test_files:
|
104
|
-
|
132
|
+
specification_version: 4
|
133
|
+
summary: A Ruby wrapper for Linux inotify, using FFI
|
134
|
+
test_files:
|
135
|
+
- spec/inotify_spec.rb
|
136
|
+
- spec/notifier_spec.rb
|
137
|
+
- spec/spec_helper.rb
|
data/MIT-LICENSE
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
Copyright (c) 2009 Nathan Weizenbaum
|
2
|
-
|
3
|
-
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
-
a copy of this software and associated documentation files (the
|
5
|
-
"Software"), to deal in the Software without restriction, including
|
6
|
-
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
-
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
-
permit persons to whom the Software is furnished to do so, subject to
|
9
|
-
the following conditions:
|
10
|
-
|
11
|
-
The above copyright notice and this permission notice shall be
|
12
|
-
included in all copies or substantial portions of the Software.
|
13
|
-
|
14
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
-
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
-
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
-
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
-
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
-
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/VERSION
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
0.8.8
|