flor 0.0.1 → 0.9.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.
Files changed (84) hide show
  1. data/CHANGELOG.md +13 -0
  2. data/LICENSE.txt +1 -1
  3. data/Makefile +66 -0
  4. data/README.md +57 -0
  5. data/fail.txt +7 -0
  6. data/flor.gemspec +12 -9
  7. data/intercepted.txt +123 -0
  8. data/lib/flor/colours.rb +140 -0
  9. data/lib/flor/conf.rb +88 -0
  10. data/lib/flor/core/executor.rb +473 -0
  11. data/lib/flor/core/node.rb +397 -0
  12. data/lib/flor/core/procedure.rb +600 -0
  13. data/lib/flor/core/texecutor.rb +209 -0
  14. data/lib/flor/core.rb +93 -0
  15. data/lib/flor/dollar.rb +248 -0
  16. data/lib/flor/errors.rb +36 -0
  17. data/lib/flor/flor.rb +556 -0
  18. data/lib/flor/log.rb +336 -0
  19. data/lib/flor/migrations/0001_tables.rb +122 -0
  20. data/lib/flor/parser.rb +414 -0
  21. data/lib/flor/pcore/_arr.rb +49 -0
  22. data/lib/flor/pcore/_atom.rb +43 -0
  23. data/lib/flor/pcore/_att.rb +160 -0
  24. data/lib/flor/pcore/_dump.rb +60 -0
  25. data/lib/flor/pcore/_err.rb +30 -0
  26. data/lib/flor/pcore/_happly.rb +73 -0
  27. data/lib/flor/pcore/_obj.rb +65 -0
  28. data/lib/flor/pcore/_skip.rb +63 -0
  29. data/lib/flor/pcore/apply.rb +60 -0
  30. data/lib/flor/pcore/arith.rb +46 -0
  31. data/lib/flor/pcore/break.rb +71 -0
  32. data/lib/flor/pcore/cmp.rb +72 -0
  33. data/lib/flor/pcore/cond.rb +57 -0
  34. data/lib/flor/pcore/cursor.rb +223 -0
  35. data/lib/flor/pcore/define.rb +96 -0
  36. data/lib/flor/pcore/fail.rb +45 -0
  37. data/lib/flor/pcore/ife.rb +56 -0
  38. data/lib/flor/pcore/loop.rb +53 -0
  39. data/lib/flor/pcore/map.rb +75 -0
  40. data/lib/flor/pcore/match.rb +70 -0
  41. data/lib/flor/pcore/move.rb +65 -0
  42. data/lib/flor/pcore/noeval.rb +46 -0
  43. data/lib/flor/pcore/noret.rb +47 -0
  44. data/lib/flor/pcore/push.rb +69 -0
  45. data/lib/flor/pcore/sequence.rb +39 -0
  46. data/lib/flor/pcore/set.rb +76 -0
  47. data/lib/flor/pcore/stall.rb +35 -0
  48. data/lib/flor/pcore/until.rb +122 -0
  49. data/lib/flor/pcore/val.rb +40 -0
  50. data/lib/flor/punit/cancel.rb +69 -0
  51. data/lib/flor/punit/cmap.rb +76 -0
  52. data/lib/flor/punit/concurrence.rb +149 -0
  53. data/lib/flor/punit/every.rb +46 -0
  54. data/lib/flor/punit/on.rb +81 -0
  55. data/lib/flor/punit/schedule.rb +68 -0
  56. data/lib/flor/punit/signal.rb +47 -0
  57. data/lib/flor/punit/sleep.rb +53 -0
  58. data/lib/flor/punit/task.rb +109 -0
  59. data/lib/flor/punit/trace.rb +51 -0
  60. data/lib/flor/punit/trap.rb +100 -0
  61. data/lib/flor/to_string.rb +81 -0
  62. data/lib/flor/tools/env.rb +103 -0
  63. data/lib/flor/tools/repl.rb +231 -0
  64. data/lib/flor/unit/executor.rb +260 -0
  65. data/lib/flor/unit/hooker.rb +186 -0
  66. data/lib/flor/unit/journal.rb +52 -0
  67. data/lib/flor/unit/loader.rb +181 -0
  68. data/lib/flor/unit/logger.rb +181 -0
  69. data/lib/flor/unit/models/execution.rb +105 -0
  70. data/lib/flor/unit/models/pointer.rb +31 -0
  71. data/lib/flor/unit/models/timer.rb +52 -0
  72. data/lib/flor/unit/models/trace.rb +31 -0
  73. data/lib/flor/unit/models/trap.rb +130 -0
  74. data/lib/flor/unit/models.rb +106 -0
  75. data/lib/flor/unit/scheduler.rb +419 -0
  76. data/lib/flor/unit/storage.rb +633 -0
  77. data/lib/flor/unit/tasker.rb +191 -0
  78. data/lib/flor/unit/waiter.rb +146 -0
  79. data/lib/flor/unit/wlist.rb +77 -0
  80. data/lib/flor/unit.rb +50 -0
  81. data/lib/flor.rb +40 -3
  82. metadata +152 -22
  83. checksums.yaml +0 -7
  84. data/Rakefile +0 -52
@@ -0,0 +1,81 @@
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
+
26
+ module Flor
27
+
28
+ def self.to_s(o=nil, k=nil)
29
+
30
+ return 'FlorModule' if o == nil && k == nil
31
+ # should it emerge somewhere...
32
+
33
+ return o.collect { |e| Flor.to_s(e, k) }.join("\n") if o.is_a?(Array)
34
+
35
+ if o.is_a?(Hash)
36
+
37
+ return send("message_#{k}_to_s", o) if k && o['point'].is_a?(String)
38
+ return message_to_s(o) if o['point'].is_a?(String)
39
+
40
+ return send("node_#{k}_to_s", o) if k && o.has_key?('parent')
41
+ return node_to_s(o) if o['parent'].is_a?(String)
42
+ end
43
+
44
+ return [ o, k ].inspect if k
45
+ o.inspect
46
+ end
47
+
48
+ def self.message_to_s(m)
49
+
50
+ s = StringIO.new
51
+ s << '(msg ' << m['nid'] << ' ' << m['point']
52
+ %w[ from flavour ].each { |k|
53
+ s << ' ' << k << ':' << m[k].to_s if m.has_key?(k) }
54
+ s << ')'
55
+
56
+ s.string
57
+ end
58
+
59
+ def self.node_status_to_s(n)
60
+
61
+ s = StringIO.new
62
+ stas = n['status'].reverse
63
+ while sta = stas.shift
64
+ s << '(status ' << (sta['status'] || 'o') # o for open
65
+ s << ' pt:' << sta['point']
66
+ if f = sta['flavour']; s << ' fla:' << f; end
67
+ if f = sta['from']; s << ' fro:' << f; end
68
+ if m = sta['m']; s << ' m:' << m; end
69
+ s << ')'
70
+ s << "\n" if stas.any?
71
+ end
72
+
73
+ s.string
74
+ end
75
+
76
+ def self.node_to_s(n) # there is already a .node_to_s in log.rb
77
+
78
+ n.inspect
79
+ end
80
+ end
81
+
@@ -0,0 +1,103 @@
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
+ require 'fileutils'
26
+
27
+
28
+ module Flor; end
29
+ module Flor::Tools; end
30
+
31
+ module Flor::Tools::Env
32
+
33
+ def self.make(path, envname=nil, opts={})
34
+
35
+ if envname.is_a?(Hash)
36
+ opts = envname
37
+ envname = nil
38
+ end
39
+
40
+ opts[:env] = envname || 'production'
41
+ opts[:sto_uri] ||= 'sqlite://tmp/dev.db'
42
+ opts[:gitkeep] = true unless opts.has_key?(:gitkeep)
43
+
44
+ mkdir(path, envname) if envname
45
+
46
+ mk_etc(path, envname, opts)
47
+ mk_lib(path, envname, opts)
48
+ mk_usr(path, envname, opts)
49
+ mk_var(path, envname, opts)
50
+ end
51
+
52
+ # protected, somehow
53
+
54
+ def self.mk_etc(*ps, opts)
55
+
56
+ mkdir(*ps, 'etc')
57
+ mkdir(*ps, 'etc', 'variables')
58
+ touch(*ps, 'etc', 'variables', '.gitkeep') if opts[:gitkeep]
59
+
60
+ write(*ps, 'etc', 'conf.json') do
61
+ "env: #{opts[:env]}\n" +
62
+ "sto_uri: #{opts[:sto_uri].inspect}"
63
+ end
64
+ end
65
+
66
+ def self.mk_lib(*ps, opts)
67
+
68
+ mkdir(*ps, 'lib')
69
+ mkdir(*ps, 'lib', 'flows')
70
+ touch(*ps, 'lib', 'flows', '.gitkeep') if opts[:gitkeep]
71
+ mkdir(*ps, 'lib', 'taskers')
72
+ touch(*ps, 'lib', 'taskers', '.gitkeep') if opts[:gitkeep]
73
+ end
74
+
75
+ def self.mk_usr(*ps, opts)
76
+
77
+ mkdir(*ps, 'usr')
78
+
79
+ if opts[:acme] == false
80
+ touch(*ps, 'usr', '.gitkeep') if opts[:gitkeep]
81
+ else
82
+ mkdir(*ps, 'usr', 'com.acme')
83
+ mk_etc(*ps, 'usr', 'com.acme', opts)
84
+ mk_lib(*ps, 'usr', 'com.acme', opts)
85
+ end
86
+ end
87
+
88
+ def self.mk_var(*ps, opts)
89
+
90
+ mkdir(*ps, 'var')
91
+ mkdir(*ps, 'var', 'log')
92
+ touch(*ps, 'var', 'log', '.gitkeep') if opts[:gitkeep]
93
+ end
94
+
95
+ def self.mkdir(*ps); FileUtils.mkdir(File.join(*ps.compact)); end
96
+ def self.touch(*ps); FileUtils.touch(File.join(*ps.compact)); end
97
+
98
+ def self.write(*ps, &block)
99
+
100
+ File.open(File.join(*ps.compact), 'wb') { |f| f.write(block.call) }
101
+ end
102
+ end
103
+
@@ -0,0 +1,231 @@
1
+
2
+ require 'flor'
3
+ require 'flor/unit'
4
+
5
+
6
+ module Flor::Tools
7
+
8
+ class Repl
9
+
10
+ def initialize(env)
11
+
12
+ @unit = Flor::Unit.new("envs/#{env}/etc/conf.json")
13
+
14
+ #pp @unit.conf
15
+ @unit.conf[:unit] = 'repl'
16
+
17
+ #unit.hooker.add('journal', Flor::Journal)
18
+ if @unit.conf['sto_uri'].match(/memory/)
19
+ @unit.storage.delete_tables
20
+ @unit.storage.migrate
21
+ end
22
+ @unit.start
23
+
24
+ @lines = []
25
+ @payload = {}
26
+ @vars = {}
27
+
28
+ @outcome = nil
29
+
30
+ @unit.hook do |message|
31
+
32
+ if ! message['consumed']
33
+ # do nothing
34
+ elsif %w[ terminated failed ].include?(message['point'])
35
+ @outcome = message
36
+ out = Flor.to_pretty_s(@outcome)
37
+ col = message['point'] == 'failed' ? _rd : _gr
38
+ out = out.gsub(/"point"=>"([^"]+)"/, "\"point\"=>\"#{col}\\1#{_yl}\"")
39
+ out = "\n" + _yl + out + _rs
40
+ out = out.split("\n").collect { |l| ' ' + l }.join("\n")
41
+ print(out)
42
+ end
43
+ end
44
+
45
+ @_c, @_dg, @_yl, @_bl, @_lg, @_gr, @_lr, @_rd = Flor.colours({})
46
+
47
+ do_loop
48
+ end
49
+
50
+ # reset dark_grey light_yellow blue light_grey light_green light_red red
51
+ attr_reader :_rs, :_dg, :_yl, :_bl, :_lg, :_gr, :_lr, :_rd
52
+
53
+ protected
54
+
55
+ def prompt
56
+
57
+ "flor l#{@lines.size} > "
58
+ end
59
+
60
+ def do_loop
61
+
62
+ loop do
63
+
64
+ line = prompt_and_read
65
+
66
+ break unless line
67
+ next if line.strip == ''
68
+
69
+ cmd = "cmd_#{line.split(/\s/).first}".to_sym
70
+
71
+ if cmd.size > 4 && methods.include?(cmd)
72
+ begin
73
+ send(cmd, line)
74
+ rescue StandardError, NotImplementedError => err
75
+ p err
76
+ err.backtrace[0, 7].each { |l| puts " #{l}" }
77
+ end
78
+ else
79
+ @lines << line
80
+ end
81
+ end
82
+
83
+ $stdout.puts
84
+ end
85
+
86
+ def hlp_launch
87
+ %{ launches the current execution code }
88
+ end
89
+ def cmd_launch(line)
90
+
91
+ exid = @unit.launch(@lines.join("\n"), vars: @vars, payload: @payload)
92
+ puts " launched #{_yl}#{exid}#{_rs}"
93
+ end
94
+
95
+ alias hlp_run hlp_launch
96
+ alias cmd_run cmd_launch
97
+
98
+ def hlp_help
99
+ %{ displays this help }
100
+ end
101
+ def cmd_help(line)
102
+
103
+ puts
104
+ puts "## available commands:"
105
+ puts
106
+ COMMANDS.each do |cmd|
107
+ print "* #{cmd}"
108
+ if hlp = (send("hlp_#{cmd}") rescue nil); print " - #{hlp.strip}"; end
109
+ puts
110
+ end
111
+ puts
112
+ end
113
+
114
+ def hlp_exit
115
+ %{ exits this repl, with the given int exit code or 0 }
116
+ end
117
+ def cmd_exit(line)
118
+
119
+ exit(line.split(/\s+/)[1].to_i)
120
+ end
121
+
122
+ def hlp_list
123
+ %{ lists the lines of the current execution code }
124
+ end
125
+ def do_list(lines)
126
+
127
+ lw = [ 2, lines.size.to_s.length ].max
128
+ sw = 5 - lw
129
+
130
+ lines.each_with_index do |l, i|
131
+ puts "#{_dg}% #{sw}s%0#{lw}i #{_yl}%s#{_rs}" % [ '', i + 1, l ]
132
+ end
133
+ end
134
+ def cmd_list(line)
135
+
136
+ do_list(@lines)
137
+ end
138
+
139
+ def hlp_parse
140
+ %{ parses the current execution code and displays its tree }
141
+ end
142
+ def cmd_parse(line)
143
+
144
+ Flor.print_tree(
145
+ Flor::Lang.parse(@lines.join("\n"), nil, {}),
146
+ '0',
147
+ headers: false)
148
+ end
149
+
150
+ def hlp_new
151
+ %w{ erases current execution code, vars and payload }
152
+ end
153
+ def cmd_new(line)
154
+
155
+ @lines = []
156
+ @vars = {}
157
+ @payload = {}
158
+ end
159
+
160
+ def fname(line)
161
+
162
+ line.split(/\s+/)[1]
163
+ end
164
+
165
+ def hlp_save
166
+ %{ saves the current execution code to the given file }
167
+ end
168
+ def cmd_save(line)
169
+
170
+ File.open(fname(line), 'wb') { |f| f.puts @lines }
171
+ end
172
+
173
+ def hlp_cat
174
+ %{ outputs the content of the give file }
175
+ end
176
+ def cmd_cat(line)
177
+
178
+ do_list(File.readlines(fname(line)).collect(&:chomp))
179
+ end
180
+
181
+ def hlp_load
182
+ %{ loads a file as execution code }
183
+ end
184
+ def cmd_load(line)
185
+
186
+ @lines = File.readlines(fname(line)).collect(&:chomp)
187
+ end
188
+
189
+ def cmd_cont(line)
190
+
191
+ fail NotImplementedError
192
+ end
193
+
194
+ def hlp_edit
195
+ %{ saves the current execution code to .tmp.flo and opens it for edition }
196
+ end
197
+ def cmd_edit(line)
198
+
199
+ cmd_save('save .tmp.flo')
200
+ system('$EDITOR .tmp.flo')
201
+ cmd_load('load .tmp.flo')
202
+ FileUtils.rm('.tmp.flo')
203
+ end
204
+
205
+ #
206
+ # use Readline if possible
207
+
208
+ COMMANDS = self.allocate.methods \
209
+ .select { |m| m.to_s.match(/^cmd_/) }.collect { |m| m[4..-1] }.sort
210
+
211
+ begin
212
+ require 'readline'
213
+ def prompt_and_read
214
+ Readline.readline(prompt, true)
215
+ end
216
+ Readline.completion_proc =
217
+ proc { |s|
218
+ r = /^#{Regexp.escape(s)}/
219
+ COMMANDS.grep(r) + Dir["#{s}*"].grep(r)
220
+ }
221
+ #Readline.completion_append_character =
222
+ # " "
223
+ rescue LoadError => le
224
+ def prompt_and_read
225
+ print(prompt)
226
+ ($stdin.readline rescue false)
227
+ end
228
+ end
229
+ end
230
+ end
231
+
@@ -0,0 +1,260 @@
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
+
26
+ module Flor
27
+
28
+ class UnitExecutor < Flor::Executor
29
+
30
+ attr_reader :exid
31
+
32
+ def initialize(unit, exid)
33
+
34
+ super(
35
+ unit,
36
+ unit.storage.fetch_traps(exid),
37
+ unit.storage.load_execution(exid))
38
+
39
+ @exid = exid
40
+ @messages = unit.storage.fetch_messages(exid)
41
+ @consumed = []
42
+
43
+ @alive = true
44
+ @shutdown = false
45
+
46
+ @thread = nil
47
+ end
48
+
49
+ def alive?; @alive; end
50
+
51
+ def run
52
+
53
+ @thread = Thread.new { do_run }
54
+ #p [ :unit_executor, :thread, @thread.object_id ]
55
+
56
+ self
57
+ end
58
+
59
+ def shutdown
60
+
61
+ @shutdown = true
62
+ @thread.join
63
+ end
64
+
65
+ protected
66
+
67
+ def do_run
68
+
69
+ log_run_start if @unit.conf['log_run']
70
+
71
+ counter_next('runs')
72
+
73
+ t0 = Time.now
74
+
75
+ (@unit.conf['exe_max_messages'] || 77).times do |i|
76
+
77
+ m = @messages.shift
78
+ break unless m
79
+ break if @shutdown
80
+
81
+ if m['point'] == 'terminated' && @messages.any?
82
+ #
83
+ # try to handle 'terminated' last
84
+ #
85
+ @messages << m
86
+ m = @messages.shift
87
+ end
88
+
89
+ point = m['point']
90
+
91
+ ms = process(m)
92
+
93
+ @consumed << m
94
+ #
95
+ #@consumed << m unless ms.include?(m)
96
+ # TODO what if msg is held / pushed back?
97
+
98
+ ims, oms = ms.partition { |m| m['exid'] == @exid }
99
+ # qui est "in", qui est "out"?
100
+
101
+ counter_add('omsgs', oms.size)
102
+ # keep track of "out" messages, messages to other executions
103
+
104
+ @messages.concat(ims)
105
+ @unit.storage.put_messages(oms)
106
+ end
107
+
108
+ @unit.storage.consume(@consumed)
109
+
110
+ @alive = false
111
+
112
+ @unit.storage.put_execution(@execution)
113
+ @unit.storage.put_messages(@messages)
114
+
115
+ log_run_end(t0) if @unit.conf['log_run']
116
+
117
+ @consumed.clear
118
+
119
+ rescue Exception => exc
120
+
121
+ # TODO eventually, have a dump dir
122
+ fn =
123
+ [
124
+ 'flor',
125
+ @unit.conf['env'], @unit.identifier, @exid,
126
+ 'r' + counter('runs').to_s
127
+ ].collect(&:to_s).join('_') + '.dump'
128
+
129
+ @unit.logger.error(
130
+ "#{self.class}#do_run()", exc, "(dumping to #{fn})")
131
+
132
+ File.open(fn, 'wb') do |f|
133
+ #f.puts(JSON.pretty_generate({
134
+ f.puts(Flor.to_pretty_s({
135
+ execution: @execution,
136
+ messages: @messages,
137
+ consumed: @consumed,
138
+ traps: @traps.collect(&:to_h),
139
+ exid: @exid,
140
+ alive: @alive,
141
+ shutdown: @shutdown,
142
+ thread: [ @thread.object_id, @thread.to_s ]
143
+ }))
144
+ f.puts('-' * 80)
145
+ f.puts(on_do_run_exc(exc))
146
+ end
147
+
148
+ puts on_do_run_exc(exc)
149
+ end
150
+
151
+ def schedule(message)
152
+
153
+ @unit.put_timer(message)
154
+
155
+ []
156
+ end
157
+
158
+ def trigger(message)
159
+
160
+ m = message['message']
161
+
162
+ m['nid'] = Flor.sub_nid(m['nid'], counter_next('subs')) \
163
+ if m['point'] == 'execute'
164
+
165
+ [ m ]
166
+ end
167
+
168
+ def log_run_start
169
+
170
+ _c = Flor.colours
171
+
172
+ s = StringIO.new
173
+
174
+ s << _c.dg
175
+ s << " /--- #{_c.lg}run starts#{_c.dg} "
176
+ s << "#{self.class} #{self.object_id} #{@exid}"
177
+ s << "\n | "
178
+ s << { thread: Thread.current.object_id }.inspect
179
+ s << "\n | "
180
+ s << {
181
+ counters: @execution['counters'],
182
+ nodes: @execution['nodes'].size,
183
+ size: @execution['size']
184
+ }.inspect
185
+ s << _c.rs
186
+
187
+ puts s.string
188
+ end
189
+
190
+ def log_run_end(t0)
191
+
192
+ _c = Flor.colours
193
+
194
+ s = StringIO.new
195
+
196
+ s << _c.dg
197
+ s << " | run ends #{self.class} #{self.object_id} #{@exid}"
198
+ s << "\n | "; s << { took: Time.now - t0 }.inspect
199
+ s << "\n | "; s << {
200
+ thread: Thread.current.object_id,
201
+ consumed: @consumed.size,
202
+ traps: @traps.size,
203
+ }.inspect
204
+ s << "\n | "; s << {
205
+ #own_traps: @traps.reject { |t| t.texid == nil }.size, # FIXME
206
+ counters: @execution['counters'],
207
+ nodes: @execution['nodes'].size,
208
+ size: @execution['size']
209
+ }.inspect
210
+ if @unit.archive
211
+ s << "\n | "
212
+ s << {
213
+ archive_size: @unit.archive[@exid].size
214
+ }.inspect
215
+ end
216
+ s << "\n \\--- ."
217
+ s << _c.rs
218
+
219
+ puts s.string
220
+ end
221
+
222
+ def on_do_run_exc(e)
223
+
224
+ io = StringIO.new
225
+ thr = Thread.current
226
+
227
+ head, kind =
228
+ e.is_a?(StandardError) ? [ '=exe', 'error' ] : [ '!exe', 'exception' ]
229
+
230
+ t = head[0, 2] + Time.now.to_f.to_s.split('.').last
231
+ io.puts ' /' + t + ' ' + head * 17
232
+ io.puts " |#{t} + in #{self.class}#do_run"
233
+ io.puts " |#{t} #{kind}: #{e.inspect}"
234
+ io.puts " |#{t} db: #{@unit.storage.db.class} #{@unit.storage.db.hash}"
235
+ io.puts " |#{t} thread: t#{thr.object_id} #{thr.inspect}"
236
+ if @execution
237
+ io.puts " |#{t} exe:"
238
+ io.puts " |#{t} exid: #{@execution['exid'].inspect}"
239
+ io.puts " |#{t} counters: #{@execution['counters'].inspect}"
240
+ end
241
+ if @messages
242
+ io.puts " |#{t} messages:"
243
+ io.puts " |#{t} #{@messages.map { |m| [ m['mid'], m['point'] ] }.inspect}"
244
+ end
245
+ if is = Thread.current[:sto_errored_items]
246
+ io.puts " |#{t} storage errored items/models:"
247
+ is.each do |i|
248
+ io.puts " |#{t} * #{i.inspect}"
249
+ end
250
+ end
251
+ io.puts " |#{t} #{kind}: #{e.inspect}"
252
+ io.puts " |#{t} backtrace:"
253
+ e.backtrace.each { |l| io.puts "|#{t} #{l}" }
254
+ io.puts ' \\' + t + ' ' + (head * 17) + ' .'
255
+
256
+ io.string
257
+ end
258
+ end
259
+ end
260
+