rerun 0.7.0.pre3 → 0.7.0.pre4
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/rerun/watcher.rb +19 -128
- data/rerun.gemspec +1 -1
- metadata +2 -2
data/lib/rerun/watcher.rb
CHANGED
@@ -5,14 +5,13 @@ Thread.abort_on_exception = true
|
|
5
5
|
# This class will watch a directory and alert you of
|
6
6
|
# new files, modified files, deleted files.
|
7
7
|
#
|
8
|
-
#
|
8
|
+
# Now uses the Listen gem, but spawns its own thread on top.
|
9
|
+
# We should probably be accessing the Listen thread directly.
|
10
|
+
#
|
9
11
|
# Author: Alex Chaffee
|
12
|
+
#
|
10
13
|
module Rerun
|
11
14
|
class Watcher
|
12
|
-
CREATED = 0
|
13
|
-
MODIFIED = 1
|
14
|
-
DELETED = 2
|
15
|
-
|
16
15
|
attr_reader :directory, :pattern, :priority
|
17
16
|
|
18
17
|
# Create a file system watcher. Start it by calling #start.
|
@@ -32,47 +31,33 @@ module Rerun
|
|
32
31
|
|
33
32
|
@pattern = options[:pattern]
|
34
33
|
@directory = options[:directory]
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
raise InvalidDirectoryError, "Dir '#{directory}' either doesnt exist or isnt readable"
|
34
|
+
@directory.chomp!("/")
|
35
|
+
unless FileTest.exists?(@directory) && FileTest.readable?(@directory)
|
36
|
+
raise InvalidDirectoryError, "Directory '#{@directory}' either doesnt exist or isnt readable"
|
39
37
|
end
|
40
38
|
@priority = options[:priority]
|
41
|
-
|
42
|
-
@found = nil
|
43
|
-
@first_time = true
|
44
39
|
@thread = nil
|
45
40
|
end
|
46
41
|
|
47
|
-
def prime
|
48
|
-
@first_time = true
|
49
|
-
@found = {}
|
50
|
-
examine
|
51
|
-
@first_time = false
|
52
|
-
end
|
53
|
-
|
54
42
|
def start
|
55
43
|
if @thread then
|
56
44
|
raise RuntimeError, "already started"
|
57
45
|
end
|
58
46
|
|
59
|
-
prime
|
60
|
-
|
61
47
|
@thread = Thread.new do
|
62
48
|
# todo: multiple dirs
|
63
49
|
|
64
50
|
regexp = Glob.new(@pattern).to_regexp
|
65
|
-
@listener = Listen::Listener.new(@directory
|
66
|
-
|
67
|
-
#d { added }
|
68
|
-
#d { removed }
|
69
|
-
examine
|
51
|
+
@listener = Listen::Listener.new(@directory, :filter => regexp) do |modified, added, removed|
|
52
|
+
@client_callback.call(:modified => modified, :added => added, :removed => removed)
|
70
53
|
end
|
71
54
|
@listener.start
|
72
55
|
end
|
73
56
|
|
74
57
|
@thread.priority = @priority
|
75
58
|
|
59
|
+
sleep 0.1 until @listener
|
60
|
+
|
76
61
|
at_exit { stop } # try really hard to clean up after ourselves
|
77
62
|
end
|
78
63
|
|
@@ -83,116 +68,22 @@ module Rerun
|
|
83
68
|
end
|
84
69
|
end
|
85
70
|
|
86
|
-
# kill the
|
71
|
+
# kill the file watcher thread
|
87
72
|
def stop
|
73
|
+
@thread.wakeup rescue ThreadError
|
88
74
|
begin
|
89
|
-
@
|
90
|
-
rescue
|
91
|
-
#
|
92
|
-
end
|
93
|
-
begin
|
94
|
-
@thread.kill
|
95
|
-
rescue ThreadError => e
|
96
|
-
# ignore
|
75
|
+
@listener.stop
|
76
|
+
rescue Exception => e
|
77
|
+
puts "#{e.class}: #{e.message} stopping listener"
|
97
78
|
end
|
79
|
+
@thread.kill rescue ThreadError
|
98
80
|
end
|
99
81
|
|
100
|
-
# wait for the
|
82
|
+
# wait for the file watcher to finish
|
101
83
|
def join
|
102
|
-
@thread.join
|
84
|
+
@thread.join if @thread
|
103
85
|
rescue Interrupt => e
|
104
86
|
# don't care
|
105
87
|
end
|
106
|
-
|
107
|
-
private
|
108
|
-
|
109
|
-
def examine
|
110
|
-
|
111
|
-
already_examined = Hash.new()
|
112
|
-
|
113
|
-
examine_files(@directory.files, already_examined)
|
114
|
-
|
115
|
-
# now diff the found files and the examined files to see if
|
116
|
-
# something has been deleted
|
117
|
-
all_found_files = @found.keys()
|
118
|
-
all_examined_files = already_examined.keys()
|
119
|
-
intersection = all_found_files - all_examined_files
|
120
|
-
|
121
|
-
intersection.each do |file_name|
|
122
|
-
@client_callback.call(DELETED, file_name)
|
123
|
-
@found.delete(file_name)
|
124
|
-
end
|
125
|
-
|
126
|
-
end
|
127
|
-
|
128
|
-
# loops over the file list check for new or modified files
|
129
|
-
def examine_files(files, already_examined)
|
130
|
-
files.each do |file_name|
|
131
|
-
# expand the file name to the fully qual path
|
132
|
-
full_file_name = File.expand_path(file_name)
|
133
|
-
|
134
|
-
# we cant do much if the file isnt readable anyway
|
135
|
-
if File.readable?(full_file_name) then
|
136
|
-
already_examined[full_file_name] = true
|
137
|
-
stat = File.stat(full_file_name)
|
138
|
-
mod_time = stat.mtime
|
139
|
-
size = stat.size
|
140
|
-
|
141
|
-
# on the first iteration just load all of the files into the foundList
|
142
|
-
if @first_time then
|
143
|
-
@found[full_file_name] = FoundFile.new(full_file_name, mod_time, size)
|
144
|
-
else
|
145
|
-
# see if we have found this file already
|
146
|
-
found_file = @found[full_file_name]
|
147
|
-
@found[full_file_name] = FoundFile.new(full_file_name, mod_time, size)
|
148
|
-
|
149
|
-
if found_file
|
150
|
-
if mod_time > found_file.mod_time || size != found_file.size then
|
151
|
-
@client_callback.call(MODIFIED, full_file_name)
|
152
|
-
end
|
153
|
-
else
|
154
|
-
@client_callback.call(CREATED, full_file_name)
|
155
|
-
end
|
156
|
-
end
|
157
|
-
end
|
158
|
-
end
|
159
|
-
end
|
160
|
-
|
161
|
-
class Directory
|
162
|
-
attr_reader :dir, :expression
|
163
|
-
|
164
|
-
def initialize(dir, expression)
|
165
|
-
@dir, @expression = dir, expression
|
166
|
-
@dir.chop! if @dir =~ %r{/$}
|
167
|
-
end
|
168
|
-
|
169
|
-
def files
|
170
|
-
return Dir["#{@dir}/#{@expression}"]
|
171
|
-
end
|
172
|
-
end
|
173
|
-
|
174
|
-
class FoundFile
|
175
|
-
attr_reader :status, :file_name, :mod_time, :size
|
176
|
-
|
177
|
-
def initialize(file_name, mod_time, size)
|
178
|
-
@file_name, @mod_time, @size = file_name, mod_time, size
|
179
|
-
end
|
180
|
-
|
181
|
-
def modified(mod_time)
|
182
|
-
@mod_time = mod_time
|
183
|
-
end
|
184
|
-
|
185
|
-
def to_s
|
186
|
-
"FoundFile[file_name=#{file_name}, mod_time=#{mod_time.to_i}, size=#{size}]"
|
187
|
-
end
|
188
|
-
end
|
189
|
-
|
190
|
-
# if the directory you want to watch doesnt exist or isn't readable this is thrown
|
191
|
-
class InvalidDirectoryError < StandardError;
|
192
|
-
end
|
193
|
-
|
194
|
-
# if the file you want to watch doesnt exist or isn't readable this is thrown
|
195
|
-
class InvalidFileError < StandardError;
|
196
|
-
end
|
197
88
|
end
|
198
89
|
end
|
data/rerun.gemspec
CHANGED
@@ -3,7 +3,7 @@ $spec = Gem::Specification.new do |s|
|
|
3
3
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
4
4
|
|
5
5
|
s.name = 'rerun'
|
6
|
-
s.version = '0.7.0.
|
6
|
+
s.version = '0.7.0.pre4'
|
7
7
|
|
8
8
|
s.description = "Restarts your app when a file changes"
|
9
9
|
s.summary = "Launches an app, and restarts it whenever the filesystem changes."
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rerun
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.7.0.
|
4
|
+
version: 0.7.0.pre4
|
5
5
|
prerelease: 6
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -61,7 +61,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
61
61
|
version: '0'
|
62
62
|
segments:
|
63
63
|
- 0
|
64
|
-
hash:
|
64
|
+
hash: -2239978270420892770
|
65
65
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
66
66
|
none: false
|
67
67
|
requirements:
|