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
@@ -0,0 +1,191 @@
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
+ module Flor
26
+
27
+ class Tasker
28
+
29
+ # NB: tasker configuration entries start with "tsk_"
30
+
31
+ def initialize(unit)
32
+
33
+ @unit = unit
34
+ end
35
+
36
+ def shutdown
37
+ end
38
+
39
+ def has_tasker?(exid, name)
40
+
41
+ domain = exid.split('-', 2).first
42
+
43
+ !! @unit.loader.tasker(domain, name)
44
+ end
45
+
46
+ def task(message)
47
+
48
+ domain = message['exid'].split('-', 2).first
49
+ tname = message['tasker']
50
+
51
+ tconf =
52
+ @unit.loader.tasker(domain, 'tasker') ||
53
+ @unit.loader.tasker(domain, tname)
54
+ #
55
+ # FIXME tasker tasker tasker lookup loop?
56
+
57
+ fail ArgumentError.new(
58
+ "tasker #{tname.inspect} not found"
59
+ ) unless tconf
60
+
61
+ message['tconf'] = tconf \
62
+ unless tconf['on_task']['include_tconf'] == false
63
+
64
+ message['vars'] = gather_vars(tconf, message)
65
+
66
+ cot = tconf['on_task']
67
+
68
+ return ruby_task(message, tconf) if cot['require'] || cot['class']
69
+ return cmd_task(message, tconf) if cot['cmd']
70
+
71
+ fail ArgumentError.new(
72
+ "don't know how to use tasker at #{tconf['_path']}"
73
+ )
74
+ end
75
+
76
+ def cancel(tasker_name, fei)
77
+
78
+ # TODO use on_cancel || on_task
79
+
80
+ fail NotImplementedError
81
+ end
82
+
83
+ def reply(message)
84
+
85
+ @unit.queue({
86
+ 'point' => 'return',
87
+ 'exid' => message['exid'],
88
+ 'nid' => message['nid'],
89
+ 'payload' => message['payload'],
90
+ 'tasker' => message['tasker'] })
91
+ end
92
+
93
+ protected
94
+
95
+ def is_a_message_array?(o)
96
+
97
+ o.is_a?(Array) &&
98
+ o.first.is_a?(Hash) &&
99
+ o.first['point'].is_a?(String)
100
+ end
101
+
102
+ def ruby_task(message, tconf)
103
+
104
+ root = File.dirname(tconf['_path'])
105
+
106
+ Array(tconf['on_task']['require'])
107
+ .each { |pa|
108
+ fail ArgumentError.new('".." not allowed in paths') if pa =~ /\.\./
109
+ require(File.join(root, pa)) }
110
+ Array(tconf['on_task']['load'])
111
+ .each { |pa|
112
+ fail ArgumentError.new('".." not allowed in paths') if pa =~ /\.\./
113
+ load(File.join(root, pa)) }
114
+
115
+ k = tconf['on_task']['class']
116
+ k = Flor.const_lookup(k)
117
+
118
+ tasker = k.new(self, tconf)
119
+
120
+ r =
121
+ if message['point'] == 'detask'
122
+ tasker.cancel(message)
123
+ else
124
+ tasker.task(message)
125
+ end
126
+
127
+ # if the tasker returns something intelligible, use it
128
+ # else reply with "nothing further to do" (empty message array)
129
+
130
+ if is_a_message_array?(r)
131
+ r
132
+ else
133
+ []
134
+ end
135
+ end
136
+
137
+ def cmd_task(message, tconf)
138
+
139
+ fail NotImplementedError
140
+
141
+ []
142
+ end
143
+
144
+ def var_match(k, filter)
145
+
146
+ filter.each { |f| return true if (f.is_a?(String) ? k == f : f.match(k)) }
147
+ false
148
+ end
149
+
150
+ def expand_filter(f)
151
+
152
+ return f unless f.is_a?(Array)
153
+
154
+ f.collect { |e|
155
+ if e.is_a?(String)
156
+ e
157
+ elsif e.is_a?(Array) && e[0] == '_rxs' && e[1].is_a?(String)
158
+
159
+ s = e[1]
160
+ li, ri = s.index('/'), s.rindex('/')
161
+ tail = s[ri + 1..-1]
162
+ ops =
163
+ (tail.index('i') ? Regexp::IGNORECASE : 0) |
164
+ (tail.index('x') ? Regexp::EXTENDED : 0)
165
+ Regexp.new(s[li + 1..ri - 1], ops)
166
+ else
167
+ nil
168
+ end
169
+ }.compact
170
+ end
171
+
172
+ def gather_vars(tconf, message)
173
+
174
+ iv = expand_filter(tconf['on_task']['include_vars'])
175
+ ev = expand_filter(tconf['on_task']['exclude_vars'])
176
+
177
+ return nil unless iv || ev
178
+
179
+ vars = @unit.executor(message['exid']).vars(message['nid'])
180
+
181
+ return vars if iv == true
182
+ return {} if ev == true
183
+
184
+ vars = vars.select { |k, v| var_match(k, iv) } if iv
185
+ vars = vars.reject { |k, v| var_match(k, ev) } if ev
186
+
187
+ vars
188
+ end
189
+ end
190
+ end
191
+
@@ -0,0 +1,146 @@
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
+ module Flor
26
+
27
+ class Waiter
28
+
29
+ DEFAULT_TIMEOUT = 4 # seconds
30
+
31
+ def initialize(exid, opts)
32
+
33
+ serie, timeout, repeat = expand_args(opts)
34
+
35
+ @exid = exid
36
+ @original_serie = repeat ? Flor.dup(serie) : nil
37
+ @serie = serie
38
+ @timeout = timeout == true ? DEFAULT_TIMEOUT : timeout
39
+
40
+ @queue = []
41
+ @mutex = Mutex.new
42
+ @var = ConditionVariable.new
43
+ end
44
+
45
+ def to_s
46
+
47
+ "#{super[0..-2]}#{
48
+ { exid: @exid,
49
+ original_serie: @original_serie,
50
+ timeout: @timeout }.inspect
51
+ }>"
52
+ end
53
+
54
+ def notify(executor, message)
55
+
56
+ @mutex.synchronize do
57
+
58
+ return false unless match?(message)
59
+
60
+ @serie.shift
61
+ return false unless @serie.empty?
62
+
63
+ @queue << [ executor, message ]
64
+ @var.signal
65
+ end
66
+
67
+ # then...
68
+ # returning false: do not remove me, I want to listen/wait further
69
+ # returning true: remove me
70
+
71
+ return true unless @original_serie
72
+
73
+ @serie = Flor.dup(@original_serie) # reset serie
74
+
75
+ false # do not remove me
76
+ end
77
+
78
+ def wait
79
+
80
+ @mutex.synchronize do
81
+
82
+ if @queue.empty?
83
+
84
+ @var.wait(@mutex, @timeout)
85
+ # will wait "in aeternum" if @timeout is nil
86
+
87
+ fail(RuntimeError, "timeout for #{self.to_s}") if @queue.empty?
88
+ end
89
+
90
+ executor, message = @queue.shift
91
+
92
+ message
93
+ end
94
+ end
95
+
96
+ protected
97
+
98
+ def match?(message)
99
+
100
+ return false if @exid && @exid != message['exid']
101
+
102
+ nid, points = @serie.first
103
+ return false if nid && message['nid'] && nid != message['nid']
104
+ return false if ! points.include?(message['point'])
105
+
106
+ true
107
+ end
108
+
109
+ def expand_args(opts)
110
+
111
+ owait = opts[:wait]
112
+ orepeat = opts[:repeat] || false
113
+ otimeout = opts[:timeout] || DEFAULT_TIMEOUT
114
+
115
+ case owait
116
+ when true
117
+ [ [ [ nil, %w[ failed terminated ] ] ], # serie
118
+ otimeout,
119
+ orepeat ]
120
+ when Numeric
121
+ [ [ [ nil, %w[ failed terminated ] ] ], # serie
122
+ owait, # timeout
123
+ orepeat ]
124
+ when String, Array
125
+ [ parse_serie(owait), # serie
126
+ otimeout,
127
+ orepeat ]
128
+ else
129
+ fail ArgumentError.new(
130
+ "don't know how to deal with #{owait.inspect} (#{owait.class})")
131
+ end
132
+ end
133
+
134
+ def parse_serie(s)
135
+
136
+ return s if s.is_a?(Array) && s.collect(&:class).uniq == [ Array ]
137
+
138
+ (s.is_a?(String) ? s.split(';') : s)
139
+ .collect { |s|
140
+ ni, pt = s.strip.match(/\A([0-9_\-]+)? *([a-z|, ]+)\z/)[1, 2]
141
+ [ ni, pt.split(/[|,]/).collect(&:strip) ]
142
+ }
143
+ end
144
+ end
145
+ end
146
+
@@ -0,0 +1,77 @@
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
+ module Flor
26
+
27
+ class WaitList
28
+
29
+ def initialize(unit)
30
+
31
+ @unit = unit
32
+
33
+ @mutex = Mutex.new
34
+ @waiters = []
35
+
36
+ @unit.instance_eval do
37
+ def wait(exid, opts=true)
38
+ @hooker['wlist'].wait(exid, opts)
39
+ end
40
+ end
41
+ end
42
+
43
+ def shutdown
44
+ end
45
+
46
+ def notify(executor, message)
47
+
48
+ @mutex.synchronize do
49
+
50
+ to_remove = []
51
+
52
+ @waiters.each do |w|
53
+ remove = w.notify(executor, message)
54
+ to_remove << w if remove
55
+ end
56
+
57
+ @waiters -= to_remove
58
+
59
+ end if message['consumed']
60
+
61
+ [] # no new messages
62
+ end
63
+
64
+ def wait(exid, opts)
65
+
66
+ opts = { wait: opts } if opts.is_a?(String) || opts == true
67
+
68
+ @mutex.synchronize do
69
+
70
+ (@waiters << Waiter.new(exid, opts)).last
71
+
72
+ end.wait
73
+ # returns the response message
74
+ end
75
+ end
76
+ end
77
+
data/lib/flor/unit.rb ADDED
@@ -0,0 +1,50 @@
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 'sequel'
26
+ require 'sequel/extensions/migration'
27
+
28
+ require 'fugit'
29
+
30
+ require 'flor'
31
+ require 'flor/unit/hooker'
32
+ require 'flor/unit/wlist'
33
+ require 'flor/unit/logger'
34
+ require 'flor/unit/journal'
35
+ require 'flor/unit/storage'
36
+ require 'flor/unit/executor'
37
+ require 'flor/unit/waiter'
38
+ require 'flor/unit/scheduler'
39
+ require 'flor/unit/models'
40
+ require 'flor/unit/loader'
41
+ require 'flor/unit/tasker'
42
+
43
+ Flor.load_procedures('punit')
44
+
45
+ module Flor
46
+
47
+ Unit = Scheduler
48
+ # an alias
49
+ end
50
+
data/lib/flor.rb CHANGED
@@ -1,6 +1,5 @@
1
-
2
1
  #--
3
- # Copyright (c) 2015-2015, John Mettraux, jmettraux+flon@gmail.com
2
+ # Copyright (c) 2015-2017, John Mettraux, jmettraux+flor@gmail.com
4
3
  #
5
4
  # Permission is hereby granted, free of charge, to any person obtaining a copy
6
5
  # of this software and associated documentation files (the "Software"), to deal
@@ -23,9 +22,47 @@
23
22
  # Made in Japan.
24
23
  #++
25
24
 
25
+ require 'pp'
26
+ require 'json'
27
+ require 'logger'
28
+ require 'thread'
29
+ require 'digest'
30
+
31
+ require 'munemo'
32
+ require 'raabro'
33
+
26
34
 
27
35
  module Flor
28
36
 
29
- VERSION = '0.0.1'
37
+ VERSION = '0.9.0'
30
38
  end
31
39
 
40
+ require 'flor/colours'
41
+
42
+ require 'flor/log'
43
+ require 'flor/flor'
44
+ require 'flor/dollar'
45
+ require 'flor/errors'
46
+ require 'flor/parser'
47
+ require 'flor/conf'
48
+ require 'flor/to_string'
49
+
50
+ require 'flor/core'
51
+ require 'flor/core/node'
52
+ require 'flor/core/procedure'
53
+ require 'flor/core/executor'
54
+ require 'flor/core/texecutor'
55
+
56
+ Flor.load_procedures('pcore')
57
+
58
+
59
+ #if RUBY_PLATFORM.match(/java/)
60
+ # class Array
61
+ # alias original_collect collect
62
+ # def collect(&block)
63
+ #puts caller[0] + " <---"
64
+ # original_collect(&block)
65
+ # end
66
+ # end
67
+ #end
68
+