filewatcher 0.5.4 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/banner.txt +17 -0
- data/bin/filewatcher +61 -124
- data/lib/filewatcher.rb +69 -122
- data/lib/filewatcher/cycles.rb +47 -0
- data/lib/filewatcher/env.rb +29 -0
- data/lib/filewatcher/runner.rb +33 -0
- data/lib/filewatcher/version.rb +7 -0
- data/test/dumpers/env_dumper.rb +10 -0
- data/test/dumpers/watched_dumper.rb +5 -0
- data/test/filewatcher/test_env.rb +70 -0
- data/test/filewatcher/test_runner.rb +75 -0
- data/test/filewatcher/test_version.rb +13 -0
- data/test/helper.rb +134 -0
- data/test/test_filewatcher.rb +266 -142
- metadata +30 -22
- data/LICENSE +0 -20
- data/README.md +0 -269
- data/Rakefile +0 -19
- data/test/fixtures/file1.txt +0 -1
- data/test/fixtures/file2.txt +0 -1
- data/test/fixtures/file3.rb +0 -1
- data/test/fixtures/file4.rb +0 -1
- data/test/fixtures/subdir/file5.rb +0 -1
- data/test/fixtures/subdir/file6.rb +0 -1
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Filewatcher
|
4
|
+
# Module for all cycles in `Filewatcher#watch`
|
5
|
+
module Cycles
|
6
|
+
private
|
7
|
+
|
8
|
+
def main_cycle
|
9
|
+
while @keep_watching
|
10
|
+
@end_snapshot = mtime_snapshot if @pausing
|
11
|
+
|
12
|
+
pausing_cycle
|
13
|
+
|
14
|
+
watching_cycle
|
15
|
+
|
16
|
+
# test and clear @changes to prevent yielding the last
|
17
|
+
# changes twice if @keep_watching has just been set to false
|
18
|
+
trigger_changes
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def pausing_cycle
|
23
|
+
while @keep_watching && @pausing
|
24
|
+
update_spinner('Pausing')
|
25
|
+
sleep @interval
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def watching_cycle
|
30
|
+
while @keep_watching && !filesystem_updated? && !@pausing
|
31
|
+
update_spinner('Watching')
|
32
|
+
sleep @interval
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def trigger_changes(on_update = @on_update)
|
37
|
+
thread = Thread.new do
|
38
|
+
changes = @every ? @changes : @changes.first(1)
|
39
|
+
changes.each do |filename, event|
|
40
|
+
on_update.call(filename, event)
|
41
|
+
end
|
42
|
+
@changes.clear
|
43
|
+
end
|
44
|
+
thread.join
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'pathname'
|
4
|
+
require_relative '../filewatcher'
|
5
|
+
|
6
|
+
class Filewatcher
|
7
|
+
# Class for building ENV variables for executable
|
8
|
+
class Env
|
9
|
+
def initialize(filename, event)
|
10
|
+
@filename = filename
|
11
|
+
@event = event
|
12
|
+
@path = Pathname.new(@filename)
|
13
|
+
@realpath = @path.realpath
|
14
|
+
@current_dir = Pathname.new(Dir.pwd)
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_h
|
18
|
+
{
|
19
|
+
'FILEPATH' => (@realpath.to_s if @event != :deleted),
|
20
|
+
'FILENAME' => @filename,
|
21
|
+
'BASENAME' => @path.basename.to_s,
|
22
|
+
'EVENT' => @event.to_s,
|
23
|
+
'DIRNAME' => @path.parent.realpath.to_s,
|
24
|
+
'ABSOLUTE_FILENAME' => @realpath.to_s,
|
25
|
+
'RELATIVE_FILENAME' => @realpath.relative_path_from(@current_dir).to_s
|
26
|
+
}
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Filewatcher
|
4
|
+
## Get runner command by filename
|
5
|
+
class Runner
|
6
|
+
## Define runners for `--exec` option
|
7
|
+
RUNNERS = {
|
8
|
+
python: %w[py],
|
9
|
+
node: %w[js],
|
10
|
+
ruby: %w[rb],
|
11
|
+
perl: %w[pl],
|
12
|
+
awk: %w[awk],
|
13
|
+
php: %w[php phtml php4 php3 php5 phps]
|
14
|
+
}.freeze
|
15
|
+
|
16
|
+
def initialize(filename)
|
17
|
+
@filename = filename
|
18
|
+
@ext = File.extname(filename).delete('.')
|
19
|
+
end
|
20
|
+
|
21
|
+
def command
|
22
|
+
"env #{runner} #{@filename}" if runner
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def runner
|
28
|
+
return @runner if defined?(@runner)
|
29
|
+
@runner, _exts = RUNNERS.find { |_cmd, exts| exts.include? @ext }
|
30
|
+
@runner
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../lib/filewatcher/env'
|
4
|
+
|
5
|
+
describe Filewatcher::Env do
|
6
|
+
describe '#initialize' do
|
7
|
+
it 'should recieve filename and event' do
|
8
|
+
-> { Filewatcher::Env.new(__FILE__, :updated) }
|
9
|
+
.should.not.raise ArgumentError
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe '#to_h' do
|
14
|
+
before do
|
15
|
+
@init = proc do |file: __FILE__, event: :updated|
|
16
|
+
Filewatcher::Env.new(file, event).to_h
|
17
|
+
end
|
18
|
+
@env = @init.call
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should return Hash' do
|
22
|
+
@env.should.be.kind_of Hash
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should return Hash with FILEPATH key for created event' do
|
26
|
+
@init.call(event: :created)['FILEPATH']
|
27
|
+
.should.equal File.join(Dir.pwd, __FILE__)
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should return Hash with FILEPATH key for updated event' do
|
31
|
+
@init.call(event: :updated)['FILEPATH']
|
32
|
+
.should.equal File.join(Dir.pwd, __FILE__)
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'should return Hash without FILEPATH key for deleted event' do
|
36
|
+
@init.call(event: :deleted)['FILEPATH']
|
37
|
+
.should.equal nil
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'should return Hash with FILENAME key' do
|
41
|
+
@init.call(file: __FILE__)['FILENAME']
|
42
|
+
.should.equal __FILE__
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'should return Hash with BASENAME key' do
|
46
|
+
@init.call(file: __FILE__)['BASENAME']
|
47
|
+
.should.equal File.basename(__FILE__)
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'should return Hash with EVENT key' do
|
51
|
+
@init.call(event: :updated)['EVENT']
|
52
|
+
.should.equal 'updated'
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'should return Hash with DIRNAME key' do
|
56
|
+
@init.call(file: __FILE__)['DIRNAME']
|
57
|
+
.should.equal File.dirname(File.join(Dir.pwd, __FILE__))
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'should return Hash with ABSOLUTE_FILENAME key' do
|
61
|
+
@init.call(file: __FILE__)['ABSOLUTE_FILENAME']
|
62
|
+
.should.equal File.join(Dir.pwd, __FILE__)
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'should return Hash with RELATIVE_FILENAME key' do
|
66
|
+
@init.call(file: __FILE__)['RELATIVE_FILENAME']
|
67
|
+
.should.equal __FILE__
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,75 @@
|
|
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
|
@@ -0,0 +1,13 @@
|
|
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
ADDED
@@ -0,0 +1,134 @@
|
|
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, :filewatcher, :thread, :watched, :processed
|
16
|
+
|
17
|
+
def initialize(
|
18
|
+
filename: 'tmp_file.txt',
|
19
|
+
directory: false,
|
20
|
+
every: false,
|
21
|
+
filewatcher: Filewatcher.new(
|
22
|
+
File.join(TMP_DIR, '**', '*'), interval: 0.1, every: every
|
23
|
+
),
|
24
|
+
action: :update
|
25
|
+
)
|
26
|
+
@filename =
|
27
|
+
filename.start_with?('/', '~') ? filename : File.join(TMP_DIR, filename)
|
28
|
+
@directory = directory
|
29
|
+
@filewatcher = filewatcher
|
30
|
+
@action = action
|
31
|
+
end
|
32
|
+
|
33
|
+
def start
|
34
|
+
File.write(@filename, 'content1') unless @action == :create
|
35
|
+
|
36
|
+
@thread = thread_initialize
|
37
|
+
sleep 3 # thread needs a chance to start
|
38
|
+
end
|
39
|
+
|
40
|
+
def run
|
41
|
+
start
|
42
|
+
|
43
|
+
make_changes
|
44
|
+
# Some OS, filesystems and Ruby interpretators
|
45
|
+
# doesn't catch milliseconds of `File.mtime`
|
46
|
+
sleep 3
|
47
|
+
|
48
|
+
stop
|
49
|
+
end
|
50
|
+
|
51
|
+
def stop
|
52
|
+
FileUtils.rm_r(@filename) if File.exist?(@filename)
|
53
|
+
@thread.exit
|
54
|
+
sleep 3
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def thread_initialize
|
60
|
+
@watched ||= 0
|
61
|
+
Thread.new(
|
62
|
+
@filewatcher, @processed = []
|
63
|
+
) do |filewatcher, processed|
|
64
|
+
filewatcher.watch do |filename, event|
|
65
|
+
increment_watched
|
66
|
+
processed.push([filename, event])
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def increment_watched
|
72
|
+
@watched += 1
|
73
|
+
end
|
74
|
+
|
75
|
+
def make_changes
|
76
|
+
return FileUtils.remove(@filename) if @action == :delete
|
77
|
+
return FileUtils.mkdir_p(@filename) if @directory
|
78
|
+
File.write(@filename, 'content2')
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
class ShellWatchRun
|
83
|
+
EXECUTABLE = "#{'ruby ' if Gem.win_platform?}" \
|
84
|
+
"#{File.realpath File.join(__dir__, '..', 'bin', 'filewatcher')}".freeze
|
85
|
+
|
86
|
+
attr_reader :output
|
87
|
+
|
88
|
+
def initialize(
|
89
|
+
options: '',
|
90
|
+
dumper: :watched,
|
91
|
+
output: File.join(WatchRun::TMP_DIR, 'env')
|
92
|
+
)
|
93
|
+
@options = options
|
94
|
+
@dumper = dumper
|
95
|
+
@output = output
|
96
|
+
end
|
97
|
+
|
98
|
+
def start
|
99
|
+
@pid = spawn(
|
100
|
+
"#{EXECUTABLE} #{@options} \"#{WatchRun::TMP_DIR}/foo*\"" \
|
101
|
+
" \"ruby #{File.join(__dir__, 'dumpers', "#{@dumper}_dumper.rb")}\""
|
102
|
+
)
|
103
|
+
Process.detach(@pid)
|
104
|
+
sleep 12
|
105
|
+
end
|
106
|
+
|
107
|
+
def run
|
108
|
+
start
|
109
|
+
|
110
|
+
make_changes
|
111
|
+
|
112
|
+
stop
|
113
|
+
end
|
114
|
+
|
115
|
+
def stop
|
116
|
+
Process.kill('KILL', @pid)
|
117
|
+
sleep 6
|
118
|
+
end
|
119
|
+
|
120
|
+
private
|
121
|
+
|
122
|
+
def make_changes
|
123
|
+
FileUtils.touch "#{WatchRun::TMP_DIR}/foo.txt"
|
124
|
+
sleep 12
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
custom_matcher :include_all_files do |obj, elements|
|
129
|
+
elements.all? { |element| obj.include? File.expand_path(element) }
|
130
|
+
end
|
131
|
+
|
132
|
+
def dump_to_env_file(content)
|
133
|
+
File.write File.join(WatchRun::TMP_DIR, 'env'), content
|
134
|
+
end
|
data/test/test_filewatcher.rb
CHANGED
@@ -1,181 +1,305 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
3
|
require 'fileutils'
|
4
|
-
|
4
|
+
require_relative '../lib/filewatcher'
|
5
5
|
|
6
|
+
describe Filewatcher do
|
7
|
+
before do
|
8
|
+
FileUtils.mkdir_p WatchRun::TMP_DIR
|
9
|
+
end
|
6
10
|
|
11
|
+
after do
|
12
|
+
FileUtils.rm_r WatchRun::TMP_DIR
|
13
|
+
end
|
7
14
|
|
8
|
-
describe
|
15
|
+
describe '#initialize' do
|
16
|
+
it 'should exclude selected file patterns' do
|
17
|
+
wr = WatchRun.new(
|
18
|
+
filewatcher: Filewatcher.new(
|
19
|
+
File.expand_path('test/tmp/**/*'),
|
20
|
+
exclude: File.expand_path('test/tmp/**/*.txt')
|
21
|
+
)
|
22
|
+
)
|
9
23
|
|
10
|
-
|
11
|
-
%w(test/fixtures/file4.rb
|
12
|
-
test/fixtures/subdir/file6.rb
|
13
|
-
test/fixtures/subdir/file5.rb
|
14
|
-
test/fixtures/file2.txt
|
15
|
-
test/fixtures/file1.txt
|
16
|
-
test/fixtures/file3.rb)
|
24
|
+
wr.run
|
17
25
|
|
18
|
-
|
26
|
+
wr.processed.should.be.empty
|
27
|
+
end
|
19
28
|
|
20
|
-
|
29
|
+
it 'should handle absolute paths with globs' do
|
30
|
+
wr = WatchRun.new(
|
31
|
+
filewatcher: Filewatcher.new(
|
32
|
+
File.expand_path('test/tmp/**/*')
|
33
|
+
)
|
34
|
+
)
|
21
35
|
|
22
|
-
|
23
|
-
FileUtils.rm_rf subfolder
|
24
|
-
end
|
36
|
+
wr.run
|
25
37
|
|
26
|
-
|
27
|
-
|
28
|
-
|
38
|
+
wr.processed.should.equal(
|
39
|
+
[[wr.filename, :updated]]
|
40
|
+
)
|
41
|
+
end
|
29
42
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
test/fixtures/subdir/file6.rb
|
35
|
-
test/fixtures/subdir/file5.rb
|
36
|
-
test/fixtures/file3.rb)
|
37
|
-
filewatcher.filenames.should.satisfy &includes_all(filtered_fixtures.map { |it| File.expand_path(it) })
|
38
|
-
end
|
39
|
-
|
40
|
-
it "should handle absolute paths with globs" do
|
41
|
-
filewatcher = FileWatcher.new(File.expand_path('test/fixtures/**/*'))
|
43
|
+
it 'should handle globs' do
|
44
|
+
wr = WatchRun.new(
|
45
|
+
filewatcher: Filewatcher.new('test/tmp/**/*')
|
46
|
+
)
|
42
47
|
|
43
|
-
|
44
|
-
end
|
45
|
-
|
46
|
-
it "should handle globs" do
|
47
|
-
filewatcher = FileWatcher.new('test/fixtures/**/*')
|
48
|
+
wr.run
|
48
49
|
|
49
|
-
|
50
|
-
|
50
|
+
wr.processed.should.equal(
|
51
|
+
[[wr.filename, :updated]]
|
52
|
+
)
|
53
|
+
end
|
51
54
|
|
55
|
+
it 'should handle explicit relative paths with globs' do
|
56
|
+
wr = WatchRun.new(
|
57
|
+
filewatcher: Filewatcher.new('./test/tmp/**/*')
|
58
|
+
)
|
52
59
|
|
53
|
-
|
54
|
-
filewatcher = FileWatcher.new('./test/fixtures/**/*')
|
60
|
+
wr.run
|
55
61
|
|
56
|
-
|
57
|
-
|
62
|
+
wr.processed.should.equal(
|
63
|
+
[[wr.filename, :updated]]
|
64
|
+
)
|
65
|
+
end
|
58
66
|
|
59
|
-
|
60
|
-
|
67
|
+
it 'should handle explicit relative paths' do
|
68
|
+
wr = WatchRun.new(
|
69
|
+
filewatcher: Filewatcher.new('./test/tmp')
|
70
|
+
)
|
61
71
|
|
62
|
-
|
63
|
-
|
72
|
+
wr.run
|
73
|
+
|
74
|
+
wr.processed.should.equal(
|
75
|
+
[[wr.filename, :updated]]
|
76
|
+
)
|
77
|
+
end
|
64
78
|
|
65
|
-
|
66
|
-
|
67
|
-
open(filename, 'w') { |f| f.puts 'content1' }
|
79
|
+
it 'should handle tilde expansion' do
|
80
|
+
filename = File.expand_path('~/file_watcher_1.txt')
|
68
81
|
|
69
|
-
|
82
|
+
wr = WatchRun.new(
|
83
|
+
filename: filename,
|
84
|
+
filewatcher: Filewatcher.new('~/file_watcher_1.txt')
|
85
|
+
)
|
70
86
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
87
|
+
wr.run
|
88
|
+
|
89
|
+
wr.processed.should.equal(
|
90
|
+
[[filename, :updated]]
|
91
|
+
)
|
75
92
|
end
|
76
|
-
end
|
77
93
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
filewatcher.filesystem_updated?.should.be.false
|
83
|
-
FileUtils.rm(filename)
|
84
|
-
filewatcher.filesystem_updated?.should.be.true
|
85
|
-
end
|
94
|
+
it 'should immediately run with corresponding option' do
|
95
|
+
wr = WatchRun.new(
|
96
|
+
filewatcher: Filewatcher.new('**/*', immediate: true)
|
97
|
+
)
|
86
98
|
|
87
|
-
|
88
|
-
|
89
|
-
FileUtils.rm(filename) if File.exists?(filename)
|
90
|
-
filewatcher = FileWatcher.new(["test/fixtures"])
|
91
|
-
filewatcher.filesystem_updated?.should.be.false
|
92
|
-
open(filename,"w") { |f| f.puts "content1" }
|
93
|
-
filewatcher.filesystem_updated?.should.be.true
|
94
|
-
end
|
99
|
+
wr.start
|
100
|
+
wr.stop
|
95
101
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
filewatcher = FileWatcher.new(["test/fixtures"])
|
100
|
-
filewatcher.filesystem_updated?.should.be.false
|
101
|
-
sleep 1
|
102
|
-
open(filename,"w") { |f| f.puts "content2" }
|
103
|
-
filewatcher.filesystem_updated?.should.be.true
|
104
|
-
end
|
102
|
+
wr.processed.should.equal [['', '']]
|
103
|
+
wr.watched.should.be > 0
|
104
|
+
end
|
105
105
|
|
106
|
-
|
107
|
-
|
106
|
+
it 'should not be executed without immediate option and changes' do
|
107
|
+
wr = WatchRun.new(
|
108
|
+
filewatcher: Filewatcher.new('**/*', immediate: false)
|
109
|
+
)
|
108
110
|
|
109
|
-
|
110
|
-
|
111
|
+
wr.start
|
112
|
+
wr.stop
|
111
113
|
|
112
|
-
|
113
|
-
|
114
|
+
wr.processed.should.be.empty
|
115
|
+
wr.watched.should.equal 0
|
116
|
+
end
|
114
117
|
end
|
115
118
|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
+
describe '#watch' do
|
120
|
+
it 'should detect file deletions' do
|
121
|
+
wr = WatchRun.new(action: :delete)
|
122
|
+
|
123
|
+
wr.run
|
124
|
+
|
125
|
+
wr.processed.should.equal(
|
126
|
+
[[wr.filename, :deleted]]
|
127
|
+
)
|
128
|
+
end
|
129
|
+
|
130
|
+
it 'should detect file additions' do
|
131
|
+
wr = WatchRun.new(action: :create)
|
132
|
+
|
133
|
+
wr.run
|
134
|
+
|
135
|
+
wr.processed.should.equal(
|
136
|
+
[[wr.filename, :created]]
|
137
|
+
)
|
138
|
+
end
|
139
|
+
|
140
|
+
it 'should detect file updates' do
|
141
|
+
wr = WatchRun.new(action: :update)
|
142
|
+
|
143
|
+
wr.run
|
144
|
+
|
145
|
+
wr.processed.should.equal(
|
146
|
+
[[wr.filename, :updated]]
|
147
|
+
)
|
148
|
+
end
|
149
|
+
|
150
|
+
it 'should detect new files in subfolders' do
|
151
|
+
FileUtils.mkdir_p subfolder = File.expand_path('test/tmp/new_sub_folder')
|
152
|
+
|
153
|
+
wr = WatchRun.new(
|
154
|
+
filename: File.join(subfolder, 'file.txt'),
|
155
|
+
action: :create,
|
156
|
+
every: true
|
157
|
+
)
|
158
|
+
wr.run
|
159
|
+
wr.processed.should.equal(
|
160
|
+
[
|
161
|
+
[subfolder, :updated],
|
162
|
+
[wr.filename, :created]
|
163
|
+
]
|
164
|
+
)
|
165
|
+
end
|
119
166
|
|
120
|
-
|
121
|
-
|
167
|
+
it 'should detect new subfolders' do
|
168
|
+
subfolder = 'new_sub_folder'
|
169
|
+
|
170
|
+
wr = WatchRun.new(
|
171
|
+
filename: subfolder,
|
172
|
+
directory: true,
|
173
|
+
action: :create
|
174
|
+
)
|
175
|
+
|
176
|
+
wr.run
|
177
|
+
|
178
|
+
wr.processed.should.equal(
|
179
|
+
[[wr.filename, :created]]
|
180
|
+
)
|
181
|
+
end
|
122
182
|
end
|
123
183
|
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
184
|
+
describe '#stop' do
|
185
|
+
it 'should work' do
|
186
|
+
wr = WatchRun.new
|
187
|
+
|
188
|
+
wr.start
|
189
|
+
|
190
|
+
wr.filewatcher.stop
|
191
|
+
|
192
|
+
# Proves thread successfully joined
|
193
|
+
wr.thread.join.should.equal wr.thread
|
194
|
+
end
|
130
195
|
end
|
131
196
|
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
197
|
+
describe '#pause, #resume' do
|
198
|
+
it 'should work' do
|
199
|
+
wr = WatchRun.new(action: :create, every: true)
|
200
|
+
|
201
|
+
wr.start
|
202
|
+
|
203
|
+
wr.filewatcher.pause
|
204
|
+
|
205
|
+
(1..4).each do |n|
|
206
|
+
File.write("test/tmp/file#{n}.txt", "content#{n}")
|
207
|
+
end
|
208
|
+
sleep 0.2 # Give filewatcher time to respond
|
209
|
+
|
210
|
+
# update block should not have been called
|
211
|
+
wr.processed.should.be.empty
|
212
|
+
|
213
|
+
wr.filewatcher.resume
|
214
|
+
sleep 0.2 # Give filewatcher time to respond
|
215
|
+
|
216
|
+
# update block still should not have been called
|
217
|
+
wr.processed.should.be.empty
|
218
|
+
|
219
|
+
added_files = (5..7).to_a.map do |n|
|
220
|
+
File.write(file = "test/tmp/file#{n}.txt", "content#{n}")
|
221
|
+
file
|
222
|
+
end
|
223
|
+
sleep 0.2 # Give filewatcher time to respond
|
224
|
+
|
225
|
+
wr.filewatcher.stop
|
226
|
+
wr.stop
|
227
|
+
wr.processed.map(&:first).should include_all_files(added_files)
|
228
|
+
end
|
157
229
|
end
|
158
230
|
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
puts "Actual: #{processed.inspect}"
|
178
|
-
# processed.should.satisfy &includes_all(added_files)
|
231
|
+
describe '#finalize' do
|
232
|
+
it 'should process all remaining changes' do
|
233
|
+
wr = WatchRun.new(action: :create, every: true)
|
234
|
+
|
235
|
+
wr.start
|
236
|
+
|
237
|
+
wr.filewatcher.stop
|
238
|
+
wr.thread.join
|
239
|
+
|
240
|
+
added_files = (1..4).to_a.map do |n|
|
241
|
+
File.write(file = "test/tmp/file#{n}.txt", "content#{n}")
|
242
|
+
file
|
243
|
+
end
|
244
|
+
|
245
|
+
wr.filewatcher.finalize
|
246
|
+
|
247
|
+
wr.processed.map(&:first).should include_all_files(added_files)
|
248
|
+
end
|
179
249
|
end
|
180
250
|
|
251
|
+
describe 'executable' do
|
252
|
+
tmp_dir = WatchRun::TMP_DIR
|
253
|
+
|
254
|
+
it 'should run' do
|
255
|
+
null_output = Gem.win_platform? ? 'NUL' : '/dev/null'
|
256
|
+
system("#{ShellWatchRun::EXECUTABLE} > #{null_output}")
|
257
|
+
.should.be.true
|
258
|
+
end
|
259
|
+
|
260
|
+
it 'should set correct ENV variables' do
|
261
|
+
swr = ShellWatchRun.new(
|
262
|
+
dumper: :env
|
263
|
+
)
|
264
|
+
|
265
|
+
swr.run
|
266
|
+
|
267
|
+
File.read(swr.output)
|
268
|
+
.should.equal(
|
269
|
+
%W[
|
270
|
+
#{tmp_dir}/foo.txt
|
271
|
+
foo.txt
|
272
|
+
created
|
273
|
+
#{tmp_dir}
|
274
|
+
#{tmp_dir}/foo.txt
|
275
|
+
test/tmp/foo.txt
|
276
|
+
].join(', ')
|
277
|
+
)
|
278
|
+
end
|
279
|
+
|
280
|
+
it 'should be executed immediately with corresponding option' do
|
281
|
+
swr = ShellWatchRun.new(
|
282
|
+
options: '--immediate',
|
283
|
+
dumper: :watched
|
284
|
+
)
|
285
|
+
|
286
|
+
swr.start
|
287
|
+
swr.stop
|
288
|
+
|
289
|
+
File.exist?(swr.output).should.be.true
|
290
|
+
File.read(swr.output).should.equal 'watched'
|
291
|
+
end
|
292
|
+
|
293
|
+
it 'should not be executed without immediate option and changes' do
|
294
|
+
swr = ShellWatchRun.new(
|
295
|
+
options: '',
|
296
|
+
dumper: :watched
|
297
|
+
)
|
298
|
+
|
299
|
+
swr.start
|
300
|
+
swr.stop
|
301
|
+
|
302
|
+
File.exist?(swr.output).should.be.false
|
303
|
+
end
|
304
|
+
end
|
181
305
|
end
|