sass 3.4.25 → 3.5.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.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/Rakefile +2 -117
- data/VERSION +1 -1
- data/VERSION_DATE +1 -1
- data/VERSION_NAME +1 -1
- data/lib/sass/cache_stores/filesystem.rb +1 -1
- data/lib/sass/css.rb +1 -2
- data/lib/sass/engine.rb +38 -20
- data/lib/sass/environment.rb +26 -5
- data/lib/sass/error.rb +2 -2
- data/lib/sass/exec/base.rb +2 -11
- data/lib/sass/features.rb +1 -0
- data/lib/sass/importers/filesystem.rb +2 -2
- data/lib/sass/plugin/compiler.rb +20 -50
- data/lib/sass/plugin/configuration.rb +2 -2
- data/lib/sass/railtie.rb +1 -1
- data/lib/sass/script/functions.rb +235 -43
- data/lib/sass/script/lexer.rb +13 -2
- data/lib/sass/script/parser.rb +69 -67
- data/lib/sass/script/tree/funcall.rb +35 -30
- data/lib/sass/script/tree/list_literal.rb +23 -8
- data/lib/sass/script/tree/map_literal.rb +2 -2
- data/lib/sass/script/tree/node.rb +0 -8
- data/lib/sass/script/tree/operation.rb +0 -7
- data/lib/sass/script/value/arg_list.rb +1 -1
- data/lib/sass/script/value/base.rb +17 -0
- data/lib/sass/script/value/callable.rb +25 -0
- data/lib/sass/script/value/color.rb +5 -0
- data/lib/sass/script/value/function.rb +19 -0
- data/lib/sass/script/value/helpers.rb +29 -9
- data/lib/sass/script/value/list.rb +35 -14
- data/lib/sass/script/value/map.rb +2 -2
- data/lib/sass/script/value/number.rb +1 -1
- data/lib/sass/script/value.rb +2 -0
- data/lib/sass/scss/parser.rb +99 -40
- data/lib/sass/scss/rx.rb +4 -10
- data/lib/sass/scss/static_parser.rb +5 -24
- data/lib/sass/selector/abstract_sequence.rb +7 -6
- data/lib/sass/selector/comma_sequence.rb +7 -4
- data/lib/sass/selector/pseudo.rb +19 -2
- data/lib/sass/selector/sequence.rb +35 -6
- data/lib/sass/selector/simple.rb +9 -2
- data/lib/sass/selector/simple_sequence.rb +8 -4
- data/lib/sass/selector.rb +4 -0
- data/lib/sass/source/map.rb +2 -2
- data/lib/sass/stack.rb +21 -1
- data/lib/sass/tree/charset_node.rb +1 -1
- data/lib/sass/tree/prop_node.rb +45 -53
- data/lib/sass/tree/rule_node.rb +3 -2
- data/lib/sass/tree/visitors/check_nesting.rb +1 -1
- data/lib/sass/tree/visitors/convert.rb +2 -3
- data/lib/sass/tree/visitors/cssize.rb +4 -15
- data/lib/sass/tree/visitors/deep_copy.rb +1 -1
- data/lib/sass/tree/visitors/extend.rb +2 -8
- data/lib/sass/tree/visitors/perform.rb +21 -9
- data/lib/sass/tree/visitors/set_options.rb +1 -1
- data/lib/sass/tree/visitors/to_css.rb +47 -13
- data/lib/sass/util/multibyte_string_scanner.rb +127 -131
- data/lib/sass/util/normalized_map.rb +1 -8
- data/lib/sass/util.rb +12 -290
- data/lib/sass/version.rb +0 -2
- data/lib/sass.rb +0 -7
- data/test/sass/cache_test.rb +0 -1
- data/test/sass/callbacks_test.rb +0 -1
- data/test/sass/compiler_test.rb +4 -15
- data/test/sass/conversion_test.rb +113 -163
- data/test/sass/css2sass_test.rb +16 -19
- data/test/sass/css_variable_test.rb +176 -71
- data/test/sass/encoding_test.rb +2 -33
- data/test/sass/engine_test.rb +71 -19
- data/test/sass/exec_test.rb +0 -1
- data/test/sass/extend_test.rb +37 -92
- data/test/sass/functions_test.rb +58 -14
- data/test/sass/importer_test.rb +2 -3
- data/test/sass/logger_test.rb +0 -1
- data/test/sass/plugin_test.rb +6 -10
- data/test/sass/results/script.css +1 -1
- data/test/sass/results/units.css +2 -2
- data/test/sass/script_conversion_test.rb +10 -2
- data/test/sass/script_test.rb +22 -24
- data/test/sass/scss/css_test.rb +3 -18
- data/test/sass/scss/rx_test.rb +0 -1
- data/test/sass/scss/scss_test.rb +49 -16
- data/test/sass/source_map_test.rb +13 -16
- data/test/sass/superselector_test.rb +0 -1
- data/test/sass/util/multibyte_string_scanner_test.rb +121 -124
- data/test/sass/util/normalized_map_test.rb +0 -1
- data/test/sass/util/subset_map_test.rb +0 -1
- data/test/sass/util_test.rb +4 -39
- data/test/sass/value_helpers_test.rb +0 -1
- data/test/sass-spec.yml +1 -1
- data/test/test_helper.rb +39 -0
- metadata +19 -44
- data/lib/sass/script/css_variable_warning.rb +0 -52
- data/lib/sass/util/cross_platform_random.rb +0 -19
- data/lib/sass/util/ordered_hash.rb +0 -192
- data/test/sass/results/import_charset_1_8.css +0 -5
- data/test/sass/templates/import_charset_1_8.sass +0 -6
- data/vendor/listen/CHANGELOG.md +0 -1
- data/vendor/listen/CONTRIBUTING.md +0 -38
- data/vendor/listen/Gemfile +0 -20
- data/vendor/listen/Guardfile +0 -8
- data/vendor/listen/LICENSE +0 -20
- data/vendor/listen/README.md +0 -349
- data/vendor/listen/Rakefile +0 -5
- data/vendor/listen/Vagrantfile +0 -96
- data/vendor/listen/lib/listen/adapter.rb +0 -327
- data/vendor/listen/lib/listen/adapters/bsd.rb +0 -75
- data/vendor/listen/lib/listen/adapters/darwin.rb +0 -48
- data/vendor/listen/lib/listen/adapters/linux.rb +0 -81
- data/vendor/listen/lib/listen/adapters/polling.rb +0 -58
- data/vendor/listen/lib/listen/adapters/windows.rb +0 -91
- data/vendor/listen/lib/listen/directory_record.rb +0 -406
- data/vendor/listen/lib/listen/listener.rb +0 -323
- data/vendor/listen/lib/listen/turnstile.rb +0 -32
- data/vendor/listen/lib/listen/version.rb +0 -3
- data/vendor/listen/lib/listen.rb +0 -54
- data/vendor/listen/listen.gemspec +0 -28
- data/vendor/listen/spec/listen/adapter_spec.rb +0 -149
- data/vendor/listen/spec/listen/adapters/bsd_spec.rb +0 -36
- data/vendor/listen/spec/listen/adapters/darwin_spec.rb +0 -37
- data/vendor/listen/spec/listen/adapters/linux_spec.rb +0 -47
- data/vendor/listen/spec/listen/adapters/polling_spec.rb +0 -68
- data/vendor/listen/spec/listen/adapters/windows_spec.rb +0 -30
- data/vendor/listen/spec/listen/directory_record_spec.rb +0 -1250
- data/vendor/listen/spec/listen/listener_spec.rb +0 -258
- data/vendor/listen/spec/listen/turnstile_spec.rb +0 -56
- data/vendor/listen/spec/listen_spec.rb +0 -67
- data/vendor/listen/spec/spec_helper.rb +0 -25
- data/vendor/listen/spec/support/adapter_helper.rb +0 -666
- data/vendor/listen/spec/support/directory_record_helper.rb +0 -57
- data/vendor/listen/spec/support/fixtures_helper.rb +0 -29
- data/vendor/listen/spec/support/listeners_helper.rb +0 -179
- data/vendor/listen/spec/support/platform_helper.rb +0 -15
|
@@ -1,327 +0,0 @@
|
|
|
1
|
-
require 'rbconfig'
|
|
2
|
-
require 'thread'
|
|
3
|
-
require 'set'
|
|
4
|
-
require 'fileutils'
|
|
5
|
-
|
|
6
|
-
module Listen
|
|
7
|
-
class Adapter
|
|
8
|
-
attr_accessor :directories, :callback, :stopped, :paused,
|
|
9
|
-
:mutex, :changed_directories, :turnstile, :latency,
|
|
10
|
-
:worker, :worker_thread, :poller_thread
|
|
11
|
-
|
|
12
|
-
# The list of existing optimized adapters.
|
|
13
|
-
OPTIMIZED_ADAPTERS = %w[Darwin Linux BSD Windows]
|
|
14
|
-
|
|
15
|
-
# The list of existing fallback adapters.
|
|
16
|
-
FALLBACK_ADAPTERS = %w[Polling]
|
|
17
|
-
|
|
18
|
-
# The list of all existing adapters.
|
|
19
|
-
ADAPTERS = OPTIMIZED_ADAPTERS + FALLBACK_ADAPTERS
|
|
20
|
-
|
|
21
|
-
# The default delay between checking for changes.
|
|
22
|
-
DEFAULT_LATENCY = 0.25
|
|
23
|
-
|
|
24
|
-
# The default warning message when falling back to polling adapter.
|
|
25
|
-
POLLING_FALLBACK_MESSAGE = <<-EOS.gsub(/^\s*/, '')
|
|
26
|
-
Listen will be polling for changes. Learn more at https://github.com/guard/listen#polling-fallback.
|
|
27
|
-
EOS
|
|
28
|
-
|
|
29
|
-
# Selects the appropriate adapter implementation for the
|
|
30
|
-
# current OS and initializes it.
|
|
31
|
-
#
|
|
32
|
-
# @param [String, Array<String>] directories the directories to watch
|
|
33
|
-
# @param [Hash] options the adapter options
|
|
34
|
-
# @option options [Boolean] force_polling to force polling or not
|
|
35
|
-
# @option options [String, Boolean] polling_fallback_message to change polling fallback message or remove it
|
|
36
|
-
# @option options [Float] latency the delay between checking for changes in seconds
|
|
37
|
-
#
|
|
38
|
-
# @yield [changed_directories, options] callback the callback called when a change happens
|
|
39
|
-
# @yieldparam [Array<String>] changed_directories the changed directories
|
|
40
|
-
# @yieldparam [Hash] options callback options (like recursive: true)
|
|
41
|
-
#
|
|
42
|
-
# @return [Listen::Adapter] the chosen adapter
|
|
43
|
-
#
|
|
44
|
-
def self.select_and_initialize(directories, options = {}, &callback)
|
|
45
|
-
forced_adapter_class = options.delete(:force_adapter)
|
|
46
|
-
force_polling = options.delete(:force_polling)
|
|
47
|
-
|
|
48
|
-
if forced_adapter_class
|
|
49
|
-
forced_adapter_class.load_dependent_adapter
|
|
50
|
-
return forced_adapter_class.new(directories, options, &callback)
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
return Adapters::Polling.new(directories, options, &callback) if force_polling
|
|
54
|
-
|
|
55
|
-
OPTIMIZED_ADAPTERS.each do |adapter|
|
|
56
|
-
namespaced_adapter = Adapters.const_get(adapter)
|
|
57
|
-
if namespaced_adapter.send(:usable_and_works?, directories, options)
|
|
58
|
-
return namespaced_adapter.new(directories, options, &callback)
|
|
59
|
-
end
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
self.warn_polling_fallback(options)
|
|
63
|
-
Adapters::Polling.new(directories, options, &callback)
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
# Initializes the adapter.
|
|
67
|
-
#
|
|
68
|
-
# @param [String, Array<String>] directories the directories to watch
|
|
69
|
-
# @param [Hash] options the adapter options
|
|
70
|
-
# @option options [Float] latency the delay between checking for changes in seconds
|
|
71
|
-
#
|
|
72
|
-
# @yield [changed_directories, options] callback Callback called when a change happens
|
|
73
|
-
# @yieldparam [Array<String>] changed_directories the changed directories
|
|
74
|
-
# @yieldparam [Hash] options callback options (like recursive: true)
|
|
75
|
-
#
|
|
76
|
-
# @return [Listen::Adapter] the adapter
|
|
77
|
-
#
|
|
78
|
-
def initialize(directories, options = {}, &callback)
|
|
79
|
-
@directories = Array(directories)
|
|
80
|
-
@callback = callback
|
|
81
|
-
@stopped = true
|
|
82
|
-
@paused = false
|
|
83
|
-
@mutex = Mutex.new
|
|
84
|
-
@changed_directories = Set.new
|
|
85
|
-
@turnstile = Turnstile.new
|
|
86
|
-
@latency = options.fetch(:latency, default_latency)
|
|
87
|
-
@worker = initialize_worker
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
# Starts the adapter and don't block the current thread.
|
|
91
|
-
#
|
|
92
|
-
# @param [Boolean] blocking whether or not to block the current thread after starting
|
|
93
|
-
#
|
|
94
|
-
def start
|
|
95
|
-
mutex.synchronize do
|
|
96
|
-
return unless stopped
|
|
97
|
-
@stopped = false
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
start_worker
|
|
101
|
-
start_poller
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
# Starts the adapter and block the current thread.
|
|
105
|
-
#
|
|
106
|
-
# @since 1.0.0
|
|
107
|
-
#
|
|
108
|
-
def start!
|
|
109
|
-
start
|
|
110
|
-
blocking_thread.join
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
# Stops the adapter.
|
|
114
|
-
#
|
|
115
|
-
def stop
|
|
116
|
-
mutex.synchronize do
|
|
117
|
-
return if stopped
|
|
118
|
-
@stopped = true
|
|
119
|
-
turnstile.signal # ensure no thread is blocked
|
|
120
|
-
end
|
|
121
|
-
|
|
122
|
-
worker.stop if worker
|
|
123
|
-
Thread.kill(worker_thread) if worker_thread
|
|
124
|
-
if poller_thread
|
|
125
|
-
poller_thread.kill
|
|
126
|
-
poller_thread.join
|
|
127
|
-
end
|
|
128
|
-
end
|
|
129
|
-
|
|
130
|
-
# Pauses the adapter.
|
|
131
|
-
#
|
|
132
|
-
def pause
|
|
133
|
-
@paused = true
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
# Unpauses the adapter.
|
|
137
|
-
#
|
|
138
|
-
def unpause
|
|
139
|
-
@paused = false
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
# Returns whether the adapter is started or not.
|
|
143
|
-
#
|
|
144
|
-
# @return [Boolean] whether the adapter is started or not
|
|
145
|
-
#
|
|
146
|
-
def started?
|
|
147
|
-
!stopped
|
|
148
|
-
end
|
|
149
|
-
|
|
150
|
-
# Returns whether the adapter is paused or not.
|
|
151
|
-
#
|
|
152
|
-
# @return [Boolean] whether the adapter is paused or not
|
|
153
|
-
#
|
|
154
|
-
def paused?
|
|
155
|
-
paused
|
|
156
|
-
end
|
|
157
|
-
|
|
158
|
-
# Blocks the main thread until the poll thread
|
|
159
|
-
# runs the callback.
|
|
160
|
-
#
|
|
161
|
-
def wait_for_callback
|
|
162
|
-
turnstile.wait unless paused
|
|
163
|
-
end
|
|
164
|
-
|
|
165
|
-
# Blocks the main thread until N changes are
|
|
166
|
-
# detected.
|
|
167
|
-
#
|
|
168
|
-
def wait_for_changes(threshold = 0)
|
|
169
|
-
changes = 0
|
|
170
|
-
|
|
171
|
-
loop do
|
|
172
|
-
mutex.synchronize { changes = changed_directories.size }
|
|
173
|
-
|
|
174
|
-
return if paused || stopped
|
|
175
|
-
return if changes >= threshold
|
|
176
|
-
|
|
177
|
-
sleep(latency)
|
|
178
|
-
end
|
|
179
|
-
end
|
|
180
|
-
|
|
181
|
-
# Checks if the adapter is usable and works on the current OS.
|
|
182
|
-
#
|
|
183
|
-
# @param [String, Array<String>] directories the directories to watch
|
|
184
|
-
# @param [Hash] options the adapter options
|
|
185
|
-
# @option options [Float] latency the delay between checking for changes in seconds
|
|
186
|
-
#
|
|
187
|
-
# @return [Boolean] whether the adapter is usable and work or not
|
|
188
|
-
#
|
|
189
|
-
def self.usable_and_works?(directories, options = {})
|
|
190
|
-
usable? && Array(directories).all? { |d| works?(d, options) }
|
|
191
|
-
end
|
|
192
|
-
|
|
193
|
-
# Checks if the adapter is usable on target OS.
|
|
194
|
-
#
|
|
195
|
-
# @return [Boolean] whether usable or not
|
|
196
|
-
#
|
|
197
|
-
def self.usable?
|
|
198
|
-
load_dependent_adapter if RbConfig::CONFIG['target_os'] =~ target_os_regex
|
|
199
|
-
end
|
|
200
|
-
|
|
201
|
-
# Load the adapter gem
|
|
202
|
-
#
|
|
203
|
-
# @return [Boolean] whether loaded or not
|
|
204
|
-
#
|
|
205
|
-
def self.load_dependent_adapter
|
|
206
|
-
return true if @loaded
|
|
207
|
-
require adapter_gem
|
|
208
|
-
return @loaded = true
|
|
209
|
-
rescue LoadError
|
|
210
|
-
false
|
|
211
|
-
end
|
|
212
|
-
|
|
213
|
-
# Runs a tests to determine if the adapter can actually pick up
|
|
214
|
-
# changes in a given directory and returns the result.
|
|
215
|
-
#
|
|
216
|
-
# @note This test takes some time depending on the adapter latency.
|
|
217
|
-
#
|
|
218
|
-
# @param [String, Pathname] directory the directory to watch
|
|
219
|
-
# @param [Hash] options the adapter options
|
|
220
|
-
# @option options [Float] latency the delay between checking for changes in seconds
|
|
221
|
-
#
|
|
222
|
-
# @return [Boolean] whether the adapter works or not
|
|
223
|
-
#
|
|
224
|
-
def self.works?(directory, options = {})
|
|
225
|
-
work = false
|
|
226
|
-
test_file = "#{directory}/.listen_test"
|
|
227
|
-
callback = lambda { |*| work = true }
|
|
228
|
-
adapter = self.new(directory, options, &callback)
|
|
229
|
-
adapter.start
|
|
230
|
-
|
|
231
|
-
FileUtils.touch(test_file)
|
|
232
|
-
|
|
233
|
-
t = Thread.new { sleep(adapter.latency * 5); adapter.stop }
|
|
234
|
-
|
|
235
|
-
adapter.wait_for_callback
|
|
236
|
-
work
|
|
237
|
-
ensure
|
|
238
|
-
Thread.kill(t) if t
|
|
239
|
-
FileUtils.rm(test_file, :force => true)
|
|
240
|
-
adapter.stop if adapter && adapter.started?
|
|
241
|
-
end
|
|
242
|
-
|
|
243
|
-
# Runs the callback and passes it the changes if there are any.
|
|
244
|
-
#
|
|
245
|
-
def report_changes
|
|
246
|
-
changed_dirs = nil
|
|
247
|
-
|
|
248
|
-
mutex.synchronize do
|
|
249
|
-
return if @changed_directories.empty?
|
|
250
|
-
changed_dirs = @changed_directories.to_a
|
|
251
|
-
@changed_directories.clear
|
|
252
|
-
end
|
|
253
|
-
|
|
254
|
-
callback.call(changed_dirs, {})
|
|
255
|
-
turnstile.signal
|
|
256
|
-
end
|
|
257
|
-
|
|
258
|
-
private
|
|
259
|
-
|
|
260
|
-
# The default delay between checking for changes.
|
|
261
|
-
#
|
|
262
|
-
# @note This method can be overriden on a per-adapter basis.
|
|
263
|
-
#
|
|
264
|
-
def default_latency
|
|
265
|
-
DEFAULT_LATENCY
|
|
266
|
-
end
|
|
267
|
-
|
|
268
|
-
# The thread on which the main thread should wait
|
|
269
|
-
# when the adapter has been started in blocking mode.
|
|
270
|
-
#
|
|
271
|
-
# @note This method can be overriden on a per-adapter basis.
|
|
272
|
-
#
|
|
273
|
-
def blocking_thread
|
|
274
|
-
worker_thread
|
|
275
|
-
end
|
|
276
|
-
|
|
277
|
-
# Initialize the adpater' specific worker.
|
|
278
|
-
#
|
|
279
|
-
# @note Each adapter must override this method
|
|
280
|
-
# to initialize its own @worker.
|
|
281
|
-
#
|
|
282
|
-
def initialize_worker
|
|
283
|
-
nil
|
|
284
|
-
end
|
|
285
|
-
|
|
286
|
-
# Should start the worker in a new thread.
|
|
287
|
-
#
|
|
288
|
-
# @note Each adapter must override this method
|
|
289
|
-
# to start its worker on a new @worker_thread thread.
|
|
290
|
-
#
|
|
291
|
-
def start_worker
|
|
292
|
-
raise NotImplementedError, "#{self.class} cannot respond to: #{__method__}"
|
|
293
|
-
end
|
|
294
|
-
|
|
295
|
-
# This method starts a new thread which poll for changes detected by
|
|
296
|
-
# the adapter and report them back to the user.
|
|
297
|
-
#
|
|
298
|
-
def start_poller
|
|
299
|
-
@poller_thread = Thread.new { poll_changed_directories }
|
|
300
|
-
end
|
|
301
|
-
|
|
302
|
-
# Warn of polling fallback unless the :polling_fallback_message
|
|
303
|
-
# has been set to false.
|
|
304
|
-
#
|
|
305
|
-
# @param [String] warning an existing warning message
|
|
306
|
-
# @param [Hash] options the adapter options
|
|
307
|
-
# @option options [Boolean] polling_fallback_message to change polling fallback message or remove it
|
|
308
|
-
#
|
|
309
|
-
def self.warn_polling_fallback(options)
|
|
310
|
-
return if options[:polling_fallback_message] == false
|
|
311
|
-
|
|
312
|
-
warning = options[:polling_fallback_message] || POLLING_FALLBACK_MESSAGE
|
|
313
|
-
Kernel.warn "[Listen warning]:\n#{warning.gsub(/^(.*)/, ' \1')}"
|
|
314
|
-
end
|
|
315
|
-
|
|
316
|
-
# Polls changed directories and reports them back when there are changes.
|
|
317
|
-
#
|
|
318
|
-
# @note This method can be overriden on a per-adapter basis.
|
|
319
|
-
#
|
|
320
|
-
def poll_changed_directories
|
|
321
|
-
until stopped
|
|
322
|
-
sleep(latency)
|
|
323
|
-
report_changes
|
|
324
|
-
end
|
|
325
|
-
end
|
|
326
|
-
end
|
|
327
|
-
end
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
module Listen
|
|
2
|
-
module Adapters
|
|
3
|
-
|
|
4
|
-
# Listener implementation for BSD's `kqueue`.
|
|
5
|
-
#
|
|
6
|
-
class BSD < Adapter
|
|
7
|
-
# Watched kqueue events
|
|
8
|
-
#
|
|
9
|
-
# @see http://www.freebsd.org/cgi/man.cgi?query=kqueue
|
|
10
|
-
# @see https://github.com/nex3/rb-kqueue/blob/master/lib/rb-kqueue/queue.rb
|
|
11
|
-
#
|
|
12
|
-
EVENTS = [:delete, :write, :extend, :attrib, :link, :rename, :revoke]
|
|
13
|
-
|
|
14
|
-
def self.target_os_regex; /freebsd/i; end
|
|
15
|
-
def self.adapter_gem; 'rb-kqueue'; end
|
|
16
|
-
|
|
17
|
-
private
|
|
18
|
-
|
|
19
|
-
# Initializes a kqueue Queue and adds a watcher for each files in
|
|
20
|
-
# the directories passed to the adapter.
|
|
21
|
-
#
|
|
22
|
-
# @return [INotify::Notifier] initialized kqueue
|
|
23
|
-
#
|
|
24
|
-
# @see Listen::Adapter#initialize_worker
|
|
25
|
-
#
|
|
26
|
-
def initialize_worker
|
|
27
|
-
require 'find'
|
|
28
|
-
|
|
29
|
-
callback = lambda do |event|
|
|
30
|
-
path = event.watcher.path
|
|
31
|
-
mutex.synchronize do
|
|
32
|
-
# kqueue watches everything, but Listen only needs the
|
|
33
|
-
# directory where stuffs happens.
|
|
34
|
-
@changed_directories << (File.directory?(path) ? path : File.dirname(path))
|
|
35
|
-
|
|
36
|
-
# If it is a directory, and it has a write flag, it means a
|
|
37
|
-
# file has been added so find out which and deal with it.
|
|
38
|
-
# No need to check for removed files, kqueue will forget them
|
|
39
|
-
# when the vfs does.
|
|
40
|
-
if File.directory?(path) && event.flags.include?(:write)
|
|
41
|
-
queue = event.watcher.queue
|
|
42
|
-
Find.find(path) do |file|
|
|
43
|
-
unless queue.watchers.detect { |k,v| v.path == file.to_s }
|
|
44
|
-
queue.watch_file(file, *EVENTS, &callback)
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
KQueue::Queue.new.tap do |queue|
|
|
52
|
-
directories.each do |directory|
|
|
53
|
-
Find.find(directory) do |path|
|
|
54
|
-
queue.watch_file(path, *EVENTS, &callback)
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
# Starts the worker in a new thread.
|
|
61
|
-
#
|
|
62
|
-
# @see Listen::Adapter#start_worker
|
|
63
|
-
#
|
|
64
|
-
def start_worker
|
|
65
|
-
@worker_thread = Thread.new do
|
|
66
|
-
until stopped
|
|
67
|
-
worker.poll
|
|
68
|
-
sleep(latency)
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
end
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
end
|
|
75
|
-
end
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
module Listen
|
|
2
|
-
module Adapters
|
|
3
|
-
|
|
4
|
-
# Adapter implementation for Mac OS X `FSEvents`.
|
|
5
|
-
#
|
|
6
|
-
class Darwin < Adapter
|
|
7
|
-
LAST_SEPARATOR_REGEX = /\/$/
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
def self.target_os_regex; /darwin(1.+)?$/i; end
|
|
11
|
-
def self.adapter_gem; 'rb-fsevent'; end
|
|
12
|
-
|
|
13
|
-
private
|
|
14
|
-
|
|
15
|
-
# Initializes a FSEvent worker and adds a watcher for
|
|
16
|
-
# each directory passed to the adapter.
|
|
17
|
-
#
|
|
18
|
-
# @return [FSEvent] initialized worker
|
|
19
|
-
#
|
|
20
|
-
# @see Listen::Adapter#initialize_worker
|
|
21
|
-
#
|
|
22
|
-
def initialize_worker
|
|
23
|
-
FSEvent.new.tap do |worker|
|
|
24
|
-
worker.watch(directories.dup, :latency => latency) do |changes|
|
|
25
|
-
next if paused
|
|
26
|
-
|
|
27
|
-
mutex.synchronize do
|
|
28
|
-
changes.each { |path| @changed_directories << path.sub(LAST_SEPARATOR_REGEX, '') }
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
# Starts the worker in a new thread and sleep 0.1 second.
|
|
35
|
-
#
|
|
36
|
-
# @see Listen::Adapter#start_worker
|
|
37
|
-
#
|
|
38
|
-
def start_worker
|
|
39
|
-
@worker_thread = Thread.new { worker.run }
|
|
40
|
-
# The FSEvent worker needs some time to start up. Turnstiles can't
|
|
41
|
-
# be used to wait for it as it runs in a loop.
|
|
42
|
-
# TODO: Find a better way to block until the worker starts.
|
|
43
|
-
sleep 0.1
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
end
|
|
48
|
-
end
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
module Listen
|
|
2
|
-
module Adapters
|
|
3
|
-
|
|
4
|
-
# Listener implementation for Linux `inotify`.
|
|
5
|
-
#
|
|
6
|
-
class Linux < Adapter
|
|
7
|
-
# Watched inotify events
|
|
8
|
-
#
|
|
9
|
-
# @see http://www.tin.org/bin/man.cgi?section=7&topic=inotify
|
|
10
|
-
# @see https://github.com/nex3/rb-inotify/blob/master/lib/rb-inotify/notifier.rb#L99-L177
|
|
11
|
-
#
|
|
12
|
-
EVENTS = [:recursive, :attrib, :create, :delete, :move, :close_write]
|
|
13
|
-
|
|
14
|
-
# The message to show when the limit of inotify watchers is not enough
|
|
15
|
-
#
|
|
16
|
-
INOTIFY_LIMIT_MESSAGE = <<-EOS.gsub(/^\s*/, '')
|
|
17
|
-
Listen error: unable to monitor directories for changes.
|
|
18
|
-
|
|
19
|
-
Please head to https://github.com/guard/listen/wiki/Increasing-the-amount-of-inotify-watchers
|
|
20
|
-
for information on how to solve this issue.
|
|
21
|
-
EOS
|
|
22
|
-
|
|
23
|
-
def self.target_os_regex; /linux/i; end
|
|
24
|
-
def self.adapter_gem; 'rb-inotify'; end
|
|
25
|
-
|
|
26
|
-
# Initializes the Adapter.
|
|
27
|
-
#
|
|
28
|
-
# @see Listen::Adapter#initialize
|
|
29
|
-
#
|
|
30
|
-
def initialize(directories, options = {}, &callback)
|
|
31
|
-
super
|
|
32
|
-
rescue Errno::ENOSPC
|
|
33
|
-
abort(INOTIFY_LIMIT_MESSAGE)
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
private
|
|
37
|
-
|
|
38
|
-
# Initializes a INotify worker and adds a watcher for
|
|
39
|
-
# each directory passed to the adapter.
|
|
40
|
-
#
|
|
41
|
-
# @return [INotify::Notifier] initialized worker
|
|
42
|
-
#
|
|
43
|
-
# @see Listen::Adapter#initialize_worker
|
|
44
|
-
#
|
|
45
|
-
def initialize_worker
|
|
46
|
-
callback = lambda do |event|
|
|
47
|
-
if paused || (
|
|
48
|
-
# Event on root directory
|
|
49
|
-
event.name == ""
|
|
50
|
-
) || (
|
|
51
|
-
# INotify reports changes to files inside directories as events
|
|
52
|
-
# on the directories themselves too.
|
|
53
|
-
#
|
|
54
|
-
# @see http://linux.die.net/man/7/inotify
|
|
55
|
-
event.flags.include?(:isdir) and (event.flags & [:close, :modify]).any?
|
|
56
|
-
)
|
|
57
|
-
# Skip all of these!
|
|
58
|
-
next
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
mutex.synchronize do
|
|
62
|
-
@changed_directories << File.dirname(event.absolute_name)
|
|
63
|
-
end
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
INotify::Notifier.new.tap do |worker|
|
|
67
|
-
directories.each { |dir| worker.watch(dir, *EVENTS, &callback) }
|
|
68
|
-
end
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
# Starts the worker in a new thread.
|
|
72
|
-
#
|
|
73
|
-
# @see Listen::Adapter#start_worker
|
|
74
|
-
#
|
|
75
|
-
def start_worker
|
|
76
|
-
@worker_thread = Thread.new { worker.run }
|
|
77
|
-
end
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
end
|
|
81
|
-
end
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
module Listen
|
|
2
|
-
module Adapters
|
|
3
|
-
|
|
4
|
-
DEFAULT_POLLING_LATENCY = 1.0
|
|
5
|
-
|
|
6
|
-
# Polling Adapter that works cross-platform and
|
|
7
|
-
# has no dependencies. This is the adapter that
|
|
8
|
-
# uses the most CPU processing power and has higher
|
|
9
|
-
# file IO than the other implementations.
|
|
10
|
-
#
|
|
11
|
-
class Polling < Adapter
|
|
12
|
-
private
|
|
13
|
-
|
|
14
|
-
# The default delay between checking for changes.
|
|
15
|
-
#
|
|
16
|
-
# @see Listen::Adapter#default_latency
|
|
17
|
-
#
|
|
18
|
-
def default_latency
|
|
19
|
-
1.0
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
# The thread on which the main thread should wait
|
|
23
|
-
# when the adapter has been started in blocking mode.
|
|
24
|
-
#
|
|
25
|
-
# @see Listen::Adapter#blocking_thread
|
|
26
|
-
#
|
|
27
|
-
def blocking_thread
|
|
28
|
-
poller_thread
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
# @see Listen::Adapter#start_worker
|
|
32
|
-
#
|
|
33
|
-
# @see Listen::Adapter#start_worker
|
|
34
|
-
#
|
|
35
|
-
def start_worker
|
|
36
|
-
# The polling adapter has no worker! Sad panda! :'(
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
# Poll listener directory for file system changes.
|
|
40
|
-
#
|
|
41
|
-
# @see Listen::Adapter#poll_changed_directories
|
|
42
|
-
#
|
|
43
|
-
def poll_changed_directories
|
|
44
|
-
until stopped
|
|
45
|
-
next if paused
|
|
46
|
-
|
|
47
|
-
start = Time.now.to_f
|
|
48
|
-
callback.call(directories.dup, :recursive => true)
|
|
49
|
-
turnstile.signal
|
|
50
|
-
nap_time = latency - (Time.now.to_f - start)
|
|
51
|
-
sleep(nap_time) if nap_time > 0
|
|
52
|
-
end
|
|
53
|
-
rescue Interrupt
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
end
|
|
58
|
-
end
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
require 'set'
|
|
2
|
-
require 'rubygems'
|
|
3
|
-
|
|
4
|
-
module Listen
|
|
5
|
-
module Adapters
|
|
6
|
-
|
|
7
|
-
# Adapter implementation for Windows `wdm`.
|
|
8
|
-
#
|
|
9
|
-
class Windows < Adapter
|
|
10
|
-
|
|
11
|
-
BUNDLER_DECLARE_GEM = <<-EOS.gsub(/^ {6}/, '')
|
|
12
|
-
Please add the following to your Gemfile to avoid polling for changes:
|
|
13
|
-
require 'rbconfig'
|
|
14
|
-
gem 'wdm', '>= 0.1.0' if RbConfig::CONFIG['target_os'] =~ /mswin|mingw/i
|
|
15
|
-
EOS
|
|
16
|
-
|
|
17
|
-
def self.target_os_regex; /mswin|mingw/i; end
|
|
18
|
-
def self.adapter_gem; 'wdm'; end
|
|
19
|
-
|
|
20
|
-
# Checks if the adapter is usable on target OS.
|
|
21
|
-
#
|
|
22
|
-
# @return [Boolean] whether usable or not
|
|
23
|
-
#
|
|
24
|
-
def self.usable?
|
|
25
|
-
super if mri? && at_least_ruby_1_9?
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
# Load the adapter gem
|
|
29
|
-
#
|
|
30
|
-
# @return [Boolean] whether required or not
|
|
31
|
-
#
|
|
32
|
-
def self.load_dependent_adapter
|
|
33
|
-
super
|
|
34
|
-
rescue Gem::LoadError
|
|
35
|
-
Kernel.warn BUNDLER_DECLARE_GEM
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
private
|
|
39
|
-
|
|
40
|
-
# Checks if Ruby engine is MRI.
|
|
41
|
-
#
|
|
42
|
-
# @return [Boolean]
|
|
43
|
-
#
|
|
44
|
-
def self.mri?
|
|
45
|
-
defined?(RUBY_ENGINE) && RUBY_ENGINE == 'ruby'
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
# Checks if Ruby engine is MRI.
|
|
49
|
-
#
|
|
50
|
-
# @return [Boolean]
|
|
51
|
-
#
|
|
52
|
-
def self.at_least_ruby_1_9?
|
|
53
|
-
Gem::Version.new(RUBY_VERSION.dup) >= Gem::Version.new('1.9.2')
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
# Initializes a WDM monitor and adds a watcher for
|
|
57
|
-
# each directory passed to the adapter.
|
|
58
|
-
#
|
|
59
|
-
# @return [WDM::Monitor] initialized worker
|
|
60
|
-
#
|
|
61
|
-
# @see Listen::Adapter#initialize_worker
|
|
62
|
-
#
|
|
63
|
-
def initialize_worker
|
|
64
|
-
callback = Proc.new do |change|
|
|
65
|
-
next if paused
|
|
66
|
-
|
|
67
|
-
mutex.synchronize do
|
|
68
|
-
@changed_directories << File.dirname(change.path)
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
WDM::Monitor.new.tap do |worker|
|
|
73
|
-
directories.each { |dir| worker.watch_recursively(dir, &callback) }
|
|
74
|
-
end
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
# Start the worker in a new thread and sleep 0.1 second.
|
|
78
|
-
#
|
|
79
|
-
# @see Listen::Adapter#start_worker
|
|
80
|
-
#
|
|
81
|
-
def start_worker
|
|
82
|
-
@worker_thread = Thread.new { worker.run! }
|
|
83
|
-
# Wait for the worker to start. This is needed to avoid a deadlock
|
|
84
|
-
# when stopping immediately after starting.
|
|
85
|
-
sleep 0.1
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
end
|
|
91
|
-
end
|