joshbuddy-guard 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG.md +370 -0
- data/LICENSE +20 -0
- data/README.md +470 -0
- data/bin/fsevent_watch_guard +0 -0
- data/bin/guard +6 -0
- data/images/failed.png +0 -0
- data/images/pending.png +0 -0
- data/images/success.png +0 -0
- data/lib/guard.rb +463 -0
- data/lib/guard/cli.rb +125 -0
- data/lib/guard/dsl.rb +370 -0
- data/lib/guard/dsl_describer.rb +150 -0
- data/lib/guard/group.rb +37 -0
- data/lib/guard/guard.rb +129 -0
- data/lib/guard/hook.rb +118 -0
- data/lib/guard/interactor.rb +116 -0
- data/lib/guard/listener.rb +351 -0
- data/lib/guard/listeners/darwin.rb +60 -0
- data/lib/guard/listeners/linux.rb +91 -0
- data/lib/guard/listeners/polling.rb +55 -0
- data/lib/guard/listeners/windows.rb +61 -0
- data/lib/guard/notifier.rb +290 -0
- data/lib/guard/templates/Guardfile +2 -0
- data/lib/guard/ui.rb +193 -0
- data/lib/guard/version.rb +6 -0
- data/lib/guard/watcher.rb +114 -0
- data/lib/vendor/darwin/Gemfile +6 -0
- data/lib/vendor/darwin/Guardfile +8 -0
- data/lib/vendor/darwin/LICENSE +20 -0
- data/lib/vendor/darwin/README.rdoc +254 -0
- data/lib/vendor/darwin/Rakefile +21 -0
- data/lib/vendor/darwin/ext/extconf.rb +61 -0
- data/lib/vendor/darwin/ext/fsevent/fsevent_watch.c +226 -0
- data/lib/vendor/darwin/lib/rb-fsevent.rb +2 -0
- data/lib/vendor/darwin/lib/rb-fsevent/fsevent.rb +105 -0
- data/lib/vendor/darwin/lib/rb-fsevent/version.rb +3 -0
- data/lib/vendor/darwin/rb-fsevent.gemspec +24 -0
- data/lib/vendor/darwin/spec/fixtures/folder1/file1.txt +0 -0
- data/lib/vendor/darwin/spec/fixtures/folder1/folder2/file2.txt +0 -0
- data/lib/vendor/darwin/spec/rb-fsevent/fsevent_spec.rb +75 -0
- data/lib/vendor/darwin/spec/spec_helper.rb +24 -0
- data/lib/vendor/linux/MIT-LICENSE +20 -0
- data/lib/vendor/linux/README.md +66 -0
- data/lib/vendor/linux/Rakefile +54 -0
- data/lib/vendor/linux/VERSION +1 -0
- data/lib/vendor/linux/lib/rb-inotify.rb +17 -0
- data/lib/vendor/linux/lib/rb-inotify/event.rb +139 -0
- data/lib/vendor/linux/lib/rb-inotify/native.rb +31 -0
- data/lib/vendor/linux/lib/rb-inotify/native/flags.rb +89 -0
- data/lib/vendor/linux/lib/rb-inotify/notifier.rb +308 -0
- data/lib/vendor/linux/lib/rb-inotify/watcher.rb +83 -0
- data/lib/vendor/linux/rb-inotify.gemspec +53 -0
- data/lib/vendor/windows/Gemfile +4 -0
- data/lib/vendor/windows/README.md +34 -0
- data/lib/vendor/windows/Rakefile +18 -0
- data/lib/vendor/windows/lib/rb-fchange.rb +14 -0
- data/lib/vendor/windows/lib/rb-fchange/event.rb +29 -0
- data/lib/vendor/windows/lib/rb-fchange/native.rb +45 -0
- data/lib/vendor/windows/lib/rb-fchange/native/flags.rb +78 -0
- data/lib/vendor/windows/lib/rb-fchange/notifier.rb +149 -0
- data/lib/vendor/windows/lib/rb-fchange/version.rb +3 -0
- data/lib/vendor/windows/lib/rb-fchange/watcher.rb +99 -0
- data/lib/vendor/windows/rb-fchange.gemspec +34 -0
- data/lib/vendor/windows/spec/fixtures/folder1/file1.txt +0 -0
- data/lib/vendor/windows/spec/fixtures/folder1/folder2/file2.txt +0 -0
- data/lib/vendor/windows/spec/rb-fchange/fchange_spec.rb +119 -0
- data/lib/vendor/windows/spec/spec_helper.rb +21 -0
- data/man/guard.1 +96 -0
- data/man/guard.1.html +181 -0
- metadata +193 -0
@@ -0,0 +1,83 @@
|
|
1
|
+
module INotify
|
2
|
+
# Watchers monitor a single path for changes,
|
3
|
+
# specified by {INotify::Notifier#watch event flags}.
|
4
|
+
# A watcher is usually created via \{Notifier#watch}.
|
5
|
+
#
|
6
|
+
# One {Notifier} may have many {Watcher}s.
|
7
|
+
# The Notifier actually takes care of the checking for events,
|
8
|
+
# via \{Notifier#run #run} or \{Notifier#process #process}.
|
9
|
+
# The main purpose of having Watcher objects
|
10
|
+
# is to be able to disable them using \{#close}.
|
11
|
+
class Watcher
|
12
|
+
# The {Notifier} that this Watcher belongs to.
|
13
|
+
#
|
14
|
+
# @return [Notifier]
|
15
|
+
attr_reader :notifier
|
16
|
+
|
17
|
+
# The path that this Watcher is watching.
|
18
|
+
#
|
19
|
+
# @return [String]
|
20
|
+
attr_reader :path
|
21
|
+
|
22
|
+
# The {INotify::Notifier#watch flags}
|
23
|
+
# specifying the events that this Watcher is watching for,
|
24
|
+
# and potentially some options as well.
|
25
|
+
#
|
26
|
+
# @return [Array<Symbol>]
|
27
|
+
attr_reader :flags
|
28
|
+
|
29
|
+
# The id for this Watcher.
|
30
|
+
# Used to retrieve this Watcher from {Notifier#watchers}.
|
31
|
+
#
|
32
|
+
# @private
|
33
|
+
# @return [Fixnum]
|
34
|
+
attr_reader :id
|
35
|
+
|
36
|
+
# Calls this Watcher's callback with the given {Event}.
|
37
|
+
#
|
38
|
+
# @private
|
39
|
+
# @param event [Event]
|
40
|
+
def callback!(event)
|
41
|
+
@callback[event]
|
42
|
+
end
|
43
|
+
|
44
|
+
# Disables this Watcher, so that it doesn't fire any more events.
|
45
|
+
#
|
46
|
+
# @raise [SystemCallError] if the watch fails to be disabled for some reason
|
47
|
+
def close
|
48
|
+
return if Native.inotify_rm_watch(@notifier.fd, @id) == 0
|
49
|
+
raise SystemCallError.new("Failed to stop watching #{path.inspect}", FFI.errno)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Creates a new {Watcher}.
|
53
|
+
#
|
54
|
+
# @private
|
55
|
+
# @see Notifier#watch
|
56
|
+
def initialize(notifier, path, *flags, &callback)
|
57
|
+
@notifier = notifier
|
58
|
+
@callback = callback || proc {}
|
59
|
+
@path = path
|
60
|
+
@flags = flags.freeze
|
61
|
+
@id = Native.inotify_add_watch(@notifier.fd, path.dup,
|
62
|
+
Native::Flags.to_mask(flags))
|
63
|
+
|
64
|
+
unless @id < 0
|
65
|
+
@notifier.watchers[@id] = self
|
66
|
+
return
|
67
|
+
end
|
68
|
+
|
69
|
+
raise SystemCallError.new(
|
70
|
+
"Failed to watch #{path.inspect}" +
|
71
|
+
case FFI.errno
|
72
|
+
when Errno::EACCES::Errno; ": read access to the given file is not permitted."
|
73
|
+
when Errno::EBADF::Errno; ": the given file descriptor is not valid."
|
74
|
+
when Errno::EFAULT::Errno; ": path points outside of the process's accessible address space."
|
75
|
+
when Errno::EINVAL::Errno; ": the given event mask contains no legal events; or fd is not an inotify file descriptor."
|
76
|
+
when Errno::ENOMEM::Errno; ": insufficient kernel memory was available."
|
77
|
+
when Errno::ENOSPC::Errno; ": The user limit on the total number of inotify watches was reached or the kernel failed to allocate a needed resource."
|
78
|
+
else; ""
|
79
|
+
end,
|
80
|
+
FFI.errno)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{rb-inotify}
|
8
|
+
s.version = "0.8.8"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Nathan Weizenbaum"]
|
12
|
+
s.date = %q{2011-09-27}
|
13
|
+
s.description = %q{A Ruby wrapper for Linux's inotify, using FFI}
|
14
|
+
s.email = %q{nex342@gmail.com}
|
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}
|
36
|
+
|
37
|
+
if s.respond_to? :specification_version then
|
38
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
39
|
+
s.specification_version = 3
|
40
|
+
|
41
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
42
|
+
s.add_runtime_dependency(%q<ffi>, [">= 0.5.0"])
|
43
|
+
s.add_development_dependency(%q<yard>, [">= 0.4.0"])
|
44
|
+
else
|
45
|
+
s.add_dependency(%q<ffi>, [">= 0.5.0"])
|
46
|
+
s.add_dependency(%q<yard>, [">= 0.4.0"])
|
47
|
+
end
|
48
|
+
else
|
49
|
+
s.add_dependency(%q<ffi>, [">= 0.5.0"])
|
50
|
+
s.add_dependency(%q<yard>, [">= 0.4.0"])
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# rb-fchange
|
2
|
+
|
3
|
+
Code is working. But there is still a lot of work.
|
4
|
+
This is a simple wrapper over the Windows Kernel functions for monitoring the specified directory or subtree.
|
5
|
+
Tested on:
|
6
|
+
|
7
|
+
- jruby 1.6.1 (ruby-1.8.7-p330) (2011-04-12 85838f6)
|
8
|
+
- ruby 1.8.7 (2011-02-18 patchlevel 334) [i386-ingw32]
|
9
|
+
- ruby 1.9.2p180 (2011-02-18) [i386-mingw32]
|
10
|
+
|
11
|
+
Example
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
require 'rb-fchange'
|
15
|
+
|
16
|
+
notifier = FChange::Notifier.new
|
17
|
+
notifier.watch("test", :all_events, :recursive) do |event|
|
18
|
+
p Time.now.utc
|
19
|
+
end
|
20
|
+
|
21
|
+
Signal.trap('INT') do
|
22
|
+
p "Bye bye...",
|
23
|
+
notifier.stop
|
24
|
+
abort("\n")
|
25
|
+
end
|
26
|
+
|
27
|
+
notifier.run
|
28
|
+
```
|
29
|
+
|
30
|
+
## TODO
|
31
|
+
|
32
|
+
- add latency setting with 0.5 default
|
33
|
+
- rework interface (should more look like rb-fsevent)
|
34
|
+
- add none-ANSI path support
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
Bundler::GemHelper.install_tasks
|
3
|
+
|
4
|
+
require 'rspec/core/rake_task'
|
5
|
+
RSpec::Core::RakeTask.new(:spec)
|
6
|
+
task :default => :spec
|
7
|
+
|
8
|
+
namespace(:spec) do
|
9
|
+
desc "Run all specs on multiple ruby versions (requires pik)"
|
10
|
+
task(:portability) do
|
11
|
+
%w[187 192 161].each do |version|
|
12
|
+
system("echo -----------#{version}------------")
|
13
|
+
system("pik use #{version}")
|
14
|
+
system("bundle install")
|
15
|
+
system("rake spec")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require "rb-fchange/native"
|
2
|
+
require "rb-fchange/native/flags"
|
3
|
+
require "rb-fchange/notifier"
|
4
|
+
require "rb-fchange/watcher"
|
5
|
+
require "rb-fchange/event"
|
6
|
+
|
7
|
+
# The root module of the library, which is laid out as so:
|
8
|
+
#
|
9
|
+
# * {Notifier} -- The main class, where the notifications are set up
|
10
|
+
# * {Watcher} -- A watcher for a single file or directory
|
11
|
+
# * {Event} -- An filesystem event notification
|
12
|
+
module FChange
|
13
|
+
|
14
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module FChange
|
2
|
+
# An event caused by a change on the filesystem.
|
3
|
+
# Each {Watcher} can fire many events,
|
4
|
+
# which are passed to that watcher's callback.
|
5
|
+
class Event
|
6
|
+
# The {Watcher} that fired this event.
|
7
|
+
#
|
8
|
+
# @return [Watcher]
|
9
|
+
attr_reader :watcher
|
10
|
+
|
11
|
+
# Creates an event from a string of binary data.
|
12
|
+
# Differs from {Event.consume} in that it doesn't modify the string.
|
13
|
+
#
|
14
|
+
# @private
|
15
|
+
# @param watcher [Watcher] The {Watcher} that fired the event
|
16
|
+
def initialize(watcher)
|
17
|
+
@watcher = watcher
|
18
|
+
end
|
19
|
+
|
20
|
+
# Calls the callback of the watcher that fired this event,
|
21
|
+
# passing in the event itself.
|
22
|
+
#
|
23
|
+
# @private
|
24
|
+
def callback!
|
25
|
+
@watcher.callback!(self)
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'ffi'
|
2
|
+
|
3
|
+
module FChange
|
4
|
+
# This module contains the low-level foreign-function.
|
5
|
+
# It's an implementation detail, and not meant for users to deal with.
|
6
|
+
#
|
7
|
+
# @private
|
8
|
+
module Native
|
9
|
+
extend FFI::Library
|
10
|
+
ffi_lib 'kernel32'
|
11
|
+
ffi_convention :stdcall
|
12
|
+
|
13
|
+
# HANDLE FindFirstChangeNotification(
|
14
|
+
# LPCTSTR lpPathName, // directory name
|
15
|
+
# BOOL bWatchSubtree, // monitoring option
|
16
|
+
# DWORD dwNotifyFilter // filter conditions
|
17
|
+
#);
|
18
|
+
attach_function :FindFirstChangeNotificationW, [:pointer, :int, :long], :long
|
19
|
+
|
20
|
+
# HANDLE FindFirstChangeNotification(
|
21
|
+
# LPCTSTR lpPathName, // directory name
|
22
|
+
# BOOL bWatchSubtree, // monitoring option
|
23
|
+
# DWORD dwNotifyFilter // filter conditions
|
24
|
+
#);
|
25
|
+
attach_function :FindFirstChangeNotificationA, [:pointer, :int, :long], :long
|
26
|
+
|
27
|
+
# BOOL FindNextChangeNotification(
|
28
|
+
# HANDLE hChangeHandle // handle to change notification
|
29
|
+
# );
|
30
|
+
attach_function :FindNextChangeNotification, [:long], :int
|
31
|
+
|
32
|
+
# DAORD WaitForMultipleObjects(
|
33
|
+
# DWORD nCount, // number of handles in array
|
34
|
+
# CONST HANDLE *lpHandles, // object-handle array
|
35
|
+
# BOOL bWaitAll, // wait option
|
36
|
+
# DWORD dwMilliseconds // time-out interval
|
37
|
+
# );
|
38
|
+
attach_function :WaitForMultipleObjects, [:long, :pointer, :int, :long], :long
|
39
|
+
|
40
|
+
# BOOL FindCloseChangeNotification(
|
41
|
+
# HANDLE hChangeHandle
|
42
|
+
# );
|
43
|
+
attach_function :FindCloseChangeNotification, [:long], :int
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module FChange
|
2
|
+
module Native
|
3
|
+
# A module containing all the flags to be passed to {Notifier#watch}.
|
4
|
+
# @see http://msdn.microsoft.com/en-us/library/aa364417(v=VS.85).aspx
|
5
|
+
#
|
6
|
+
# @private
|
7
|
+
module Flags
|
8
|
+
|
9
|
+
# Any file name change in the watched directory or subtree causes a change
|
10
|
+
# notification wait operation to return. Changes include renaming,
|
11
|
+
# creating, or deleting a file name.
|
12
|
+
FILE_NOTIFY_CHANGE_FILE_NAME = 0x00000001
|
13
|
+
|
14
|
+
# Any directory-name change in the watched directory or subtree causes a
|
15
|
+
# change notification wait operation to return. Changes include creating
|
16
|
+
# or deleting a directory.
|
17
|
+
FILE_NOTIFY_CHANGE_DIR_NAME = 0x00000002
|
18
|
+
|
19
|
+
# Any attribute change in the watched directory or subtree causes a change
|
20
|
+
# notification wait operation to return.
|
21
|
+
FILE_NOTIFY_CHANGE_ATTRIBUTES = 0x00000004
|
22
|
+
|
23
|
+
# Any file-size change in the watched directory or subtree causes a change
|
24
|
+
# notification wait operation to return. The operating system detects a
|
25
|
+
# change in file size only when the file is written to the disk.
|
26
|
+
# For operating systems that use extensive caching, detection occurs only
|
27
|
+
# when the cache is sufficiently flushed.
|
28
|
+
FILE_NOTIFY_CHANGE_SIZE = 0x00000008
|
29
|
+
|
30
|
+
# Any change to the last write-time of files in the watched directory or
|
31
|
+
# subtree causes a change notification wait operation to return.
|
32
|
+
# The operating system detects a change to the last write-time only when
|
33
|
+
# the file is written to the disk. For operating systems that use
|
34
|
+
# extensive caching, detection occurs only when the cache is sufficiently
|
35
|
+
# flushed
|
36
|
+
FILE_NOTIFY_CHANGE_LAST_WRITE = 0x00000010
|
37
|
+
|
38
|
+
# Any change to the last access time of files in the watched directory or
|
39
|
+
# subtree causes a change notification wait operation to return.
|
40
|
+
FILE_NOTIFY_CHANGE_LAST_ACCESS = 0x00000020
|
41
|
+
|
42
|
+
# Any change to the creation time of files in the watched directory or
|
43
|
+
# subtree causes a change notification wait operation to return.
|
44
|
+
FILE_NOTIFY_CHANGE_CREATION = 0x00000040
|
45
|
+
|
46
|
+
# Any security-descriptor change in the watched directory or subtree
|
47
|
+
# causes a change notification wait operation to return.
|
48
|
+
FILE_NOTIFY_CHANGE_SECURITY = 0x00000100
|
49
|
+
|
50
|
+
FILE_NOTIFY_CHANGE_ALL_EVENTS = (
|
51
|
+
FILE_NOTIFY_CHANGE_DIR_NAME |
|
52
|
+
FILE_NOTIFY_CHANGE_FILE_NAME |
|
53
|
+
FILE_NOTIFY_CHANGE_LAST_WRITE
|
54
|
+
)
|
55
|
+
|
56
|
+
# Converts a list of flags to the bitmask that the C API expects.
|
57
|
+
#
|
58
|
+
# @param flags [Array<Symbol>]
|
59
|
+
# @return [Fixnum]
|
60
|
+
def self.to_mask(flags)
|
61
|
+
flags.map {|flag| const_get("FILE_NOTIFY_CHANGE_#{flag.to_s.upcase}")}.
|
62
|
+
inject(0) {|mask, flag| mask | flag}
|
63
|
+
end
|
64
|
+
|
65
|
+
# Converts a bitmask from the C API into a list of flags.
|
66
|
+
#
|
67
|
+
# @param mask [Fixnum]
|
68
|
+
# @return [Array<Symbol>]
|
69
|
+
def self.from_mask(mask)
|
70
|
+
constants.map {|c| c.to_s}.select do |c|
|
71
|
+
next false unless c =~ /^FILE_NOTIFY_CHANGE_/
|
72
|
+
const_get(c) & mask != 0
|
73
|
+
end.map {|c| c.sub("FILE_NOTIFY_CHANGE_", "").downcase.to_sym} - [:all_events]
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,149 @@
|
|
1
|
+
module FChange
|
2
|
+
# Notifier wraps a single instance of FChange.
|
3
|
+
# It's possible to have more than one instance,
|
4
|
+
# but usually unnecessary.
|
5
|
+
#
|
6
|
+
# @example
|
7
|
+
# # Create the notifier
|
8
|
+
# notifier = FChange::Notifier.new
|
9
|
+
#
|
10
|
+
# # Run this callback whenever the file path/to/foo.txt is read
|
11
|
+
# notifier.watch("path/to/foo/", :all_events) do
|
12
|
+
# puts "foo was accessed!"
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# # Nothing happens until you run the notifier!
|
16
|
+
# notifier.run
|
17
|
+
class Notifier
|
18
|
+
|
19
|
+
#
|
20
|
+
INFINITE = 0xFFFFFFFF
|
21
|
+
|
22
|
+
#
|
23
|
+
WAIT_OBJECT_0 = 0x00000000
|
24
|
+
|
25
|
+
# A hash from {Watcher} ids to the instances themselves.
|
26
|
+
#
|
27
|
+
# @private
|
28
|
+
# @return [{Fixnum => Watcher}]
|
29
|
+
attr_reader :watchers
|
30
|
+
|
31
|
+
attr_reader :dwChangeHandles
|
32
|
+
attr_reader :lp_dwChangeHandles
|
33
|
+
|
34
|
+
# Creates a new {Notifier}.
|
35
|
+
#
|
36
|
+
# @return [Notifier]
|
37
|
+
def initialize
|
38
|
+
@watchers = {}
|
39
|
+
@dwChangeHandles = []
|
40
|
+
@lp_dwChangeHandles = 0
|
41
|
+
end
|
42
|
+
|
43
|
+
# Adds a new {Watcher} to the queue.
|
44
|
+
def add_watcher(watcher)
|
45
|
+
|
46
|
+
@watchers[watcher.id] = watcher
|
47
|
+
|
48
|
+
@dwChangeHandles.push watcher.id
|
49
|
+
|
50
|
+
# Pack event handles into newly created storage area
|
51
|
+
# to be used for Win32 call
|
52
|
+
@lp_dwChangeHandles = dwChangeHandles.pack("L" * dwChangeHandles.count)
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
# Watches a file or directory for changes,
|
57
|
+
# calling the callback when there are.
|
58
|
+
# This is only activated once \{#process} or \{#run} is called.
|
59
|
+
#
|
60
|
+
# **Note that by default, this does not recursively watch subdirectories
|
61
|
+
# of the watched directory**.
|
62
|
+
# To do so, use the `:recursive` flag.
|
63
|
+
#
|
64
|
+
# `:recursive`
|
65
|
+
# : Recursively watch any subdirectories that are created.
|
66
|
+
#
|
67
|
+
# @param path [String] The path to the file or directory
|
68
|
+
# @param flags [Array<Symbol>] Which events to watch for
|
69
|
+
# @yield [event] A block that will be called
|
70
|
+
# whenever one of the specified events occur
|
71
|
+
# @yieldparam event [Event] The Event object containing information
|
72
|
+
# about the event that occured
|
73
|
+
# @return [Watcher] A Watcher set up to watch this path for these events
|
74
|
+
# @raise [SystemCallError] if the file or directory can't be watched,
|
75
|
+
# e.g. if the file isn't found, read access is denied,
|
76
|
+
# or the flags don't contain any events
|
77
|
+
def watch(path, *flags, &callback)
|
78
|
+
recursive = flags.include?(:recursive)
|
79
|
+
#:latency = 0.5
|
80
|
+
flags = flags - [:recursive]
|
81
|
+
if flags.empty?
|
82
|
+
@flags = [:all_events]
|
83
|
+
else
|
84
|
+
@flags = flags.freeze
|
85
|
+
end
|
86
|
+
Watcher.new(self, path, recursive, *@flags, &callback)
|
87
|
+
end
|
88
|
+
|
89
|
+
# Starts the notifier watching for filesystem events.
|
90
|
+
# Blocks until \{#stop} is called.
|
91
|
+
#
|
92
|
+
# @see #process
|
93
|
+
def run
|
94
|
+
@stop = false
|
95
|
+
process until @stop
|
96
|
+
end
|
97
|
+
|
98
|
+
# Stop watching for filesystem events.
|
99
|
+
# That is, if we're in a \{#run} loop,
|
100
|
+
# exit out as soon as we finish handling the events.
|
101
|
+
def stop
|
102
|
+
@stop = true
|
103
|
+
end
|
104
|
+
|
105
|
+
# Blocks until there are one or more filesystem events
|
106
|
+
# that this notifier has watchers registered for.
|
107
|
+
# Once there are events, the appropriate callbacks are called
|
108
|
+
# and this function returns.
|
109
|
+
#
|
110
|
+
# @see #run
|
111
|
+
def process
|
112
|
+
read_events.each {|event| event.callback!}
|
113
|
+
end
|
114
|
+
|
115
|
+
# Blocks until there are one or more filesystem events
|
116
|
+
# that this notifier has watchers registered for.
|
117
|
+
# Once there are events, returns their {Event} objects.
|
118
|
+
#
|
119
|
+
# @private
|
120
|
+
def read_events
|
121
|
+
|
122
|
+
# can return WAIT_TIMEOUT = 0x00000102
|
123
|
+
dwWaitStatus = Native.WaitForMultipleObjects(@dwChangeHandles.count,
|
124
|
+
@lp_dwChangeHandles, 0, 500)
|
125
|
+
|
126
|
+
events = []
|
127
|
+
|
128
|
+
# this call blocks all threads completely.
|
129
|
+
@dwChangeHandles.each_index do |index|
|
130
|
+
if dwWaitStatus == WAIT_OBJECT_0 + index
|
131
|
+
|
132
|
+
ev = Event.new(@watchers[@dwChangeHandles[index]])
|
133
|
+
events << ev
|
134
|
+
|
135
|
+
r = Native.FindNextChangeNotification(@dwChangeHandles[index])
|
136
|
+
if r == 0
|
137
|
+
raise SystemCallError.new("Failed to watch", r)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
events
|
142
|
+
end
|
143
|
+
|
144
|
+
def close
|
145
|
+
|
146
|
+
end
|
147
|
+
|
148
|
+
end
|
149
|
+
end
|