filewatcher 1.1.1 → 2.0.0.beta5
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 +5 -5
- data/lib/filewatcher.rb +46 -60
- data/lib/filewatcher/cycles.rb +21 -12
- data/lib/filewatcher/snapshot.rb +64 -0
- data/lib/filewatcher/snapshots.rb +47 -0
- data/lib/filewatcher/spec_helper.rb +89 -0
- data/lib/filewatcher/spec_helper/watch_run.rb +72 -0
- data/lib/filewatcher/version.rb +1 -3
- data/spec/filewatcher/snapshot_spec.rb +68 -0
- data/spec/filewatcher/version_spec.rb +9 -0
- data/spec/filewatcher_spec.rb +302 -0
- data/spec/spec_helper.rb +22 -0
- data/spec/spec_helper/ruby_watch_run.rb +82 -0
- metadata +110 -46
- data/bin/banner.txt +0 -17
- data/bin/filewatcher +0 -106
- data/lib/filewatcher/env.rb +0 -33
- data/lib/filewatcher/runner.rb +0 -33
- data/test/dumpers/env_dumper.rb +0 -10
- data/test/dumpers/watched_dumper.rb +0 -5
- data/test/filewatcher/test_env.rb +0 -70
- data/test/filewatcher/test_runner.rb +0 -75
- data/test/filewatcher/test_version.rb +0 -13
- data/test/helper.rb +0 -238
- data/test/test_filewatcher.rb +0 -354
data/lib/filewatcher/env.rb
DELETED
@@ -1,33 +0,0 @@
|
|
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.exist? ? @path.realpath : @path
|
14
|
-
@current_dir = Pathname.new(Dir.pwd)
|
15
|
-
# For safely `immediate` option with empty-strings arguments
|
16
|
-
@relative_path =
|
17
|
-
(@realpath.to_s.empty? ? @current_dir : @realpath)
|
18
|
-
.relative_path_from(@current_dir)
|
19
|
-
end
|
20
|
-
|
21
|
-
def to_h
|
22
|
-
{
|
23
|
-
'FILEPATH' => (@realpath.to_s if @event != :deleted),
|
24
|
-
'FILENAME' => @filename,
|
25
|
-
'BASENAME' => @path.basename.to_s,
|
26
|
-
'EVENT' => @event.to_s,
|
27
|
-
'DIRNAME' => @path.parent.realpath.to_s,
|
28
|
-
'ABSOLUTE_FILENAME' => @realpath.to_s,
|
29
|
-
'RELATIVE_FILENAME' => @relative_path.to_s
|
30
|
-
}
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
data/lib/filewatcher/runner.rb
DELETED
@@ -1,33 +0,0 @@
|
|
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
|
data/test/dumpers/env_dumper.rb
DELETED
@@ -1,70 +0,0 @@
|
|
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
|
@@ -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,238 +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 =~ %r{^(/|~|[A-Z]:)} ? 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
|
-
SLEEP_MULTIPLIER = Gem::Platform.local.os == 'darwin' ? 5 : 1
|
59
|
-
|
60
|
-
attr_reader :filewatcher, :thread, :watched, :processed
|
61
|
-
|
62
|
-
def initialize(
|
63
|
-
every: false,
|
64
|
-
filewatcher: Filewatcher.new(
|
65
|
-
File.join(TMP_DIR, '**', '*'), interval: 0.1, every: every
|
66
|
-
),
|
67
|
-
**args
|
68
|
-
)
|
69
|
-
super(**args)
|
70
|
-
@filewatcher = filewatcher
|
71
|
-
end
|
72
|
-
|
73
|
-
def start
|
74
|
-
super
|
75
|
-
@thread = thread_initialize
|
76
|
-
# thread needs a chance to start
|
77
|
-
wait 12 do
|
78
|
-
filewatcher.keep_watching
|
79
|
-
end
|
80
|
-
|
81
|
-
# a little more time
|
82
|
-
sleep 1 * SLEEP_MULTIPLIER
|
83
|
-
end
|
84
|
-
|
85
|
-
def stop
|
86
|
-
thread.exit
|
87
|
-
|
88
|
-
wait 12 do
|
89
|
-
thread.stop?
|
90
|
-
end
|
91
|
-
|
92
|
-
# a little more time
|
93
|
-
sleep 1 * SLEEP_MULTIPLIER
|
94
|
-
|
95
|
-
super
|
96
|
-
end
|
97
|
-
|
98
|
-
private
|
99
|
-
|
100
|
-
def make_changes
|
101
|
-
super
|
102
|
-
|
103
|
-
# Some OS, filesystems and Ruby interpretators
|
104
|
-
# doesn't catch milliseconds of `File.mtime`
|
105
|
-
wait 12 do
|
106
|
-
processed.any?
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
def thread_initialize
|
111
|
-
@watched ||= 0
|
112
|
-
Thread.new(
|
113
|
-
@filewatcher, @processed = []
|
114
|
-
) do |filewatcher, processed|
|
115
|
-
filewatcher.watch do |filename, event|
|
116
|
-
increment_watched
|
117
|
-
processed.push([filename, event])
|
118
|
-
end
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
def increment_watched
|
123
|
-
@watched += 1
|
124
|
-
end
|
125
|
-
|
126
|
-
def wait(seconds)
|
127
|
-
max_count = seconds / filewatcher.interval
|
128
|
-
count = 0
|
129
|
-
while count < max_count && !yield
|
130
|
-
sleep filewatcher.interval
|
131
|
-
count += 1
|
132
|
-
end
|
133
|
-
end
|
134
|
-
end
|
135
|
-
|
136
|
-
class ShellWatchRun < WatchRun
|
137
|
-
EXECUTABLE = "#{'ruby ' if Gem.win_platform?}" \
|
138
|
-
"#{File.realpath File.join(__dir__, '..', 'bin', 'filewatcher')}".freeze
|
139
|
-
|
140
|
-
SLEEP_MULTIPLIER = RUBY_PLATFORM == 'java' ? 5 : 1
|
141
|
-
|
142
|
-
ENV_FILE = File.join(TMP_DIR, 'env')
|
143
|
-
|
144
|
-
def initialize(
|
145
|
-
options: {},
|
146
|
-
dumper: :watched,
|
147
|
-
**args
|
148
|
-
)
|
149
|
-
super(**args)
|
150
|
-
@options = options
|
151
|
-
@options[:interval] ||= 0.1
|
152
|
-
@options_string =
|
153
|
-
@options.map { |key, value| "--#{key}=#{value}" }.join(' ')
|
154
|
-
@dumper = dumper
|
155
|
-
end
|
156
|
-
|
157
|
-
def start
|
158
|
-
super
|
159
|
-
|
160
|
-
@pid = spawn_filewatcher
|
161
|
-
|
162
|
-
Process.detach(@pid)
|
163
|
-
|
164
|
-
wait 12 do
|
165
|
-
pid_state == 'S' && (!@options[:immediate] || File.exist?(ENV_FILE))
|
166
|
-
end
|
167
|
-
|
168
|
-
# a little more time
|
169
|
-
sleep 1 * SLEEP_MULTIPLIER
|
170
|
-
end
|
171
|
-
|
172
|
-
def stop
|
173
|
-
kill_filewatcher
|
174
|
-
|
175
|
-
wait 12 do
|
176
|
-
pid_state.empty?
|
177
|
-
end
|
178
|
-
|
179
|
-
# a little more time
|
180
|
-
sleep 1 * SLEEP_MULTIPLIER
|
181
|
-
|
182
|
-
super
|
183
|
-
end
|
184
|
-
|
185
|
-
private
|
186
|
-
|
187
|
-
SPAWN_OPTIONS = Gem.win_platform? ? {} : { pgroup: true }
|
188
|
-
|
189
|
-
def spawn_filewatcher
|
190
|
-
spawn(
|
191
|
-
"#{EXECUTABLE} #{@options_string} \"#{@filename}\"" \
|
192
|
-
" \"ruby #{File.join(__dir__, "dumpers/#{@dumper}_dumper.rb")}\"",
|
193
|
-
**SPAWN_OPTIONS
|
194
|
-
)
|
195
|
-
end
|
196
|
-
|
197
|
-
def make_changes
|
198
|
-
super
|
199
|
-
|
200
|
-
wait 12 do
|
201
|
-
File.exist?(ENV_FILE)
|
202
|
-
end
|
203
|
-
end
|
204
|
-
|
205
|
-
def kill_filewatcher
|
206
|
-
if Gem.win_platform?
|
207
|
-
Process.kill('KILL', @pid)
|
208
|
-
else
|
209
|
-
## Problems: https://github.com/thomasfl/filewatcher/pull/83
|
210
|
-
## Solution: https://stackoverflow.com/a/45032252/2630849
|
211
|
-
Process.kill('TERM', -Process.getpgid(@pid))
|
212
|
-
Process.waitall
|
213
|
-
end
|
214
|
-
end
|
215
|
-
|
216
|
-
def pid_state
|
217
|
-
## For macOS output:
|
218
|
-
## https://travis-ci.org/thomasfl/filewatcher/jobs/304433538
|
219
|
-
`ps -ho state -p #{@pid}`.sub('STAT', '').strip
|
220
|
-
end
|
221
|
-
|
222
|
-
def wait(seconds)
|
223
|
-
max_count = seconds / @options[:interval]
|
224
|
-
count = 0
|
225
|
-
while count < max_count && !yield
|
226
|
-
sleep @options[:interval]
|
227
|
-
count += 1
|
228
|
-
end
|
229
|
-
end
|
230
|
-
end
|
231
|
-
|
232
|
-
custom_matcher :include_all_files do |obj, elements|
|
233
|
-
elements.all? { |element| obj.include? File.expand_path(element) }
|
234
|
-
end
|
235
|
-
|
236
|
-
def dump_to_env_file(content)
|
237
|
-
File.write File.join(ShellWatchRun::ENV_FILE), content
|
238
|
-
end
|