flor 0.10.0 → 0.11.0
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/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
|