flor 0.0.1 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
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
data/lib/flor/log.rb ADDED
@@ -0,0 +1,336 @@
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.log_message(executor, m, opts={})
29
+
30
+ _c = colours(opts)
31
+
32
+ nid = m['nid']
33
+ nd = executor.node(nid)
34
+
35
+ a = [ ' ' ]
36
+
37
+ n =
38
+ Time.now.utc
39
+ tm =
40
+ if opts[:date]
41
+ n.strftime('%Y%m%d.%H:%M:%S') + sprintf('.%06d', n.usec)[0, 4]
42
+ else
43
+ n.strftime('%H:%M:%S') + sprintf('.%06d', n.usec)[0, 4]
44
+ end
45
+ a << tm
46
+ a << ' '
47
+ a << _c.dg
48
+
49
+ if ex = (m['exid'] || '').split('.').last
50
+ a << ex[-2..-1]
51
+ a << ' '
52
+ end
53
+
54
+ a << "#{nd ? _c.dg : _c.dim + _c.dg}#{nid}#{_c.rs}#{_c.dg} " if nid
55
+
56
+ pt = m['point'][0, 3]
57
+ _pt =
58
+ case pt
59
+ when 'tri', 'sig' then _c.gr
60
+ when 'cea', 'ter' then _c.lg
61
+ when 'can' then _c.ma
62
+ else _c.bl
63
+ end
64
+ a << "#{_pt}#{pt}#{_c.dg}"
65
+
66
+ fla = m['flavour']
67
+ a << " #{_c.lg}#{fla}#{_c.dg}" if fla
68
+
69
+ st = nd && nd['status'].last
70
+ a << " #{_c.dim}#{_c.lg}#{st['status']}:#{st['flavour']}#{_c.rs}#{_c.dg}" \
71
+ if st && st['status']
72
+
73
+ t =
74
+ m['tree']
75
+ rw =
76
+ (t && m['rewritten']) ? 'rw->' : ''
77
+ nt =
78
+ t || Node.new(executor, nd, m).lookup_tree(nid)
79
+ t0 =
80
+ if t
81
+ " [#{rw}#{_c.yl}#{Flor.s_to_d(t[0], compact: true)}#{_c.dg} L#{t[2]}]"
82
+ elsif nt
83
+ " [#{_c.dg}#{Flor.s_to_d(nt[0], compact: true)}#{_c.dg} L#{nt[2]}]"
84
+ else
85
+ ''
86
+ end
87
+ a << t0
88
+
89
+ oe = m['on_error'] ? " #{_c.rd}on_error" : ''
90
+ a << oe
91
+
92
+ tmi = m['timer_id']
93
+ tmi = tmi ? " #{_c.dg}tmi:#{tmi}" : ''
94
+ a << tmi
95
+ #
96
+ tri = m['trap_id']
97
+ tri = tri ? " #{_c.dg}tri:#{tri}" : ''
98
+ a << tri
99
+
100
+ cn = t ? " #{_c.dg}#{Flor.to_d(t[1], compact: true, inner: true)}" : ''
101
+ cn = cn.length > 49 ? "#{cn[0, 49]}..." : cn
102
+ a << cn
103
+
104
+ hp = nd && nd['heap']
105
+ hp = hp && (hp != (t || [])[0]) ? " #{_c.dg}hp:#{nd['heap']}" : ''
106
+ a << hp
107
+
108
+ msr = " #{_c.dg}m#{m['m']}s#{m['sm'] || '_'}"
109
+ msr << "r#{m['er']}>#{m['pr']}" if m['er'] && m['er'] > -1
110
+ a << msr
111
+
112
+ fr = m['from'] ? " from #{m['from']}" : ''
113
+ a << fr
114
+
115
+ rt = ret_to_s(executor, m)
116
+ rt = rt.length > 0 ? " #{_c.lg}f.ret #{rt}" : ''
117
+ a << rt
118
+
119
+ ta =
120
+ m['point'] == 'entered' || m['point'] == 'left' ?
121
+ " #{_c.dg}tags:#{_c.gr}#{m['tags'].join(',')}" :
122
+ nil
123
+ a << ta
124
+
125
+ vs =
126
+ (nd && nd['vars']) ?
127
+ " #{_c.dg}vars:#{_c.gr}#{nd['vars'].keys.join("#{_c.dg},#{_c.gr}")}" :
128
+ ''
129
+ a << vs
130
+
131
+ %w[ fpoint dbg ].each do |k|
132
+ a << " #{_c.dg}#{k}:#{m[k]}" if m.has_key?(k)
133
+ end
134
+
135
+ a << _c.rs
136
+
137
+ puts a.join
138
+ end
139
+
140
+ def self.print_src(src, opts={})
141
+
142
+ _c = colours(opts)
143
+
144
+ puts "#{_c.dg}+---#{_c.rs}"
145
+
146
+ puts "#{_c.dg}| #{opts.inspect}#{_c.rs}" if opts.any?
147
+
148
+ if src.is_a?(String)
149
+ src.split("\n").select { |l| l.strip.length > 0 }.each do |line|
150
+ puts "#{_c.dg}| #{_c.yl}#{line}#{_c.rs}"
151
+ end
152
+ else
153
+ ss = Flor.to_pretty_s(src).split("\n")
154
+ ss.each do |line|
155
+ puts "#{_c.dg}| #{_c.yl}#{line}#{_c.rs}"
156
+ end
157
+ end
158
+
159
+ puts "#{_c.dg}.#{_c.rs}"
160
+ end
161
+
162
+ def self.print_tree(tree, nid='0', opts={})
163
+
164
+ _c = colours(opts)
165
+
166
+ ind = ' ' * (opts[:ind] || 0)
167
+
168
+ headers = opts[:headers]; headers = true if headers.nil?
169
+ headers = true if opts[:title]
170
+
171
+ h = "#{_c.yl}#{Flor.s_to_d(tree[0], compact: true)}"
172
+ c = tree[1].is_a?(Array) ? '' : " #{_c.yl}#{tree[1]}"
173
+ l = " #{_c.dg}L#{tree[2]}"
174
+
175
+ puts "#{ind}#{_c.dg}+--- #{opts[:title]}#{_c.rs}" if headers && nid == '0'
176
+ puts "#{ind}#{_c.dg}| #{nid} #{h}#{c}#{l}#{_c.rs}"
177
+ if tree[1].is_a?(Array)
178
+ tree[1].each_with_index { |ct, i| print_tree(ct, "#{nid}_#{i}", opts) }
179
+ end
180
+ puts "#{ind}#{_c.dg}.#{_c.rs}" if headers && nid == '0'
181
+ end
182
+
183
+ def self.print_flat_tree(tree, nid, opts)
184
+
185
+ _c = colours(opts)
186
+
187
+ s = opts[:s]
188
+
189
+ s << ' ' << nid << ' ' << _c.yl << tree[0] << _c.dg
190
+
191
+ if tree[1].is_a?(Array)
192
+ tree[1].each_with_index do |t, i|
193
+ print_flat_tree(t, "#{nid}_#{i}", opts)
194
+ end
195
+ else
196
+ s << ' ' << tree[1]
197
+ end
198
+ end
199
+
200
+ def self.print_compact_tree(tree, nid='0', opts={})
201
+
202
+ _c = colours(opts)
203
+
204
+ is_root = opts[:s].nil?
205
+ ind = ' ' * (opts[:ind] || 0)
206
+
207
+ atts, natts =
208
+ tree[1].is_a?(Array) ?
209
+ tree[1].partition { |t| Flor.is_att_tree?(t) } :
210
+ [ [], [] ]
211
+
212
+ s = (opts[:s] ||= StringIO.new)
213
+
214
+ if t = opts.delete(:title)
215
+ s << ind << _c.dg << '+--- ' << t << "\n"
216
+ end
217
+
218
+ s << ind << _c.dg << '| ' << nid << ' '
219
+ s << _c.yl << Flor.s_to_d(tree[0], compact: true) << _c.dg << ' L' << tree[2]
220
+
221
+ atts.each_with_index do |ct, i|
222
+ print_flat_tree(ct, "_#{i}", opts)
223
+ end
224
+
225
+ natts.each_with_index do |ct, i|
226
+ i = atts.size + i
227
+ s << "\n"
228
+ print_compact_tree(ct, "#{nid}_#{i}", opts)
229
+ end
230
+
231
+ s << "\n" << ind << _c.dg << '\---' if is_root && opts[:close]
232
+
233
+ s << _c.rs
234
+
235
+ puts s.string if is_root
236
+ end
237
+
238
+ def self.ret_to_s(executor, m)
239
+
240
+ ret = (m['payload'] || {})['ret']
241
+ s = Flor.to_d(ret, compact: true)
242
+ l = s.length
243
+ l < 35 ? s : "#{s[0, 35]}(...L#{l})"
244
+ end
245
+
246
+ def self.nod_to_s(executor, n, opts, here=false)
247
+
248
+ _c = colours(opts)
249
+
250
+ t = n['tree'] || Node.new(executor, n, nil).lookup_tree(n['nid'])
251
+ t = Flor.to_d(t, compact: true) if t
252
+ t = t[0, 35] + '...' if t && t.length > 35
253
+
254
+ h = {}
255
+ %w[ parent cnid noreply dbg removed ].each do |k|
256
+ h[k] = n[k] if n.has_key?(k)
257
+ end
258
+
259
+ dbg = n['dbg'] ? "dbg:#{n['dbg']}" : nil
260
+ nr = n.has_key?('noreply') ? "nr:#{n['noreply']}" : nil
261
+ h = h.collect { |k, v| "#{k}:#{v}" }.join(' ')
262
+
263
+ vs = n['vars']
264
+ vs = 'vars:' + vs.keys.join(',') if vs
265
+ ts = n['tags']
266
+ ts = 'tags:' + ts.join(',') if ts
267
+
268
+ flr = n['failure'] ? "#{_c.rd}flre" : ''
269
+
270
+ here = here ? "#{_c.dg}<---msg['nid']" : nil
271
+
272
+ [ _c.yl + n['nid'], t, h, ts, vs, flr, here ].compact.join(' ')
273
+ end
274
+
275
+ def self.ncns_to_s(executor, ncn, msg, opts, sio, ind, seen)
276
+
277
+ n, cn = ncn
278
+ nid = n['nid']
279
+
280
+ return if seen.include?(nid)
281
+ seen << nid
282
+
283
+ sio.print(ind)
284
+ sio.print(nod_to_s(executor, n, opts, nid == msg['nid']))
285
+ sio.print("\n")
286
+ cn.each { |c| ncns_to_s(executor, c, msg, opts, sio, ind + ' ', seen) }
287
+ end
288
+
289
+ def self.nods_to_s(executor, msg, opts)
290
+
291
+ nodes = executor.execution['nodes'].values
292
+
293
+ nodes = nodes.inject({}) { |h, n| h[n['nid']] = [ n, [] ]; h }
294
+ nodes.values.each { |ncn|
295
+ pa = ncn.first['parent']; next unless pa
296
+ pan, pacn = nodes[pa]
297
+ pacn << ncn if pacn
298
+ }
299
+
300
+ sio = StringIO.new
301
+ seen = []
302
+ nodes.values.each do |ncn|
303
+ ncns_to_s(executor, ncn, msg, opts, sio, ' ', seen)
304
+ end
305
+
306
+ sio.string
307
+ end
308
+
309
+ def self.detail_msg(executor, m, opts={})
310
+
311
+ return if m['_detail_msg_flag']
312
+ m['_detail_msg_flag'] = true if opts[:flag]
313
+
314
+ _c = colours(opts)
315
+
316
+ nid = m['nid']
317
+ n = executor.execution['nodes'][nid]
318
+ node = n ? Flor::Node.new(executor, n, m) : nil
319
+
320
+ puts "#{_c.dg}<Flor.detail_msg>#{_c.rs}"
321
+ print "#{_c.yl}"
322
+ Kernel::pp(m)
323
+ puts "#{_c.dg}payload:#{_c.yl}"
324
+ Kernel::pp(m['payload'])
325
+ puts "#{_c.dg}tree:"
326
+ print_tree(node.lookup_tree(nid), nid) if node
327
+ puts "#{_c.dg}node:#{_c.yl}"
328
+ Kernel::pp(n) if n
329
+ puts "#{_c.dg}nodes:"
330
+ puts nods_to_s(executor, m, opts)
331
+ z = executor.execution['nodes'].size
332
+ puts "#{_c.yl}#{z} node#{z == 1 ? '' : 's'}."
333
+ puts "#{_c.dg}</Flor.detail_msg>#{_c.rs}"
334
+ end
335
+ end
336
+
@@ -0,0 +1,122 @@
1
+
2
+ Sequel.migration do
3
+
4
+ up do
5
+
6
+ create_table :flor_messages do
7
+
8
+ primary_key :id, type: :Bignum
9
+ String :domain, null: false
10
+ String :exid, null: false
11
+ String :point, null: false # 'execute', 'task', 'receive', 'schedule', ...
12
+ File :content # JSON
13
+ String :status, null: false
14
+ String :ctime, null: false
15
+ String :mtime, null: false
16
+
17
+ index :exid
18
+ end
19
+
20
+ create_table :flor_executions do
21
+
22
+ primary_key :id, type: :Bignum
23
+ String :domain, null: false
24
+ String :exid, null: false
25
+ File :content # JSON
26
+ String :status, null: false # 'active' or something else like 'archived'
27
+ String :ctime, null: false
28
+ String :mtime, null: false
29
+
30
+ index :exid
31
+ end
32
+
33
+ create_table :flor_timers do
34
+
35
+ primary_key :id, type: :Bignum
36
+ String :domain, null: false
37
+ String :exid, null: false
38
+ String :nid, null: false
39
+ String :type, null: false # 'at', 'in', 'cron', 'every', ...
40
+ String :schedule, null: false # '20141128.103239' or '00 23 * * *'
41
+ String :ntime # next time
42
+ File :content # JSON msg to trigger
43
+ Bignum :count, null: false
44
+ String :status, null: false
45
+ String :ctime, null: false
46
+ String :mtime, null: false
47
+
48
+ index :exid
49
+ index [ :exid, :nid ]
50
+ end
51
+
52
+ create_table :flor_traps do
53
+
54
+ primary_key :id, type: :Bignum
55
+ String :domain, null: false
56
+ String :exid, null: false
57
+ String :onid, null: false
58
+ String :nid, null: false
59
+ #
60
+ TrueClass :tconsumed, null: false, default: false
61
+ String :trange, null: false
62
+ String :tpoints, null: true
63
+ String :ttags, null: true
64
+ String :theats, null: true
65
+ String :theaps, null: true
66
+ #
67
+ File :content # JSON msg to trigger
68
+ #
69
+ String :status, null: false
70
+ String :ctime, null: false
71
+ String :mtime, null: false
72
+
73
+ index :exid
74
+ index [ :exid, :nid ]
75
+ end
76
+
77
+ create_table :flor_pointers do
78
+
79
+ primary_key :id, type: :Bignum
80
+ String :domain, null: false
81
+ String :exid, null: false
82
+ String :nid, null: false
83
+ String :type, null: false # task, tasked, tag, var
84
+ String :name, null: false # task name, tasked name, tag name, var name
85
+ String :value
86
+ String :ctime, null: false
87
+
88
+ # no :status, no :mtime
89
+
90
+ index :exid
91
+ index [ :exid, :nid ]
92
+ index [ :type, :name, :value ]
93
+
94
+ #unique [ :exid, :type, :name, :value ]
95
+ # we don't care, pointers are cleaned anyway when the flow dies
96
+ end
97
+
98
+ create_table :flor_traces do
99
+
100
+ primary_key :id, type: :Bignum
101
+ String :domain, null: false
102
+ String :exid, null: false
103
+ String :nid, null: true
104
+ String :tracer, null: false # 'executor', 'trace'
105
+ String :text, null: false # 'blah blah blah'
106
+ String :ctime, null: false
107
+
108
+ index :exid
109
+ end
110
+ end
111
+
112
+ down do
113
+
114
+ drop_table :flor_messages
115
+ drop_table :flor_executions
116
+ drop_table :flor_timers
117
+ drop_table :flor_traps
118
+ drop_table :flor_pointers
119
+ drop_table :flor_traces
120
+ end
121
+ end
122
+