joshbuddy-guard 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- 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,114 @@
|
|
1
|
+
module Guard
|
2
|
+
|
3
|
+
# The watcher defines a RegExp that will be matched against file system modifications.
|
4
|
+
# When a watcher matches a change, an optional action block is executed to enable
|
5
|
+
# processing the file system change result.
|
6
|
+
#
|
7
|
+
class Watcher
|
8
|
+
|
9
|
+
attr_accessor :pattern, :action
|
10
|
+
|
11
|
+
# Initialize a file watcher.
|
12
|
+
#
|
13
|
+
# @param [String, Regexp] pattern the pattern to be watched by the guard
|
14
|
+
# @param [Block] action the action to execute before passing the result to the Guard
|
15
|
+
#
|
16
|
+
def initialize(pattern, action = nil)
|
17
|
+
@pattern, @action = pattern, action
|
18
|
+
@@warning_printed ||= false
|
19
|
+
|
20
|
+
# deprecation warning
|
21
|
+
if @pattern.is_a?(String) && @pattern =~ /(^(\^))|(>?(\\\.)|(\.\*))|(\(.*\))|(\[.*\])|(\$$)/
|
22
|
+
unless @@warning_printed
|
23
|
+
UI.info "*"*20 + "\nDEPRECATION WARNING!\n" + "*"*20
|
24
|
+
UI.info <<-MSG
|
25
|
+
You have a string in your Guardfile watch patterns that seem to represent a Regexp.
|
26
|
+
Guard matches String with == and Regexp with Regexp#match.
|
27
|
+
You should either use plain String (without Regexp special characters) or real Regexp.
|
28
|
+
MSG
|
29
|
+
@@warning_printed = true
|
30
|
+
end
|
31
|
+
|
32
|
+
UI.info "\"#{@pattern}\" has been converted to #{ Regexp.new(@pattern).inspect }\n"
|
33
|
+
@pattern = Regexp.new(@pattern)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Finds the files that matches a Guard.
|
38
|
+
#
|
39
|
+
# @param [Guard::Guard] guard the guard which watchers are used
|
40
|
+
# @param [Array<String>] files the changed files
|
41
|
+
# @return [Array<Object>] the matched watcher response
|
42
|
+
#
|
43
|
+
def self.match_files(guard, files)
|
44
|
+
guard.watchers.inject([]) do |paths, watcher|
|
45
|
+
files.each do |file|
|
46
|
+
if matches = watcher.match_file?(file)
|
47
|
+
if watcher.action
|
48
|
+
result = watcher.call_action(matches)
|
49
|
+
if guard.options[:any_return]
|
50
|
+
paths << result
|
51
|
+
elsif result.respond_to?(:empty?) && !result.empty?
|
52
|
+
paths << Array(result)
|
53
|
+
end
|
54
|
+
else
|
55
|
+
paths << matches[0]
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
guard.options[:any_return] ? paths : paths.flatten.map { |p| p.to_s }
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# Test if a file would be matched by any of the Guards watchers.
|
65
|
+
#
|
66
|
+
# @param [Array<Guard::Guard>] guards the guards to use the watchers from
|
67
|
+
# @param [Array<String>] files the files to test
|
68
|
+
# @return [Boolean] Whether a file matches
|
69
|
+
#
|
70
|
+
def self.match_files?(guards, files)
|
71
|
+
guards.any? do |guard|
|
72
|
+
guard.watchers.any? do |watcher|
|
73
|
+
files.any? { |file| watcher.match_file?(file) }
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# Test the watchers pattern against a file.
|
79
|
+
#
|
80
|
+
# @param [String] file the file to test
|
81
|
+
# @return [Boolean] whether the given file is matched
|
82
|
+
#
|
83
|
+
def match_file?(file)
|
84
|
+
if @pattern.is_a?(Regexp)
|
85
|
+
file.match(@pattern)
|
86
|
+
else
|
87
|
+
file == @pattern ? [file] : nil
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# Test if any of the files is the Guardfile.
|
92
|
+
#
|
93
|
+
# @param [Array<String>] the files to test
|
94
|
+
# @return [Boolean] whether one of these files is the Guardfile
|
95
|
+
#
|
96
|
+
def self.match_guardfile?(files)
|
97
|
+
files.any? { |file| "#{ Dir.pwd }/#{ file }" == Dsl.guardfile_path }
|
98
|
+
end
|
99
|
+
|
100
|
+
# Executes a watcher action.
|
101
|
+
#
|
102
|
+
# @param [String, MatchData] the matched path or the match from the Regex
|
103
|
+
# @return [String] the final paths
|
104
|
+
#
|
105
|
+
def call_action(matches)
|
106
|
+
begin
|
107
|
+
@action.arity > 0 ? @action.call(matches) : @action.call
|
108
|
+
rescue Exception => e
|
109
|
+
UI.error "Problem with watch action!\n#{ e.message }\n\n#{ e.backtrace.join("\n") }"
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Thibaud Guillaume-Gentil
|
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.
|
@@ -0,0 +1,254 @@
|
|
1
|
+
= rb-fsevent
|
2
|
+
|
3
|
+
Very simple & usable Mac OSX FSEvents API
|
4
|
+
|
5
|
+
- RubyCocoa not required!
|
6
|
+
- Signals are working (really)
|
7
|
+
- Tested on MRI 1.8.7 & 1.9.2
|
8
|
+
- Tested on JRuby 1.6.3
|
9
|
+
|
10
|
+
== Install
|
11
|
+
|
12
|
+
gem install rb-fsevent
|
13
|
+
|
14
|
+
== Usage
|
15
|
+
|
16
|
+
=== Singular path
|
17
|
+
|
18
|
+
require 'rb-fsevent'
|
19
|
+
|
20
|
+
fsevent = FSEvent.new
|
21
|
+
fsevent.watch Dir.pwd do |directories|
|
22
|
+
puts "Detected change inside: #{directories.inspect}"
|
23
|
+
end
|
24
|
+
fsevent.run
|
25
|
+
|
26
|
+
=== Multiple paths
|
27
|
+
|
28
|
+
require 'rb-fsevent'
|
29
|
+
|
30
|
+
paths = ['/tmp/path/one', '/tmp/path/two', Dir.pwd]
|
31
|
+
|
32
|
+
fsevent = FSEvent.new
|
33
|
+
fsevent.watch paths do |directories|
|
34
|
+
puts "Detected change inside: #{directories.inspect}"
|
35
|
+
end
|
36
|
+
fsevent.run
|
37
|
+
|
38
|
+
=== Multiple paths and additional options as a Hash
|
39
|
+
|
40
|
+
require 'rb-fsevent'
|
41
|
+
|
42
|
+
paths = ['/tmp/path/one', '/tmp/path/two', Dir.pwd]
|
43
|
+
options = {:latency => 1.5, :no_defer => true }
|
44
|
+
|
45
|
+
fsevent = FSEvent.new
|
46
|
+
fsevent.watch paths, options do |directories|
|
47
|
+
puts "Detected change inside: #{directories.inspect}"
|
48
|
+
end
|
49
|
+
fsevent.run
|
50
|
+
|
51
|
+
=== Multiple paths and additional options as an Array
|
52
|
+
|
53
|
+
require 'rb-fsevent'
|
54
|
+
|
55
|
+
paths = ['/tmp/path/one', '/tmp/path/two', Dir.pwd]
|
56
|
+
options = ['--latency', 1.5, '--no-defer']
|
57
|
+
|
58
|
+
fsevent = FSEvent.new
|
59
|
+
fsevent.watch paths, options do |directories|
|
60
|
+
puts "Detected change inside: #{directories.inspect}"
|
61
|
+
end
|
62
|
+
fsevent.run
|
63
|
+
|
64
|
+
== Options
|
65
|
+
|
66
|
+
When defining options using a hash or hash-like object, it gets checked for validity and converted to the appropriate fsevent_watch commandline arguments array when the FSEvent class is instantiated. This is obviously the safest and preferred method of passing in options.
|
67
|
+
|
68
|
+
You may, however, choose to pass in an array of commandline arguments as your options value and it will be passed on, unmodified, to the fsevent_watch binary when called.
|
69
|
+
|
70
|
+
So far, the following options are supported...
|
71
|
+
|
72
|
+
- :latency => 0.5 # in seconds
|
73
|
+
- :no_defer => true
|
74
|
+
- :watch_root => true
|
75
|
+
- :since_when => 18446744073709551615 # an FSEventStreamEventId
|
76
|
+
|
77
|
+
=== Latency
|
78
|
+
|
79
|
+
The :latency parameter determines how long the service should wait after the first event before passing that information along to the client. If your latency is set to 4 seconds, and 300 changes occur in the first three, then the callback will be fired only once. If latency is set to 0.1 in the exact same scenario, you will see that callback fire somewhere closer to between 25 and 30 times.
|
80
|
+
|
81
|
+
Setting a higher latency value allows for more effective temporal coalescing, resulting in fewer callbacks and greater overall efficiency... at the cost of apparent responsiveness. Setting this to a reasonably high value (and NOT setting :no_defer) is particularly well suited for background, daemon, or batch processing applications.
|
82
|
+
|
83
|
+
Implementation note: It appears that FSEvents will only coalesce events from a maximum of 32 distinct subpaths, making the above completely accurate only when events are to fewer than 32 subpaths. Creating 300 files in one directory, for example, or 30 files in 10 subdirectories, but not 300 files within 300 subdirectories. In the latter case, you may receive 31 callbacks in one go after the latency period. As this appears to be an implementation detail, the number could potentially differ across OS revisions. It is entirely possible that this number is somehow configurable, but I have not yet discovered an accepted method of doing so.
|
84
|
+
|
85
|
+
=== NoDefer
|
86
|
+
|
87
|
+
The :no_defer option changes the behavior of the latency parameter completely. Rather than waiting for $latency period of time before sending along events in an attempt to coalesce a potential deluge ahead of time, that first event is sent along to the client immediately and is followed by a $latency period of silence before sending along any additional events that occurred within that period.
|
88
|
+
|
89
|
+
This behavior is particularly useful for interactive applications where that feeling of apparent responsiveness is most important, but you still don't want to get overwhelmed by a series of events that occur in rapid succession.
|
90
|
+
|
91
|
+
=== WatchRoot
|
92
|
+
|
93
|
+
The :watch_root option allows for catching the scenario where you start watching "~/src/demo_project" and either it is later renamed to "~/src/awesome_sauce_3000" or the path changes in such a manner that the original directory is now at "~/clients/foo/iteration4/demo_project".
|
94
|
+
|
95
|
+
Unfortunately, while this behavior is somewhat supported in the fsevent_watch binary built as part of this project, support for passing across detailed metadata is not (yet). As a result, you would not receive the appropriate RootChanged event and be able to react appropriately. Also, since the C code doesn't open watched directories and retain that file descriptor as part of path-specific callback metadata, we are unable to issue an F_GETPATH fcntl() to determine the directory's new path.
|
96
|
+
|
97
|
+
Please do not use this option until proper support is added in an upcoming (planned) release.
|
98
|
+
|
99
|
+
=== SinceWhen
|
100
|
+
|
101
|
+
The FSEventStreamEventId passed in to :since_when is used as a base for reacting to historic events. Unfortunately, not only is the metadata for transitioning from historic to live events not currently passed along, but it is incorrectly passed as a change event on the root path, and only per-host event streams are currently supported. When using per-host event streams, the event IDs are not guaranteed to be unique or contiguous when shared volumes (firewire/USB/net/etc) are used on multiple macs.
|
102
|
+
|
103
|
+
Please do not use this option until proper support is added in an upcoming (planned) release, unless it's acceptable for you to receive that one fake event that's handled incorrectly when events transition from historical to live. Even in that scenario, there's no metadata available for determining the FSEventStreamEventId of the last received event.
|
104
|
+
|
105
|
+
WARNING: passing in 0 as the parameter to :since_when will return events for every directory modified since "the beginning of time".
|
106
|
+
|
107
|
+
== Debugging output
|
108
|
+
|
109
|
+
If the gem is installed with the environment variable FWDEBUG set to the string "true", then fsevent_watch will be built with its various DEBUG sections defined, and the output to STDERR is truly verbose (and hopefully helpful in debugging your application and not just fsevent_watch itself). If enough people find this to be directly useful when developing code that makes use of rb-fsevent, then it wouldn't be hard to clean this up and make it a feature enabled by a commandline argument instead. Until somebody files an issue, however, I will assume otherwise.
|
110
|
+
|
111
|
+
append_path called for: /tmp/moo/cow/
|
112
|
+
resolved path to: /private/tmp/moo/cow
|
113
|
+
|
114
|
+
config.sinceWhen 18446744073709551615
|
115
|
+
config.latency 0.300000
|
116
|
+
config.flags 00000000
|
117
|
+
config.paths
|
118
|
+
/private/tmp/moo/cow
|
119
|
+
|
120
|
+
FSEventStreamRef @ 0x100108540:
|
121
|
+
allocator = 0x7fff705a4ee0
|
122
|
+
callback = 0x10000151e
|
123
|
+
context = {0, 0x0, 0x0, 0x0, 0x0}
|
124
|
+
numPathsToWatch = 1
|
125
|
+
pathsToWatch = 0x7fff705a4ee0
|
126
|
+
pathsToWatch[0] = '/private/tmp/moo/cow'
|
127
|
+
latestEventId = -1
|
128
|
+
latency = 300000 (microseconds)
|
129
|
+
flags = 0x00000000
|
130
|
+
runLoop = 0x0
|
131
|
+
runLoopMode = 0x0
|
132
|
+
|
133
|
+
|
134
|
+
FSEventStreamCallback fired!
|
135
|
+
numEvents: 32
|
136
|
+
event path: /private/tmp/moo/cow/1/a/
|
137
|
+
event flags: 00000000
|
138
|
+
event ID: 1023767
|
139
|
+
event path: /private/tmp/moo/cow/1/b/
|
140
|
+
event flags: 00000000
|
141
|
+
event ID: 1023782
|
142
|
+
event path: /private/tmp/moo/cow/1/c/
|
143
|
+
event flags: 00000000
|
144
|
+
event ID: 1023797
|
145
|
+
event path: /private/tmp/moo/cow/1/d/
|
146
|
+
event flags: 00000000
|
147
|
+
event ID: 1023812
|
148
|
+
event path: /private/tmp/moo/cow/1/e/
|
149
|
+
event flags: 00000000
|
150
|
+
event ID: 1023827
|
151
|
+
event path: /private/tmp/moo/cow/1/f/
|
152
|
+
event flags: 00000000
|
153
|
+
event ID: 1023842
|
154
|
+
event path: /private/tmp/moo/cow/1/g/
|
155
|
+
event flags: 00000000
|
156
|
+
event ID: 1023857
|
157
|
+
event path: /private/tmp/moo/cow/1/h/
|
158
|
+
event flags: 00000000
|
159
|
+
event ID: 1023872
|
160
|
+
event path: /private/tmp/moo/cow/1/i/
|
161
|
+
event flags: 00000000
|
162
|
+
event ID: 1023887
|
163
|
+
event path: /private/tmp/moo/cow/1/j/
|
164
|
+
event flags: 00000000
|
165
|
+
event ID: 1023902
|
166
|
+
event path: /private/tmp/moo/cow/1/k/
|
167
|
+
event flags: 00000000
|
168
|
+
event ID: 1023917
|
169
|
+
event path: /private/tmp/moo/cow/1/l/
|
170
|
+
event flags: 00000000
|
171
|
+
event ID: 1023932
|
172
|
+
event path: /private/tmp/moo/cow/1/m/
|
173
|
+
event flags: 00000000
|
174
|
+
event ID: 1023947
|
175
|
+
event path: /private/tmp/moo/cow/1/n/
|
176
|
+
event flags: 00000000
|
177
|
+
event ID: 1023962
|
178
|
+
event path: /private/tmp/moo/cow/1/o/
|
179
|
+
event flags: 00000000
|
180
|
+
event ID: 1023977
|
181
|
+
event path: /private/tmp/moo/cow/1/p/
|
182
|
+
event flags: 00000000
|
183
|
+
event ID: 1023992
|
184
|
+
event path: /private/tmp/moo/cow/1/q/
|
185
|
+
event flags: 00000000
|
186
|
+
event ID: 1024007
|
187
|
+
event path: /private/tmp/moo/cow/1/r/
|
188
|
+
event flags: 00000000
|
189
|
+
event ID: 1024022
|
190
|
+
event path: /private/tmp/moo/cow/1/s/
|
191
|
+
event flags: 00000000
|
192
|
+
event ID: 1024037
|
193
|
+
event path: /private/tmp/moo/cow/1/t/
|
194
|
+
event flags: 00000000
|
195
|
+
event ID: 1024052
|
196
|
+
event path: /private/tmp/moo/cow/1/u/
|
197
|
+
event flags: 00000000
|
198
|
+
event ID: 1024067
|
199
|
+
event path: /private/tmp/moo/cow/1/v/
|
200
|
+
event flags: 00000000
|
201
|
+
event ID: 1024082
|
202
|
+
event path: /private/tmp/moo/cow/1/w/
|
203
|
+
event flags: 00000000
|
204
|
+
event ID: 1024097
|
205
|
+
event path: /private/tmp/moo/cow/1/x/
|
206
|
+
event flags: 00000000
|
207
|
+
event ID: 1024112
|
208
|
+
event path: /private/tmp/moo/cow/1/y/
|
209
|
+
event flags: 00000000
|
210
|
+
event ID: 1024127
|
211
|
+
event path: /private/tmp/moo/cow/1/z/
|
212
|
+
event flags: 00000000
|
213
|
+
event ID: 1024142
|
214
|
+
event path: /private/tmp/moo/cow/1/
|
215
|
+
event flags: 00000000
|
216
|
+
event ID: 1024145
|
217
|
+
event path: /private/tmp/moo/cow/2/a/
|
218
|
+
event flags: 00000000
|
219
|
+
event ID: 1024160
|
220
|
+
event path: /private/tmp/moo/cow/2/b/
|
221
|
+
event flags: 00000000
|
222
|
+
event ID: 1024175
|
223
|
+
event path: /private/tmp/moo/cow/2/c/
|
224
|
+
event flags: 00000000
|
225
|
+
event ID: 1024190
|
226
|
+
event path: /private/tmp/moo/cow/2/d/
|
227
|
+
event flags: 00000000
|
228
|
+
event ID: 1024205
|
229
|
+
event path: /private/tmp/moo/cow/2/e/
|
230
|
+
event flags: 00000000
|
231
|
+
event ID: 1024220
|
232
|
+
|
233
|
+
== Note about FFI
|
234
|
+
|
235
|
+
rb-fsevent doesn't use {ruby-ffi}[http://github.com/ffi/ffi] anymore because it sadly doesn't allow for catching Signals. You can still see the code in the {ffi branch}[http://github.com/thibaudgg/rb-fsevent/tree/ffi].
|
236
|
+
|
237
|
+
== Development
|
238
|
+
|
239
|
+
- Source hosted at {GitHub}[http://github.com/thibaudgg/rb-fsevent]
|
240
|
+
- Report issues/Questions/Feature requests on {GitHub Issues}[http://github.com/thibaudgg/rb-fsevent/issues]
|
241
|
+
|
242
|
+
Pull requests are quite welcome! Please ensure that your commits are in a topic branch for each individual changeset than can be reasonably isolated. It is also important to ensure that your changes are well tested... whether that means new tests, modified tests, or fixing a scenario where the existing tests currently fail. If you have rvm and the required rubies currently installed, we have a helper task for running the testsuite in all of them:
|
243
|
+
|
244
|
+
rake spec:portability
|
245
|
+
|
246
|
+
The list of tested RVM targets is currently:
|
247
|
+
|
248
|
+
%w[1.8.6 1.8.7 1.9.2 jruby-head]
|
249
|
+
|
250
|
+
== Authors
|
251
|
+
|
252
|
+
- {Thibaud Guillaume-Gentil}[http://github.com/thibaudgg]
|
253
|
+
- {Travis Tilley}[http://github.com/ttilley]
|
254
|
+
|
@@ -0,0 +1,21 @@
|
|
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 rvm)"
|
10
|
+
task(:portability) do
|
11
|
+
%w[1.8.6 1.8.7 1.9.2 jruby-head].each do |version|
|
12
|
+
system <<-BASH
|
13
|
+
bash -c 'source ~/.rvm/scripts/rvm;
|
14
|
+
rvm #{version};
|
15
|
+
echo "--------- version #{version} ----------\n";
|
16
|
+
bundle install;
|
17
|
+
rake spec'
|
18
|
+
BASH
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# Workaround to make Rubygems believe it builds a native gem
|
2
|
+
require 'mkmf'
|
3
|
+
create_makefile('none')
|
4
|
+
|
5
|
+
# TODO: determine whether we really need to be working around instead of with mkmf
|
6
|
+
|
7
|
+
if `uname -s`.chomp != 'Darwin'
|
8
|
+
puts "Warning! Only Darwin (Mac OS X) systems are supported, nothing will be compiled"
|
9
|
+
else
|
10
|
+
begin
|
11
|
+
xcode_path = %x[xcode-select -print-path].to_s.strip!
|
12
|
+
rescue Errno::ENOENT
|
13
|
+
end
|
14
|
+
|
15
|
+
raise "Could not find a suitable Xcode installation" unless xcode_path
|
16
|
+
|
17
|
+
gem_root = File.expand_path(File.join('..'))
|
18
|
+
darwin_version = `uname -r`.to_i
|
19
|
+
sdk_version = { 9 => '10.5', 10 => '10.6', 11 => '10.7' }[darwin_version]
|
20
|
+
|
21
|
+
raise "Only Darwin systems greater than 8 (Mac OS X 10.5+) are supported" unless sdk_version
|
22
|
+
|
23
|
+
core_flags = %W{
|
24
|
+
-isysroot #{xcode_path}/SDKs/MacOSX#{sdk_version}.sdk
|
25
|
+
-mmacosx-version-min=#{sdk_version} -mdynamic-no-pic -std=gnu99
|
26
|
+
}
|
27
|
+
|
28
|
+
cflags = core_flags + %w{-Os -pipe}
|
29
|
+
|
30
|
+
wflags = %w{
|
31
|
+
-Wmissing-prototypes -Wreturn-type -Wmissing-braces -Wparentheses -Wswitch
|
32
|
+
-Wunused-function -Wunused-label -Wunused-parameter -Wunused-variable
|
33
|
+
-Wunused-value -Wuninitialized -Wunknown-pragmas -Wshadow
|
34
|
+
-Wfour-char-constants -Wsign-compare -Wnewline-eof -Wconversion
|
35
|
+
-Wshorten-64-to-32 -Wglobal-constructors -pedantic
|
36
|
+
}
|
37
|
+
|
38
|
+
ldflags = %w{
|
39
|
+
-dead_strip -framework CoreServices
|
40
|
+
}
|
41
|
+
|
42
|
+
cc_opts = core_flags + ldflags
|
43
|
+
|
44
|
+
cc_opts += %w{
|
45
|
+
-D DEBUG=true
|
46
|
+
} if ENV['FWDEBUG'] == "true"
|
47
|
+
|
48
|
+
cc_bin = `which clang || which gcc`.to_s.strip!
|
49
|
+
|
50
|
+
compile_command = "CFLAGS='#{cflags.join(' ')} #{wflags.join(' ')}' #{cc_bin} #{cc_opts.join(' ')} -o '#{gem_root}/bin/fsevent_watch' fsevent/fsevent_watch.c"
|
51
|
+
|
52
|
+
STDERR.puts(compile_command)
|
53
|
+
|
54
|
+
# Compile the actual fsevent_watch binary
|
55
|
+
system "mkdir -p #{File.join(gem_root, 'bin')}"
|
56
|
+
system compile_command
|
57
|
+
|
58
|
+
unless File.executable?("#{gem_root}/bin/fsevent_watch")
|
59
|
+
raise "Compilation of fsevent_watch failed (see README)"
|
60
|
+
end
|
61
|
+
end
|