joshbuddy-guard 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. data/CHANGELOG.md +370 -0
  2. data/LICENSE +20 -0
  3. data/README.md +470 -0
  4. data/bin/fsevent_watch_guard +0 -0
  5. data/bin/guard +6 -0
  6. data/images/failed.png +0 -0
  7. data/images/pending.png +0 -0
  8. data/images/success.png +0 -0
  9. data/lib/guard.rb +463 -0
  10. data/lib/guard/cli.rb +125 -0
  11. data/lib/guard/dsl.rb +370 -0
  12. data/lib/guard/dsl_describer.rb +150 -0
  13. data/lib/guard/group.rb +37 -0
  14. data/lib/guard/guard.rb +129 -0
  15. data/lib/guard/hook.rb +118 -0
  16. data/lib/guard/interactor.rb +116 -0
  17. data/lib/guard/listener.rb +351 -0
  18. data/lib/guard/listeners/darwin.rb +60 -0
  19. data/lib/guard/listeners/linux.rb +91 -0
  20. data/lib/guard/listeners/polling.rb +55 -0
  21. data/lib/guard/listeners/windows.rb +61 -0
  22. data/lib/guard/notifier.rb +290 -0
  23. data/lib/guard/templates/Guardfile +2 -0
  24. data/lib/guard/ui.rb +193 -0
  25. data/lib/guard/version.rb +6 -0
  26. data/lib/guard/watcher.rb +114 -0
  27. data/lib/vendor/darwin/Gemfile +6 -0
  28. data/lib/vendor/darwin/Guardfile +8 -0
  29. data/lib/vendor/darwin/LICENSE +20 -0
  30. data/lib/vendor/darwin/README.rdoc +254 -0
  31. data/lib/vendor/darwin/Rakefile +21 -0
  32. data/lib/vendor/darwin/ext/extconf.rb +61 -0
  33. data/lib/vendor/darwin/ext/fsevent/fsevent_watch.c +226 -0
  34. data/lib/vendor/darwin/lib/rb-fsevent.rb +2 -0
  35. data/lib/vendor/darwin/lib/rb-fsevent/fsevent.rb +105 -0
  36. data/lib/vendor/darwin/lib/rb-fsevent/version.rb +3 -0
  37. data/lib/vendor/darwin/rb-fsevent.gemspec +24 -0
  38. data/lib/vendor/darwin/spec/fixtures/folder1/file1.txt +0 -0
  39. data/lib/vendor/darwin/spec/fixtures/folder1/folder2/file2.txt +0 -0
  40. data/lib/vendor/darwin/spec/rb-fsevent/fsevent_spec.rb +75 -0
  41. data/lib/vendor/darwin/spec/spec_helper.rb +24 -0
  42. data/lib/vendor/linux/MIT-LICENSE +20 -0
  43. data/lib/vendor/linux/README.md +66 -0
  44. data/lib/vendor/linux/Rakefile +54 -0
  45. data/lib/vendor/linux/VERSION +1 -0
  46. data/lib/vendor/linux/lib/rb-inotify.rb +17 -0
  47. data/lib/vendor/linux/lib/rb-inotify/event.rb +139 -0
  48. data/lib/vendor/linux/lib/rb-inotify/native.rb +31 -0
  49. data/lib/vendor/linux/lib/rb-inotify/native/flags.rb +89 -0
  50. data/lib/vendor/linux/lib/rb-inotify/notifier.rb +308 -0
  51. data/lib/vendor/linux/lib/rb-inotify/watcher.rb +83 -0
  52. data/lib/vendor/linux/rb-inotify.gemspec +53 -0
  53. data/lib/vendor/windows/Gemfile +4 -0
  54. data/lib/vendor/windows/README.md +34 -0
  55. data/lib/vendor/windows/Rakefile +18 -0
  56. data/lib/vendor/windows/lib/rb-fchange.rb +14 -0
  57. data/lib/vendor/windows/lib/rb-fchange/event.rb +29 -0
  58. data/lib/vendor/windows/lib/rb-fchange/native.rb +45 -0
  59. data/lib/vendor/windows/lib/rb-fchange/native/flags.rb +78 -0
  60. data/lib/vendor/windows/lib/rb-fchange/notifier.rb +149 -0
  61. data/lib/vendor/windows/lib/rb-fchange/version.rb +3 -0
  62. data/lib/vendor/windows/lib/rb-fchange/watcher.rb +99 -0
  63. data/lib/vendor/windows/rb-fchange.gemspec +34 -0
  64. data/lib/vendor/windows/spec/fixtures/folder1/file1.txt +0 -0
  65. data/lib/vendor/windows/spec/fixtures/folder1/folder2/file2.txt +0 -0
  66. data/lib/vendor/windows/spec/rb-fchange/fchange_spec.rb +119 -0
  67. data/lib/vendor/windows/spec/spec_helper.rb +21 -0
  68. data/man/guard.1 +96 -0
  69. data/man/guard.1.html +181 -0
  70. 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,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in rb-fchange.gemspec
4
+ gemspec
@@ -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