xpflow 0.1b
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.
- data/bin/xpflow +96 -0
- data/lib/colorado.rb +198 -0
- data/lib/json/add/core.rb +243 -0
- data/lib/json/add/rails.rb +8 -0
- data/lib/json/common.rb +423 -0
- data/lib/json/editor.rb +1369 -0
- data/lib/json/ext.rb +28 -0
- data/lib/json/pure/generator.rb +442 -0
- data/lib/json/pure/parser.rb +320 -0
- data/lib/json/pure.rb +15 -0
- data/lib/json/version.rb +8 -0
- data/lib/json.rb +62 -0
- data/lib/mime/types.rb +881 -0
- data/lib/mime-types.rb +3 -0
- data/lib/restclient/abstract_response.rb +106 -0
- data/lib/restclient/exceptions.rb +193 -0
- data/lib/restclient/net_http_ext.rb +55 -0
- data/lib/restclient/payload.rb +235 -0
- data/lib/restclient/raw_response.rb +34 -0
- data/lib/restclient/request.rb +316 -0
- data/lib/restclient/resource.rb +169 -0
- data/lib/restclient/response.rb +24 -0
- data/lib/restclient.rb +174 -0
- data/lib/xpflow/bash.rb +341 -0
- data/lib/xpflow/bundle.rb +113 -0
- data/lib/xpflow/cmdline.rb +249 -0
- data/lib/xpflow/collection.rb +122 -0
- data/lib/xpflow/concurrency.rb +79 -0
- data/lib/xpflow/data.rb +393 -0
- data/lib/xpflow/dsl.rb +816 -0
- data/lib/xpflow/engine.rb +574 -0
- data/lib/xpflow/ensemble.rb +135 -0
- data/lib/xpflow/events.rb +56 -0
- data/lib/xpflow/experiment.rb +65 -0
- data/lib/xpflow/exts/facter.rb +30 -0
- data/lib/xpflow/exts/g5k.rb +931 -0
- data/lib/xpflow/exts/g5k_use.rb +50 -0
- data/lib/xpflow/exts/gui.rb +140 -0
- data/lib/xpflow/exts/model.rb +155 -0
- data/lib/xpflow/graph.rb +1603 -0
- data/lib/xpflow/graph_xpflow.rb +251 -0
- data/lib/xpflow/import.rb +196 -0
- data/lib/xpflow/library.rb +349 -0
- data/lib/xpflow/logging.rb +153 -0
- data/lib/xpflow/manager.rb +147 -0
- data/lib/xpflow/nodes.rb +1250 -0
- data/lib/xpflow/runs.rb +773 -0
- data/lib/xpflow/runtime.rb +125 -0
- data/lib/xpflow/scope.rb +168 -0
- data/lib/xpflow/ssh.rb +186 -0
- data/lib/xpflow/stat.rb +50 -0
- data/lib/xpflow/stdlib.rb +381 -0
- data/lib/xpflow/structs.rb +369 -0
- data/lib/xpflow/taktuk.rb +193 -0
- data/lib/xpflow/templates/ssh-config.basic +14 -0
- data/lib/xpflow/templates/ssh-config.inria +18 -0
- data/lib/xpflow/templates/ssh-config.proxy +13 -0
- data/lib/xpflow/templates/taktuk +6590 -0
- data/lib/xpflow/templates/utils/batch +4 -0
- data/lib/xpflow/templates/utils/bootstrap +12 -0
- data/lib/xpflow/templates/utils/hostname +3 -0
- data/lib/xpflow/templates/utils/ping +3 -0
- data/lib/xpflow/templates/utils/rsync +12 -0
- data/lib/xpflow/templates/utils/scp +17 -0
- data/lib/xpflow/templates/utils/scp_many +8 -0
- data/lib/xpflow/templates/utils/ssh +3 -0
- data/lib/xpflow/templates/utils/ssh-interactive +4 -0
- data/lib/xpflow/templates/utils/taktuk +19 -0
- data/lib/xpflow/threads.rb +187 -0
- data/lib/xpflow/utils.rb +569 -0
- data/lib/xpflow/visual.rb +230 -0
- data/lib/xpflow/with_g5k.rb +7 -0
- data/lib/xpflow.rb +349 -0
- metadata +135 -0
data/lib/xpflow/runs.rb
ADDED
@@ -0,0 +1,773 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
#
|
4
|
+
# Implementation of 'runs' or actions that can be executed
|
5
|
+
# within the experiment engine. They build logic behind DSL.
|
6
|
+
#
|
7
|
+
|
8
|
+
require 'timeout'
|
9
|
+
|
10
|
+
module XPFlow
|
11
|
+
|
12
|
+
class AbstractRun
|
13
|
+
|
14
|
+
include Traverse
|
15
|
+
include Meta
|
16
|
+
|
17
|
+
attr_accessor :key
|
18
|
+
constructor :key
|
19
|
+
|
20
|
+
def engine
|
21
|
+
# shortcut to get an engine
|
22
|
+
return Scope.engine
|
23
|
+
end
|
24
|
+
|
25
|
+
def run()
|
26
|
+
exc = nil
|
27
|
+
begin
|
28
|
+
x = execute()
|
29
|
+
Scope.current[@key] = x
|
30
|
+
rescue => e
|
31
|
+
raise if (e.is_a?(RunError)) and (e.run == self)
|
32
|
+
exc = RunError.new(self, e)
|
33
|
+
end
|
34
|
+
raise exc unless exc.nil?
|
35
|
+
return x
|
36
|
+
end
|
37
|
+
|
38
|
+
def run_threads(list, opts = {}, &block)
|
39
|
+
# TODO: pool should be in the scope...
|
40
|
+
list = listize(list)
|
41
|
+
pool_size = engine.getset.get(:pool)
|
42
|
+
nonnil = opts.select { |k, v| !v.nil? }
|
43
|
+
opts = { :pool => pool_size }.merge(nonnil)
|
44
|
+
return Threads.run(self, list, opts, &block)
|
45
|
+
end
|
46
|
+
|
47
|
+
def restart()
|
48
|
+
# returns non-nil value (in fact, a hash) when can restart from this activity
|
49
|
+
# the returned hash contains hash to copy to the scope
|
50
|
+
return false
|
51
|
+
end
|
52
|
+
|
53
|
+
def listize(o)
|
54
|
+
# tries to execute :to_list, if not
|
55
|
+
# checks if is an array, otherwise panics
|
56
|
+
if o.respond_to?(:to_list)
|
57
|
+
o = o.to_list
|
58
|
+
end
|
59
|
+
if !o.is_a?(Array)
|
60
|
+
raise "#{o} is not an array"
|
61
|
+
end
|
62
|
+
return o
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
class SequenceRun < AbstractRun
|
69
|
+
|
70
|
+
attr_reader :body
|
71
|
+
|
72
|
+
constructor [ :key ], :body
|
73
|
+
children :body
|
74
|
+
|
75
|
+
def check_restartability()
|
76
|
+
name = engine.config(:checkpoint)
|
77
|
+
if engine.config(:ignore_checkpoints)
|
78
|
+
engine.paranoic("Ignoring checkpoints.") \
|
79
|
+
if @body.any? { |r| r.is_a?(CheckpointRun) }
|
80
|
+
return @body
|
81
|
+
end
|
82
|
+
list = []
|
83
|
+
# TODO: I should collect all checkpoints and verify
|
84
|
+
for r in @body.reverse do
|
85
|
+
if name.nil? == false and r.is_a?(CheckpointRun) and r.name.to_s != name
|
86
|
+
list = [ r ] + list
|
87
|
+
next
|
88
|
+
end
|
89
|
+
cp = r.restart()
|
90
|
+
if cp == true
|
91
|
+
# we restarted
|
92
|
+
engine.log("Checkpoint '#{r.name}' restarted.")
|
93
|
+
break
|
94
|
+
else
|
95
|
+
list = [ r ] + list # standard case
|
96
|
+
end
|
97
|
+
end
|
98
|
+
return list
|
99
|
+
end
|
100
|
+
|
101
|
+
def execute()
|
102
|
+
tail = check_restartability()
|
103
|
+
results = []
|
104
|
+
for r in tail do
|
105
|
+
x = r.run()
|
106
|
+
results.push(x)
|
107
|
+
end
|
108
|
+
return results.last
|
109
|
+
end
|
110
|
+
|
111
|
+
def attach_to_checkpoints(obj)
|
112
|
+
@body.each do |i|
|
113
|
+
if i.is_a?(CheckpointRun)
|
114
|
+
i.parent = obj
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def split(node)
|
120
|
+
before = []
|
121
|
+
after = []
|
122
|
+
first = true
|
123
|
+
@body.each do |el|
|
124
|
+
first = false if el == node
|
125
|
+
(first ? before : after).push(el) if el != node
|
126
|
+
end
|
127
|
+
return [before, after].map { |x| ActivityList.new(x) }
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|
131
|
+
|
132
|
+
class SeqtryRun < AbstractRun
|
133
|
+
|
134
|
+
attr_reader :body
|
135
|
+
constructor [ :key ], :body
|
136
|
+
|
137
|
+
children :body
|
138
|
+
|
139
|
+
def execute()
|
140
|
+
result = nil
|
141
|
+
return nil if @body.length == 0
|
142
|
+
for r in @body do
|
143
|
+
fine = true
|
144
|
+
begin
|
145
|
+
result = r.run()
|
146
|
+
rescue RunError => e
|
147
|
+
engine.verbose("Error caused by #{e.summary}. Trying the next activity.")
|
148
|
+
fine = false
|
149
|
+
end
|
150
|
+
return result if fine == true
|
151
|
+
end
|
152
|
+
raise "Seqtry execution failed."
|
153
|
+
end
|
154
|
+
|
155
|
+
end
|
156
|
+
|
157
|
+
class ExperimentRun < AbstractRun
|
158
|
+
|
159
|
+
constructor [ :key ], :name, :args
|
160
|
+
children :name, :args
|
161
|
+
|
162
|
+
def execute()
|
163
|
+
# TODO: more things here
|
164
|
+
r = nil
|
165
|
+
name = @name.evaluate(Scope.current)
|
166
|
+
args = @args.evaluate(Scope.current)
|
167
|
+
full_name = "#{name}.__standard__"
|
168
|
+
ActivityRun.run_activity_block(full_name) do |activity|
|
169
|
+
Scope.region do |scope|
|
170
|
+
# scope[:__collection__] = Collection.new
|
171
|
+
text = "Running experiment #{name}"
|
172
|
+
r = engine.activity_period(text, { :gantt => true }) do
|
173
|
+
activity.execute(args, &@block)
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
return r
|
178
|
+
end
|
179
|
+
|
180
|
+
def get_name()
|
181
|
+
# tries to evaluate the experiment name
|
182
|
+
# without running (if it is possible)
|
183
|
+
# returns nil otherwise
|
184
|
+
return @name.evaluate_offline()
|
185
|
+
end
|
186
|
+
|
187
|
+
end
|
188
|
+
|
189
|
+
class ActivityRun < AbstractRun
|
190
|
+
|
191
|
+
constructor [ :key ], :name, :args, :opts, :block
|
192
|
+
children :args
|
193
|
+
|
194
|
+
attr_reader :opts
|
195
|
+
attr_reader :name
|
196
|
+
|
197
|
+
def self.run_activity_block(full_name)
|
198
|
+
# runs activity using the current scope
|
199
|
+
full_name = full_name.to_s
|
200
|
+
lib = Scope.current[:__library__]
|
201
|
+
ns = Scope.current[:__namespace__]
|
202
|
+
if full_name.start_with?("/")
|
203
|
+
full_name = full_name[1..-1]
|
204
|
+
lib = Scope.engine
|
205
|
+
end
|
206
|
+
libs, name = lib.into_parts(full_name)
|
207
|
+
library = lib.resolve_libs(libs)
|
208
|
+
result = Scope.region do |scope|
|
209
|
+
scope[:__library__] = library
|
210
|
+
scope[:__namespace__] = namespace = ns + libs
|
211
|
+
activity = library.get_activity_object(name)
|
212
|
+
raise "No such activity '#{namespace.join(".")}.#{name}'" if activity.nil?
|
213
|
+
yield(activity)
|
214
|
+
end
|
215
|
+
return result
|
216
|
+
end
|
217
|
+
|
218
|
+
def execute()
|
219
|
+
r = nil
|
220
|
+
this_name = @name.evaluate(Scope.current)
|
221
|
+
preargs = []
|
222
|
+
if this_name.is_a?(RunLater)
|
223
|
+
preargs = this_name.args
|
224
|
+
this_name = this_name.name
|
225
|
+
end
|
226
|
+
ActivityRun.run_activity_block(this_name) do |activity|
|
227
|
+
|
228
|
+
activity_id = engine.activity_id(this_name)
|
229
|
+
args = preargs + @args.evaluate(Scope.current)
|
230
|
+
|
231
|
+
opts = { :gantt => true }.merge(activity.opts).merge(@opts)
|
232
|
+
|
233
|
+
text = "#{this_name}:#{activity_id}"
|
234
|
+
|
235
|
+
log_level = :verbose
|
236
|
+
if this_name.to_s.start_with?("__")
|
237
|
+
log_level = :paranoic
|
238
|
+
end
|
239
|
+
if activity.doc.nil? == false
|
240
|
+
text = "[#{activity.doc}] (#{text})"
|
241
|
+
log_level = :normal
|
242
|
+
end
|
243
|
+
|
244
|
+
if !opts[:log_level].nil?
|
245
|
+
log_level = opts[:log_level]
|
246
|
+
end
|
247
|
+
|
248
|
+
period_opts = opts.merge({ :log_level => log_level })
|
249
|
+
r = engine.activity_period(text, period_opts) do
|
250
|
+
activity.execute(args, &@block)
|
251
|
+
end
|
252
|
+
end
|
253
|
+
return r
|
254
|
+
end
|
255
|
+
|
256
|
+
def get_name
|
257
|
+
@name
|
258
|
+
end
|
259
|
+
|
260
|
+
def report(started, args)
|
261
|
+
age = Time.now - started
|
262
|
+
return {
|
263
|
+
:title => "Activity #{get_name.to_s}",
|
264
|
+
:args => args.inspect,
|
265
|
+
:started => started,
|
266
|
+
:age => "#{age} s"
|
267
|
+
}
|
268
|
+
end
|
269
|
+
|
270
|
+
def to_s
|
271
|
+
"<Activity #{get_name}>"
|
272
|
+
end
|
273
|
+
|
274
|
+
def builtin?
|
275
|
+
# TODO: do it properly
|
276
|
+
name = get_name().to_s
|
277
|
+
return name.start_with?('__') && !name.start_with?('__nodes__')
|
278
|
+
end
|
279
|
+
|
280
|
+
end
|
281
|
+
|
282
|
+
class ForEachRun < AbstractRun
|
283
|
+
|
284
|
+
attr_reader :body
|
285
|
+
|
286
|
+
constructor [ :key ], :list, :iter, :opts, :body
|
287
|
+
children :list, :body
|
288
|
+
declares :iter
|
289
|
+
|
290
|
+
def execute()
|
291
|
+
list = @list.evaluate(Scope.current)
|
292
|
+
opts = @opts.evaluate(Scope.current)
|
293
|
+
ignore_errors = opts[:ignore_errors]
|
294
|
+
result = []
|
295
|
+
for item in listize(list) do
|
296
|
+
Scope.region do |scope|
|
297
|
+
scope[@iter] = item
|
298
|
+
x = Marker.new
|
299
|
+
begin
|
300
|
+
x = @body.run()
|
301
|
+
rescue RunError
|
302
|
+
raise if !ignore_errors
|
303
|
+
end
|
304
|
+
result.push(x) if !x.is_a?(Marker)
|
305
|
+
end
|
306
|
+
end
|
307
|
+
return result
|
308
|
+
end
|
309
|
+
|
310
|
+
end
|
311
|
+
|
312
|
+
class Marker
|
313
|
+
end
|
314
|
+
|
315
|
+
class ForAllRun < AbstractRun
|
316
|
+
|
317
|
+
attr_reader :body
|
318
|
+
|
319
|
+
constructor [ :key ], :list, :iter, :opts, :body
|
320
|
+
children :list, :body
|
321
|
+
declares :iter
|
322
|
+
|
323
|
+
def execute()
|
324
|
+
list = @list.evaluate(Scope.current)
|
325
|
+
opts = @opts.evaluate(Scope.current)
|
326
|
+
size = opts[:pool]
|
327
|
+
ignore_errors = opts[:ignore_errors]
|
328
|
+
result = OrderedArray.new
|
329
|
+
scope = Scope.current
|
330
|
+
run_threads(list, :pool => size) do |el, i|
|
331
|
+
Scope.set(scope.push, { @iter => el })
|
332
|
+
x = Marker.new
|
333
|
+
begin
|
334
|
+
x = @body.run()
|
335
|
+
rescue RunError
|
336
|
+
raise if !ignore_errors
|
337
|
+
end
|
338
|
+
result.give(i, x)
|
339
|
+
end
|
340
|
+
tabl = result.take(list.length)
|
341
|
+
tabl = tabl.select { |x| !x.is_a?(Marker) }
|
342
|
+
return tabl
|
343
|
+
end
|
344
|
+
|
345
|
+
end
|
346
|
+
|
347
|
+
class ForManyRun < AbstractRun
|
348
|
+
|
349
|
+
attr_reader :body
|
350
|
+
|
351
|
+
constructor [ :key ], :number, :list, :iter, :body
|
352
|
+
children :number, :list, :body
|
353
|
+
declares :iter
|
354
|
+
|
355
|
+
def execute()
|
356
|
+
rendez = Meeting.new(self)
|
357
|
+
n = @number.evaluate(Scope.current)
|
358
|
+
list = @list.evaluate(Scope.current)
|
359
|
+
scope = Scope.current
|
360
|
+
run_threads(list, :join => false) do |it, _|
|
361
|
+
Scope.set(scope.push, { @iter => it })
|
362
|
+
x = @body.run()
|
363
|
+
rendez.give(x)
|
364
|
+
end
|
365
|
+
# TODO: what about joining?
|
366
|
+
return rendez.take(n)
|
367
|
+
end
|
368
|
+
|
369
|
+
end
|
370
|
+
|
371
|
+
class ManyRun < AbstractRun
|
372
|
+
|
373
|
+
attr_reader :body
|
374
|
+
|
375
|
+
constructor [ :key ], :number, :body
|
376
|
+
children :number, :body
|
377
|
+
|
378
|
+
def execute()
|
379
|
+
n = @number.evaluate(Scope.current)
|
380
|
+
rendez = Meeting.new(self)
|
381
|
+
scope = Scope.current
|
382
|
+
run_threads(@body, :join => false) do |r, _|
|
383
|
+
Scope.set(scope)
|
384
|
+
x = r.run()
|
385
|
+
rendez.give(x)
|
386
|
+
end
|
387
|
+
return rendez.take(n)
|
388
|
+
end
|
389
|
+
|
390
|
+
end
|
391
|
+
|
392
|
+
class ParallelRun < AbstractRun
|
393
|
+
|
394
|
+
attr_reader :body
|
395
|
+
|
396
|
+
constructor [ :key ], :body
|
397
|
+
children :body
|
398
|
+
|
399
|
+
def execute()
|
400
|
+
arr = OrderedArray.new
|
401
|
+
scope = Scope.current
|
402
|
+
rs = run_threads(@body) do |r, i|
|
403
|
+
Scope.set(scope)
|
404
|
+
x = r.run()
|
405
|
+
arr.give(i, x)
|
406
|
+
end
|
407
|
+
values = arr.take(@body.length)
|
408
|
+
return values.last
|
409
|
+
end
|
410
|
+
end
|
411
|
+
|
412
|
+
class IfRun < AbstractRun
|
413
|
+
|
414
|
+
attr_reader :on_true
|
415
|
+
attr_reader :on_false
|
416
|
+
|
417
|
+
constructor [ :key ], :condition, :on_true, :on_false
|
418
|
+
children :condition, :on_true, :on_false
|
419
|
+
|
420
|
+
def execute()
|
421
|
+
x = @condition.evaluate(Scope.current)
|
422
|
+
if x
|
423
|
+
return @on_true.run()
|
424
|
+
else
|
425
|
+
return @on_false.run()
|
426
|
+
end
|
427
|
+
end
|
428
|
+
|
429
|
+
end
|
430
|
+
|
431
|
+
class SwitchRun < AbstractRun
|
432
|
+
|
433
|
+
constructor [ :key ], :cases, :default
|
434
|
+
children :cases, :default
|
435
|
+
|
436
|
+
def execute()
|
437
|
+
matches = @cases.select { |cond, result| cond.evaluate(Scope.current) }
|
438
|
+
return execute_cases(matches)
|
439
|
+
end
|
440
|
+
|
441
|
+
def execute_cases(cases)
|
442
|
+
if cases.length != 0
|
443
|
+
_, r = cases.first # execute only the first match
|
444
|
+
return r.run()
|
445
|
+
elsif @default
|
446
|
+
return @default.run()
|
447
|
+
else
|
448
|
+
return nil
|
449
|
+
end
|
450
|
+
end
|
451
|
+
|
452
|
+
end
|
453
|
+
|
454
|
+
class MultiRun < SwitchRun
|
455
|
+
|
456
|
+
def execute_cases(cases)
|
457
|
+
if cases.length != 0
|
458
|
+
scope = Scope.current
|
459
|
+
arr = OrderedArray.new
|
460
|
+
ress = run_threads(cases) do |r, i|
|
461
|
+
Scope.set(scope.push)
|
462
|
+
x = r.last.run()
|
463
|
+
arr.give(i, x)
|
464
|
+
end
|
465
|
+
return arr.take(cases.length)
|
466
|
+
elsif @default
|
467
|
+
return @default.run()
|
468
|
+
else
|
469
|
+
return nil
|
470
|
+
end
|
471
|
+
end
|
472
|
+
|
473
|
+
end
|
474
|
+
|
475
|
+
class BoundSwitchRun < SwitchRun
|
476
|
+
|
477
|
+
constructor [ :key, :cases, :default ], :condition
|
478
|
+
children :cases, :default, :condition
|
479
|
+
|
480
|
+
def execute()
|
481
|
+
v = @condition.evaluate(Scope.current)
|
482
|
+
matches = @cases.select { |cond, result|
|
483
|
+
cond.evaluate(Scope.current) == v
|
484
|
+
}
|
485
|
+
return execute_cases(matches)
|
486
|
+
end
|
487
|
+
|
488
|
+
end
|
489
|
+
|
490
|
+
class CheckpointRun < AbstractRun
|
491
|
+
|
492
|
+
attr_accessor :parent
|
493
|
+
|
494
|
+
constructor [ :key ], :name, :opts, :parent
|
495
|
+
children
|
496
|
+
|
497
|
+
def name
|
498
|
+
return '[no name]' if @name.nil?
|
499
|
+
return @name
|
500
|
+
end
|
501
|
+
|
502
|
+
def parent_keys
|
503
|
+
return @parent.args # arguments to the process
|
504
|
+
end
|
505
|
+
|
506
|
+
def state_keys
|
507
|
+
before, after = @parent.split(self)
|
508
|
+
vars1 = before.declarations.keys # vars defined BEFORE the checkpoint
|
509
|
+
vars2 = after.vars # vars used AFTER the checkpoint
|
510
|
+
return (vars1 + parent_keys) # & vars2
|
511
|
+
end
|
512
|
+
|
513
|
+
def meta_info(scope)
|
514
|
+
{
|
515
|
+
:type => :checkpoint,
|
516
|
+
:args => parent_keys.map { |x| scope[x] },
|
517
|
+
:name => @name,
|
518
|
+
:key => @key,
|
519
|
+
:parent => @parent.name
|
520
|
+
}
|
521
|
+
end
|
522
|
+
|
523
|
+
def checkpointable_libs()
|
524
|
+
libs = engine.get_libraries
|
525
|
+
libs = libs.select { |ns, l| l.respond_to?(:checkpoint) }
|
526
|
+
return libs
|
527
|
+
end
|
528
|
+
|
529
|
+
def execute()
|
530
|
+
scope = Scope.current
|
531
|
+
state = { 'vars' => {} }
|
532
|
+
state_keys.each { |k| state['vars'][k] = scope.get(k, true) } # TODO: fix this
|
533
|
+
state['meta'] = meta_info(scope)
|
534
|
+
lib_dump = checkpointable_libs().map do |ns, l|
|
535
|
+
{
|
536
|
+
:state => l.checkpoint(),
|
537
|
+
:namespace => ns
|
538
|
+
}
|
539
|
+
end
|
540
|
+
state['libs'] = lib_dump
|
541
|
+
engine.dumper.dump(state, @opts)
|
542
|
+
engine.verbose "Checkpoint '#{name}' saved."
|
543
|
+
return nil
|
544
|
+
end
|
545
|
+
|
546
|
+
def restart()
|
547
|
+
scope = Scope.current
|
548
|
+
m = meta_info(scope)
|
549
|
+
obj = engine.dumper.load(m)
|
550
|
+
return false if obj.nil?
|
551
|
+
vars = obj['vars']
|
552
|
+
libs = obj['libs']
|
553
|
+
vars.each_pair { |k, v| scope[k] = v }
|
554
|
+
cplibs = checkpointable_libs()
|
555
|
+
raise "Fatal checkpoint error (#{cplibs.length} != #{libs.length})" if cplibs.length != libs.length
|
556
|
+
raise "Fatal checkpoint error (something wrong)" if cplibs.length != libs.length
|
557
|
+
names1 = cplibs.map { |x| x.last }
|
558
|
+
names2 = libs.map { |x| x[:namespace] }
|
559
|
+
libs.each do |cp|
|
560
|
+
ns = cp[:namespace]
|
561
|
+
library = cplibs[ns]
|
562
|
+
library.restore(cp[:state])
|
563
|
+
end
|
564
|
+
return true
|
565
|
+
end
|
566
|
+
|
567
|
+
def to_s
|
568
|
+
"<Checkpoint #{@name.inspect}>"
|
569
|
+
end
|
570
|
+
|
571
|
+
end
|
572
|
+
|
573
|
+
class CacheRun < AbstractRun
|
574
|
+
|
575
|
+
attr_reader :body
|
576
|
+
|
577
|
+
constructor [ :key ], :opts, :body
|
578
|
+
children :body
|
579
|
+
|
580
|
+
def meta_info()
|
581
|
+
{
|
582
|
+
:type => :cache,
|
583
|
+
:key => @key
|
584
|
+
}
|
585
|
+
end
|
586
|
+
|
587
|
+
def execute()
|
588
|
+
ignoring = engine.config(:ignore_checkpoints)
|
589
|
+
m = meta_info()
|
590
|
+
o = engine.dumper.load(m)
|
591
|
+
if o.nil? or ignoring == true
|
592
|
+
value = @body.run()
|
593
|
+
obj = { 'meta' => m, 'value' => value }
|
594
|
+
engine.dumper.dump(obj)
|
595
|
+
return value
|
596
|
+
else
|
597
|
+
engine.verbose("Cached block for key = #{@key} loaded.")
|
598
|
+
return o['value']
|
599
|
+
end
|
600
|
+
end
|
601
|
+
|
602
|
+
end
|
603
|
+
|
604
|
+
class InfoRun < AbstractRun
|
605
|
+
|
606
|
+
attr_reader :body
|
607
|
+
|
608
|
+
constructor [ :key ], :opts, :body
|
609
|
+
children :body
|
610
|
+
|
611
|
+
def execute()
|
612
|
+
opts = @opts.evaluate(Scope.current)
|
613
|
+
opts = { :fail => true }.merge(opts)
|
614
|
+
failed = false
|
615
|
+
begin
|
616
|
+
start_time = Time.now.to_f
|
617
|
+
@body.run()
|
618
|
+
end_time = Time.now.to_f
|
619
|
+
total_time = end_time - start_time
|
620
|
+
rescue RunError => e
|
621
|
+
engine.verbose("Info run errored with #{e.summary}")
|
622
|
+
failed = true
|
623
|
+
total_time = 0.0
|
624
|
+
end
|
625
|
+
if opts[:fail] and failed
|
626
|
+
raise "info block failed: "
|
627
|
+
end
|
628
|
+
return {
|
629
|
+
:time => total_time,
|
630
|
+
:failed => failed
|
631
|
+
}
|
632
|
+
end
|
633
|
+
|
634
|
+
end
|
635
|
+
|
636
|
+
class TryRun < AbstractRun
|
637
|
+
|
638
|
+
attr_reader :body
|
639
|
+
|
640
|
+
constructor [ :key ], :opts, :body
|
641
|
+
children :body
|
642
|
+
|
643
|
+
def execute()
|
644
|
+
opts = { :retry => 1, :timeout => 0 }.merge(@opts.evaluate(Scope.current))
|
645
|
+
engine.verbose("Try block: #{opts}")
|
646
|
+
timeout, times = opts[:timeout], opts[:retry]
|
647
|
+
times = 1 if times == false
|
648
|
+
times = Infinity if times == true
|
649
|
+
exc = nil
|
650
|
+
for i in 1..times do
|
651
|
+
begin
|
652
|
+
if timeout == 0
|
653
|
+
return @body.run()
|
654
|
+
else
|
655
|
+
begin
|
656
|
+
r = Timeout::timeout(timeout, exc) do
|
657
|
+
@body.run()
|
658
|
+
end
|
659
|
+
return r
|
660
|
+
rescue Timeout::Error => e
|
661
|
+
raise RunMsgError.new(self, "Timeout")
|
662
|
+
end
|
663
|
+
end
|
664
|
+
rescue RunError => e
|
665
|
+
engine.verbose("Try rerun at #{meta.location}; caused by #{e.summary}")
|
666
|
+
exc = e
|
667
|
+
end
|
668
|
+
end
|
669
|
+
raise exc
|
670
|
+
end
|
671
|
+
end
|
672
|
+
|
673
|
+
class ResultRun < AbstractRun
|
674
|
+
|
675
|
+
attr_reader :body
|
676
|
+
|
677
|
+
constructor [ :key ], :path, :opts, :body
|
678
|
+
children :body
|
679
|
+
|
680
|
+
def execute()
|
681
|
+
path = @path.evaluate(Scope.current)
|
682
|
+
opts = @opts.evaluate(Scope.current)
|
683
|
+
if File.exist?(path)
|
684
|
+
engine.log("Result `#{path}' exists already. I won't run again.")
|
685
|
+
yaml = IO.read(path)
|
686
|
+
return YAML.load(yaml)
|
687
|
+
end
|
688
|
+
r = @body.run()
|
689
|
+
IO.write(path, r.to_yaml)
|
690
|
+
return r
|
691
|
+
end
|
692
|
+
|
693
|
+
end
|
694
|
+
|
695
|
+
class TimesRun < AbstractRun
|
696
|
+
|
697
|
+
attr_reader :body
|
698
|
+
|
699
|
+
constructor [ :key ], :loops, :iter, :body
|
700
|
+
children :body
|
701
|
+
|
702
|
+
def execute()
|
703
|
+
loops = @loops.evaluate(Scope.current)
|
704
|
+
vals = []
|
705
|
+
for i in 0...loops do
|
706
|
+
Scope.region do |scope|
|
707
|
+
scope[@iter] = i
|
708
|
+
r = @body.run()
|
709
|
+
vals.push(r)
|
710
|
+
end
|
711
|
+
end
|
712
|
+
return vals
|
713
|
+
end
|
714
|
+
|
715
|
+
end
|
716
|
+
|
717
|
+
class LoopRun < AbstractRun
|
718
|
+
|
719
|
+
attr_reader :body
|
720
|
+
|
721
|
+
constructor [ :key ], :flag, :iter, :array, :body, :opts
|
722
|
+
children :body
|
723
|
+
|
724
|
+
def execute()
|
725
|
+
opts = @opts.evaluate(Scope.current)
|
726
|
+
max = opts[:max]
|
727
|
+
arr = []
|
728
|
+
result = Scope.region do |scope|
|
729
|
+
scope[@flag] = done = [ :nothing, nil ]
|
730
|
+
|
731
|
+
count = 0
|
732
|
+
while true do
|
733
|
+
scope[@iter] = count
|
734
|
+
scope[@array] = arr.clone
|
735
|
+
res = nil
|
736
|
+
for r in @body do
|
737
|
+
res = r.run()
|
738
|
+
done = scope[@flag]
|
739
|
+
break if done.first != :nothing
|
740
|
+
end
|
741
|
+
break if done.first == :return
|
742
|
+
arr.push(res)
|
743
|
+
count += 1
|
744
|
+
break if (!max.nil? and count >= max)
|
745
|
+
end
|
746
|
+
|
747
|
+
if done.last.nil?
|
748
|
+
arr
|
749
|
+
else
|
750
|
+
done.last
|
751
|
+
end
|
752
|
+
end
|
753
|
+
return result
|
754
|
+
end
|
755
|
+
|
756
|
+
end
|
757
|
+
|
758
|
+
class ReturnLoopRun < AbstractRun
|
759
|
+
|
760
|
+
constructor [ :key ], :flag, :cond, :value
|
761
|
+
children
|
762
|
+
|
763
|
+
def execute()
|
764
|
+
v = @cond.evaluate(Scope.current)
|
765
|
+
if v then
|
766
|
+
r = @value.evaluate(Scope.current)
|
767
|
+
Scope.current[@flag] = [ :return, r ]
|
768
|
+
end
|
769
|
+
end
|
770
|
+
end
|
771
|
+
|
772
|
+
end
|
773
|
+
|