flor 0.14.0 → 0.15.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +9 -0
- data/CREDITS.md +21 -0
- data/LICENSE.txt +4 -1
- data/Makefile +4 -0
- data/README.md +8 -0
- data/flor.gemspec +10 -10
- data/lib/flor.rb +2 -2
- data/lib/flor/changes.rb +3 -3
- data/lib/flor/colours.rb +14 -8
- data/lib/flor/conf.rb +63 -58
- data/lib/flor/core.rb +4 -4
- data/lib/flor/core/executor.rb +65 -29
- data/lib/flor/core/node.rb +37 -20
- data/lib/flor/core/procedure.rb +182 -40
- data/lib/flor/core/texecutor.rb +125 -52
- data/lib/flor/djan.rb +111 -82
- data/lib/flor/dollar.rb +31 -30
- data/lib/flor/flor.rb +314 -237
- data/lib/flor/id.rb +7 -2
- data/lib/flor/log.rb +250 -245
- data/lib/flor/parser.rb +72 -38
- data/lib/flor/pcore/_arr.rb +10 -10
- data/lib/flor/pcore/_att.rb +49 -14
- data/lib/flor/pcore/_coll.rb +18 -0
- data/lib/flor/pcore/_obj.rb +23 -7
- data/lib/flor/pcore/_pat_.rb +1 -1
- data/lib/flor/pcore/_pat_guard.rb +8 -0
- data/lib/flor/pcore/_pat_obj.rb +3 -3
- data/lib/flor/pcore/_pat_or.rb +4 -0
- data/lib/flor/pcore/_pat_regex.rb +24 -0
- data/lib/flor/pcore/_skip.rb +4 -0
- data/lib/flor/pcore/_val.rb +0 -1
- data/lib/flor/pcore/all.rb +111 -0
- data/lib/flor/pcore/any.rb +83 -0
- data/lib/flor/pcore/arith.rb +35 -6
- data/lib/flor/pcore/break.rb +39 -1
- data/lib/flor/pcore/case.rb +82 -4
- data/lib/flor/pcore/cmp.rb +7 -7
- data/lib/flor/pcore/collect.rb +50 -0
- data/lib/flor/pcore/cond.rb +17 -3
- data/lib/flor/pcore/cursor.rb +8 -2
- data/lib/flor/pcore/detect.rb +45 -0
- data/lib/flor/pcore/each.rb +52 -0
- data/lib/flor/pcore/empty.rb +60 -0
- data/lib/flor/pcore/filter.rb +94 -0
- data/lib/flor/pcore/find.rb +67 -0
- data/lib/flor/pcore/for_each.rb +65 -0
- data/lib/flor/pcore/includes.rb +32 -0
- data/lib/flor/pcore/inject.rb +55 -0
- data/lib/flor/pcore/iterator.rb +151 -0
- data/lib/flor/pcore/keys.rb +60 -0
- data/lib/flor/pcore/length.rb +34 -7
- data/lib/flor/pcore/logo.rb +18 -0
- data/lib/flor/pcore/loop.rb +4 -0
- data/lib/flor/pcore/map.rb +77 -46
- data/lib/flor/pcore/match.rb +8 -2
- data/lib/flor/pcore/matchr.rb +4 -5
- data/lib/flor/pcore/move.rb +3 -3
- data/lib/flor/pcore/noeval.rb +13 -0
- data/lib/flor/pcore/not.rb +16 -0
- data/lib/flor/pcore/on.rb +172 -0
- data/lib/flor/pcore/on_cancel.rb +54 -0
- data/lib/flor/pcore/on_error.rb +68 -0
- data/lib/flor/pcore/rand.rb +2 -2
- data/lib/flor/pcore/range.rb +2 -1
- data/lib/flor/pcore/reduce.rb +124 -0
- data/lib/flor/pcore/reverse.rb +46 -0
- data/lib/flor/pcore/select.rb +72 -0
- data/lib/flor/pcore/set.rb +8 -0
- data/lib/flor/pcore/stall.rb +10 -0
- data/lib/flor/pcore/to_array.rb +61 -0
- data/lib/flor/pcore/until.rb +34 -0
- data/lib/flor/punit/cancel.rb +30 -5
- data/lib/flor/punit/ccollect.rb +11 -0
- data/lib/flor/punit/cmap.rb +10 -5
- data/lib/flor/punit/concurrence.rb +42 -51
- data/lib/flor/punit/cron.rb +33 -0
- data/lib/flor/punit/do_trap.rb +42 -0
- data/lib/flor/punit/every.rb +48 -13
- data/lib/flor/punit/graft.rb +3 -3
- data/lib/flor/punit/on_timeout.rb +38 -0
- data/lib/flor/punit/schedule.rb +69 -6
- data/lib/flor/punit/signal.rb +54 -0
- data/lib/flor/punit/sleep.rb +1 -1
- data/lib/flor/punit/task.rb +4 -1
- data/lib/flor/punit/trap.rb +188 -13
- data/lib/flor/tools/shell.rb +408 -62
- data/lib/flor/tools/shell_out.rb +31 -0
- data/lib/flor/unit.rb +1 -1
- data/lib/flor/unit/caller.rb +177 -0
- data/lib/flor/unit/executor.rb +1 -0
- data/lib/flor/unit/ganger.rb +15 -21
- data/lib/flor/unit/hook.rb +1 -1
- data/lib/flor/unit/hooker.rb +22 -10
- data/lib/flor/unit/loader.rb +22 -22
- data/lib/flor/unit/logger.rb +63 -36
- data/lib/flor/unit/models.rb +6 -1
- data/lib/flor/unit/models/execution.rb +12 -1
- data/lib/flor/unit/models/message.rb +7 -0
- data/lib/flor/unit/models/trap.rb +31 -17
- data/lib/flor/unit/scheduler.rb +18 -10
- data/lib/flor/unit/storage.rb +83 -23
- data/lib/flor/unit/waiter.rb +1 -2
- metadata +96 -52
- data/lib/flor/deep.rb +0 -144
- data/lib/flor/punit/on.rb +0 -57
- data/lib/flor/unit/runner.rb +0 -84
- data/match.md +0 -22
data/lib/flor/punit/signal.rb
CHANGED
@@ -1,5 +1,59 @@
|
|
1
1
|
|
2
2
|
class Flor::Pro::Signal < Flor::Procedure
|
3
|
+
#
|
4
|
+
# Used in conjuction with "on".
|
5
|
+
#
|
6
|
+
# An external (or internal) agent may send a signal to an execution and the
|
7
|
+
# execution may have a "on" handler for it.
|
8
|
+
#
|
9
|
+
# For example, imagine an execution with a sub part that checks every day
|
10
|
+
# at noon and closes cases that are over a certain date:
|
11
|
+
#
|
12
|
+
# ```
|
13
|
+
# on 'close'
|
14
|
+
# # close the case and then cancel main part...
|
15
|
+
# cancel ref: 'main'
|
16
|
+
#
|
17
|
+
# every 'day at noon'
|
18
|
+
# signal 'close' if f.date_to < today
|
19
|
+
#
|
20
|
+
# sequence tag: 'main'
|
21
|
+
# # main part ...
|
22
|
+
# ```
|
23
|
+
#
|
24
|
+
# The "every day at noon" sub part could be replaced by a signal emitted by
|
25
|
+
# a Ruby script triggered by a cron daemon, thus going from internal agent
|
26
|
+
# to external agent.
|
27
|
+
#
|
28
|
+
# The `Flor::Unit` class has a `#signal` method handy for that:
|
29
|
+
# ```ruby
|
30
|
+
# flor_unit.signal('close', exid: execution_id)
|
31
|
+
# ```
|
32
|
+
# It accepts `exid:` and `payload:` messages.
|
33
|
+
#
|
34
|
+
# ## signal payloads
|
35
|
+
#
|
36
|
+
# The payload at the point of signalling is transmitted over to the
|
37
|
+
# receiving "on" or "trap".
|
38
|
+
#
|
39
|
+
# ```
|
40
|
+
# set f.a 'A'
|
41
|
+
# signal 'close'
|
42
|
+
# set f.b 'B'
|
43
|
+
# [ 0 1 2 ]
|
44
|
+
# set f.c 'C'
|
45
|
+
# ```
|
46
|
+
# passes `{ 'ret' => [ 0, 1, 2 ], 'a' => 'A', 'b' => 'B' }` as payload
|
47
|
+
# to any intercepting "on" or "trap" (`c` is not passed).
|
48
|
+
#
|
49
|
+
# Externally, you can signal with a specific payload thanks to:
|
50
|
+
# ```ruby
|
51
|
+
# flor_unit.signal('close', exid: execution_id, payload: { 'f0' => 'zero' })
|
52
|
+
# ```
|
53
|
+
#
|
54
|
+
# ## see also
|
55
|
+
#
|
56
|
+
# On and trap.
|
3
57
|
|
4
58
|
name 'signal'
|
5
59
|
|
data/lib/flor/punit/sleep.rb
CHANGED
@@ -19,7 +19,7 @@ class Flor::Pro::Sleep < Flor::Procedure
|
|
19
19
|
def receive_last
|
20
20
|
|
21
21
|
t = att('for', nil)
|
22
|
-
fail
|
22
|
+
fail Flor::FlorError.new("missing a sleep time duration", self) unless t
|
23
23
|
|
24
24
|
m = wrap('point' => 'receive').first
|
25
25
|
|
data/lib/flor/punit/task.rb
CHANGED
@@ -43,11 +43,11 @@ class Flor::Pro::Task < Flor::Procedure
|
|
43
43
|
wrap(
|
44
44
|
'point' => 'task',
|
45
45
|
'exid' => exid, 'nid' => nid,
|
46
|
+
'tags' => list_tags,
|
46
47
|
'tasker' => tasker,
|
47
48
|
'taskname' => taskname,
|
48
49
|
'attl' => attl, 'attd' => attd,
|
49
50
|
'payload' => determine_payload)
|
50
|
-
#.tap { |x| pp x.first }
|
51
51
|
end
|
52
52
|
|
53
53
|
def cancel
|
@@ -59,6 +59,7 @@ class Flor::Pro::Task < Flor::Procedure
|
|
59
59
|
wrap(
|
60
60
|
'point' => 'detask',
|
61
61
|
'exid' => exid, 'nid' => nid,
|
62
|
+
'tags' => list_tags,
|
62
63
|
'tasker' => att(nil),
|
63
64
|
'attl' => attl, 'attd' => attd,
|
64
65
|
'payload' => determine_payload)
|
@@ -66,6 +67,8 @@ class Flor::Pro::Task < Flor::Procedure
|
|
66
67
|
|
67
68
|
protected
|
68
69
|
|
70
|
+
# Returns an array attribute list / attribute dictionary.
|
71
|
+
#
|
69
72
|
def determine_atts
|
70
73
|
|
71
74
|
attl, attd = [], {}
|
data/lib/flor/punit/trap.rb
CHANGED
@@ -1,17 +1,186 @@
|
|
1
1
|
|
2
|
-
#
|
3
|
-
|
4
|
-
# ## range:/scope:
|
5
|
-
# * subnid (default)
|
6
|
-
# * execution/exe
|
7
|
-
# * domain
|
8
|
-
# * subdomain
|
9
|
-
#
|
10
|
-
# ## bind:
|
11
|
-
# * parent (default)
|
12
|
-
# * root
|
13
|
-
#
|
2
|
+
# Would it be worth the pain implementing bind:?
|
3
|
+
|
14
4
|
class Flor::Pro::Trap < Flor::Procedure
|
5
|
+
#
|
6
|
+
# Watches the messages emitted in the execution and reacts when
|
7
|
+
# a message matches certain criteria.
|
8
|
+
#
|
9
|
+
# Once the trap is set (once the execution interprets its branch), it
|
10
|
+
# will trigger for any matching message, unless the `count:` attribute
|
11
|
+
# is set.
|
12
|
+
#
|
13
|
+
# When the execution terminates, the trap is removed as well.
|
14
|
+
#
|
15
|
+
# By default, the observation range is the execution, only messages
|
16
|
+
# in the execution where the trap was set are considered.
|
17
|
+
# The trap can be extended via the `range:` attribute.
|
18
|
+
#
|
19
|
+
# "trap" triggers a function, while "on" triggers a block.
|
20
|
+
#
|
21
|
+
# ## the point: criterion
|
22
|
+
#
|
23
|
+
# The simplest thing to trap is a 'point'. Here, the trap is set for
|
24
|
+
# any message whose point is 'terminated':
|
25
|
+
# ```
|
26
|
+
# sequence
|
27
|
+
# trap 'terminated'
|
28
|
+
# def msg \ trace "terminated(f:$(msg.from))"
|
29
|
+
# trace "here($(nid))"
|
30
|
+
# # OR
|
31
|
+
# #sequence
|
32
|
+
# # trap 'terminated'
|
33
|
+
# # def msg \ trace "terminated(f:$(msg.from))"
|
34
|
+
# # trace "here($(nid))"
|
35
|
+
# ```
|
36
|
+
#
|
37
|
+
# ## the heap: criterion
|
38
|
+
#
|
39
|
+
# Given a procedure like `sequence`, `concurrence` or `apply`, trigger
|
40
|
+
# a piece of code each time the procedure receives the "execute" or the
|
41
|
+
# "receive" message.
|
42
|
+
#
|
43
|
+
# ```
|
44
|
+
# trap heap: 'sequence'
|
45
|
+
# def msg
|
46
|
+
# trace "$(msg.point)-$(msg.tree.0)-$(msg.nid)<-$(msg.from)"
|
47
|
+
# sequence
|
48
|
+
# noret _
|
49
|
+
# #
|
50
|
+
# # will trace:
|
51
|
+
# # 0:execute-sequence-0_1<-0
|
52
|
+
# # 1:receive--0_1<-0_1_0
|
53
|
+
# # 2:receive--0<-0_1
|
54
|
+
# ```
|
55
|
+
#
|
56
|
+
# ## the heat: criterion
|
57
|
+
#
|
58
|
+
# While `heap:` filters on the actual flor procedure names, `heat:` is
|
59
|
+
# looser, it catches whatever stands "at the beginning of the flor line".
|
60
|
+
# It's useful to catch function calls.
|
61
|
+
#
|
62
|
+
# ```
|
63
|
+
# trap heat: 'fun0'
|
64
|
+
# def msg
|
65
|
+
# trace "t-$(msg.tree.0)-$(msg.nid)"
|
66
|
+
# define fun0
|
67
|
+
# trace "c-fun0-$(nid)"
|
68
|
+
# sequence
|
69
|
+
# fun0 _
|
70
|
+
# fun0 # not a call
|
71
|
+
#
|
72
|
+
# # will trace:
|
73
|
+
# # 0:t-fun0-0_2_0
|
74
|
+
# # 1:c-fun0-0_1_1_0_0-2
|
75
|
+
# # 2:t--0_2_0
|
76
|
+
# # 3:t--0_2_0
|
77
|
+
# # 4:t-fun0-0_2_1
|
78
|
+
# ```
|
79
|
+
#
|
80
|
+
# `heat:` accepts strings or regular expressions:
|
81
|
+
#
|
82
|
+
# ```
|
83
|
+
# trap heat: [ /^fun\d+$/ 'funx' ]
|
84
|
+
# def msg \ trace "t-$(msg.tree.0)-$(msg.nid)"
|
85
|
+
# ```
|
86
|
+
#
|
87
|
+
# ## the tag: criterion
|
88
|
+
#
|
89
|
+
# Traps one or multiple tags. Default to trapping on "entered". May trap
|
90
|
+
# leaving tags with `point: 'left'` or any with
|
91
|
+
# `point: [ 'entered', 'left' ]`.
|
92
|
+
#
|
93
|
+
# ```
|
94
|
+
# trap tag: 'x'
|
95
|
+
# def msg
|
96
|
+
# trace "$(msg.tags.-1)-$(msg.point)"
|
97
|
+
# # ...
|
98
|
+
# sequence tag: 'x'
|
99
|
+
# trace 'c'
|
100
|
+
#
|
101
|
+
# # will trace "x-entered" and "c"
|
102
|
+
# ```
|
103
|
+
#
|
104
|
+
# ## the signal: criterion
|
105
|
+
#
|
106
|
+
# `signal:` traps signals directed at the execution. Signals are
|
107
|
+
# directly
|
108
|
+
# ```
|
109
|
+
# trap signal: 'S0'
|
110
|
+
# def msg
|
111
|
+
# trace "S0"
|
112
|
+
# # ...
|
113
|
+
# signal 'S0'
|
114
|
+
# ```
|
115
|
+
#
|
116
|
+
# Note that it's OK to trap all signals, whatever their name, directed at
|
117
|
+
# the execution by using `point: 'signal'`, as in:
|
118
|
+
# ```
|
119
|
+
# trap point: 'signal'
|
120
|
+
# def msg
|
121
|
+
# trace "caught signal '$(sig)'"
|
122
|
+
# ```
|
123
|
+
#
|
124
|
+
# [on](on.md) is a macro that turns
|
125
|
+
# ```
|
126
|
+
# on 'rejected'
|
127
|
+
# trace "execution received signal $(sig)"
|
128
|
+
# ```
|
129
|
+
# into
|
130
|
+
# ```
|
131
|
+
# trap signal: 'rejected'
|
132
|
+
# def msg
|
133
|
+
# trace "execution received signal $(sig)"
|
134
|
+
# ```
|
135
|
+
# Please note how "on" accepts a block while "trap" accepts a function.
|
136
|
+
#
|
137
|
+
# ## the range: limit
|
138
|
+
#
|
139
|
+
# The range limit determines what is the range, or scope of the trap.
|
140
|
+
# By default the trap only care about nodes below its parent. In other words,
|
141
|
+
# the trap binds itself to its parent and observes the messages occuring
|
142
|
+
# in the execution in the branch of nodes whose root is the parent.
|
143
|
+
#
|
144
|
+
# The possible values for `range:` are:
|
145
|
+
# * 'subnid' (default)
|
146
|
+
# * 'execution'
|
147
|
+
# * 'domain'
|
148
|
+
# * 'subdomain'
|
149
|
+
#
|
150
|
+
# With 'execution', the trap observes all the messages emitted within the
|
151
|
+
# same execution.
|
152
|
+
#
|
153
|
+
# With 'domain', all the messages in all the execution of the same domain are
|
154
|
+
# observed. For example,
|
155
|
+
# ```
|
156
|
+
# trap point: 'signal', domain: 'net.acme'
|
157
|
+
# def msg \ trace "signal '$(sig)' caught"
|
158
|
+
# ```
|
159
|
+
# once set, will be triggered for each signal received by an execution in the
|
160
|
+
# 'net.acme' domain.
|
161
|
+
#
|
162
|
+
# Likewise,
|
163
|
+
# ```
|
164
|
+
# trap point: 'signal', subdomain: 'org.acme'
|
165
|
+
# def msg \ trace "signal '$(sig)' caught"
|
166
|
+
# ```
|
167
|
+
# Will trap all signals in the domain "org.acme" and its subdomains,
|
168
|
+
# (org.acme.accounting, org.acme.engineering, org.acme.whatever.x.y.z, ...)
|
169
|
+
#
|
170
|
+
#
|
171
|
+
# ## the count: limit
|
172
|
+
#
|
173
|
+
# ```
|
174
|
+
# trap tag: 'x' count: 2
|
175
|
+
# # ...
|
176
|
+
# ```
|
177
|
+
# will trigger when the execution enters the tag 'x', but will trigger only
|
178
|
+
# twice.
|
179
|
+
#
|
180
|
+
#
|
181
|
+
# ## see also
|
182
|
+
#
|
183
|
+
# On and signal.
|
15
184
|
|
16
185
|
name 'trap'
|
17
186
|
|
@@ -40,9 +209,15 @@ class Flor::Pro::Trap < Flor::Procedure
|
|
40
209
|
points = att_a(nil, nil) unless points || tags
|
41
210
|
points = [ 'entered' ] if tags && ! points
|
42
211
|
|
212
|
+
att_a('sig', 'signal', 'signals', [])
|
213
|
+
.each { |sig| (points ||= []) << 'signal'; (names ||= []) << sig }
|
214
|
+
|
215
|
+
points = points.uniq if points
|
216
|
+
names = names.uniq if names
|
217
|
+
|
43
218
|
msg =
|
44
219
|
if fun
|
45
|
-
apply(fun, [], tree[2], false).first
|
220
|
+
apply(fun, [], tree[2], anid: false).first
|
46
221
|
else
|
47
222
|
wrap_reply.first
|
48
223
|
end
|
data/lib/flor/tools/shell.rb
CHANGED
@@ -1,8 +1,10 @@
|
|
1
1
|
|
2
|
+
require 'io/console'
|
2
3
|
require 'terminal-table'
|
3
4
|
|
4
5
|
require 'flor'
|
5
6
|
require 'flor/unit'
|
7
|
+
require 'flor/tools/shell_out'
|
6
8
|
|
7
9
|
|
8
10
|
module Flor::Tools
|
@@ -25,6 +27,8 @@ module Flor::Tools
|
|
25
27
|
prepare_hooks
|
26
28
|
|
27
29
|
@hook = 'on'
|
30
|
+
@mute = false
|
31
|
+
@paging = true
|
28
32
|
|
29
33
|
@unit.start
|
30
34
|
|
@@ -35,7 +39,9 @@ module Flor::Tools
|
|
35
39
|
|
36
40
|
@c = Flor.colours({})
|
37
41
|
|
38
|
-
|
42
|
+
load_floshrc
|
43
|
+
|
44
|
+
if argv && argv.any?
|
39
45
|
do_eval(argv.join(' '))
|
40
46
|
else
|
41
47
|
print_header
|
@@ -47,6 +53,11 @@ module Flor::Tools
|
|
47
53
|
|
48
54
|
protected
|
49
55
|
|
56
|
+
def parse_single_json_value(s)
|
57
|
+
|
58
|
+
Flor::ConfExecutor.interpret_line(s) rescue nil
|
59
|
+
end
|
60
|
+
|
50
61
|
def prepare_home
|
51
62
|
|
52
63
|
home = File.join(@root, 'home')
|
@@ -102,15 +113,35 @@ module Flor::Tools
|
|
102
113
|
end
|
103
114
|
end
|
104
115
|
|
116
|
+
def load_floshrc
|
117
|
+
|
118
|
+
@mute = true
|
119
|
+
|
120
|
+
[
|
121
|
+
File.join(@root, 'etc/floshrc'),
|
122
|
+
File.join(@root, 'home/.floshrc'),
|
123
|
+
'.floshrc'
|
124
|
+
].each { |f| (File.readlines(f) rescue []).each { |l| do_eval(l) } }
|
125
|
+
|
126
|
+
ensure
|
127
|
+
|
128
|
+
@mute = false
|
129
|
+
end
|
130
|
+
|
105
131
|
def print_header
|
106
132
|
|
107
|
-
|
133
|
+
git = (' ' + `git log -1`.lines.first.split.last[0, 7]) rescue ''
|
134
|
+
git = "#{@c.yellow}#{git}#{@c.reset}"
|
135
|
+
|
136
|
+
puts "flosh - a flor #{Flor::VERSION}#{git} shell"
|
108
137
|
end
|
109
138
|
|
110
139
|
def prompt
|
111
140
|
|
112
141
|
root = @c.dark_gray(@root + '/')
|
113
142
|
|
143
|
+
time = Time.now.strftime(' %H:%M:%S')
|
144
|
+
|
114
145
|
ec = @unit.executions.where(status: 'active').count
|
115
146
|
exes = ' ' + @c.yellow("ex#{ec}")
|
116
147
|
|
@@ -123,13 +154,13 @@ module Flor::Tools
|
|
123
154
|
end
|
124
155
|
tas = ta > 0 ? ' ' + @c.yellow("ta#{ta}") : ''
|
125
156
|
|
126
|
-
"#{root}#{exes}#{tis}#{tas} > "
|
157
|
+
"#{root}#{time}#{exes}#{tis}#{tas} > "
|
127
158
|
end
|
128
159
|
|
129
160
|
def do_eval(line)
|
130
161
|
|
131
|
-
line = line.
|
132
|
-
return if line
|
162
|
+
line = line.match(/\A([^#]*)(#.+)?\n*\z/)[1]
|
163
|
+
return if line == ''
|
133
164
|
|
134
165
|
md = line.split(/\s/).first
|
135
166
|
cmd = "cmd_#{md}".to_sym
|
@@ -155,7 +186,6 @@ module Flor::Tools
|
|
155
186
|
line = prompt_and_read
|
156
187
|
|
157
188
|
break unless line
|
158
|
-
next if line.strip == ''
|
159
189
|
|
160
190
|
do_eval(line)
|
161
191
|
end
|
@@ -166,15 +196,26 @@ module Flor::Tools
|
|
166
196
|
#
|
167
197
|
# command helpers
|
168
198
|
|
199
|
+
ALIASES = {}
|
200
|
+
|
169
201
|
def self.make_alias(a, b)
|
170
202
|
|
171
203
|
define_method("hlp_#{a}") { "alias to #{b.inspect}" }
|
172
204
|
alias_method "man_#{a}", "man_#{b}" rescue nil
|
173
205
|
alias_method "cmd_#{a}", "cmd_#{b}"
|
206
|
+
|
207
|
+
(ALIASES[b] ||= []) << a
|
174
208
|
end
|
175
209
|
|
176
|
-
def
|
177
|
-
|
210
|
+
def self.is_alias?(c)
|
211
|
+
|
212
|
+
!! ALIASES.values.find { |a| a.include?(c) }
|
213
|
+
end
|
214
|
+
|
215
|
+
def args(line); line.split(/\s+/); end
|
216
|
+
def argc(line); args(line).count; end
|
217
|
+
def arg(line, index=1); args(line)[index]; end
|
218
|
+
alias fname arg
|
178
219
|
|
179
220
|
def choose_path(line)
|
180
221
|
|
@@ -186,9 +227,19 @@ module Flor::Tools
|
|
186
227
|
when /\Ap/
|
187
228
|
@payload_path
|
188
229
|
when /\At/
|
230
|
+
fail ArgumentError.new("'frag' argument missing") unless b
|
189
231
|
Dir[File.join(@root, 'var/tasks/**/*.json')].find { |pa| pa.index(b) }
|
190
232
|
when /\Ar/
|
191
233
|
@ra_flow_path
|
234
|
+
when /\Ae/
|
235
|
+
exe = lookup_execution(b)
|
236
|
+
#p exe
|
237
|
+
#pp exe.data
|
238
|
+
#puts JSON.pretty_generate(exe.data)
|
239
|
+
#puts JSON.dump(exe.data)
|
240
|
+
#puts JSON.generate(exe.data, indent: ' ', space: ' ', object_nl: "\n", array_nl: "\n")
|
241
|
+
puts Flor.to_d(exe.data, width: true, colours: true)
|
242
|
+
fail NotImplementedError
|
192
243
|
else
|
193
244
|
@flow_path
|
194
245
|
end
|
@@ -232,19 +283,162 @@ module Flor::Tools
|
|
232
283
|
.find { |e| e.data['nodes'][nid] }
|
233
284
|
|
234
285
|
fail ArgumentError.new(
|
235
|
-
"found #{exes.count} execution#{exes.count
|
286
|
+
"found #{exes.count} execution#{exes.count != 1 ? 's' : ''} " +
|
236
287
|
"matching \"%#{exid}%\", but none with a #{onid.inspect} node"
|
237
288
|
) unless exe
|
238
289
|
|
239
290
|
[ exe.exid, nid ]
|
240
291
|
end
|
241
292
|
|
293
|
+
def print(o)
|
294
|
+
|
295
|
+
::Kernel.print(o) unless @mute
|
296
|
+
end
|
297
|
+
|
298
|
+
def puts(o)
|
299
|
+
|
300
|
+
::Kernel.puts(o) unless @mute
|
301
|
+
end
|
302
|
+
|
303
|
+
def page_puts(s)
|
304
|
+
::Kernel.puts s
|
305
|
+
end
|
306
|
+
def page_vi(s)
|
307
|
+
IO.popen(
|
308
|
+
@unit.conf['fls_vi'] || 'vi -',
|
309
|
+
mode: 'w'
|
310
|
+
) { |io| io.write(Flor.decolour(s)) }
|
311
|
+
end
|
312
|
+
def page_more(s)
|
313
|
+
IO.popen(
|
314
|
+
@unit.conf['fls_more'] || 'less -R -N',
|
315
|
+
mode: 'w'
|
316
|
+
) { |io| io.write(s) }
|
317
|
+
end
|
318
|
+
|
319
|
+
def page(o)
|
320
|
+
|
321
|
+
return if @mute
|
322
|
+
|
323
|
+
s = o.is_a?(String) ? o : o.string
|
324
|
+
|
325
|
+
if @paging == false
|
326
|
+
page_puts(s)
|
327
|
+
elsif @paging == :vi
|
328
|
+
page_vi(s)
|
329
|
+
elsif @paging == :more
|
330
|
+
page_more(s)
|
331
|
+
else
|
332
|
+
if s.lines.to_a.size > IO.console.winsize[0]
|
333
|
+
page_more(s)
|
334
|
+
else
|
335
|
+
page_puts(s)
|
336
|
+
end
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
242
340
|
#
|
243
341
|
# the commands
|
244
342
|
|
343
|
+
def hlp_paging
|
344
|
+
%{ sets the paging mode }
|
345
|
+
end
|
346
|
+
def man_paging
|
347
|
+
%{
|
348
|
+
* paging off
|
349
|
+
disable paging, command output will always be output to stdout
|
350
|
+
* paging on
|
351
|
+
enable paging, command output longer than terminal height will be paged
|
352
|
+
* paging vi|vim
|
353
|
+
always page into vim, whatever length, loses the colours
|
354
|
+
* paging more|less
|
355
|
+
always page into vim, whatever length, loses the colours
|
356
|
+
}
|
357
|
+
end
|
358
|
+
def cmd_paging(line)
|
359
|
+
|
360
|
+
@paging =
|
361
|
+
case arg(line)
|
362
|
+
when 'vi', 'vim' then :vi
|
363
|
+
when 'no', 'off', 'false' then false
|
364
|
+
when 'more', 'less' then :more
|
365
|
+
#when 'on', 'true' then true
|
366
|
+
else true
|
367
|
+
end
|
368
|
+
puts "paging set to #{@paging}"
|
369
|
+
end
|
370
|
+
|
371
|
+
def hlp_read
|
372
|
+
%{ reads (pages) a file }
|
373
|
+
end
|
374
|
+
def man_read
|
375
|
+
%{
|
376
|
+
* read filename
|
377
|
+
reads (pages) a file
|
378
|
+
}
|
379
|
+
end
|
380
|
+
def cmd_read(line)
|
381
|
+
page(File.read(arg(line)))
|
382
|
+
end
|
383
|
+
|
384
|
+
def hlp_page
|
385
|
+
%{ pages the output of the remainder of the command line }
|
386
|
+
end
|
387
|
+
def man_page
|
388
|
+
%{
|
389
|
+
* page filepath
|
390
|
+
reads the file and pages it
|
391
|
+
* page command arg0 arg1 ... argN
|
392
|
+
runs `command arg0 arg1 ... argN` and pages its output
|
393
|
+
}
|
394
|
+
end
|
395
|
+
def cmd_page(line, paging=:more)
|
396
|
+
|
397
|
+
current_paging = @paging
|
398
|
+
@paging = paging
|
399
|
+
|
400
|
+
line = line.strip.split(/\s+/, 2)[1]
|
401
|
+
|
402
|
+
if line.nil? || line.empty?
|
403
|
+
do_eval('man page')
|
404
|
+
elsif File.exist?(line) && ! File.directory?(line)
|
405
|
+
page(File.read(line))
|
406
|
+
else
|
407
|
+
do_eval(line)
|
408
|
+
end
|
409
|
+
|
410
|
+
ensure
|
411
|
+
|
412
|
+
@paging = current_paging
|
413
|
+
end
|
414
|
+
|
415
|
+
def hlp_vi
|
416
|
+
%{ runs the remainder of the command line and then edit output in vi }
|
417
|
+
end
|
418
|
+
def man_vi
|
419
|
+
%{
|
420
|
+
* vi filepath
|
421
|
+
reads the file and edits it
|
422
|
+
* vi command arg0 arg1 ... argN
|
423
|
+
runs `command arg0 arg1 ... argN` and opens its output with vi
|
424
|
+
}
|
425
|
+
end
|
426
|
+
def cmd_vi(line)
|
427
|
+
cmd_page(line, :vi)
|
428
|
+
end
|
429
|
+
make_alias('vim', 'vi')
|
430
|
+
|
245
431
|
def hlp_launch
|
246
432
|
%{ launches a new execution of #{@flow_path} }
|
247
433
|
end
|
434
|
+
def man_launch
|
435
|
+
%{
|
436
|
+
* launch
|
437
|
+
launches an execution of the current flow
|
438
|
+
* launch k0: v0, k1: v1, ...
|
439
|
+
launches an execution with the given variables
|
440
|
+
}
|
441
|
+
end
|
248
442
|
def cmd_launch(line)
|
249
443
|
|
250
444
|
flow = File.read(@flow_path)
|
@@ -252,6 +446,9 @@ module Flor::Tools
|
|
252
446
|
payload = Flor::ConfExecutor.interpret(@payload_path)
|
253
447
|
domain = 'shell'
|
254
448
|
|
449
|
+
vars = Flor::ConfExecutor.interpret_line("\n" + line[6..-1]) rescue {}
|
450
|
+
variables.merge!(vars)
|
451
|
+
|
255
452
|
exid = @unit.launch(
|
256
453
|
flow, domain: domain, vars: variables, payload: payload)
|
257
454
|
|
@@ -271,13 +468,16 @@ module Flor::Tools
|
|
271
468
|
end
|
272
469
|
def cmd_help(line)
|
273
470
|
|
471
|
+
o = StringIO.new
|
472
|
+
|
274
473
|
if cmd = arg(line)
|
474
|
+
|
275
475
|
begin
|
276
476
|
send("man_#{cmd}").split("\n").collect(&:strip).each do |l|
|
277
477
|
if l[0, 1] == '*'
|
278
|
-
puts " #{@c.dg}*#{@c.rs} #{l[1..-1].strip}"
|
478
|
+
o.puts " #{@c.dg}*#{@c.rs} #{l[1..-1].strip}"
|
279
479
|
else
|
280
|
-
puts " #{@c.dark_gray(l)}"
|
480
|
+
o.puts " #{@c.dark_gray(l)}"
|
281
481
|
end
|
282
482
|
end
|
283
483
|
rescue => err
|
@@ -286,16 +486,20 @@ module Flor::Tools
|
|
286
486
|
|
287
487
|
else
|
288
488
|
|
289
|
-
puts
|
290
|
-
puts "## available commands:"
|
291
|
-
puts
|
489
|
+
o.puts
|
490
|
+
o.puts "## available commands:"
|
491
|
+
o.puts
|
292
492
|
COMMANDS.each do |cmd|
|
293
|
-
print "* #{@c.yellow(cmd)}"
|
294
|
-
if hlp = (send("hlp_#{cmd}") rescue nil)
|
295
|
-
|
493
|
+
o.print "* #{@c.yellow(cmd)}"
|
494
|
+
if hlp = (send("hlp_#{cmd}") rescue nil)
|
495
|
+
o.print " - #{hlp.strip}"
|
496
|
+
end
|
497
|
+
o.puts
|
296
498
|
end
|
297
|
-
puts
|
499
|
+
o.puts
|
298
500
|
end
|
501
|
+
|
502
|
+
page(o)
|
299
503
|
end
|
300
504
|
make_alias('h', 'help')
|
301
505
|
make_alias('man', 'help')
|
@@ -324,7 +528,7 @@ module Flor::Tools
|
|
324
528
|
def cmd_parse(line)
|
325
529
|
|
326
530
|
source = File.read(@flow_path)
|
327
|
-
tree = Flor
|
531
|
+
tree = Flor.parse(source, nil, {})
|
328
532
|
|
329
533
|
case arg(line)
|
330
534
|
when 'd', 'raw'
|
@@ -336,7 +540,7 @@ module Flor::Tools
|
|
336
540
|
when 'p'
|
337
541
|
p tree
|
338
542
|
else
|
339
|
-
Flor.
|
543
|
+
puts Flor.tree_to_s(tree, '0', headers: false)
|
340
544
|
end
|
341
545
|
end
|
342
546
|
|
@@ -365,20 +569,62 @@ module Flor::Tools
|
|
365
569
|
puts "not found"
|
366
570
|
end
|
367
571
|
end
|
572
|
+
make_alias('e', 'edit')
|
573
|
+
|
574
|
+
def hlp_cat
|
575
|
+
%{ prints the current flow }
|
576
|
+
end
|
577
|
+
def man_cat
|
578
|
+
%{
|
579
|
+
* cat
|
580
|
+
prints the current flow
|
581
|
+
}
|
582
|
+
end
|
583
|
+
def cmd_cat(line)
|
584
|
+
|
585
|
+
puts " # #{@flow_path}\n"
|
586
|
+
File.readlines(@flow_path).each { |line| puts " #{line}" }
|
587
|
+
end
|
368
588
|
|
369
589
|
def hlp_conf
|
370
|
-
%{ prints current unit configuration }
|
590
|
+
%{ prints or sets in current unit configuration }
|
591
|
+
end
|
592
|
+
def man_conf
|
593
|
+
%{
|
594
|
+
* conf
|
595
|
+
prints current unit configuration
|
596
|
+
* conf key
|
597
|
+
prints value for a single key
|
598
|
+
* conf key value
|
599
|
+
sets value for key
|
600
|
+
}
|
371
601
|
end
|
372
602
|
def cmd_conf(line)
|
373
|
-
|
603
|
+
|
604
|
+
key, value = arg(line), (args(line)[2..-1] || []).join(' ')
|
605
|
+
|
606
|
+
if key && @unit.conf.has_key?(key)
|
607
|
+
puts Flor.to_d(
|
608
|
+
{ key: @unit.conf[key] }, colour: true, indent: 1, width: true)
|
609
|
+
end
|
610
|
+
|
611
|
+
if key && argc(line) > 2
|
612
|
+
@unit.conf[key] = parse_single_json_value(value)
|
613
|
+
puts " #{@c.dg}# ==>#{@c.reset}"
|
614
|
+
puts Flor.to_d(
|
615
|
+
{ key: @unit.conf[key] }, colour: true, indent: 1, width: true)
|
616
|
+
elsif key
|
617
|
+
# alreay done
|
618
|
+
else
|
619
|
+
page(Flor.to_d(@unit.conf, colour: true, indent: 1, width: true))
|
620
|
+
end
|
374
621
|
end
|
375
622
|
|
376
623
|
def hlp_t
|
377
624
|
%{ prints the file hierarchy for #{@root} }
|
378
625
|
end
|
379
626
|
def cmd_t(line)
|
380
|
-
|
381
|
-
system("tree -C #{@root}")
|
627
|
+
page(`tree -C #{@root}`)
|
382
628
|
end
|
383
629
|
|
384
630
|
def hlp_tasks
|
@@ -394,6 +640,8 @@ module Flor::Tools
|
|
394
640
|
end
|
395
641
|
def cmd_tasks(line)
|
396
642
|
|
643
|
+
o = StringIO.new
|
644
|
+
|
397
645
|
frag = arg(line)
|
398
646
|
|
399
647
|
table = Terminal::Table.new(
|
@@ -425,33 +673,54 @@ module Flor::Tools
|
|
425
673
|
table.add_row([
|
426
674
|
aright(i), tasker, nid, @c.yellow(exid), pl, mt ]) }
|
427
675
|
|
428
|
-
puts table
|
429
|
-
puts "#{tas.count} task#{tas.count
|
676
|
+
o.puts table
|
677
|
+
o.puts "#{tas.count} task#{tas.count != 1 ? 's' : ''}.\n"
|
678
|
+
|
679
|
+
page(o)
|
430
680
|
end
|
431
681
|
make_alias('tas', 'tasks')
|
432
682
|
|
433
683
|
def hlp_executions
|
434
684
|
%{ lists the executions currently active }
|
435
685
|
end
|
686
|
+
def man_executions
|
687
|
+
%{
|
688
|
+
* executions
|
689
|
+
lists all the executions currently active
|
690
|
+
* executions all
|
691
|
+
lists all the executions
|
692
|
+
}
|
693
|
+
end
|
436
694
|
def cmd_executions(line)
|
437
695
|
|
696
|
+
o = StringIO.new
|
697
|
+
|
438
698
|
exes = @unit.executions
|
439
699
|
exes = exes.where(status: 'active') unless arg(line) == 'all'
|
440
700
|
|
441
701
|
table = Terminal::Table.new(
|
442
702
|
#title: 'executions',
|
443
|
-
headings: %w[ id exid started ],
|
703
|
+
headings: %w[ id exid name started tis status ],
|
444
704
|
style: table_style)
|
445
705
|
#table.align_column(0, :right)
|
446
706
|
|
447
707
|
exes
|
448
708
|
.each { |e|
|
709
|
+
vs = e.zero_variables
|
449
710
|
table.add_row([
|
450
|
-
aright(e.id),
|
711
|
+
aright(e.id),
|
712
|
+
@c.yl(e.exid),
|
713
|
+
%w[ execution_name process_name flow_name name ]
|
714
|
+
.collect { |k| vs[k] }.compact.first,
|
715
|
+
e.ctime[0, 19],
|
716
|
+
aright(@unit.timers.where(exid: e.exid, status: 'active').count),
|
717
|
+
e.failed? ? 'failed' : 'running'
|
451
718
|
]) }
|
452
719
|
|
453
|
-
puts table
|
454
|
-
puts "#{exes.count} execution#{exes.count
|
720
|
+
o.puts table
|
721
|
+
o.puts "#{exes.count} execution#{exes.count != 1 ? 's' : ''}.\n"
|
722
|
+
|
723
|
+
page(o)
|
455
724
|
end
|
456
725
|
make_alias('exes', 'executions')
|
457
726
|
|
@@ -460,6 +729,8 @@ module Flor::Tools
|
|
460
729
|
end
|
461
730
|
def cmd_timers(line)
|
462
731
|
|
732
|
+
o = StringIO.new
|
733
|
+
|
463
734
|
tis = @unit.timers
|
464
735
|
tis = tis.where(status: 'active') unless arg(line) == 'all'
|
465
736
|
|
@@ -477,8 +748,10 @@ module Flor::Tools
|
|
477
748
|
aright(t.schedule), t.ntime[0, 19]
|
478
749
|
]) }
|
479
750
|
|
480
|
-
puts table
|
481
|
-
puts "#{tis.count} timer#{tis.count
|
751
|
+
o.puts table
|
752
|
+
o.puts "#{tis.count} timer#{tis.count != 1 ? 's' : ''}.\n"
|
753
|
+
|
754
|
+
page(o)
|
482
755
|
end
|
483
756
|
make_alias('tis', 'timers')
|
484
757
|
|
@@ -508,6 +781,8 @@ module Flor::Tools
|
|
508
781
|
"couldn't find a task matching #{t.inspect}"
|
509
782
|
) unless path
|
510
783
|
|
784
|
+
puts "found task at #{path}"
|
785
|
+
|
511
786
|
m = JSON.parse(File.read(path))
|
512
787
|
@unit.return(m)
|
513
788
|
FileUtils.rm(path)
|
@@ -530,10 +805,13 @@ module Flor::Tools
|
|
530
805
|
@unit.conf.select! { |k, v| ! k.match(/\Alog_/) }
|
531
806
|
|
532
807
|
rest = line.match(/\A[a-z]+(\s+.+)?/)[1]
|
533
|
-
rest =
|
534
|
-
rest =
|
808
|
+
rest = rest.strip if rest
|
809
|
+
rest = nil if rest && rest == 'off'
|
810
|
+
rest = 'stdout,dbg' if rest && %w[ on 1 ].include?(rest)
|
811
|
+
|
812
|
+
@unit.conf.merge!(Flor::Conf.interpret_flor_debug(debug: rest)) if rest
|
535
813
|
|
536
|
-
|
814
|
+
cmd_conf('') # display conf
|
537
815
|
end
|
538
816
|
|
539
817
|
def hlp_hook
|
@@ -584,39 +862,49 @@ module Flor::Tools
|
|
584
862
|
table
|
585
863
|
end
|
586
864
|
|
865
|
+
def lookup_execution(id)
|
866
|
+
|
867
|
+
if id.match(/\A\d+\z/)
|
868
|
+
@unit.executions[id.to_i] ||
|
869
|
+
fail(ArgumentError.new("execution #{id} not found"))
|
870
|
+
else
|
871
|
+
@unit.executions.first(Sequel.like(:exid, "%#{id}%")) ||
|
872
|
+
fail(ArgumentError.new("execution matching \"%#{id}%\" not found"))
|
873
|
+
end
|
874
|
+
end
|
875
|
+
|
587
876
|
def detail_execution(id)
|
588
877
|
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
fail(ArgumentError.new("execution #{id} not found"))
|
593
|
-
else
|
594
|
-
@unit.executions.first(Sequel.like(:exid, "%#{id}%")) ||
|
595
|
-
fail(ArgumentError.new("execution matching \"%#{id}%\" not found"))
|
596
|
-
end
|
878
|
+
o = StringIO.new
|
879
|
+
|
880
|
+
exe = lookup_execution(id)
|
597
881
|
|
598
882
|
eid = { id: exe.id, exid: exe.exid }.inspect
|
599
883
|
con = Flor::Storage.from_blob(exe.values.delete(:content))
|
600
884
|
exe.values[:content] = '...'
|
601
885
|
|
602
|
-
puts @c.dg("--- exe #{eid} :")
|
603
|
-
puts h_to_table(exe.values)
|
604
|
-
puts @c.dg(" exe #{eid} content:")
|
886
|
+
o.puts @c.dg("--- exe #{eid} :")
|
887
|
+
o.puts h_to_table(exe.values)
|
888
|
+
o.puts @c.dg(" exe #{eid} content:")
|
605
889
|
nodes = con.delete('nodes')
|
606
890
|
con['nodes'] = '...'
|
607
|
-
puts indent(' ', h_to_table(con))
|
608
|
-
puts @c.dg(" exe #{eid} content/nodes:")
|
891
|
+
o.puts indent(' ', h_to_table(con))
|
892
|
+
o.puts @c.dg(" exe #{eid} content/nodes:")
|
609
893
|
table = Terminal::Table.new(
|
610
894
|
headings: %w[ nid data ],
|
611
895
|
style: table_style.merge(all_separators: true))
|
612
896
|
nodes.each do |k, v|
|
613
897
|
table.add_row([ k, Flor.to_d(v, colour: true, indent: 0, width: 70) ])
|
614
898
|
end
|
615
|
-
puts indent(' ', table)
|
899
|
+
o.puts indent(' ', table)
|
900
|
+
|
901
|
+
page(o)
|
616
902
|
end
|
617
903
|
|
618
904
|
def detail_timer(id)
|
619
905
|
|
906
|
+
o = StringIO.new
|
907
|
+
|
620
908
|
timer = @unit.timers[id.to_i]
|
621
909
|
|
622
910
|
fail ArgumentError.new("timer #{id} not found") unless timer
|
@@ -626,15 +914,33 @@ module Flor::Tools
|
|
626
914
|
con = Flor::Storage.from_blob(timer.delete(:content))
|
627
915
|
timer[:content] = '...'
|
628
916
|
|
629
|
-
puts @c.dg("--- timer #{tid} :")
|
630
|
-
puts Flor.to_d(timer, colour: true, indent: 1, width: true)
|
631
|
-
puts @c.dg("--- timer #{tid} content:")
|
632
|
-
puts Flor.to_d(con, colour: true, indent: 1, width: true)
|
917
|
+
o.puts @c.dg("--- timer #{tid} :")
|
918
|
+
o.puts Flor.to_d(timer, colour: true, indent: 1, width: true)
|
919
|
+
o.puts @c.dg("--- timer #{tid} content:")
|
920
|
+
o.puts Flor.to_d(con, colour: true, indent: 1, width: true)
|
921
|
+
|
922
|
+
page(o)
|
633
923
|
end
|
634
924
|
|
635
925
|
def detail_task(id)
|
636
926
|
|
637
|
-
|
927
|
+
pa = Dir["#{@root}/var/tasks/**/*#{id}*.json"].first
|
928
|
+
|
929
|
+
fail ArgumentError.new("found no task matching #{id}") unless pa
|
930
|
+
|
931
|
+
ta = JSON.load(File.read(pa))
|
932
|
+
tconf = ta['tconf']; ta['tconf'] = '...'
|
933
|
+
payload = ta['payload']; ta['payload'] = '...'
|
934
|
+
|
935
|
+
o = StringIO.new
|
936
|
+
o.puts "#{@c.dg} #\n # path: #{pa}\n ##{@c.reset}"
|
937
|
+
o.puts Flor.to_d(ta, colour: true, indent: 1, width: true)
|
938
|
+
o.puts "#{@c.dg} # tconf:#{@c.reset}"
|
939
|
+
o.puts Flor.to_d(tconf, colour: true, indent: 3, width: true)
|
940
|
+
o.puts "#{@c.dg} # payload:#{@c.reset}"
|
941
|
+
o.puts Flor.to_d(payload, colour: true, indent: 3, width: true)
|
942
|
+
|
943
|
+
page(o)
|
638
944
|
end
|
639
945
|
|
640
946
|
def hlp_detail
|
@@ -646,7 +952,7 @@ fail NotImplementedError
|
|
646
952
|
displays full execution information
|
647
953
|
* detail ti|timer id
|
648
954
|
displays full timer information
|
649
|
-
* detail task frag
|
955
|
+
* detail t|task frag
|
650
956
|
displays task
|
651
957
|
}
|
652
958
|
end
|
@@ -688,7 +994,7 @@ fail NotImplementedError
|
|
688
994
|
end
|
689
995
|
make_alias('can', 'cancel')
|
690
996
|
|
691
|
-
def render_node(t, nid)
|
997
|
+
def render_node(o, t, nid)
|
692
998
|
|
693
999
|
ni = nid
|
694
1000
|
head = t[0]
|
@@ -703,12 +1009,12 @@ fail NotImplementedError
|
|
703
1009
|
rest = @c.green(" <--")
|
704
1010
|
end
|
705
1011
|
|
706
|
-
puts " #{ni} #{head}#{rest}"
|
1012
|
+
o.puts " #{ni} #{head}#{rest}"
|
707
1013
|
|
708
1014
|
return unless t[1].is_a?(Array)
|
709
1015
|
|
710
1016
|
t[1].each_with_index do |ct, i|
|
711
|
-
render_node(t[1][i], "#{nid}_#{i}")
|
1017
|
+
render_node(o, t[1][i], "#{nid}_#{i}")
|
712
1018
|
end
|
713
1019
|
end
|
714
1020
|
|
@@ -724,12 +1030,18 @@ fail NotImplementedError
|
|
724
1030
|
end
|
725
1031
|
def cmd_render(line)
|
726
1032
|
|
1033
|
+
o = StringIO.new
|
1034
|
+
|
727
1035
|
frag = arg(line)
|
728
1036
|
|
729
1037
|
exe =
|
730
1038
|
@unit.executions.first(Sequel.like(:exid, "%#{frag}%")) ||
|
731
|
-
fail(ArgumentError.new("execution matching \"%#{
|
732
|
-
|
1039
|
+
fail(ArgumentError.new("execution matching \"%#{frag}%\" not found"))
|
1040
|
+
o.puts
|
1041
|
+
o.puts " exid: #{@c.yellow(exe.exid)}"
|
1042
|
+
o.puts " status: #{@c.yellow(exe.status)}"
|
1043
|
+
o.puts
|
1044
|
+
|
733
1045
|
tree = exe.full_tree
|
734
1046
|
nodes = exe.nodes
|
735
1047
|
|
@@ -752,7 +1064,9 @@ fail NotImplementedError
|
|
752
1064
|
end
|
753
1065
|
end
|
754
1066
|
|
755
|
-
render_node(tree, '0')
|
1067
|
+
render_node(o, tree, '0')
|
1068
|
+
|
1069
|
+
page(o)
|
756
1070
|
end
|
757
1071
|
make_alias('r', 'render')
|
758
1072
|
|
@@ -776,12 +1090,44 @@ fail NotImplementedError
|
|
776
1090
|
puts @c.yellow("re-apply message queued for #{exid} #{nid}")
|
777
1091
|
end
|
778
1092
|
|
1093
|
+
def hlp_flosh
|
1094
|
+
%{ displays flosh explanation }
|
1095
|
+
end
|
1096
|
+
def man_flosh
|
1097
|
+
%{
|
1098
|
+
* flosh
|
1099
|
+
displays flosh explanation
|
1100
|
+
}
|
1101
|
+
end
|
1102
|
+
def cmd_flosh(line)
|
1103
|
+
page %{
|
1104
|
+
#{@c.yellow}# flosh#{@c.reset}
|
1105
|
+
|
1106
|
+
Flosh is a flor shell.
|
1107
|
+
|
1108
|
+
It's meant for demonstration purposes, to show how flor works.
|
1109
|
+
|
1110
|
+
Opening a flor shell, starts a flor scheduler pointing to #{@root}
|
1111
|
+
|
1112
|
+
#{@c.yellow}# flosh provided taskers#{@c.reset}
|
1113
|
+
|
1114
|
+
The following names can be used as "nato" taskers: alpha, bravo, charly, delta, fox, foxtrott, golf, echo, and hotel.
|
1115
|
+
|
1116
|
+
Nato taskers simply put their tasks under #{@root}/var/tasks/{tasker-name}/ as JSON files. Those file can be edited with the `edit task {frag}`.
|
1117
|
+
|
1118
|
+
Once edited (or not), a nato tasker task can be returned to flor (to the scheduler) with `return {frag}`.
|
1119
|
+
}
|
1120
|
+
end
|
1121
|
+
|
779
1122
|
#
|
780
|
-
#
|
1123
|
+
# enumerate commands (for cmd_help)
|
781
1124
|
|
782
1125
|
COMMANDS = self.allocate.methods \
|
783
1126
|
.select { |m| m.to_s.match(/^cmd_/) }.collect { |m| m[4..-1] }.sort
|
784
1127
|
|
1128
|
+
#
|
1129
|
+
# use Readline if possible
|
1130
|
+
|
785
1131
|
begin
|
786
1132
|
require 'readline'
|
787
1133
|
def prompt_and_read
|