flor 1.0.1 → 1.2.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
-
[![
|
4
|
+
[![tests](https://github.com/floraison/flor/workflows/test/badge.svg)](https://github.com/floraison/flor/actions)
|
5
5
|
[![Gem Version](https://badge.fury.io/rb/flor.svg)](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
|