flor 0.10.0 → 0.11.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +12 -0
- data/README.md +5 -1
- data/fail.txt +3 -0
- data/lib/flor.rb +1 -1
- data/lib/flor/conf.rb +1 -1
- data/lib/flor/core/executor.rb +34 -6
- data/lib/flor/core/node.rb +15 -1
- data/lib/flor/core/texecutor.rb +19 -4
- data/lib/flor/djan.rb +1 -1
- data/lib/flor/flor.rb +37 -2
- data/lib/flor/parser.rb +55 -29
- data/lib/flor/pcore/apply.rb +23 -24
- data/lib/flor/pcore/case.rb +24 -26
- data/lib/flor/pcore/fail.rb +10 -0
- data/lib/flor/pcore/if.rb +36 -1
- data/lib/flor/pcore/twig.rb +32 -0
- data/lib/flor/pcore/val.rb +1 -1
- data/lib/flor/punit/graft.rb +39 -1
- data/lib/flor/unit.rb +3 -0
- data/lib/flor/unit/executor.rb +1 -0
- data/lib/flor/unit/ganger.rb +19 -68
- data/lib/flor/unit/hook.rb +32 -0
- data/lib/flor/unit/hooker.rb +5 -12
- data/lib/flor/unit/hooks.rb +37 -0
- data/lib/flor/unit/loader.rb +44 -17
- data/lib/flor/unit/logger.rb +1 -0
- data/lib/flor/unit/models/trap.rb +22 -26
- data/lib/flor/unit/runner.rb +84 -0
- data/lib/flor/unit/scheduler.rb +57 -46
- data/lib/flor/unit/spooler.rb +109 -0
- data/lib/flor/unit/storage.rb +1 -1
- data/lib/flor/unit/waiter.rb +2 -4
- data/lib/flor/unit/wlist.rb +13 -0
- metadata +8 -2
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,18 @@
|
|
2
2
|
# flor CHANGELOG.md
|
3
3
|
|
4
4
|
|
5
|
+
## flor 0.11.0 released 2017-03-17
|
6
|
+
|
7
|
+
- Simplification of the tasker configuration files
|
8
|
+
(alignment on hooks configuration files)
|
9
|
+
- Introduction of lib/hooks/
|
10
|
+
- go for ; and | (same level) and \ (child level)
|
11
|
+
- Implement "twig"
|
12
|
+
- Implement basic spooler (var/spool/)
|
13
|
+
- Introduce runner service
|
14
|
+
- Fix Storage#any_message (misuse of Sequel Dataset#count)
|
15
|
+
|
16
|
+
|
5
17
|
## flor 0.10.0 released 2017-03-03
|
6
18
|
|
7
19
|
- Enhance shell, bring in bin/flosh (though not in gem)
|
data/README.md
CHANGED
@@ -21,9 +21,13 @@ Flor is a "Ruby workflow engine", if that makes any sense.
|
|
21
21
|
* All in all should be easy to maintain (engine itself and executions running
|
22
22
|
on top of it)
|
23
23
|
|
24
|
+
## Quickstart
|
25
|
+
|
26
|
+
See [quickstart/](quickstart/).
|
27
|
+
|
24
28
|
## Documentation
|
25
29
|
|
26
|
-
|
30
|
+
See [doc/](doc/).
|
27
31
|
|
28
32
|
|
29
33
|
## LICENSE
|
data/fail.txt
ADDED
@@ -0,0 +1,3 @@
|
|
1
|
+
rspec ./spec/unit/push_and_runs_spec.rb:30 # Flor unit push (run spanning) works
|
2
|
+
rspec ./spec/unit/scheduler_spec.rb:371 # Flor unit Flor::Scheduler sch_msg_max_res_time flags as "active" messages that have been reserved for too long
|
3
|
+
rspec ./spec/unit/waiter_spec.rb:127 # Flor::Waiter as a launch option lets wait until the scheduler gets idle
|
data/lib/flor.rb
CHANGED
data/lib/flor/conf.rb
CHANGED
data/lib/flor/core/executor.rb
CHANGED
@@ -5,13 +5,16 @@ module Flor
|
|
5
5
|
|
6
6
|
attr_reader :unit
|
7
7
|
attr_reader :execution
|
8
|
+
attr_reader :hooks
|
8
9
|
attr_reader :traps
|
9
10
|
|
10
|
-
def initialize(unit, traps, execution)
|
11
|
+
def initialize(unit, hooks, traps, execution)
|
11
12
|
|
12
13
|
@unit = unit
|
13
14
|
@execution = execution
|
14
|
-
|
15
|
+
|
16
|
+
@hooks = hooks # raw hooks if any, fresh from the loader
|
17
|
+
@traps = traps # array of Trap instances
|
15
18
|
end
|
16
19
|
|
17
20
|
def conf; @unit.conf; end
|
@@ -54,17 +57,32 @@ module Flor
|
|
54
57
|
counter_add(key, 1)
|
55
58
|
end
|
56
59
|
|
60
|
+
def trigger_trap(trap, message)
|
61
|
+
|
62
|
+
del, msgs = trap.trigger(self, message)
|
63
|
+
@traps.delete(trap) if del
|
64
|
+
|
65
|
+
msgs
|
66
|
+
end
|
67
|
+
|
57
68
|
def trigger_hook(hook, message)
|
58
69
|
|
59
70
|
hook.notify(self, message)
|
60
71
|
end
|
61
72
|
|
62
|
-
def
|
73
|
+
def trigger_block(block, opts, message)
|
63
74
|
|
64
|
-
|
65
|
-
|
75
|
+
r =
|
76
|
+
if block.arity == 1
|
77
|
+
block.call(message)
|
78
|
+
elsif block.arity == 2
|
79
|
+
block.call(message, opts)
|
80
|
+
else
|
81
|
+
block.call(self, message, opts)
|
82
|
+
end
|
66
83
|
|
67
|
-
|
84
|
+
r.is_a?(Array) && r.all? { |e| e.is_a?(Hash) } ? r : []
|
85
|
+
# be lenient with block hooks, help them return an array
|
68
86
|
end
|
69
87
|
|
70
88
|
# Given a nid, returns a copy of all the var the node sees
|
@@ -88,6 +106,16 @@ module Flor
|
|
88
106
|
vs
|
89
107
|
end
|
90
108
|
|
109
|
+
def traps_and_hooks
|
110
|
+
|
111
|
+
@htraps = nil if @htraps && @htraps.size != @traps.size
|
112
|
+
|
113
|
+
@htraps ||= @traps.collect(&:to_hook)
|
114
|
+
@hhooks ||= @hooks.collect(&:to_hook)
|
115
|
+
|
116
|
+
@htraps + @hhooks
|
117
|
+
end
|
118
|
+
|
91
119
|
protected
|
92
120
|
|
93
121
|
def make_node(message)
|
data/lib/flor/core/node.rb
CHANGED
@@ -152,6 +152,8 @@ class Flor::Node
|
|
152
152
|
@node
|
153
153
|
elsif cat == 'v'
|
154
154
|
lookup_var(@node, mod, key)
|
155
|
+
elsif cat == 't'
|
156
|
+
lookup_tag(mod, key)
|
155
157
|
else
|
156
158
|
lookup_field(mod, key)
|
157
159
|
end
|
@@ -371,6 +373,17 @@ class Flor::Node
|
|
371
373
|
lookup_var_name(parent_node(node), val)
|
372
374
|
end
|
373
375
|
|
376
|
+
def lookup_tag(mod, key)
|
377
|
+
|
378
|
+
nids =
|
379
|
+
@execution['nodes'].inject([]) do |a, (nid, n)|
|
380
|
+
a << nid if n['tags'] && n['tags'].include?(key)
|
381
|
+
a
|
382
|
+
end
|
383
|
+
|
384
|
+
nids.empty? ? [ '_nul', nil, -1 ] : nids
|
385
|
+
end
|
386
|
+
|
374
387
|
def lookup_field(mod, key)
|
375
388
|
|
376
389
|
Flor.deep_get(payload.current, key)[1]
|
@@ -378,7 +391,8 @@ class Flor::Node
|
|
378
391
|
|
379
392
|
def key_split(key) # => category, mode, key
|
380
393
|
|
381
|
-
m = key.match(
|
394
|
+
m = key.match(
|
395
|
+
/\A(?:([lgd]?)((?:v|var|variable)|w|f|fld|field|t|tag)\.)?(.+)\z/)
|
382
396
|
|
383
397
|
#fail ArgumentError.new("couldn't split key #{key.inspect}") unless m
|
384
398
|
# spare that
|
data/lib/flor/core/texecutor.rb
CHANGED
@@ -64,6 +64,7 @@ module Flor
|
|
64
64
|
|
65
65
|
super(
|
66
66
|
TransientUnit.new(conf),
|
67
|
+
[], # no hooks
|
67
68
|
[], # no traps
|
68
69
|
{
|
69
70
|
'exid' => Flor.generate_exid('eval', 'u0'),
|
@@ -166,8 +167,17 @@ module Flor
|
|
166
167
|
ls.reject! { |l| l.strip[0, 1] == '#' }
|
167
168
|
s = ls.join("\n").strip
|
168
169
|
end
|
170
|
+
|
171
|
+
a, b = s[0, 1], s[-1, 1]
|
172
|
+
|
169
173
|
s =
|
170
|
-
|
174
|
+
if (a == '{' && b == '}') || (a == '[' && b == ']')
|
175
|
+
s
|
176
|
+
elsif s.match(/[^\r\n{]+:/) || s == ''
|
177
|
+
"{\n#{s}\n}"
|
178
|
+
else
|
179
|
+
"[\n#{s}\n]"
|
180
|
+
end
|
171
181
|
|
172
182
|
vs = Hash.new { |h, k| k }
|
173
183
|
class << vs
|
@@ -188,11 +198,16 @@ module Flor
|
|
188
198
|
fail ae
|
189
199
|
end
|
190
200
|
|
191
|
-
|
201
|
+
o = Flor.dup(r['payload']['ret'])
|
192
202
|
|
193
|
-
|
203
|
+
if o.is_a?(Hash)
|
204
|
+
o['_path'] = path unless path.match(/[\r\n]/)
|
205
|
+
o['root'] ||= Flor.relativize_path(vs['root'])
|
206
|
+
elsif o.is_a?(Array)
|
207
|
+
o.each { |e| e['_path'] = path } unless path.match(/[\r\n]/)
|
208
|
+
end
|
194
209
|
|
195
|
-
|
210
|
+
o
|
196
211
|
end
|
197
212
|
|
198
213
|
def self.determine_root(path)
|
data/lib/flor/djan.rb
CHANGED
data/lib/flor/flor.rb
CHANGED
@@ -11,6 +11,11 @@ module Flor
|
|
11
11
|
#
|
12
12
|
# miscellaneous functions
|
13
13
|
|
14
|
+
def self.env_i(k)
|
15
|
+
|
16
|
+
v = ENV[k]; (v && v.match(/\A\d+\z/)) ? v.to_i : nil
|
17
|
+
end
|
18
|
+
|
14
19
|
def self.dup(o)
|
15
20
|
|
16
21
|
Marshal.load(Marshal.dump(o))
|
@@ -49,7 +54,7 @@ module Flor
|
|
49
54
|
h['kla'] = o.class.to_s
|
50
55
|
t = nil
|
51
56
|
|
52
|
-
if o.is_a?(Exception)
|
57
|
+
if o.is_a?(::Exception)
|
53
58
|
|
54
59
|
h['msg'] = o.message
|
55
60
|
|
@@ -68,6 +73,8 @@ module Flor
|
|
68
73
|
end
|
69
74
|
|
70
75
|
h['trc'] = t[0..(t.rindex { |l| l.match(/\/lib\/flor\//) }) + 1] if t
|
76
|
+
h['cwd'] = Dir.pwd
|
77
|
+
h['rlp'] = $: if o.is_a?(::LoadError)
|
71
78
|
|
72
79
|
h
|
73
80
|
end
|
@@ -89,7 +96,7 @@ module Flor
|
|
89
96
|
|
90
97
|
path = path[from.length + 1..-1] if path[0, from.length] == from
|
91
98
|
|
92
|
-
path
|
99
|
+
path || '.'
|
93
100
|
end
|
94
101
|
|
95
102
|
def self.is_array_of_messages?(o)
|
@@ -101,6 +108,25 @@ module Flor
|
|
101
108
|
e.keys.all? { |k| k.is_a?(String) } }
|
102
109
|
end
|
103
110
|
|
111
|
+
def self.h_fetch_a(h, *keys)
|
112
|
+
|
113
|
+
default = keys.last.is_a?(String) ? [] : keys.pop
|
114
|
+
|
115
|
+
k = keys.find { |k| h.has_key?(k) }
|
116
|
+
v = k ? h[k] : nil
|
117
|
+
|
118
|
+
v_to_a(v) || default
|
119
|
+
end
|
120
|
+
|
121
|
+
def self.v_to_a(o)
|
122
|
+
|
123
|
+
return o if o.is_a?(Array)
|
124
|
+
return o.split(',') if o.is_a?(String)
|
125
|
+
return nil if o.nil?
|
126
|
+
|
127
|
+
fail ArgumentError.new("cannot turn instance of #{o.class} into an array")
|
128
|
+
end
|
129
|
+
|
104
130
|
#
|
105
131
|
# functions about time
|
106
132
|
|
@@ -132,6 +158,15 @@ module Flor
|
|
132
158
|
isostamp(true, false, false, t)
|
133
159
|
end
|
134
160
|
|
161
|
+
def self.tamp(t=Time.now)
|
162
|
+
|
163
|
+
t = t.utc
|
164
|
+
s = StringIO.new
|
165
|
+
s << t.strftime('%Y%m%dT%H%M%S') << sprintf('.%06dZ', t.usec)
|
166
|
+
|
167
|
+
s.string
|
168
|
+
end
|
169
|
+
|
135
170
|
# hour stamp
|
136
171
|
#
|
137
172
|
def self.hstamp(t=Time.now)
|
data/lib/flor/parser.rb
CHANGED
@@ -10,7 +10,6 @@ module Flor
|
|
10
10
|
def dot(i); str(nil, i, '.'); end
|
11
11
|
def colon(i); str(nil, i, ':'); end
|
12
12
|
def comma(i); str(nil, i, ','); end
|
13
|
-
def bslash(i); str(nil, i, '\\'); end
|
14
13
|
|
15
14
|
def pstart(i); str(nil, i, '('); end
|
16
15
|
def pend(i); str(nil, i, ')'); end
|
@@ -72,11 +71,10 @@ module Flor
|
|
72
71
|
def postval(i); rep(nil, i, :eol, 0); end
|
73
72
|
|
74
73
|
def comma_eol(i); seq(nil, i, :comma, :eol, :ws_star); end
|
75
|
-
def
|
76
|
-
def sep(i); alt(nil, i, :comma_eol, :bslash_eol, :ws_star); end
|
74
|
+
def sep(i); alt(nil, i, :comma_eol, :ws_star); end
|
77
75
|
|
78
76
|
def comma_qmark_eol(i); seq(nil, i, :comma, '?', :eol); end
|
79
|
-
def coll_sep(i); alt(nil, i, :
|
77
|
+
def coll_sep(i); alt(nil, i, :comma_qmark_eol, :ws_star); end
|
80
78
|
|
81
79
|
def ent(i); seq(:ent, i, :key, :postval, :colon, :postval, :exp, :postval); end
|
82
80
|
def ent_qmark(i); rep(nil, i, :ent, 0, 1); end
|
@@ -125,15 +123,20 @@ module Flor
|
|
125
123
|
alias exp eor
|
126
124
|
|
127
125
|
def key(i); seq(:key, i, :exp); end
|
128
|
-
def keycol(i); seq(nil, i, :key, :ws_star, :colon, :eol); end
|
126
|
+
def keycol(i); seq(nil, i, :key, :ws_star, :colon, :eol, :ws_star); end
|
129
127
|
|
130
128
|
def att(i); seq(:att, i, :sep, :keycol, '?', :exp); end
|
131
129
|
def head(i); seq(:head, i, :exp); end
|
132
|
-
def indent(i); rex(:indent, i, /[
|
130
|
+
def indent(i); rex(:indent, i, /[ \t]*/); end
|
133
131
|
def node(i); seq(:node, i, :indent, :head, :att, '*'); end
|
134
132
|
|
133
|
+
def linjoin(i); rex(nil, i, /[ \t]*[\\|;][ \t]*/); end
|
134
|
+
def outjnl(i); seq(nil, i, :linjoin, :comment, '?', :retnew); end
|
135
|
+
def outnlj(i); seq(nil, i, :ws_star, :comment, '?', :retnew, :linjoin); end
|
136
|
+
def outdent(i); alt(:outdent, i, :outjnl, :outnlj, :eol); end
|
137
|
+
|
135
138
|
def line(i)
|
136
|
-
seq(:line, i, :node, '?', :
|
139
|
+
seq(:line, i, :node, '?', :outdent)
|
137
140
|
end
|
138
141
|
def panode(i)
|
139
142
|
seq(:panode, i, :pstart, :eol, :ws_star, :line, '*', :eol, :pend)
|
@@ -151,7 +154,7 @@ module Flor
|
|
151
154
|
|
152
155
|
def rewrite_par(t)
|
153
156
|
|
154
|
-
Nod.new(t.lookup(:node)).to_a
|
157
|
+
Nod.new(t.lookup(:node), nil).to_a
|
155
158
|
end
|
156
159
|
|
157
160
|
def rewrite_ref(t); [ t.string, [], ln(t) ]; end
|
@@ -237,7 +240,7 @@ module Flor
|
|
237
240
|
attr_accessor :parent, :indent
|
238
241
|
attr_reader :children
|
239
242
|
|
240
|
-
def initialize(tree)
|
243
|
+
def initialize(tree, outdent)
|
241
244
|
|
242
245
|
@parent = nil
|
243
246
|
@indent = -1
|
@@ -245,15 +248,21 @@ module Flor
|
|
245
248
|
@children = []
|
246
249
|
@line = 0
|
247
250
|
|
251
|
+
@outdent = outdent ? outdent.strip : nil
|
252
|
+
@outdent = nil if @outdent && @outdent.size < 1
|
253
|
+
|
248
254
|
read(tree) if tree
|
249
255
|
end
|
250
256
|
|
251
257
|
def append(node)
|
252
258
|
|
253
|
-
if
|
254
|
-
|
255
|
-
|
256
|
-
|
259
|
+
if @outdent
|
260
|
+
if @outdent.index('\\')
|
261
|
+
node.indent = self.indent + 2
|
262
|
+
elsif @outdent.index('|') || @outdent.index(';')
|
263
|
+
node.indent = self.indent
|
264
|
+
end
|
265
|
+
@outdent = nil
|
257
266
|
end
|
258
267
|
|
259
268
|
if node.indent > self.indent
|
@@ -270,6 +279,21 @@ module Flor
|
|
270
279
|
|
271
280
|
cn = @children.collect(&:to_a)
|
272
281
|
|
282
|
+
# make sure `[ 1 2 3 ] timeout: '2h'`
|
283
|
+
# turns into `_arr timeout: '2h'; 1 | 2 | 3`
|
284
|
+
|
285
|
+
if (
|
286
|
+
@head.is_a?(Array) &&
|
287
|
+
(@head[0] == '_arr' || @head[0] == '_obj') &&
|
288
|
+
#Flor.is_array_of_trees?(@head[1]) &&
|
289
|
+
cn.all? { |c| c[0] == '_att' && c[1].size > 1 }
|
290
|
+
)
|
291
|
+
cn = @head[1] + cn
|
292
|
+
@head = @head[0]
|
293
|
+
att, non_att = cn.partition { |c| c[0] == '_att' }
|
294
|
+
cn = att + non_att
|
295
|
+
end
|
296
|
+
|
273
297
|
# detect if/unless suffix
|
274
298
|
|
275
299
|
atts =
|
@@ -279,7 +303,6 @@ module Flor
|
|
279
303
|
c.size == 1 && %w[ if unless ].include?(c[0][0]) && c[0][1] == []
|
280
304
|
}
|
281
305
|
|
282
|
-
#return cn.first if @head == 'sequence' && @line == 0 && cn.size == 1
|
283
306
|
return [ @head, cn, @line ] unless i
|
284
307
|
|
285
308
|
# rewrite if/unless suffix
|
@@ -295,20 +318,20 @@ module Flor
|
|
295
318
|
|
296
319
|
def read(tree)
|
297
320
|
|
298
|
-
if it = tree.lookup(:indent)
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
321
|
+
#if it = tree.lookup(:indent)
|
322
|
+
# #s = it.string
|
323
|
+
# #semicount = s.count(';')
|
324
|
+
# #pipe = s.index('|')
|
325
|
+
# #
|
326
|
+
# #@indent =
|
327
|
+
# # if semicount == 1 then :east
|
328
|
+
# # elsif semicount > 1 || pipe then :south
|
329
|
+
# # else s.length; end
|
330
|
+
#end
|
331
|
+
@indent = tree.lookup(:indent).string.length
|
309
332
|
|
310
333
|
ht = tree.lookup(:head)
|
311
|
-
@line = Lang.line_number(ht)
|
334
|
+
@line = Flor::Lang.line_number(ht)
|
312
335
|
|
313
336
|
@head = Flor::Lang.rewrite(ht.c0)
|
314
337
|
@head = @head[0] if @head[0].is_a?(String) && @head[1] == []
|
@@ -341,10 +364,13 @@ module Flor
|
|
341
364
|
|
342
365
|
def rewrite_flor(t)
|
343
366
|
|
344
|
-
prev = root = Nod.new(nil)
|
367
|
+
prev = root = Nod.new(nil, nil)
|
345
368
|
|
346
|
-
t.gather(:node).each do |nt|
|
347
|
-
|
369
|
+
#t.gather(:node).each do |nt|
|
370
|
+
t.gather(:line).each do |lt|
|
371
|
+
nt = lt.lookup(:node); next unless nt
|
372
|
+
ot = lt.lookup(:outdent).string
|
373
|
+
n = Nod.new(nt, ot)
|
348
374
|
prev.append(n)
|
349
375
|
prev = n
|
350
376
|
end
|