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/lib/flor/pcore/apply.rb
CHANGED
@@ -1,29 +1,28 @@
|
|
1
|
-
#--
|
2
|
-
# Copyright (c) 2015-2017, John Mettraux, jmettraux+flor@gmail.com
|
3
|
-
#
|
4
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
|
-
# of this software and associated documentation files (the "Software"), to deal
|
6
|
-
# in the Software without restriction, including without limitation the rights
|
7
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
-
# copies of the Software, and to permit persons to whom the Software is
|
9
|
-
# furnished to do so, subject to the following conditions:
|
10
|
-
#
|
11
|
-
# The above copyright notice and this permission notice shall be included in
|
12
|
-
# all copies or substantial portions of the Software.
|
13
|
-
#
|
14
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
16
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
17
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
18
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
19
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
20
|
-
# THE SOFTWARE.
|
21
|
-
#
|
22
|
-
# Made in Japan.
|
23
|
-
#++
|
24
|
-
|
25
1
|
|
26
2
|
class Flor::Pro::Apply < Flor::Procedure
|
3
|
+
#
|
4
|
+
# Applies a function.
|
5
|
+
#
|
6
|
+
# ```
|
7
|
+
# sequence
|
8
|
+
# define sum a b
|
9
|
+
# +
|
10
|
+
# a
|
11
|
+
# b
|
12
|
+
# apply sum 1 2
|
13
|
+
# ```
|
14
|
+
#
|
15
|
+
# It is usually used implicitely, as in
|
16
|
+
# ```
|
17
|
+
# sequence
|
18
|
+
# define sum a b
|
19
|
+
# +
|
20
|
+
# a
|
21
|
+
# b
|
22
|
+
# sum 1 2
|
23
|
+
# ```
|
24
|
+
# where flor figures out by itself it has to use this "apply" procedure
|
25
|
+
# to call the function.
|
27
26
|
|
28
27
|
name 'apply'
|
29
28
|
|
data/lib/flor/pcore/case.rb
CHANGED
@@ -82,39 +82,37 @@ class Flor::Pro::Case < Flor::Procedure
|
|
82
82
|
# ot = tree; return if ot[1].size < 2
|
83
83
|
# t = Flor.dup(ot)
|
84
84
|
#
|
85
|
-
# nchildren = [
|
85
|
+
# nchildren = []
|
86
86
|
# mode = :array
|
87
87
|
#
|
88
|
-
# t[1][1..-1].each do |ct|
|
88
|
+
# #t[1][1..-1].each do |ct|
|
89
|
+
# non_att_children.each do |ct|
|
89
90
|
#
|
90
|
-
# if mode == :
|
91
|
+
# if nchildren.empty? || mode == :clause
|
92
|
+
# nchildren << ct
|
93
|
+
# mode = :array
|
94
|
+
# next
|
95
|
+
# end
|
91
96
|
#
|
92
|
-
#
|
93
|
-
# puts "---"
|
94
|
-
# dct0 = deref(ct[0])
|
95
|
-
# hct0 = toheap(ct, dct0)
|
96
|
-
# p dct0
|
97
|
-
# p hct0
|
98
|
-
# puts "/---"
|
99
|
-
# end
|
97
|
+
# ct0, ct1, ct2 = ct
|
100
98
|
#
|
101
|
-
#
|
102
|
-
#
|
103
|
-
#
|
104
|
-
#
|
105
|
-
#
|
106
|
-
#
|
107
|
-
#
|
108
|
-
# end
|
109
|
-
# else
|
110
|
-
# nchildren << ct
|
111
|
-
# mode = :clause
|
99
|
+
# if (Flor.is_tree?(ct0) || ct0 == 'else') && ct1.any?
|
100
|
+
# nchildren << (ct0 == 'else' ? [ 'else', [], ct2 ] : ct0)
|
101
|
+
# if ct1.size == 1
|
102
|
+
# nchildren << ct1.first
|
103
|
+
# else # ct1.size > 1
|
104
|
+
# sequence = [ 'sequence', ct1, ct1.first[2] ]
|
105
|
+
# nchildren << sequence
|
112
106
|
# end
|
113
|
-
#
|
114
|
-
#
|
115
|
-
#
|
107
|
+
# #elsif ct0.is_a?(String) && ct1.is_a?(Array) && ct1.any?
|
108
|
+
# # p ct
|
109
|
+
# # dct0 = deref(ct0)
|
110
|
+
# # hct0 = reheap(ct, dct0)
|
111
|
+
# # p dct0
|
112
|
+
# # p hct0
|
113
|
+
# else
|
116
114
|
# nchildren << ct
|
117
|
-
# mode = :
|
115
|
+
# mode = :clause
|
118
116
|
# end
|
119
117
|
# end
|
120
118
|
#
|
data/lib/flor/pcore/fail.rb
CHANGED
@@ -1,5 +1,15 @@
|
|
1
1
|
|
2
2
|
class Flor::Pro::Fail < Flor::Procedure
|
3
|
+
#
|
4
|
+
# Explicitely raises an error.
|
5
|
+
#
|
6
|
+
# ```
|
7
|
+
# fail "not enough water in the tank"
|
8
|
+
# # or
|
9
|
+
# error "not enough water in the tank"
|
10
|
+
# ```
|
11
|
+
#
|
12
|
+
# (I prefer "fail" because it's a verb over "error", pick the one you like)
|
3
13
|
|
4
14
|
names 'fail', 'error'
|
5
15
|
|
data/lib/flor/pcore/if.rb
CHANGED
@@ -2,10 +2,45 @@
|
|
2
2
|
class Flor::Pro::If < Flor::Procedure
|
3
3
|
#
|
4
4
|
# The classical "if" (and its "unless" sidequick)
|
5
|
+
#
|
6
|
+
# ```
|
7
|
+
# if
|
8
|
+
# > f.age 3
|
9
|
+
# set f.designation 'child' # then
|
10
|
+
# set f.designation 'baby' # else
|
11
|
+
#
|
12
|
+
# if (f.age > 3)
|
13
|
+
# sequence # then
|
14
|
+
# set f.designation 'child'
|
15
|
+
# sequence # else
|
16
|
+
# set f.designation 'baby'
|
17
|
+
# order_baby_food
|
18
|
+
# ```
|
19
|
+
#
|
20
|
+
# Warning, the direct children are relevant. In the following snip,
|
21
|
+
# `order_child_seat` is considered the "else" part of the `if`
|
22
|
+
# ```
|
23
|
+
# if (f.age > 3)
|
24
|
+
# set f.designation 'child'
|
25
|
+
# order_child_seat
|
26
|
+
# ```
|
27
|
+
#
|
28
|
+
# ## postfix `if` and `unless`
|
29
|
+
#
|
30
|
+
# The flor parser will automatically turn
|
31
|
+
# ```
|
32
|
+
# task 'bob' if a > b
|
33
|
+
# ```
|
34
|
+
# into the syntax tree that would result from
|
35
|
+
# ```
|
36
|
+
# if
|
37
|
+
# a > b
|
38
|
+
# task 'bob'
|
39
|
+
# ```
|
5
40
|
|
6
41
|
names %w[ if unless ife unlesse ]
|
7
42
|
#
|
8
|
-
# removing "ife" and "unlesse"
|
43
|
+
# removing "ife" and "unlesse" leads to
|
9
44
|
# LoadError: cannot load such file -- sequel/adapters/
|
10
45
|
# when running spec/unit/ and spec/punit/
|
11
46
|
# weird...
|
@@ -0,0 +1,32 @@
|
|
1
|
+
|
2
|
+
class Flor::Pro::Twig < Flor::Procedure
|
3
|
+
|
4
|
+
name 'twig'
|
5
|
+
|
6
|
+
def pre_execute
|
7
|
+
|
8
|
+
unatt_unkeyed_children
|
9
|
+
stringify_first_child
|
10
|
+
end
|
11
|
+
|
12
|
+
def receive_first
|
13
|
+
|
14
|
+
nac = non_att_children
|
15
|
+
|
16
|
+
if nac.size == 1
|
17
|
+
reply('ret' => nac.first)
|
18
|
+
else
|
19
|
+
super
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def receive_non_att
|
24
|
+
|
25
|
+
t = non_att_children.last
|
26
|
+
|
27
|
+
set_value(payload['ret'], t)
|
28
|
+
|
29
|
+
reply
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
data/lib/flor/pcore/val.rb
CHANGED
data/lib/flor/punit/graft.rb
CHANGED
@@ -1,5 +1,43 @@
|
|
1
1
|
|
2
2
|
class Flor::Pro::Graft < Flor::Procedure
|
3
|
+
#
|
4
|
+
# Graft a subtree into the current flo
|
5
|
+
#
|
6
|
+
# Given
|
7
|
+
# ```
|
8
|
+
# # sub0.flo
|
9
|
+
# sequence
|
10
|
+
# task 'a'
|
11
|
+
# task 'b'
|
12
|
+
# ```
|
13
|
+
# and
|
14
|
+
# ```
|
15
|
+
# # sub1.flo
|
16
|
+
# sequence
|
17
|
+
# task 'c'
|
18
|
+
# task 'd'
|
19
|
+
# ```
|
20
|
+
# then
|
21
|
+
# ```
|
22
|
+
# # main.flo
|
23
|
+
# concurrence
|
24
|
+
# graft 'sub0.flo'
|
25
|
+
# graft 'sub1' # suffix can be omitted
|
26
|
+
# graft 'sub0'
|
27
|
+
# #
|
28
|
+
# # which is thus equivalent to
|
29
|
+
# #
|
30
|
+
# concurrence
|
31
|
+
# sequence
|
32
|
+
# task 'a'
|
33
|
+
# task 'b'
|
34
|
+
# sequence
|
35
|
+
# task 'c'
|
36
|
+
# task 'd'
|
37
|
+
# sequence
|
38
|
+
# task 'a'
|
39
|
+
# task 'b'
|
40
|
+
# ```
|
3
41
|
|
4
42
|
names 'graft', 'import'
|
5
43
|
|
@@ -14,7 +52,7 @@ class Flor::Pro::Graft < Flor::Procedure
|
|
14
52
|
# look up subtree
|
15
53
|
|
16
54
|
sub =
|
17
|
-
att('tree', 'subtree', 'flow', 'subflow', nil)
|
55
|
+
att('tree', 'subtree', 'flow', 'subflow', 'twig', nil)
|
18
56
|
source_path, source =
|
19
57
|
@executor.unit.loader.library(domain, sub, subflows: true)
|
20
58
|
|
data/lib/flor/unit.rb
CHANGED
@@ -5,7 +5,9 @@ require 'sequel/extensions/migration'
|
|
5
5
|
require 'fugit'
|
6
6
|
|
7
7
|
require 'flor'
|
8
|
+
require 'flor/unit/hook'
|
8
9
|
require 'flor/unit/hooker'
|
10
|
+
require 'flor/unit/runner'
|
9
11
|
require 'flor/unit/wlist'
|
10
12
|
require 'flor/unit/logger'
|
11
13
|
require 'flor/unit/journal'
|
@@ -16,6 +18,7 @@ require 'flor/unit/scheduler'
|
|
16
18
|
require 'flor/unit/models'
|
17
19
|
require 'flor/unit/loader'
|
18
20
|
require 'flor/unit/ganger'
|
21
|
+
require 'flor/unit/spooler'
|
19
22
|
require 'flor/unit/taskers'
|
20
23
|
|
21
24
|
Flor.load_procedures('punit')
|
data/lib/flor/unit/executor.rb
CHANGED
data/lib/flor/unit/ganger.rb
CHANGED
@@ -42,26 +42,26 @@ module Flor
|
|
42
42
|
"tasker #{tname.inspect} not found"
|
43
43
|
) unless tconf
|
44
44
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
45
|
+
if tconf.is_a?(Array)
|
46
|
+
tconf =
|
47
|
+
tconf.find { |h| h['point'] == message['point'] } ||
|
48
|
+
tconf.find { |h| h['point'] == nil }
|
49
|
+
tconf ||=
|
50
|
+
tconf.find { |h| h['point'] == 'cancel' } \
|
51
|
+
if message['point'] == 'detask'
|
52
|
+
end
|
51
53
|
|
52
|
-
|
53
|
-
return cmd_task(message, tconf) if cot['cmd']
|
54
|
+
message['tconf'] = tconf unless tconf['include_tconf'] == false
|
54
55
|
|
55
|
-
|
56
|
-
"don't know how to use tasker at #{tconf['_path']}"
|
57
|
-
)
|
58
|
-
end
|
59
|
-
|
60
|
-
def cancel(tasker_name, fei)
|
56
|
+
message['vars'] = gather_vars(executor, tconf, message)
|
61
57
|
|
62
|
-
|
58
|
+
r = @unit.runner.run(self, tconf, message)
|
63
59
|
|
64
|
-
|
60
|
+
if is_a_message_array?(r)
|
61
|
+
r
|
62
|
+
else
|
63
|
+
[]
|
64
|
+
end
|
65
65
|
end
|
66
66
|
|
67
67
|
def return(message)
|
@@ -78,53 +78,6 @@ module Flor
|
|
78
78
|
o.first['point'].is_a?(String)
|
79
79
|
end
|
80
80
|
|
81
|
-
def ruby_task(message, tconf)
|
82
|
-
|
83
|
-
root = File.dirname(tconf['_path'])
|
84
|
-
|
85
|
-
Array(tconf['on_task']['require'])
|
86
|
-
.each { |pa|
|
87
|
-
fail ArgumentError.new('".." not allowed in paths') if pa =~ /\.\./
|
88
|
-
require(File.join(root, pa)) }
|
89
|
-
Array(tconf['on_task']['load'])
|
90
|
-
.each { |pa|
|
91
|
-
fail ArgumentError.new('".." not allowed in paths') if pa =~ /\.\./
|
92
|
-
load(File.join(root, pa)) }
|
93
|
-
|
94
|
-
k = tconf['on_task']['class']
|
95
|
-
k = Flor.const_lookup(k)
|
96
|
-
|
97
|
-
ka = k.instance_method(:initialize).arity
|
98
|
-
|
99
|
-
m =
|
100
|
-
message['point'] == 'detask' ?
|
101
|
-
:cancel :
|
102
|
-
:task
|
103
|
-
|
104
|
-
r =
|
105
|
-
if ka == 2
|
106
|
-
k.new(self, tconf).send(m, message)
|
107
|
-
else # ka == 3
|
108
|
-
k.new(self, tconf, message).send(m)
|
109
|
-
end
|
110
|
-
|
111
|
-
# if the tasker returns something intelligible, use it
|
112
|
-
# else reply with "nothing further to do" (empty message array)
|
113
|
-
|
114
|
-
if is_a_message_array?(r)
|
115
|
-
r
|
116
|
-
else
|
117
|
-
[]
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
def cmd_task(message, tconf)
|
122
|
-
|
123
|
-
fail NotImplementedError
|
124
|
-
|
125
|
-
[]
|
126
|
-
end
|
127
|
-
|
128
81
|
def var_match(k, filter)
|
129
82
|
|
130
83
|
filter.each { |f| return true if (f.is_a?(String) ? k == f : f.match(k)) }
|
@@ -155,17 +108,15 @@ module Flor
|
|
155
108
|
|
156
109
|
def gather_vars(executor, tconf, message)
|
157
110
|
|
158
|
-
ot = tconf['on_task']
|
159
|
-
|
160
111
|
# try to return before calling executor.vars(nid) which my be costly...
|
161
112
|
|
162
|
-
return nil if (
|
113
|
+
return nil if (tconf.keys & %w[ include_vars exclude_vars ]).empty?
|
163
114
|
# default behaviour, don't pass variables to taskers
|
164
115
|
|
165
|
-
iv = expand_filter(
|
116
|
+
iv = expand_filter(tconf['include_vars'])
|
166
117
|
return nil if iv == false
|
167
118
|
|
168
|
-
ev = expand_filter(
|
119
|
+
ev = expand_filter(tconf['exclude_vars'])
|
169
120
|
return {} if ev == true
|
170
121
|
|
171
122
|
vars = executor.vars(message['nid'])
|
@@ -0,0 +1,32 @@
|
|
1
|
+
|
2
|
+
module Flor
|
3
|
+
|
4
|
+
class Hook
|
5
|
+
|
6
|
+
def initialize(unit, exid, h)
|
7
|
+
|
8
|
+
@unit = unit
|
9
|
+
@exid = exid
|
10
|
+
@h = h
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_hook
|
14
|
+
|
15
|
+
opts = {}
|
16
|
+
opts[:consumed] = @h['consumed']
|
17
|
+
opts[:point] = Flor.h_fetch_a(@h, 'points', 'point', nil)
|
18
|
+
opts[:heap] = Flor.h_fetch_a(@h, 'heaps', 'heap', nil)
|
19
|
+
opts[:heat] = Flor.h_fetch_a(@h, 'heats', 'heat', nil)
|
20
|
+
#opts[:name] = data['names']
|
21
|
+
|
22
|
+
[ "hook#{object_id}", opts, self, nil ]
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
def notify(executor, message)
|
27
|
+
|
28
|
+
@unit.runner.run(executor, @h, message)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|