flor 1.0.1 → 1.2.2
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 +4 -4
- data/CHANGELOG.md +30 -0
- data/LICENSE.txt +1 -1
- data/README.md +1 -1
- data/lib/flor.rb +2 -1
- data/lib/flor/core/texecutor.rb +26 -1
- data/lib/flor/flor.rb +24 -6
- data/lib/flor/log.rb +12 -7
- data/lib/flor/punit/c_iterator.rb +1 -1
- data/lib/flor/punit/concurrence.rb +6 -5
- data/lib/flor/punit/{m_ram.rb → m_receive_and_merge.rb} +0 -0
- data/lib/flor/tools/firb.rb +33 -0
- data/lib/flor/tools/shell.rb +12 -3
- data/lib/flor/unit.rb +1 -0
- data/lib/flor/unit/caller.rb +6 -4
- data/lib/flor/unit/caller_jruby.rb +8 -7
- data/lib/flor/unit/executor.rb +18 -13
- data/lib/flor/unit/ganger.rb +3 -0
- data/lib/flor/unit/gangers.rb +125 -0
- data/lib/flor/unit/loader.rb +42 -10
- data/lib/flor/unit/logger.rb +11 -2
- data/lib/flor/unit/models/message.rb +5 -0
- data/lib/flor/unit/models/pointer.rb +20 -1
- data/lib/flor/unit/scheduler.rb +13 -8
- data/lib/flor/unit/storage.rb +53 -44
- data/lib/flor/unit/taskers.rb +68 -0
- data/lib/flor/unit/waiter.rb +2 -2
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f1dae0857de545986e18ad31a41f37a6ead6687b34d3c06de22aafa606369283
|
4
|
+
data.tar.gz: 9843d0124a2c3948ffc6846e7854854f5eda37d95bd02bfc02cecfefab0e5ea1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 185490e0054ffdfe7c078b71955834679a398266e613be5d8bb6b63bc626bf4727bd4fd45249e7dea14cdd91a85c5ad92a1f6b3b120117c7c274b41d5478ba31
|
7
|
+
data.tar.gz: e6dde7ae40f3ef6d2c7a620d6a07840c6591b745798962d039ac39fa426e4bcef51f3c67e97d9a367bb981918ec5fe98934393eec2cd7e87046b8d491b9a6511
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,36 @@
|
|
2
2
|
# CHANGELOG.md
|
3
3
|
|
4
4
|
|
5
|
+
## flor 1.2.2 released 2021-03-29
|
6
|
+
|
7
|
+
* Include data in flor_pointers
|
8
|
+
* Ensure flor_pointers name is a string
|
9
|
+
|
10
|
+
|
11
|
+
## flor 1.2.1 released 2021-03-22
|
12
|
+
|
13
|
+
* If conf sto_db_logger is false, do not attach a logger to the db connection
|
14
|
+
|
15
|
+
|
16
|
+
## flor 1.2.0 released 2021-03-15
|
17
|
+
|
18
|
+
* Add #attd, #attl, #att_texts to Flor::Pointer
|
19
|
+
|
20
|
+
|
21
|
+
## flor 1.1.1 released 2021-03-03
|
22
|
+
|
23
|
+
* Use YAML to have more compact msg_to_detail_s
|
24
|
+
|
25
|
+
|
26
|
+
## flor 1.1.0 released 2021-01-06
|
27
|
+
|
28
|
+
* Introduce Tasker #set_payload and #set_vars
|
29
|
+
* Introduce the ModuleGanger
|
30
|
+
* Allow for domain/dot.json taskers
|
31
|
+
* Introduce Flor::StagedBasicTasker
|
32
|
+
* Fix service/executor issue in Caller
|
33
|
+
|
34
|
+
|
5
35
|
## flor 1.0.1 released 2020-11-23
|
6
36
|
|
7
37
|
* Accept sto_uri strings pointing to constant like 'DB'
|
data/LICENSE.txt
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
|
2
|
-
Copyright (c) 2015-
|
2
|
+
Copyright (c) 2015-2021, John Mettraux, jmettraux+flor@gmail.com
|
3
3
|
|
4
4
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
5
|
of this software and associated documentation files (the "Software"), to deal
|
data/README.md
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
|
2
2
|
# flor
|
3
3
|
|
4
|
-
[](https://github.com/floraison/flor/actions)
|
5
5
|
[](http://badge.fury.io/rb/flor)
|
6
6
|
|
7
7
|
Flor is a "Ruby workflow engine", if that makes any sense.
|
data/lib/flor.rb
CHANGED
data/lib/flor/core/texecutor.rb
CHANGED
@@ -254,7 +254,7 @@ module Flor
|
|
254
254
|
o.each { |ee| ee['_path'] = path if ee.is_a?(Hash) }
|
255
255
|
end
|
256
256
|
|
257
|
-
o
|
257
|
+
rework_conf(o)
|
258
258
|
end
|
259
259
|
|
260
260
|
def interpret_path(path, context=nil)
|
@@ -299,6 +299,31 @@ module Flor
|
|
299
299
|
|
300
300
|
ps.last == 'etc' ? File.absolute_path(File.join(dir, '..')) : dir
|
301
301
|
end
|
302
|
+
|
303
|
+
protected
|
304
|
+
|
305
|
+
# For now, only the return procedure has to be marshalled back
|
306
|
+
# to the "return" string, gh-36
|
307
|
+
#
|
308
|
+
def rework_conf(o)
|
309
|
+
|
310
|
+
case o
|
311
|
+
when Array
|
312
|
+
o.collect { |e|
|
313
|
+
rework_conf(e) }
|
314
|
+
when Hash
|
315
|
+
o.inject({}) { |h, (k, v)|
|
316
|
+
h[k] =
|
317
|
+
if Flor.is_proc_tree?(v) && v[1]['proc'] == 'return'
|
318
|
+
'return'
|
319
|
+
else
|
320
|
+
rework_conf(v)
|
321
|
+
end
|
322
|
+
h }
|
323
|
+
else
|
324
|
+
o
|
325
|
+
end
|
326
|
+
end
|
302
327
|
end
|
303
328
|
end
|
304
329
|
end
|
data/lib/flor/flor.rb
CHANGED
@@ -20,7 +20,7 @@ module Flor
|
|
20
20
|
signal cancel
|
21
21
|
terminated failed ceased
|
22
22
|
idle
|
23
|
-
|
23
|
+
].freeze
|
24
24
|
|
25
25
|
class << self
|
26
26
|
|
@@ -279,13 +279,19 @@ module Flor
|
|
279
279
|
#
|
280
280
|
# functions about time
|
281
281
|
|
282
|
+
# Used by the storage in its next_time endeavours
|
283
|
+
#
|
284
|
+
def tstam
|
285
|
+
Time.now.utc.strftime('%FT%T')
|
286
|
+
end
|
287
|
+
|
282
288
|
def isostamp(show_date, show_time, show_usec, time)
|
283
289
|
|
284
290
|
t = (time || Time.now).utc
|
285
291
|
s = StringIO.new
|
286
292
|
|
287
|
-
s << t.strftime('%
|
288
|
-
s << t.strftime('T%
|
293
|
+
s << t.strftime('%F') if show_date # YYYY-mm-dd
|
294
|
+
s << t.strftime('T%T') if show_time # THH:MM:SS
|
289
295
|
s << sprintf('.%06d', t.usec) if show_time && show_usec
|
290
296
|
s << 'Z' if show_time
|
291
297
|
|
@@ -323,6 +329,11 @@ module Flor
|
|
323
329
|
isostamp(false, true, true, t)
|
324
330
|
end
|
325
331
|
|
332
|
+
def monow
|
333
|
+
|
334
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
335
|
+
end
|
336
|
+
|
326
337
|
# def to_time(ts)
|
327
338
|
#
|
328
339
|
# m = ts.match(/\A(\d{4})(\d{2})(\d{2})\.(\d{2})(\d{2})(\d{2})(\d+)([uU]?)\z/)
|
@@ -367,11 +378,18 @@ module Flor
|
|
367
378
|
sub_domain?(dom, sub)
|
368
379
|
end
|
369
380
|
|
381
|
+
def dot_join(*elts)
|
382
|
+
|
383
|
+
elts.collect(&:to_s).select { |e| e.length > 0 }.join('.')
|
384
|
+
end
|
385
|
+
|
370
386
|
def sub_domain?(dom, sub)
|
371
387
|
|
372
|
-
dom
|
373
|
-
|
374
|
-
|
388
|
+
d = dom.is_a?(Array) ? dot_join(*dom) : dom.to_s
|
389
|
+
|
390
|
+
d == '' ||
|
391
|
+
sub == d ||
|
392
|
+
sub[0, d.length + 1] == d + '.'
|
375
393
|
end
|
376
394
|
alias subdomain? sub_domain?
|
377
395
|
|
data/lib/flor/log.rb
CHANGED
@@ -324,6 +324,7 @@ module Flor
|
|
324
324
|
def msg_to_detail_s(executor, m, opts={})
|
325
325
|
|
326
326
|
return if m['_detail_msg_flag']
|
327
|
+
#
|
327
328
|
m['_detail_msg_flag'] = true if opts[:flag]
|
328
329
|
|
329
330
|
o = StringIO.new
|
@@ -333,18 +334,22 @@ module Flor
|
|
333
334
|
n = executor.execution['nodes'][nid]
|
334
335
|
node = n ? Flor::Node.new(executor, n, m) : nil
|
335
336
|
|
336
|
-
o.puts "#{_c.
|
337
|
-
|
338
|
-
o.puts "#{_c.dg}
|
339
|
-
o.puts
|
340
|
-
|
337
|
+
o.puts "#{_c.rs}#{_c.dg}<Flor.msg_to_detail_s>"
|
338
|
+
|
339
|
+
o.puts "#{_c.dg}message:#{_c.yl}"
|
340
|
+
o.puts YAML.dump(m)
|
341
|
+
|
342
|
+
o.puts "#{_c.dg}tree:#{_c.yl}"
|
341
343
|
o.puts(tree_to_s(node.lookup_tree(nid), nid, out: o)) if node
|
344
|
+
|
342
345
|
o.puts "#{_c.dg}node:#{_c.yl}"
|
343
|
-
o.puts(
|
344
|
-
|
346
|
+
o.puts YAML.dump(n.merge('tree' => '(above)'))
|
347
|
+
|
348
|
+
o.puts "#{_c.dg}nodes:#{_c.yl}"
|
345
349
|
o.puts nods_to_s(executor, m, opts)
|
346
350
|
z = executor.execution['nodes'].size
|
347
351
|
o.puts "#{_c.yl}#{z} node#{z == 1 ? '' : 's'}."
|
352
|
+
|
348
353
|
o.puts "#{_c.dg}</Flor.msg_to_detail_s>#{_c.rs}"
|
349
354
|
|
350
355
|
o.string
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'flor/punit/
|
3
|
+
require 'flor/punit/m_receive_and_merge'
|
4
4
|
|
5
5
|
|
6
6
|
class Flor::Pro::Concurrence < Flor::Procedure
|
@@ -387,10 +387,11 @@ class Flor::Pro::Concurrence < Flor::Procedure
|
|
387
387
|
|
388
388
|
REWRITE_AS_ATTS = %w[
|
389
389
|
on_receive on_merge
|
390
|
-
child_on_error children_on_error
|
391
|
-
|
392
|
-
|
393
|
-
|
390
|
+
child_on_error children_on_error
|
391
|
+
].freeze
|
392
|
+
#
|
393
|
+
# heads of the child nodes that should get rewritten as attributes
|
394
|
+
# of the concurrence ...
|
394
395
|
|
395
396
|
def pre_execute_rewrite
|
396
397
|
|
File without changes
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'irb'
|
4
|
+
|
5
|
+
#require 'sequel'
|
6
|
+
require 'flor'
|
7
|
+
require 'flor/unit'
|
8
|
+
|
9
|
+
|
10
|
+
p [ RUBY_VERSION, RUBY_PLATFORM ]
|
11
|
+
|
12
|
+
puts
|
13
|
+
|
14
|
+
ENV.each do |k, v|
|
15
|
+
next unless k.match?(/RUBY|GEM/)
|
16
|
+
puts "* #{k}: #{v}"
|
17
|
+
end
|
18
|
+
|
19
|
+
ARGV.each do |arg|
|
20
|
+
if arg.match(/:/)
|
21
|
+
DB = Sequel.connect(arg)
|
22
|
+
p DB
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
#MODELS = [ :executions, :timers, :traces, :traps, :pointers, :messages ]
|
27
|
+
if defined?(DB)
|
28
|
+
Flor::Message.dataset = DB[:flor_messages]
|
29
|
+
end
|
30
|
+
|
31
|
+
ARGV.clear
|
32
|
+
IRB.start
|
33
|
+
|
data/lib/flor/tools/shell.rb
CHANGED
@@ -15,11 +15,16 @@ module Flor::Tools
|
|
15
15
|
def initialize(argv=nil)
|
16
16
|
|
17
17
|
env = ENV['FLOR_ENV'] || 'shell'
|
18
|
-
|
18
|
+
|
19
|
+
@root = File.directory?(env) ? env : "envs/#{env}"
|
19
20
|
|
20
21
|
prepare_home
|
21
22
|
|
22
|
-
|
23
|
+
over_conf = {}
|
24
|
+
#
|
25
|
+
c = ENV['FLOR_STO_URI']; over_conf['sto_uri'] = c if c
|
26
|
+
|
27
|
+
@unit = Flor::Unit.new("#{@root}/etc/conf.json", over_conf)
|
23
28
|
|
24
29
|
@unit.conf['unit'] = 'cli'
|
25
30
|
#unit.hooker.add('journal', Flor::Journal)
|
@@ -31,7 +36,11 @@ module Flor::Tools
|
|
31
36
|
@mute = false
|
32
37
|
@paging = true
|
33
38
|
|
34
|
-
|
39
|
+
if ENV['FLOR_NO_START']
|
40
|
+
@unit.check_migration_version
|
41
|
+
else
|
42
|
+
@unit.start
|
43
|
+
end
|
35
44
|
|
36
45
|
@flow_path = File.join(@root, 'home/scratch.flo')
|
37
46
|
@ra_flow_path = File.join(@root, 'home/ra_scratch.flo')
|
data/lib/flor/unit.rb
CHANGED
data/lib/flor/unit/caller.rb
CHANGED
@@ -107,9 +107,11 @@ module Flor
|
|
107
107
|
#
|
108
108
|
# call
|
109
109
|
|
110
|
-
|
111
|
-
|
112
|
-
ms =
|
110
|
+
pt = message['point']
|
111
|
+
|
112
|
+
ms = [ "call_#{pt}", "on_#{pt}", :on_message, :on, pt ]
|
113
|
+
ms = ms + [ :on_cancel, :cancel ] if pt == 'detask'
|
114
|
+
|
113
115
|
m = ms.find { |mm| o.respond_to?(mm) }
|
114
116
|
|
115
117
|
fail(
|
@@ -121,7 +123,7 @@ module Flor
|
|
121
123
|
case o.method(m).arity
|
122
124
|
when 1 then o.send(m, message)
|
123
125
|
when 2 then o.send(m, conf, message)
|
124
|
-
when 3 then o.send(m,
|
126
|
+
when 3 then o.send(m, service, conf, message)
|
125
127
|
when -1 then o.send(m, {
|
126
128
|
service: service, configuration: conf, message: message })
|
127
129
|
else o.send(m)
|
@@ -23,7 +23,7 @@ module Flor
|
|
23
23
|
@exitstatus = exitstatus
|
24
24
|
end
|
25
25
|
|
26
|
-
def pid; @process.pid; end
|
26
|
+
def pid; @process.pid; rescue; nil; end
|
27
27
|
end
|
28
28
|
|
29
29
|
def spawn(conf, data)
|
@@ -41,7 +41,7 @@ module Flor
|
|
41
41
|
henv.each { |k, v| builder.environment.put(k, v) }
|
42
42
|
|
43
43
|
process = builder.start
|
44
|
-
pid = process.pid
|
44
|
+
pid = process.respond_to?(:pid) ? process.pid : nil
|
45
45
|
|
46
46
|
o = process.outputStream.to_io
|
47
47
|
i = process.inputStream.to_io
|
@@ -61,10 +61,12 @@ module Flor
|
|
61
61
|
|
62
62
|
rescue => err
|
63
63
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
64
|
+
if pid
|
65
|
+
Process.detach(pid)
|
66
|
+
(Process.kill(9, pid) rescue nil) unless Flor.no?(conf['on_error_kill'])
|
67
|
+
else
|
68
|
+
process.destroy rescue nil
|
69
|
+
end
|
68
70
|
|
69
71
|
raise err if err.is_a?(SpawnError)
|
70
72
|
raise WrappedSpawnError.new(conf, { to: to, t0: t0, pid: pid }, err)
|
@@ -72,7 +74,6 @@ module Flor
|
|
72
74
|
ensure
|
73
75
|
|
74
76
|
[ i, o, f ].each { |x| x.close rescue nil }
|
75
|
-
|
76
77
|
end
|
77
78
|
|
78
79
|
module CmdParser include Raabro
|
data/lib/flor/unit/executor.rb
CHANGED
@@ -109,15 +109,13 @@ module Flor
|
|
109
109
|
rescue Exception => exc
|
110
110
|
|
111
111
|
# TODO eventually, have a dump dir
|
112
|
+
|
112
113
|
fn =
|
113
|
-
[
|
114
|
-
'
|
115
|
-
@unit.conf['env'], @unit.identifier, @exid,
|
116
|
-
'r' + counter('runs').to_s
|
117
|
-
].collect(&:to_s).join('_') + '.dump'
|
114
|
+
[ 'flor', @unit.conf['env'], @unit.identifier, @exid,
|
115
|
+
'r' + counter('runs').to_s ].collect(&:to_s).join('_') + '.dump'
|
118
116
|
|
119
117
|
@unit.logger.error(
|
120
|
-
"#{self.class}#do_run()", exc, "(dumping to #{fn})")
|
118
|
+
"#{self.class}#do_run()", exc, "(dumping to #{fn} ...)")
|
121
119
|
|
122
120
|
File.open(fn, 'wb') do |f|
|
123
121
|
f.puts(Flor.to_pretty_s({
|
@@ -134,19 +132,26 @@ module Flor
|
|
134
132
|
f.puts(on_do_run_exc(exc))
|
135
133
|
end
|
136
134
|
|
135
|
+
@unit.logger.error(
|
136
|
+
"#{self.class}#do_run()", exc, "(dumped to #{fn})")
|
137
|
+
|
137
138
|
#puts on_do_run_exc(exc)
|
138
139
|
# dump notification above
|
139
140
|
end
|
140
141
|
|
141
142
|
def task(message)
|
142
143
|
|
143
|
-
|
144
|
-
|
145
|
-
message
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
144
|
+
if message['routed'] == false
|
145
|
+
|
146
|
+
t = message['tasker']
|
147
|
+
n = node(message['nid'])
|
148
|
+
|
149
|
+
msg = n['heat0'] != t ?
|
150
|
+
"tasker #{t.inspect} not found" :
|
151
|
+
"don't know how to apply #{t.inspect}"
|
152
|
+
|
153
|
+
return error_reply(n, message, msg)
|
154
|
+
end
|
150
155
|
|
151
156
|
@unit.ganger.task(self, message)
|
152
157
|
end
|
data/lib/flor/unit/ganger.rb
CHANGED
@@ -54,6 +54,9 @@ module Flor
|
|
54
54
|
(@unit.loader.tasker(domain, 'ganger', message) ||
|
55
55
|
@unit.loader.tasker(domain, 'tasker', message))) ||
|
56
56
|
@unit.loader.tasker(domain, tname, message)
|
57
|
+
#puts "=" * 80
|
58
|
+
#pp tconf
|
59
|
+
#puts "=" * 80
|
57
60
|
|
58
61
|
fail ArgumentError.new(
|
59
62
|
"tasker #{tname.inspect} not found"
|
@@ -0,0 +1,125 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Flor
|
4
|
+
|
5
|
+
# A ModuleGanger accepts a `module:` conf entry that points to a Ruby
|
6
|
+
# module. The tasker implementations are searched for among the classes
|
7
|
+
# in the given module.
|
8
|
+
#
|
9
|
+
# Among the tasker classes (classes that respond to on_task, on_detask, ...)
|
10
|
+
# it selects the first tasker that matches the tasker name.
|
11
|
+
#
|
12
|
+
class ModuleGanger
|
13
|
+
|
14
|
+
def initialize(service, conf, message)
|
15
|
+
|
16
|
+
@service = service
|
17
|
+
@conf = conf
|
18
|
+
@message = message
|
19
|
+
end
|
20
|
+
|
21
|
+
def task
|
22
|
+
|
23
|
+
tas = @message['tasker']
|
24
|
+
clas = list_tasker_classes
|
25
|
+
cla = clas.find { |c| tasker_name(c) == tas }
|
26
|
+
|
27
|
+
return [ Flor.dup_and_merge(@message, 'routed' => false) ] \
|
28
|
+
unless cla
|
29
|
+
|
30
|
+
call_tasker(cla)
|
31
|
+
end
|
32
|
+
|
33
|
+
alias detask task
|
34
|
+
|
35
|
+
protected
|
36
|
+
|
37
|
+
def list_tasker_classes
|
38
|
+
|
39
|
+
mod_name = @conf['module']
|
40
|
+
|
41
|
+
fail ArgumentError.new('ganger module: configuration entry missing') \
|
42
|
+
unless mod_name
|
43
|
+
|
44
|
+
mod = Flor.const_lookup(mod_name) rescue nil
|
45
|
+
|
46
|
+
fail ArgumentError.new("ganger cannot find module #{mod_name.inspect}") \
|
47
|
+
unless mod
|
48
|
+
|
49
|
+
list_classes(mod, [])
|
50
|
+
end
|
51
|
+
|
52
|
+
def list_classes(start, r)
|
53
|
+
|
54
|
+
# place leave classes on top if possible
|
55
|
+
# within a level, sort alphabetically
|
56
|
+
|
57
|
+
clas = start.constants.collect { |co| start.const_get(co) }
|
58
|
+
clas, mods = clas.partition { |c| c.is_a?(Class) }
|
59
|
+
|
60
|
+
mods.each { |m| list_classes(m, r) }
|
61
|
+
r.concat(clas.select { |c| tasker?(c) }.sort_by { |c| c.name })
|
62
|
+
|
63
|
+
r
|
64
|
+
end
|
65
|
+
|
66
|
+
TASKER_METHODS = [
|
67
|
+
:on, :on_message,
|
68
|
+
:task, :on_task,
|
69
|
+
:detask, :on_detask, :cancel, :on_cancel
|
70
|
+
].freeze
|
71
|
+
|
72
|
+
def tasker?(cla)
|
73
|
+
|
74
|
+
return true if (TASKER_METHODS & cla.public_instance_methods).any?
|
75
|
+
return true if (TASKER_METHODS & cla.public_methods).any?
|
76
|
+
false
|
77
|
+
end
|
78
|
+
|
79
|
+
def tasker_name(cla)
|
80
|
+
|
81
|
+
if cla.public_instance_methods.include?(:tasker_name)
|
82
|
+
|
83
|
+
unless cla.respond_to?(:_ganged)
|
84
|
+
class << cla
|
85
|
+
attr_accessor :_ganged
|
86
|
+
end
|
87
|
+
cla._ganged = cla.allocate
|
88
|
+
end
|
89
|
+
|
90
|
+
call_tasker_name(cla._ganged)
|
91
|
+
|
92
|
+
elsif cla.public_methods.include?(:tasker_name)
|
93
|
+
|
94
|
+
call_tasker_name(cla)
|
95
|
+
|
96
|
+
else
|
97
|
+
|
98
|
+
cla.name.split('::').last.gsub(/Tasker\z/, '')
|
99
|
+
.gsub(/([a-z])([A-Z])/) { |_| $1 + '_' + $2.downcase }
|
100
|
+
.gsub(/([A-Z])/) { |c| c.downcase }
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def call_tasker_name(o)
|
105
|
+
|
106
|
+
case i = o.method(:tasker_name).arity
|
107
|
+
when 1 then o.tasker_name(@message)
|
108
|
+
when 2 then o.tasker_name(@conf, @message)
|
109
|
+
when 3 then o.tasker_name(@service, @conf, @message)
|
110
|
+
when -1 then o.tasker_name(
|
111
|
+
service: @service, conf: @conf, message: @message)
|
112
|
+
else o.tasker_name
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def call_tasker(c)
|
117
|
+
|
118
|
+
cnf = @conf.merge('class' => c)
|
119
|
+
|
120
|
+
@service.unit.caller
|
121
|
+
.call(@service, cnf, @message)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
data/lib/flor/unit/loader.rb
CHANGED
@@ -46,7 +46,7 @@ module Flor
|
|
46
46
|
.collect { |pa| [ pa, expose_d(pa, {}) ] }
|
47
47
|
.select { |pa, d| Flor.sub_domain?(d, domain) }
|
48
48
|
.sort_by { |pa, d| d.count('.') }
|
49
|
-
.inject({}) { |vars, (pa, _)| vars.merge!(
|
49
|
+
.inject({}) { |vars, (pa, _)| vars.merge!(eval_variables(pa, {})) }
|
50
50
|
end
|
51
51
|
|
52
52
|
#def procedures(path)
|
@@ -87,25 +87,28 @@ module Flor
|
|
87
87
|
.select { |pa| pa.index('/lib/taskers/') }
|
88
88
|
.collect { |pa| [ pa, *expose_dn(pa, {}) ] }
|
89
89
|
.select { |pa, d, n|
|
90
|
-
Flor.sub_domain?([ d, n ]
|
90
|
+
Flor.sub_domain?([ d, n ], domain) ||
|
91
91
|
(n == name && Flor.sub_domain?(d, domain)) }
|
92
92
|
.sort_by { |pa, d, n| d.count('.') }
|
93
93
|
.last
|
94
94
|
|
95
95
|
return nil unless pat
|
96
96
|
|
97
|
-
conf =
|
97
|
+
conf = eval_tasker_conf(pat, message)
|
98
98
|
|
99
99
|
return conf if nam == name
|
100
100
|
|
101
|
-
|
101
|
+
cnf = conf[name]
|
102
102
|
|
103
|
-
return nil unless
|
103
|
+
return nil unless cnf
|
104
104
|
|
105
|
-
|
106
|
-
|
105
|
+
extras = conf.select { |_, v| ! v.is_a?(Hash) }
|
106
|
+
extras['_path'] = pat
|
107
107
|
|
108
|
-
|
108
|
+
(cnf.is_a?(Array) ? cnf : [ cnf ])
|
109
|
+
.each { |h| h.merge!(extras) }
|
110
|
+
|
111
|
+
cnf
|
109
112
|
end
|
110
113
|
|
111
114
|
def hooks(domain)
|
@@ -119,8 +122,8 @@ module Flor
|
|
119
122
|
.select { |pa, d| Flor.sub_domain?(d, domain) }
|
120
123
|
.sort_by { |pa, d| d.count('.') }
|
121
124
|
.collect { |pa, d|
|
122
|
-
|
123
|
-
.each_with_index { |h, i| h['_path'] = pa
|
125
|
+
eval_hook_conf(pa, {})
|
126
|
+
.each_with_index { |h, i| h['_path'] = "#{pa}:#{i}" } }
|
124
127
|
.flatten(1)
|
125
128
|
end
|
126
129
|
|
@@ -247,6 +250,35 @@ module Flor
|
|
247
250
|
end
|
248
251
|
end
|
249
252
|
|
253
|
+
def eval_variables(path, context)
|
254
|
+
eval(path, context)
|
255
|
+
end
|
256
|
+
def eval_tasker_conf(path, context)
|
257
|
+
eval(path, context)
|
258
|
+
end
|
259
|
+
# TODO like in eval_hook_conf, reject fautly tasker confs...
|
260
|
+
# TODO like in eval_hook_conf, reject fautly variables...
|
261
|
+
|
262
|
+
def eval_hook_conf(path, context)
|
263
|
+
|
264
|
+
a = eval(path, context)
|
265
|
+
|
266
|
+
fail ArgumentError.new(
|
267
|
+
"hook conf at #{path} must be an array of hashes"
|
268
|
+
) unless a.is_a?(Array)
|
269
|
+
|
270
|
+
a.each do |e|
|
271
|
+
fail ArgumentError.new(
|
272
|
+
"hook conf at #{path} has non-hash entry #{e.inspect}"
|
273
|
+
) unless e.is_a?(Hash)
|
274
|
+
fail ArgumentError.new(
|
275
|
+
"hook conf at #{path} has incorrect point #{e['point'].inspect}"
|
276
|
+
) unless e['point'].is_a?(String)
|
277
|
+
end
|
278
|
+
|
279
|
+
a
|
280
|
+
end
|
281
|
+
|
250
282
|
def eval(path, context)
|
251
283
|
|
252
284
|
ext =
|
data/lib/flor/unit/logger.rb
CHANGED
@@ -71,7 +71,8 @@ module Flor
|
|
71
71
|
dbi = ' ' + dbi if dbi.length > 0
|
72
72
|
|
73
73
|
txt = elts.collect(&:to_s).join(' ')
|
74
|
-
|
74
|
+
|
75
|
+
err = find_err(elts)
|
75
76
|
|
76
77
|
head = "#{stp} #{@uni}#{dbi} #{lvl} "
|
77
78
|
|
@@ -198,7 +199,8 @@ module Flor
|
|
198
199
|
|
199
200
|
return unless @unit.conf['log_err']
|
200
201
|
|
201
|
-
|
202
|
+
s = Flor.msg_to_detail_s(executor, message, opts.merge(flag: true))
|
203
|
+
@out.puts(s) if s
|
202
204
|
end
|
203
205
|
|
204
206
|
def log_src(source, opts, log_opts={})
|
@@ -245,6 +247,13 @@ module Flor
|
|
245
247
|
message[0..k + 2 + 4] + "(...len#{i - (k + 2 + 1)})" + message[i..-1]
|
246
248
|
end
|
247
249
|
|
250
|
+
def find_err(elts)
|
251
|
+
|
252
|
+
elts.find { |e| e.is_a?(Exception) } ||
|
253
|
+
(defined?(Java) &&
|
254
|
+
elts.find { |e| e.class.ancestors.include?(Java::JavaLang::Error) })
|
255
|
+
end
|
256
|
+
|
248
257
|
class Out
|
249
258
|
|
250
259
|
attr_reader :unit
|
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
|
3
4
|
module Flor
|
4
5
|
|
5
6
|
class Message < FlorModel
|
@@ -19,6 +20,10 @@ module Flor
|
|
19
20
|
#
|
20
21
|
# index :exid
|
21
22
|
#end
|
23
|
+
|
24
|
+
def nid; data['nid']; end
|
25
|
+
def tasker; data['tasker']; end
|
26
|
+
alias payload data
|
22
27
|
end
|
23
28
|
end
|
24
29
|
|
@@ -30,7 +30,7 @@ module Flor
|
|
30
30
|
#end
|
31
31
|
|
32
32
|
# If the pointer is a "var" pointer, returns the full value
|
33
|
-
# for the variable, as
|
33
|
+
# for the variable, as found in the execution's node "0".
|
34
34
|
#
|
35
35
|
def full_value
|
36
36
|
|
@@ -38,6 +38,25 @@ module Flor
|
|
38
38
|
|
39
39
|
node['vars'][name]
|
40
40
|
end
|
41
|
+
|
42
|
+
def attd
|
43
|
+
|
44
|
+
data['atts'].inject({}) { |h, (k, v)| h[k] = v if k; h }
|
45
|
+
|
46
|
+
rescue; []
|
47
|
+
end
|
48
|
+
|
49
|
+
def attl
|
50
|
+
|
51
|
+
data['atts'].inject([]) { |a, (k, v)| a << v if k == nil; a }
|
52
|
+
|
53
|
+
rescue; []
|
54
|
+
end
|
55
|
+
|
56
|
+
def att_texts
|
57
|
+
|
58
|
+
attl.select { |e| e.is_a?(String) }
|
59
|
+
end
|
41
60
|
end
|
42
61
|
end
|
43
62
|
|
data/lib/flor/unit/scheduler.rb
CHANGED
@@ -138,11 +138,7 @@ module Flor
|
|
138
138
|
|
139
139
|
# TODO heartbeat, every x minutes, when idle, log something
|
140
140
|
|
141
|
-
|
142
|
-
"database not ready, " +
|
143
|
-
"db ver: #{@storage.db_version.inspect}, " +
|
144
|
-
"mig ver: #{@storage.migration_version}"
|
145
|
-
) if !! @conf['sto_migration_check'] && @storage.ready?
|
141
|
+
check_migration_version
|
146
142
|
|
147
143
|
@thread_status = :running
|
148
144
|
|
@@ -162,6 +158,15 @@ module Flor
|
|
162
158
|
self
|
163
159
|
end
|
164
160
|
|
161
|
+
def check_migration_version
|
162
|
+
|
163
|
+
fail(
|
164
|
+
"database not ready, " +
|
165
|
+
"db ver: #{@storage.db_version.inspect}, " +
|
166
|
+
"mig ver: #{@storage.migration_version}"
|
167
|
+
) if !! @conf['sto_migration_check'] && @storage.ready?
|
168
|
+
end
|
169
|
+
|
165
170
|
def stop
|
166
171
|
|
167
172
|
@thread_status = :stop
|
@@ -590,7 +595,7 @@ module Flor
|
|
590
595
|
|
591
596
|
rescue Exception => ex
|
592
597
|
|
593
|
-
puts
|
598
|
+
puts(on_start_exc(ex))
|
594
599
|
end
|
595
600
|
|
596
601
|
def prepare_message(point, args)
|
@@ -678,9 +683,9 @@ module Flor
|
|
678
683
|
def should_wake_up?
|
679
684
|
|
680
685
|
return true if @wake_up
|
681
|
-
return true if Time.now - @reloaded_at >= reload_after
|
686
|
+
return true if (Time.now - @reloaded_at) >= reload_after
|
682
687
|
|
683
|
-
@next_time && @next_time <= Flor.
|
688
|
+
@next_time && (@next_time <= Flor.tstam)
|
684
689
|
end
|
685
690
|
|
686
691
|
def unreserve_messages
|
data/lib/flor/unit/storage.rb
CHANGED
@@ -7,6 +7,15 @@ module Flor
|
|
7
7
|
|
8
8
|
class Storage
|
9
9
|
|
10
|
+
MESSAGE_COLUMNS = [
|
11
|
+
:domain, :exid, :point, :content,
|
12
|
+
:status, :ctime, :mtime, :cunit, :munit
|
13
|
+
].freeze
|
14
|
+
POINTER_COLUMNS = [
|
15
|
+
:domain, :exid, :nid, :type, :name, :value, :ctime, :cunit,
|
16
|
+
:content
|
17
|
+
].freeze
|
18
|
+
|
10
19
|
attr_reader :unit, :db, :models
|
11
20
|
|
12
21
|
attr_reader :mutex
|
@@ -352,8 +361,7 @@ module Flor
|
|
352
361
|
|
353
362
|
@db[:flor_messages]
|
354
363
|
.import(
|
355
|
-
|
356
|
-
:status, :ctime, :mtime, :cunit, :munit ],
|
364
|
+
MESSAGE_COLUMNS,
|
357
365
|
unstored.map { |m|
|
358
366
|
[ Flor.domain(m['exid']), m['exid'], m['point'], to_blob(m),
|
359
367
|
'created', n, n, u, u ] }) \
|
@@ -517,25 +525,6 @@ module Flor
|
|
517
525
|
end
|
518
526
|
end
|
519
527
|
|
520
|
-
def put_task_pointer(msg, tname, tconf)
|
521
|
-
|
522
|
-
exid = msg['exid']
|
523
|
-
dom = Flor.domain(exid)
|
524
|
-
|
525
|
-
synchronize do
|
526
|
-
|
527
|
-
@db[:flor_pointers]
|
528
|
-
.insert(
|
529
|
-
domain: dom,
|
530
|
-
exid: exid,
|
531
|
-
nid: msg['nid'],
|
532
|
-
type: 'tasker',
|
533
|
-
name: tname,
|
534
|
-
ctime: Flor.tstamp,
|
535
|
-
cunit: @unit.identifier)
|
536
|
-
end
|
537
|
-
end
|
538
|
-
|
539
528
|
def fetch_next_time
|
540
529
|
|
541
530
|
t =
|
@@ -598,14 +587,13 @@ module Flor
|
|
598
587
|
|
599
588
|
@db[:flor_messages]
|
600
589
|
.where(
|
601
|
-
id: messages.collect { |m| m['mid'] }.compact)
|
590
|
+
id: messages.collect { |m| m['mid'] }.uniq.compact)
|
602
591
|
.update(
|
603
592
|
status: 'consumed', mtime: n, munit: u)
|
604
593
|
|
605
594
|
@db[:flor_messages]
|
606
595
|
.import(
|
607
|
-
|
608
|
-
:status, :ctime, :mtime, :cunit, :munit ],
|
596
|
+
MESSAGE_COLUMNS,
|
609
597
|
messages
|
610
598
|
.select { |m|
|
611
599
|
! m['mid'] && POINTS_TO_ARCHIVE.include?(m['point']) }
|
@@ -621,19 +609,16 @@ module Flor
|
|
621
609
|
|
622
610
|
@db[:flor_messages]
|
623
611
|
.where(
|
624
|
-
id: messages.collect { |m| m['mid'] }.compact)
|
612
|
+
id: messages.collect { |m| m['mid'] }.uniq.compact)
|
625
613
|
.delete
|
626
614
|
end
|
627
615
|
end
|
628
616
|
|
629
617
|
def load_timers
|
630
618
|
|
631
|
-
now = Flor.tstamp
|
632
|
-
no = now[0, now.rindex('.')]
|
633
|
-
|
634
619
|
timers
|
635
620
|
.where(status: 'active')
|
636
|
-
.where { ntime <=
|
621
|
+
.where { ntime <= Flor.tstam }
|
637
622
|
.order(:ntime)
|
638
623
|
.all
|
639
624
|
|
@@ -703,9 +688,9 @@ module Flor
|
|
703
688
|
|
704
689
|
def update_pointers(exe, status, now)
|
705
690
|
|
706
|
-
# Q
|
707
|
-
#
|
708
|
-
#
|
691
|
+
# Q Should we archive old pointers?
|
692
|
+
# A Well, it might be better to only archive the execution and leave
|
693
|
+
# in there enough information...
|
709
694
|
|
710
695
|
exid = exe['exid']
|
711
696
|
|
@@ -731,23 +716,25 @@ module Flor
|
|
731
716
|
|
732
717
|
ts = node['tags']
|
733
718
|
ts.each { |t|
|
734
|
-
a << [ dom, exid, nid, 'tag', t, nil, now, u ] } if ts
|
719
|
+
a << [ dom, exid, nid, 'tag', t, nil, now, u, nil ] } if ts
|
735
720
|
|
736
721
|
vs = nid == '0' ? node['vars'] : nil
|
737
722
|
vs.each { |k, v|
|
738
723
|
case v; when Numeric, String, TrueClass, FalseClass, NilClass
|
739
|
-
a << [ dom, exid, '0', 'var', k, v.to_s, now, u ]
|
724
|
+
a << [ dom, exid, '0', 'var', k, v.to_s, now, u, v ]
|
740
725
|
when Array, Hash
|
741
726
|
s = '(array)'; s = '(object)' if v.is_a?(Hash)
|
742
|
-
a << [ dom, exid, '0', 'var', k, s, now, u ]
|
727
|
+
a << [ dom, exid, '0', 'var', k, s, now, u, v ]
|
743
728
|
else
|
744
|
-
a << [ dom, exid, '0', 'var', k, nil, now, u ]
|
729
|
+
a << [ dom, exid, '0', 'var', k, nil, now, u, v ]
|
745
730
|
end } if vs
|
746
731
|
|
747
|
-
|
748
|
-
|
749
|
-
|
750
|
-
|
732
|
+
if ta = node['task']
|
733
|
+
tasker = ta['tasker']
|
734
|
+
n = ta['name']; name = n.is_a?(String) ? n : JSON.dump(n)
|
735
|
+
content = { message: node['message'], atts: node['atts'] }
|
736
|
+
a << [ dom, exid, nid, 'tasker', tasker, name, now, u, content ]
|
737
|
+
end
|
751
738
|
|
752
739
|
a }
|
753
740
|
|
@@ -755,17 +742,36 @@ module Flor
|
|
755
742
|
.where(exid: exid)
|
756
743
|
.select(:nid, :type, :name)
|
757
744
|
.all
|
758
|
-
pointers.reject! { |_, _, ni, ty, na, _, _, _|
|
745
|
+
pointers.reject! { |_, _, ni, ty, na, _, _, _, _|
|
759
746
|
cps.find { |cp| cp[:nid] == ni && cp[:type] == ty && cp[:name] == na } }
|
760
747
|
#
|
761
748
|
# don't insert when already inserted
|
762
749
|
|
750
|
+
#if pointer_columns.include?(:content)
|
751
|
+
pointers.each { |ptr| c = ptr[8]; ptr[8] = to_blob(c) if c }
|
752
|
+
#else
|
753
|
+
# pointers.each { |ptr| ptr.pop }
|
754
|
+
#end
|
755
|
+
|
756
|
+
#@db[:flor_pointers]
|
757
|
+
# .import(
|
758
|
+
# pointer_columns,
|
759
|
+
# pointers)
|
763
760
|
@db[:flor_pointers]
|
764
761
|
.import(
|
765
|
-
|
762
|
+
POINTER_COLUMNS,
|
766
763
|
pointers)
|
767
764
|
end
|
768
765
|
|
766
|
+
#def pointer_columns
|
767
|
+
# @pointer_columns ||=
|
768
|
+
# if @db[:flor_pointers].columns.include?(:content)
|
769
|
+
# POINTER_COLUMNS + [ :content ]
|
770
|
+
# else
|
771
|
+
# POINTER_COLUMNS
|
772
|
+
# end
|
773
|
+
#end
|
774
|
+
|
769
775
|
def determine_type_and_schedule(message)
|
770
776
|
|
771
777
|
t, s = message['type'], message['string']
|
@@ -845,8 +851,11 @@ module Flor
|
|
845
851
|
# NB: -1 means "check at every use"
|
846
852
|
end
|
847
853
|
|
848
|
-
@
|
849
|
-
|
854
|
+
if @unit.conf['sto_db_logger'] != false
|
855
|
+
|
856
|
+
@db_logger = DbLogger.new(@unit)
|
857
|
+
@db.loggers << @db_logger
|
858
|
+
end
|
850
859
|
end
|
851
860
|
|
852
861
|
class << self
|
data/lib/flor/unit/taskers.rb
CHANGED
@@ -29,6 +29,29 @@ module Flor
|
|
29
29
|
alias task_name taskname
|
30
30
|
|
31
31
|
def vars; @message['vars']; end
|
32
|
+
alias variables vars
|
33
|
+
|
34
|
+
def set_payload(h)
|
35
|
+
fail TypeError.new("not a hash but a #{fs.class}") unless h.is_a?(Hash)
|
36
|
+
@message['payload'] = h
|
37
|
+
end
|
38
|
+
alias set_fields set_payload
|
39
|
+
|
40
|
+
def set_vars(h)
|
41
|
+
fail TypeError.new("not a hash but a #{fs.class}") unless h.is_a?(Hash)
|
42
|
+
@message['vars'] = h
|
43
|
+
end
|
44
|
+
alias set_variables set_vars
|
45
|
+
|
46
|
+
#def merge_into_payload(h)
|
47
|
+
# @message['payload'].merge(h)
|
48
|
+
#end
|
49
|
+
#alias merge_into_fields merge_into_payload
|
50
|
+
#def merge_into_vars(h)
|
51
|
+
# @message['vars'].merge(h)
|
52
|
+
#end
|
53
|
+
#
|
54
|
+
# no for now, payload.merge(h) and vars.merge(h) do suffice
|
32
55
|
|
33
56
|
def execution
|
34
57
|
|
@@ -112,5 +135,50 @@ module Flor
|
|
112
135
|
h
|
113
136
|
end
|
114
137
|
end
|
138
|
+
|
139
|
+
# A BasicTasker with stages (pre / on / post)
|
140
|
+
#
|
141
|
+
class StagedBasicTasker < BasicTasker
|
142
|
+
|
143
|
+
def call_task
|
144
|
+
|
145
|
+
call_one_of(:pre_task)
|
146
|
+
call_one_of(:on_task, :task)
|
147
|
+
end
|
148
|
+
|
149
|
+
def call_detask
|
150
|
+
|
151
|
+
call_one_of(:pre_detask, :pre_cancel)
|
152
|
+
call_one_of(:on_detask, :on_cancel, :detask, :cancel)
|
153
|
+
end
|
154
|
+
|
155
|
+
protected
|
156
|
+
|
157
|
+
def call_one_of(*ms)
|
158
|
+
|
159
|
+
m = ms.flatten.find { |mm| respond_to?(mm) }
|
160
|
+
|
161
|
+
send(m) if m
|
162
|
+
end
|
163
|
+
|
164
|
+
def reply(message=@message, force=false)
|
165
|
+
|
166
|
+
fail ArgumentError.new(
|
167
|
+
"argument to reply must be a Hash but is #{message.class}"
|
168
|
+
) unless message.is_a?(Hash)
|
169
|
+
|
170
|
+
pt = @message['point']
|
171
|
+
|
172
|
+
ms = [ "post_#{pt}" ]; ms << :post_cancel if pt == 'detask'
|
173
|
+
#
|
174
|
+
call_one_of(ms)
|
175
|
+
|
176
|
+
msg = derive_message(message)
|
177
|
+
|
178
|
+
@ganger.return(msg) if force || @ganger
|
179
|
+
|
180
|
+
[] # very important, return no further messages
|
181
|
+
end
|
182
|
+
end
|
115
183
|
end
|
116
184
|
|
data/lib/flor/unit/waiter.rb
CHANGED
@@ -53,7 +53,7 @@ module Flor
|
|
53
53
|
|
54
54
|
@mutex.synchronize do
|
55
55
|
|
56
|
-
return false unless
|
56
|
+
return false unless msg_match?(message)
|
57
57
|
|
58
58
|
@serie.shift
|
59
59
|
return false if @serie.any?
|
@@ -151,7 +151,7 @@ module Flor
|
|
151
151
|
|
152
152
|
protected
|
153
153
|
|
154
|
-
def
|
154
|
+
def msg_match?(message)
|
155
155
|
|
156
156
|
mpoint = message['point']
|
157
157
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: flor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- John Mettraux
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-03-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: munemo
|
@@ -237,7 +237,7 @@ files:
|
|
237
237
|
- lib/flor/punit/do_trap.rb
|
238
238
|
- lib/flor/punit/every.rb
|
239
239
|
- lib/flor/punit/graft.rb
|
240
|
-
- lib/flor/punit/
|
240
|
+
- lib/flor/punit/m_receive_and_merge.rb
|
241
241
|
- lib/flor/punit/on_timeout.rb
|
242
242
|
- lib/flor/punit/part.rb
|
243
243
|
- lib/flor/punit/schedule.rb
|
@@ -248,6 +248,7 @@ files:
|
|
248
248
|
- lib/flor/punit/trap.rb
|
249
249
|
- lib/flor/to_string.rb
|
250
250
|
- lib/flor/tools/env.rb
|
251
|
+
- lib/flor/tools/firb.rb
|
251
252
|
- lib/flor/tools/shell.rb
|
252
253
|
- lib/flor/tools/shell_out.rb
|
253
254
|
- lib/flor/tt.rb
|
@@ -257,6 +258,7 @@ files:
|
|
257
258
|
- lib/flor/unit/dump.rb
|
258
259
|
- lib/flor/unit/executor.rb
|
259
260
|
- lib/flor/unit/ganger.rb
|
261
|
+
- lib/flor/unit/gangers.rb
|
260
262
|
- lib/flor/unit/hloader.rb
|
261
263
|
- lib/flor/unit/hook.rb
|
262
264
|
- lib/flor/unit/hooker.rb
|