filewatcher 1.0.1 → 2.0.0.beta3

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,75 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative '../../lib/filewatcher/runner'
4
-
5
- describe Filewatcher::Runner do
6
- before do
7
- @init = proc do |filename|
8
- Filewatcher::Runner.new(filename)
9
- end
10
- end
11
-
12
- describe '#initialize' do
13
- it 'should recieve filename' do
14
- -> { @init.call('file.txt') }
15
- .should.not.raise ArgumentError
16
- end
17
- end
18
-
19
- describe '#command' do
20
- it 'should return correct command for file with .py extension' do
21
- @init.call('file.py').command
22
- .should.equal 'env python file.py'
23
- end
24
-
25
- it 'should return correct command for file with .js extension' do
26
- @init.call('file.js').command
27
- .should.equal 'env node file.js'
28
- end
29
-
30
- it 'should return correct command for file with .rb extension' do
31
- @init.call('file.rb').command
32
- .should.equal 'env ruby file.rb'
33
- end
34
-
35
- it 'should return correct command for file with .pl extension' do
36
- @init.call('file.pl').command
37
- .should.equal 'env perl file.pl'
38
- end
39
-
40
- it 'should return correct command for file with .awk extension' do
41
- @init.call('file.awk').command
42
- .should.equal 'env awk file.awk'
43
- end
44
-
45
- it 'should return correct command for file with .php extension' do
46
- @init.call('file.php').command
47
- .should.equal 'env php file.php'
48
- end
49
-
50
- it 'should return correct command for file with .phtml extension' do
51
- @init.call('file.phtml').command
52
- .should.equal 'env php file.phtml'
53
- end
54
-
55
- it 'should return correct command for file with .php4 extension' do
56
- @init.call('file.php4').command
57
- .should.equal 'env php file.php4'
58
- end
59
-
60
- it 'should return correct command for file with .php3 extension' do
61
- @init.call('file.php3').command
62
- .should.equal 'env php file.php3'
63
- end
64
-
65
- it 'should return correct command for file with .php5 extension' do
66
- @init.call('file.php5').command
67
- .should.equal 'env php file.php5'
68
- end
69
-
70
- it 'should return correct command for file with .phps extension' do
71
- @init.call('file.phps').command
72
- .should.equal 'env php file.phps'
73
- end
74
- end
75
- end
@@ -1,13 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative '../../lib/filewatcher/version'
4
-
5
- describe Filewatcher::VERSION do
6
- it 'should exist as constant' do
7
- Filewatcher.const_defined?(:VERSION).should.be.true
8
- end
9
-
10
- it 'should be an instance of String' do
11
- Filewatcher::VERSION.class.should.equal String
12
- end
13
- end
data/test/helper.rb DELETED
@@ -1,216 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'bacon'
4
- require 'bacon/custom_matchers_messages'
5
-
6
- begin
7
- require 'pry-byebug'
8
- rescue LoadError
9
- nil
10
- end
11
-
12
- class WatchRun
13
- TMP_DIR = File.join(__dir__, 'tmp')
14
-
15
- attr_reader :filename
16
-
17
- def initialize(
18
- filename: 'tmp_file.txt',
19
- directory: false,
20
- action: :update
21
- )
22
- @filename =
23
- filename.start_with?('/', '~') ? filename : File.join(TMP_DIR, filename)
24
- @directory = directory
25
- @action = action
26
- end
27
-
28
- def start
29
- File.write(@filename, 'content1') unless @action == :create
30
- end
31
-
32
- def run
33
- start
34
-
35
- make_changes
36
-
37
- stop
38
- end
39
-
40
- def stop
41
- FileUtils.rm_r(@filename) if File.exist?(@filename)
42
- end
43
-
44
- private
45
-
46
- def make_changes
47
- if @action == :delete
48
- FileUtils.remove(@filename)
49
- elsif @directory
50
- FileUtils.mkdir_p(@filename)
51
- else
52
- File.write(@filename, 'content2')
53
- end
54
- end
55
- end
56
-
57
- class RubyWatchRun < WatchRun
58
- attr_reader :filewatcher, :thread, :watched, :processed
59
-
60
- def initialize(
61
- every: false,
62
- filewatcher: Filewatcher.new(
63
- File.join(TMP_DIR, '**', '*'), interval: 0.1, every: every
64
- ),
65
- **args
66
- )
67
- super(**args)
68
- @filewatcher = filewatcher
69
- end
70
-
71
- def start
72
- super
73
- @thread = thread_initialize
74
- # thread needs a chance to start
75
- wait 3 do
76
- filewatcher.keep_watching
77
- end
78
- end
79
-
80
- def stop
81
- thread.exit
82
-
83
- wait 3 do
84
- thread.stop?
85
- end
86
-
87
- super
88
- end
89
-
90
- private
91
-
92
- def make_changes
93
- super
94
-
95
- # Some OS, filesystems and Ruby interpretators
96
- # doesn't catch milliseconds of `File.mtime`
97
- wait 3 do
98
- processed.any?
99
- end
100
- end
101
-
102
- def thread_initialize
103
- @watched ||= 0
104
- Thread.new(
105
- @filewatcher, @processed = []
106
- ) do |filewatcher, processed|
107
- filewatcher.watch do |filename, event|
108
- increment_watched
109
- processed.push([filename, event])
110
- end
111
- end
112
- end
113
-
114
- def increment_watched
115
- @watched += 1
116
- end
117
-
118
- def wait(seconds)
119
- max_count = seconds / filewatcher.interval
120
- count = 0
121
- while count < max_count && !yield
122
- sleep filewatcher.interval
123
- count += 1
124
- end
125
- end
126
- end
127
-
128
- class ShellWatchRun < WatchRun
129
- EXECUTABLE = "#{'ruby ' if Gem.win_platform?}" \
130
- "#{File.realpath File.join(__dir__, '..', 'bin', 'filewatcher')}".freeze
131
-
132
- SLEEP_MULTIPLIER = RUBY_PLATFORM == 'java' ? 5 : 1
133
-
134
- ENV_FILE = File.join(TMP_DIR, 'env')
135
-
136
- def initialize(
137
- options: {},
138
- dumper: :watched,
139
- **args
140
- )
141
- super(**args)
142
- @options = options
143
- @options[:interval] ||= 0.1
144
- @options_string =
145
- @options.map { |key, value| "--#{key}=#{value}" }.join(' ')
146
- @dumper = dumper
147
- end
148
-
149
- def start
150
- super
151
-
152
- @pid = spawn(
153
- "#{EXECUTABLE} #{@options_string} \"#{@filename}\"" \
154
- " \"ruby #{File.join(__dir__, 'dumpers', "#{@dumper}_dumper.rb")}\"",
155
- pgroup: true
156
- )
157
-
158
- Process.detach(@pid)
159
-
160
- wait 12 do
161
- pid_state == 'S' && (!@options[:immediate] || File.exist?(ENV_FILE))
162
- end
163
-
164
- # a little more time
165
- sleep 1 * SLEEP_MULTIPLIER
166
- end
167
-
168
- def stop
169
- ## Problems: https://github.com/thomasfl/filewatcher/pull/83
170
- ## Solution: https://stackoverflow.com/a/45032252/2630849
171
- Process.kill('TERM', -Process.getpgid(@pid))
172
- Process.waitall
173
-
174
- wait 12 do
175
- pid_state.empty?
176
- end
177
-
178
- # a little more time
179
- sleep 1 * SLEEP_MULTIPLIER
180
-
181
- super
182
- end
183
-
184
- private
185
-
186
- def make_changes
187
- super
188
-
189
- wait 12 do
190
- File.exist?(ENV_FILE)
191
- end
192
- end
193
-
194
- def pid_state
195
- ## For macOS output:
196
- ## https://travis-ci.org/thomasfl/filewatcher/jobs/304433538
197
- `ps -ho state -p #{@pid}`.sub('STAT', '').strip
198
- end
199
-
200
- def wait(seconds)
201
- max_count = seconds / @options[:interval]
202
- count = 0
203
- while count < max_count && !yield
204
- sleep @options[:interval]
205
- count += 1
206
- end
207
- end
208
- end
209
-
210
- custom_matcher :include_all_files do |obj, elements|
211
- elements.all? { |element| obj.include? File.expand_path(element) }
212
- end
213
-
214
- def dump_to_env_file(content)
215
- File.write File.join(ShellWatchRun::ENV_FILE), content
216
- end
@@ -1,340 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'fileutils'
4
- require_relative '../lib/filewatcher'
5
-
6
- describe Filewatcher do
7
- before do
8
- FileUtils.mkdir_p WatchRun::TMP_DIR
9
- end
10
-
11
- after do
12
- FileUtils.rm_r WatchRun::TMP_DIR
13
-
14
- interval = 0.1
15
- wait = 5
16
- count = 0
17
- while File.exist?(WatchRun::TMP_DIR) && count < (wait / interval)
18
- sleep interval
19
- end
20
- end
21
-
22
- describe '#initialize' do
23
- it 'should exclude selected file patterns' do
24
- wr = RubyWatchRun.new(
25
- filewatcher: Filewatcher.new(
26
- File.expand_path('test/tmp/**/*'),
27
- exclude: File.expand_path('test/tmp/**/*.txt')
28
- )
29
- )
30
-
31
- wr.run
32
-
33
- wr.processed.should.be.empty
34
- end
35
-
36
- it 'should handle absolute paths with globs' do
37
- wr = RubyWatchRun.new(
38
- filewatcher: Filewatcher.new(
39
- File.expand_path('test/tmp/**/*')
40
- )
41
- )
42
-
43
- wr.run
44
-
45
- wr.processed.should.equal(
46
- [[wr.filename, :updated]]
47
- )
48
- end
49
-
50
- it 'should handle globs' do
51
- wr = RubyWatchRun.new(
52
- filewatcher: Filewatcher.new('test/tmp/**/*')
53
- )
54
-
55
- wr.run
56
-
57
- wr.processed.should.equal(
58
- [[wr.filename, :updated]]
59
- )
60
- end
61
-
62
- it 'should handle explicit relative paths with globs' do
63
- wr = RubyWatchRun.new(
64
- filewatcher: Filewatcher.new('./test/tmp/**/*')
65
- )
66
-
67
- wr.run
68
-
69
- wr.processed.should.equal(
70
- [[wr.filename, :updated]]
71
- )
72
- end
73
-
74
- it 'should handle explicit relative paths' do
75
- wr = RubyWatchRun.new(
76
- filewatcher: Filewatcher.new('./test/tmp')
77
- )
78
-
79
- wr.run
80
-
81
- wr.processed.should.equal(
82
- [[wr.filename, :updated]]
83
- )
84
- end
85
-
86
- it 'should handle tilde expansion' do
87
- filename = File.expand_path('~/file_watcher_1.txt')
88
-
89
- wr = RubyWatchRun.new(
90
- filename: filename,
91
- filewatcher: Filewatcher.new('~/file_watcher_1.txt')
92
- )
93
-
94
- wr.run
95
-
96
- wr.processed.should.equal(
97
- [[filename, :updated]]
98
- )
99
- end
100
-
101
- it 'should immediately run with corresponding option' do
102
- wr = RubyWatchRun.new(
103
- filewatcher: Filewatcher.new('**/*', immediate: true)
104
- )
105
-
106
- wr.start
107
- wr.stop
108
-
109
- wr.processed.should.equal [['', '']]
110
- wr.watched.should.be > 0
111
- end
112
-
113
- it 'should not be executed without immediate option and changes' do
114
- wr = RubyWatchRun.new(
115
- filewatcher: Filewatcher.new('**/*', immediate: false)
116
- )
117
-
118
- wr.start
119
- wr.stop
120
-
121
- wr.processed.should.be.empty
122
- wr.watched.should.equal 0
123
- end
124
- end
125
-
126
- describe '#watch' do
127
- it 'should detect file deletions' do
128
- wr = RubyWatchRun.new(action: :delete)
129
-
130
- wr.run
131
-
132
- wr.processed.should.equal(
133
- [[wr.filename, :deleted]]
134
- )
135
- end
136
-
137
- it 'should detect file additions' do
138
- wr = RubyWatchRun.new(action: :create)
139
-
140
- wr.run
141
-
142
- wr.processed.should.equal(
143
- [[wr.filename, :created]]
144
- )
145
- end
146
-
147
- it 'should detect file updates' do
148
- wr = RubyWatchRun.new(action: :update)
149
-
150
- wr.run
151
-
152
- wr.processed.should.equal(
153
- [[wr.filename, :updated]]
154
- )
155
- end
156
-
157
- it 'should detect new files in subfolders' do
158
- FileUtils.mkdir_p subfolder = File.expand_path('test/tmp/new_sub_folder')
159
-
160
- wr = RubyWatchRun.new(
161
- filename: File.join(subfolder, 'file.txt'),
162
- action: :create,
163
- every: true
164
- )
165
- wr.run
166
- wr.processed.should.equal(
167
- [
168
- [subfolder, :updated],
169
- [wr.filename, :created]
170
- ]
171
- )
172
- end
173
-
174
- it 'should detect new subfolders' do
175
- subfolder = 'new_sub_folder'
176
-
177
- wr = RubyWatchRun.new(
178
- filename: subfolder,
179
- directory: true,
180
- action: :create
181
- )
182
-
183
- wr.run
184
-
185
- wr.processed.should.equal(
186
- [[wr.filename, :created]]
187
- )
188
- end
189
- end
190
-
191
- describe '#stop' do
192
- it 'should work' do
193
- wr = RubyWatchRun.new
194
-
195
- wr.start
196
-
197
- wr.filewatcher.stop
198
-
199
- # Proves thread successfully joined
200
- wr.thread.join.should.equal wr.thread
201
- end
202
- end
203
-
204
- describe '#pause, #resume' do
205
- it 'should work' do
206
- wr = RubyWatchRun.new(action: :create, every: true)
207
-
208
- wr.start
209
-
210
- wr.filewatcher.pause
211
-
212
- (1..4).each do |n|
213
- File.write("test/tmp/file#{n}.txt", "content#{n}")
214
- end
215
- sleep 0.2 # Give filewatcher time to respond
216
-
217
- # update block should not have been called
218
- wr.processed.should.be.empty
219
-
220
- wr.filewatcher.resume
221
- sleep 0.2 # Give filewatcher time to respond
222
-
223
- # update block still should not have been called
224
- wr.processed.should.be.empty
225
-
226
- added_files = (5..7).to_a.map do |n|
227
- File.write(file = "test/tmp/file#{n}.txt", "content#{n}")
228
- file
229
- end
230
- sleep 0.2 # Give filewatcher time to respond
231
-
232
- wr.filewatcher.stop
233
- wr.stop
234
- wr.processed.map(&:first).should include_all_files(added_files)
235
- end
236
- end
237
-
238
- describe '#finalize' do
239
- it 'should process all remaining changes' do
240
- wr = RubyWatchRun.new(action: :create, every: true)
241
-
242
- wr.start
243
-
244
- wr.filewatcher.stop
245
- wr.thread.join
246
-
247
- added_files = (1..4).to_a.map do |n|
248
- File.write(file = "test/tmp/file#{n}.txt", "content#{n}")
249
- file
250
- end
251
-
252
- wr.filewatcher.finalize
253
-
254
- wr.processed.map(&:first).should include_all_files(added_files)
255
- end
256
- end
257
-
258
- describe 'executable' do
259
- tmp_dir = ShellWatchRun::TMP_DIR
260
-
261
- it 'should run' do
262
- null_output = Gem.win_platform? ? 'NUL' : '/dev/null'
263
- system("#{ShellWatchRun::EXECUTABLE} > #{null_output}")
264
- .should.be.true
265
- end
266
-
267
- it 'should set correct ENV variables for file creation' do
268
- filename = 'foo.txt'
269
-
270
- swr = ShellWatchRun.new(
271
- filename: filename,
272
- action: :create,
273
- dumper: :env
274
- )
275
-
276
- swr.run
277
-
278
- File.read(ShellWatchRun::ENV_FILE)
279
- .should.equal(
280
- %W[
281
- #{tmp_dir}/#{filename}
282
- #{filename}
283
- created
284
- #{tmp_dir}
285
- #{tmp_dir}/#{filename}
286
- test/tmp/#{filename}
287
- ].join(', ')
288
- )
289
- end
290
-
291
- it 'should set correct ENV variables for file deletion' do
292
- filename = 'foo.txt'
293
-
294
- swr = ShellWatchRun.new(
295
- filename: filename,
296
- action: :delete,
297
- dumper: :env
298
- )
299
-
300
- swr.run
301
-
302
- File.read(ShellWatchRun::ENV_FILE)
303
- .should.equal(
304
- %W[
305
- #{tmp_dir}/#{filename}
306
- #{filename}
307
- deleted
308
- #{tmp_dir}
309
- #{tmp_dir}/#{filename}
310
- test/tmp/#{filename}
311
- ].join(', ')
312
- )
313
- end
314
-
315
- it 'should be executed immediately with corresponding option' do
316
- swr = ShellWatchRun.new(
317
- options: { immediate: true },
318
- dumper: :watched
319
- )
320
-
321
- swr.start
322
- swr.stop
323
-
324
- File.exist?(ShellWatchRun::ENV_FILE).should.be.true
325
- File.read(ShellWatchRun::ENV_FILE).should.equal 'watched'
326
- end
327
-
328
- it 'should not be executed without immediate option and changes' do
329
- swr = ShellWatchRun.new(
330
- options: {},
331
- dumper: :watched
332
- )
333
-
334
- swr.start
335
- swr.stop
336
-
337
- File.exist?(ShellWatchRun::ENV_FILE).should.be.false
338
- end
339
- end
340
- end