autorespawn 0.4.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8d577eb9b9d0d736476e22b3431a5a791ed704e6
4
- data.tar.gz: f80a5b60abbe557c1316a9a560be65be4243a43c
3
+ metadata.gz: 7611aabbaa1ad2c8d52ca80fa16ea0c66960dec5
4
+ data.tar.gz: 72812f7b5baf6deefa772122cd8cee4f29f4ff53
5
5
  SHA512:
6
- metadata.gz: 869b489054c370e01612a5b1b7dfed6a0dad02de82e1b00ac8de9b8903cb0d0020b68dccd3e8b0fa0fa1b2aaa1e3793cbfe0d3efe40f154c546fe25502e92a4f
7
- data.tar.gz: 5ffdcebad8ac26a6f37068543de8f36d0e641ccd91d4625a06821cd1d12f0e978a7f079cb4d7508928bf26afd6c0587af8a33468db95792f88fa9e54314eb6e0
6
+ metadata.gz: d94adfafc6192c05751edfb426a4f0fda3077bdc111ccdfdda44374feb4bba8410308bc13a3053e1d4017b3a20462b14b82a69acf9dbe3a67ecacfed67e93962
7
+ data.tar.gz: f466b32d71fdf8a7b14216c85025c20727f14a361331d779c98f6e3a5deb317b8a33e2c9d3ced02c14075add52fd78e58b30d53147dedf71ea96fffa8ea86152
data/.gitignore CHANGED
@@ -8,3 +8,4 @@
8
8
  /spec/reports/
9
9
  /tmp/
10
10
  /vendor/
11
+ .*.sw?
data/autorespawn.gemspec CHANGED
@@ -31,5 +31,6 @@ EOD
31
31
  spec.add_development_dependency "minitest", ">= 5.0", "~> 5.0"
32
32
  spec.add_development_dependency "fakefs", ">= 0.6", "~> 0.6.0"
33
33
  spec.add_development_dependency 'flexmock', ">= 2.0", '~> 2.0'
34
+ spec.add_development_dependency "simplecov", '>= 0.11'
34
35
  spec.add_development_dependency "coveralls"
35
36
  end
data/lib/autorespawn.rb CHANGED
@@ -8,6 +8,7 @@
8
8
  require "autorespawn/slave"
9
9
  require "autorespawn/self"
10
10
  require "autorespawn/manager"
11
+ require 'autorespawn/tracked_file'
11
12
 
12
13
  # Automatically exec's the current program when one of the source file changes
13
14
  #
@@ -25,6 +25,9 @@ class Manager
25
25
  attr_reader :active_slaves
26
26
  # @return [Array<Slave>] list of slaves explicitely queued with {#queue}
27
27
  attr_reader :queued_slaves
28
+ # @return [Hash<Pathname,TrackedFile>] the whole set of files that are
29
+ # tracked by this manager's slaves
30
+ attr_reader :tracked_files
28
31
 
29
32
  # @!group Hooks
30
33
 
@@ -74,6 +77,7 @@ def initialize(name: nil, parallel_level: 1)
74
77
  @workers = Array.new
75
78
  @name = name
76
79
  @seed = ProgramID.for_self
80
+ @tracked_files = Hash.new
77
81
 
78
82
  @self_slave = Self.new(name: name)
79
83
  @workers << self_slave
@@ -121,6 +125,7 @@ def active?(slave)
121
125
  # reporting / tracking
122
126
  def add_slave(*cmdline, name: nil, **spawn_options)
123
127
  slave = Slave.new(*cmdline, name: name, seed: seed, **spawn_options)
128
+ slave.needed!
124
129
  register_slave(slave)
125
130
  slave
126
131
  end
@@ -168,11 +173,20 @@ def collect_finished_slaves
168
173
  def process_finished_slave(pid, status)
169
174
  return if !(slave = active_slaves.delete(pid))
170
175
 
171
- slave.finished(status)
176
+ if slave.finished(status).empty?
177
+ # Do not register the slave if it is already marked as needed?
178
+ slave.each_tracked_file(with_status: true) do |path, mtime, size|
179
+ tracker = (tracked_files[path] ||= TrackedFile.new(path, mtime: mtime, size: size))
180
+ tracker.slaves << slave
181
+ end
182
+ slave.not_needed!
183
+ end
184
+
172
185
  slave.subcommands.each do |name, cmdline, spawn_options|
173
186
  add_slave(*cmdline, name: name, **spawn_options)
174
187
  end
175
188
  seed.merge!(slave.program_id)
189
+
176
190
  run_hook :on_slave_finished, slave
177
191
  slave
178
192
  end
@@ -214,10 +228,25 @@ def run
214
228
  end
215
229
  end
216
230
 
231
+ def trigger_slaves_as_necessary
232
+ tracked_files.delete_if do |path, tracker|
233
+ tracker.slaves.delete_if(&:needed?)
234
+ if tracker.slaves.empty?
235
+ true
236
+ elsif tracker.update
237
+ tracker.slaves.each(&:needed!)
238
+ true
239
+ end
240
+ end
241
+ end
242
+
217
243
  # Wait for children to terminate and spawns them when needed
218
- def poll(autospawn: true)
244
+ def poll(autospawn: true, update_files: true)
219
245
  finished_slaves = collect_finished_slaves
220
246
  new_slaves = Array.new
247
+
248
+ trigger_slaves_as_necessary
249
+
221
250
  while active_slaves.size < parallel_level + 1
222
251
  if slave = queued_slaves.find { |s| !s.running? }
223
252
  queued_slaves.delete(slave)
@@ -228,6 +257,9 @@ def poll(autospawn: true)
228
257
 
229
258
  if slave
230
259
  slave.spawn
260
+ # We manually track the slave's needed flag, just forcefully
261
+ # set it to false at that point
262
+ slave.not_needed!
231
263
  run_hook :__on_slave_start, slave
232
264
  new_slaves << slave
233
265
  active_slaves[slave.pid] = slave
@@ -128,8 +128,15 @@ def refresh
128
128
  # Enumerate the path of all the files that are being tracked
129
129
  #
130
130
  # @yieldparam [Pathname] path
131
- def each_tracked_file(&block)
132
- files.keys.each(&block)
131
+ def each_tracked_file(with_status: false, &block)
132
+ if with_status
133
+ return enum_for(__method__, with_status: true) if !block_given?
134
+ files.each do |path, info|
135
+ yield(path, info.mtime, info.size)
136
+ end
137
+ else
138
+ files.keys.each(&block)
139
+ end
133
140
  end
134
141
 
135
142
  # Returns a string that can ID this program
@@ -7,7 +7,7 @@ def initialize(*args, **options)
7
7
  @pid = Process.pid
8
8
  end
9
9
 
10
- def needed?; false end
10
+ def needed?(*); false end
11
11
  def needed!; end
12
12
  def spawn
13
13
  pid
@@ -61,6 +61,11 @@ def inspect
61
61
  "#<Autorespawn::Slave #{object_id.to_s(16)} #{cmdline.join(" ")}>"
62
62
  end
63
63
 
64
+ # Enumerate the files that are tracked for {#needed?}
65
+ def each_tracked_file(with_status: false, &block)
66
+ @program_id.each_tracked_file(with_status: with_status, &block)
67
+ end
68
+
64
69
  def to_s; inspect end
65
70
 
66
71
  # Register files on the program ID
@@ -85,7 +90,7 @@ def spawn
85
90
  SLAVE_RESULT_ENV => result_w.fileno.to_s)
86
91
 
87
92
  program_id.refresh
88
- @needed = false
93
+ @needed = nil
89
94
  pid = Kernel.spawn(env, *cmdline, initial_r => initial_r, result_w => result_w, **spawn_options)
90
95
  initial_r.close
91
96
  result_w.close
@@ -113,7 +118,11 @@ def spawn
113
118
  # Whether this slave would need to be spawned, either because it has
114
119
  # never be, or because the program ID changed
115
120
  def needed?
116
- !running? && (@needed || program_id.changed?)
121
+ if running? then false
122
+ elsif !@needed.nil?
123
+ @needed
124
+ else program_id.changed?
125
+ end
117
126
  end
118
127
 
119
128
  # Marks this slave for execution
@@ -127,11 +136,18 @@ def needed!
127
136
  @needed = true
128
137
  end
129
138
 
130
- # Resets {#needed?} to false
139
+ # Forces {#needed?} to return false
140
+ #
141
+ # Call {#needed_auto} to revert back to determining if the slave is
142
+ # needed or not using the tracked files
131
143
  def not_needed!
132
144
  @needed = false
133
145
  end
134
146
 
147
+ def needed_auto
148
+ @needed = nil
149
+ end
150
+
135
151
  # Whether the slave is running
136
152
  def running?
137
153
  pid && !status
@@ -177,6 +193,9 @@ def success?
177
193
  # Announce that the slave already finished, with the given exit status
178
194
  #
179
195
  # @param [Process::Status] the exit status
196
+ # @return [Array<Pathname>] a set of files that either changed or got
197
+ # added since the call to {#spawn}. If not empty, the slave calls
198
+ # {#needed!} by itself to force a re-execution
180
199
  def finished(status)
181
200
  @status = status
182
201
  read_queued_result
@@ -188,8 +207,8 @@ def finished(status)
188
207
  file_list = Array.new
189
208
  @success = false
190
209
  end
191
- modified = program_id.register_files(file_list)
192
210
  @program_id = program_id.slice(file_list)
211
+ modified = program_id.register_files(file_list)
193
212
  if !modified.empty?
194
213
  needed!
195
214
  end
@@ -0,0 +1,25 @@
1
+ class Autorespawn
2
+ class TrackedFile
3
+ attr_reader :path, :mtime, :size, :slaves
4
+
5
+ def initialize(path, mtime: nil, size: nil)
6
+ @path = path
7
+ @mtime = mtime
8
+ @size = size
9
+ @slaves = Array.new
10
+ end
11
+
12
+ def update
13
+ return true if !path.exist?
14
+ return true if !mtime
15
+
16
+ stat = path.stat
17
+ if stat.mtime != mtime || stat.size != size
18
+ @mtime = stat.mtime
19
+ @size = stat.size
20
+ true
21
+ end
22
+ end
23
+ end
24
+ end
25
+
@@ -1,3 +1,3 @@
1
1
  class Autorespawn
2
- VERSION = "0.4.1"
2
+ VERSION = "0.5.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: autorespawn
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sylvain Joyeux
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2015-12-22 00:00:00.000000000 Z
11
+ date: 2015-12-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: hooks
@@ -112,6 +112,20 @@ dependencies:
112
112
  - - "~>"
113
113
  - !ruby/object:Gem::Version
114
114
  version: '2.0'
115
+ - !ruby/object:Gem::Dependency
116
+ name: simplecov
117
+ requirement: !ruby/object:Gem::Requirement
118
+ requirements:
119
+ - - ">="
120
+ - !ruby/object:Gem::Version
121
+ version: '0.11'
122
+ type: :development
123
+ prerelease: false
124
+ version_requirements: !ruby/object:Gem::Requirement
125
+ requirements:
126
+ - - ">="
127
+ - !ruby/object:Gem::Version
128
+ version: '0.11'
115
129
  - !ruby/object:Gem::Dependency
116
130
  name: coveralls
117
131
  requirement: !ruby/object:Gem::Requirement
@@ -151,6 +165,7 @@ files:
151
165
  - lib/autorespawn/program_id.rb
152
166
  - lib/autorespawn/self.rb
153
167
  - lib/autorespawn/slave.rb
168
+ - lib/autorespawn/tracked_file.rb
154
169
  - lib/autorespawn/version.rb
155
170
  - lib/autorespawn/watch.rb
156
171
  homepage: https://github.com/doudou/autorespawn