abid 0.3.0.pre.alpha.3 → 0.3.0.pre.alpha.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -3
  3. data/abid.gemspec +1 -2
  4. data/exe/abidsc +1 -1
  5. data/lib/abid.rb +3 -30
  6. data/lib/abid/application.rb +83 -13
  7. data/lib/abid/cli/assume.rb +7 -8
  8. data/lib/abid/cli/list.rb +2 -2
  9. data/lib/abid/cli/migrate.rb +1 -1
  10. data/lib/abid/cli/revoke.rb +9 -10
  11. data/lib/abid/config.rb +2 -0
  12. data/lib/abid/dsl/abid_job.rb +58 -0
  13. data/lib/abid/dsl/actions.rb +36 -0
  14. data/lib/abid/dsl/job.rb +58 -0
  15. data/lib/abid/dsl/job_manager.rb +53 -0
  16. data/lib/abid/dsl/mixin.rb +52 -0
  17. data/lib/abid/dsl/params_spec.rb +64 -0
  18. data/lib/abid/dsl/play.rb +35 -0
  19. data/lib/abid/dsl/play_core.rb +354 -0
  20. data/lib/abid/dsl/rake_job.rb +41 -0
  21. data/lib/abid/dsl/syntax.rb +34 -0
  22. data/lib/abid/dsl/task.rb +53 -0
  23. data/lib/abid/engine.rb +36 -6
  24. data/lib/abid/engine/executor.rb +30 -48
  25. data/lib/abid/engine/process.rb +102 -68
  26. data/lib/abid/engine/process_manager.rb +72 -28
  27. data/lib/abid/engine/scheduler.rb +24 -30
  28. data/lib/abid/engine/waiter.rb +20 -30
  29. data/lib/abid/engine/worker_manager.rb +26 -60
  30. data/lib/abid/environment.rb +12 -27
  31. data/lib/abid/error.rb +2 -0
  32. data/lib/abid/params_format.rb +29 -12
  33. data/lib/abid/rake_extensions.rb +11 -3
  34. data/lib/abid/state_manager.rb +40 -0
  35. data/lib/abid/state_manager/state.rb +52 -114
  36. data/lib/abid/state_manager/state_service.rb +88 -0
  37. data/lib/abid/status.rb +63 -0
  38. data/lib/abid/version.rb +1 -1
  39. metadata +19 -32
  40. data/lib/Abidfile.rb +0 -1
  41. data/lib/abid/dsl_definition.rb +0 -29
  42. data/lib/abid/job.rb +0 -67
  43. data/lib/abid/job_manager.rb +0 -22
  44. data/lib/abid/mixin_task.rb +0 -29
  45. data/lib/abid/params_parser.rb +0 -50
  46. data/lib/abid/play.rb +0 -66
  47. data/lib/abid/play_core.rb +0 -53
  48. data/lib/abid/rake_extensions/task.rb +0 -41
  49. data/lib/abid/state_manager/database.rb +0 -40
  50. data/lib/abid/state_manager/state_proxy.rb +0 -65
  51. data/lib/abid/task.rb +0 -123
  52. data/lib/abid/task_manager.rb +0 -61
@@ -0,0 +1,58 @@
1
+ require 'forwardable'
2
+
3
+ module Abid
4
+ module DSL
5
+ # Common interface for RakeJob and AbidJob
6
+ class Job
7
+ extend Forwardable
8
+
9
+ def self.interface(name, args = [])
10
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
11
+ def #{name}(#{args.join(', ')})
12
+ raise NotImplementedError
13
+ end
14
+ RUBY
15
+ end
16
+ private_class_method :interface
17
+
18
+ interface :name
19
+ interface :arg_names
20
+ interface :worker
21
+ interface :prerequisites
22
+ interface :execute, %w(args)
23
+
24
+ interface :volatile?
25
+ interface :concerned?
26
+ interface :needed?
27
+
28
+ def initialize(task, params)
29
+ @task = task
30
+ @params = params
31
+ @options = task.application.options
32
+ end
33
+ attr_reader :task, :params, :options
34
+ def_delegators :task, :name, :arg_names
35
+
36
+ def trace_invoke
37
+ return unless @task.application.options.trace
38
+ @task.application.trace "** Invoke #{@task.name}"
39
+ end
40
+
41
+ def to_s
42
+ ParamsFormat.format_with_name(name, params)
43
+ end
44
+
45
+ def repair?
46
+ @options.repair
47
+ end
48
+
49
+ def dryrun?
50
+ @options.dryrun
51
+ end
52
+
53
+ def preview?
54
+ @options.preview
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,53 @@
1
+ require 'monitor'
2
+
3
+ module Abid
4
+ module DSL
5
+ # JobManager manages jobs.
6
+ class JobManager
7
+ def initialize(application)
8
+ @app = application
9
+ @tasks = Hash.new { |h, k| h[k] = {} }
10
+ @mon = Monitor.new
11
+ end
12
+
13
+ # Resolves params using params_spec and bind the task and resolved params.
14
+ # @param name [String,Symbol] task name
15
+ # @param params [Hash]
16
+ # @param scope [Rake::Scope]
17
+ # @return [Abid::DSL::TaskInstance]
18
+ def [](name, params = {}, scope = nil)
19
+ task = @app[name, scope]
20
+ resolved = resolve_params(task, params)
21
+ bind(task.name, resolved)
22
+ end
23
+
24
+ # Binds the task and params.
25
+ # @param name [String,Symbol] task name
26
+ # @param params [Hash]
27
+ # @return [Abid::DSL::TaskInstance]
28
+ def bind(name, params)
29
+ return @tasks[name][params] if @tasks[name][params]
30
+
31
+ @mon.synchronize do
32
+ @tasks[name][params.dup.freeze] ||= @app[name].bind(params)
33
+ end
34
+ end
35
+
36
+ def resolve_params(task, params)
37
+ ret = task.params_spec.each_with_object({}) do |(key, spec), h|
38
+ h[key] = fetch_param(task, key, spec, params, @app.global_params)
39
+ end
40
+ ParamsFormat.validate_params!(ret)
41
+ ret
42
+ end
43
+
44
+ def fetch_param(task, key, spec, *params_list)
45
+ found = params_list.find { |params| params.include?(key) }
46
+ return found[key] if found
47
+ return spec[:default] if spec.include?(:default)
48
+ raise "#{task.name}: param #{key} is not specified"
49
+ end
50
+ private :fetch_param
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,52 @@
1
+ require 'abid/dsl/play_core'
2
+
3
+ module Abid
4
+ module DSL
5
+ # `mixin` definition is evaluated in Mixin module context.
6
+ #
7
+ # mixin :foo do
8
+ # # this is evaluated in Mixin module context
9
+ # end
10
+ #
11
+ module Mixin
12
+ # Create new Mixin object.
13
+ # @param task [Rake::Task] owner task
14
+ def self.create(task)
15
+ mod = self
16
+ Module.new do
17
+ include mod
18
+ extend Mixin::ClassMethods
19
+ include task.application.global_mixin
20
+ extend helpers
21
+ self.task = task
22
+ end
23
+ end
24
+
25
+ # Create new global mixin.
26
+ # `global_mixin` does not include Application#global_mixin.
27
+ def self.create_global_mixin
28
+ Module.new do
29
+ include Mixin
30
+ extend Mixin::ClassMethods
31
+ end
32
+ end
33
+
34
+ include PlayCore
35
+
36
+ module ClassMethods
37
+ include PlayCore::ClassMethods
38
+
39
+ def included(obj)
40
+ return unless obj.is_a? PlayCore::ClassMethods
41
+ merge_helpers(obj)
42
+ end
43
+
44
+ def merge_helpers(obj)
45
+ my_helpers = helpers
46
+ obj.helpers.module_eval { include my_helpers }
47
+ obj.extend(obj.helpers) # re-extend by helpers
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,64 @@
1
+ module Abid
2
+ module DSL
3
+ # ParamsSpec manages params specifications declared in a play definition.
4
+ #
5
+ # Ancestors' params_spec are inherited.
6
+ class ParamsSpec
7
+ include Enumerable
8
+
9
+ attr_reader :specs
10
+ protected :specs
11
+
12
+ def initialize(play_class)
13
+ @play_class = play_class
14
+ @specs = {}
15
+ end
16
+
17
+ # @param key [Symbol] param name
18
+ # @return [Hash] param specification
19
+ def [](key)
20
+ @play_class.superplays.each do |sp|
21
+ h = sp.params_spec.specs
22
+ return h[key] if h.include?(key)
23
+ end
24
+ nil
25
+ end
26
+
27
+ # @param key [Symbol] param name
28
+ # @param val [Hash] param specification
29
+ def []=(key, val)
30
+ @specs[key] = val
31
+ end
32
+
33
+ # Mark given param as deleted.
34
+ # It does not affect ancestors' params_spec.
35
+ # @param key [Symbol] param name
36
+ def delete(key)
37
+ val = self[key]
38
+ @specs[key] = nil
39
+ val
40
+ end
41
+
42
+ # @yield [key, val] param name and spec
43
+ def each(&block)
44
+ to_h.each(&block)
45
+ end
46
+
47
+ def to_h
48
+ h = {}
49
+ @play_class.superplays.reverse.each do |sp|
50
+ h.update(sp.params_spec.specs)
51
+ end
52
+ h.reject { |_, v| v.nil? }
53
+ end
54
+
55
+ def inspect
56
+ to_h.inspect
57
+ end
58
+
59
+ def to_s
60
+ to_h.to_s
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,35 @@
1
+ require 'abid/dsl/play_core'
2
+
3
+ module Abid
4
+ module DSL
5
+ # `play` definition is evaluated in Play class context.
6
+ #
7
+ # play :foo do
8
+ # # this is evaluated in Play class context
9
+ # end
10
+ #
11
+ class Play
12
+ def self.create(task)
13
+ Class.new(self) do
14
+ include task.application.global_mixin
15
+ extend helpers
16
+ self.task = task
17
+ end
18
+ end
19
+
20
+ include PlayCore
21
+ extend PlayCore::ClassMethods
22
+
23
+ def initialize(params)
24
+ @params = params
25
+ @prerequisite_tasks = []
26
+ end
27
+
28
+ # default settings
29
+ worker :default
30
+ volatile false
31
+ set :concerned, true
32
+ set :needed, true
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,354 @@
1
+ module Abid
2
+ module DSL
3
+ # Common methods for Play and Mixin
4
+ module PlayCore
5
+ attr_reader :prerequisite_tasks
6
+ attr_reader :params
7
+
8
+ # Declared prerequisite tasks.
9
+ #
10
+ # play :foo do
11
+ # setup do
12
+ # needs :TASK_NAME, bar: 0
13
+ # end
14
+ # end
15
+ #
16
+ # @param task_name [Symbol, String] task name
17
+ # @param params [Hash] task params
18
+ def needs(task_name, **params)
19
+ t = task.application[task_name, @scope_in_actions]
20
+ (@prerequisite_tasks ||= []) << [t, self.params.merge(params)]
21
+ end
22
+
23
+ def run
24
+ # noop
25
+ end
26
+
27
+ def task
28
+ self.class.task
29
+ end
30
+
31
+ # Evaluates each actions in the task scope where the action is declared.
32
+ # @param tag [Symbol] action name
33
+ # @param args [Array] arguments
34
+ def call_action(tag, *args)
35
+ self.class.actions[tag].each do |scope, block|
36
+ @scope_in_actions = scope
37
+ instance_exec(*args, &block)
38
+ end
39
+ ensure
40
+ @scope_in_actions = nil
41
+ end
42
+
43
+ # @!visibility private
44
+ def eval_setting(value = nil, &block)
45
+ return instance_exec(&value) if value.is_a? Proc
46
+ return value unless value.nil?
47
+ return instance_exec(&block) if block_given?
48
+ true
49
+ end
50
+ private :eval_setting
51
+
52
+ def logger
53
+ task.application.logger
54
+ end
55
+
56
+ def preview?
57
+ task.application.options.dryrun || task.application.options.preview
58
+ end
59
+
60
+ # Play definition's body is extended by ClassMethods.
61
+ #
62
+ module ClassMethods
63
+ attr_accessor :task
64
+ private :task=
65
+
66
+ # Task params specification.
67
+ def params_spec
68
+ @params_spec ||= ParamsSpec.new(self)
69
+ end
70
+
71
+ # Actions include `setup` blocks and `after` blocks.
72
+ #
73
+ # play :foo do
74
+ # setup { 'this block is added to actions[:setup]' }
75
+ # after { ... }
76
+ # end
77
+ def actions
78
+ @actions ||= Actions.new(self)
79
+ end
80
+
81
+ # Define helper methods.
82
+ #
83
+ # play :foo do
84
+ # helpers do
85
+ # def country
86
+ # :jp
87
+ # end
88
+ # end
89
+ #
90
+ # today #=> :jp
91
+ # end
92
+ #
93
+ # `helpers` block is evaluated in the helpers module context, which
94
+ # extends the play class.
95
+ #
96
+ # If no block given, it returns the helper module.
97
+ #
98
+ # @return [Module] helpers module
99
+ def helpers(*extensions, &block)
100
+ @helpers ||= Module.new
101
+ @helpers.module_eval(&block) if block_given?
102
+ @helpers.module_eval { include(*extensions) } if extensions.any?
103
+ @helpers
104
+ end
105
+
106
+ # Declared setting.
107
+ #
108
+ # play :foo do
109
+ # set :first_name, 'Taro'
110
+ # set :family_name, 'Yamada'
111
+ # set :full_name, -> { first_name + ' ' + family_name }
112
+ #
113
+ # def run
114
+ # full_name #=> 'Taro Yamada'
115
+ # end
116
+ # end
117
+ #
118
+ # Settings are defiend as an intance methods of the play.
119
+ #
120
+ # If a param is declared with the same name of the setting, the param is
121
+ # undefined.
122
+ #
123
+ # mixin :bar do
124
+ # param :country
125
+ # end
126
+ #
127
+ # play :baz do
128
+ # include :bar
129
+ # set :country, :jp
130
+ #
131
+ # params_spec #=> {}
132
+ # end
133
+ #
134
+ # When block is given, it is lazily evaluated in the play context.
135
+ def set(name, value = nil, &block)
136
+ var = :"@#{name}"
137
+
138
+ params_spec.delete(name) # undef param
139
+ define_method(name) do
140
+ unless instance_variable_defined?(var)
141
+ val = eval_setting(value, &block)
142
+ instance_variable_set(var, val)
143
+ end
144
+ instance_variable_get(var)
145
+ end
146
+ end
147
+
148
+ # Declare task param.
149
+ #
150
+ # play :foo do
151
+ # param :city
152
+ # param :country, default: 'Japan'
153
+ #
154
+ # params_spec # => { city: {}, country: { default: 'Japan'} }
155
+ #
156
+ # def run
157
+ # puts "#{city}, #{country}"
158
+ # end
159
+ # end
160
+ #
161
+ # $ abid foo city=Tokyo
162
+ # Tokyo, Japan
163
+ #
164
+ # An instance method of the same name is defined.
165
+ #
166
+ # @param name [Symbol] param name
167
+ # @param spec [Hash] specification
168
+ # @option spec [Object] :default default value
169
+ def param(name, **spec)
170
+ define_method(name) do
171
+ raise NoParamError, "undefined param `#{name}' for #{task.name}" \
172
+ unless params.include?(name)
173
+ params[name]
174
+ end
175
+ params_spec[name] = spec
176
+ end
177
+
178
+ #
179
+ # Setting Helpers
180
+ #
181
+
182
+ # @!visibility private
183
+ def self.def_setting_helper(name)
184
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
185
+ def #{name}(val = nil, &block)
186
+ set :#{name}, val, &block
187
+ end
188
+ RUBY
189
+ end
190
+
191
+ # @!method worker(val = nil, &block)
192
+ # Set :worker name.
193
+ #
194
+ # play :foo do
195
+ # worker :my_worker
196
+ # action { ... }
197
+ # end
198
+ #
199
+ # This is short-hand style of `set :worker, :my_worker`
200
+ def_setting_helper :worker
201
+
202
+ # @!method volatile(val = nil, &block)
203
+ # Set :volatile flag.
204
+ #
205
+ # play :foo do
206
+ # volatile
207
+ # action { ... }
208
+ # end
209
+ #
210
+ # This is short-hand style of `set :volatile, true`
211
+ def_setting_helper :volatile
212
+
213
+ # Delete the param from params_spec.
214
+ #
215
+ # mixin :bar do
216
+ # param :country
217
+ # end
218
+ #
219
+ # play :baz do
220
+ # include :bar
221
+ #
222
+ # params_spec #=> { country: {} }
223
+ #
224
+ # undef_param :country
225
+ # params_spec #=> {}
226
+ # end
227
+ def undef_param(name)
228
+ params_spec.delete(name)
229
+ end
230
+
231
+ #
232
+ # Actions
233
+ #
234
+
235
+ # @!visibility :private
236
+ def self.define_action(name)
237
+ define_method(name) do |&block|
238
+ actions.add(name, task.scope, block)
239
+ end
240
+ end
241
+
242
+ # @!method setup(&block)
243
+ # Register _setup_ action.
244
+ #
245
+ # Setup action is called before #run.
246
+ # All prerequisites should be declared inside the setup blocks.
247
+ #
248
+ # play :foo do
249
+ # setup do
250
+ # needs :bar
251
+ # puts 'Setup!'
252
+ # end
253
+ #
254
+ # def run
255
+ # puts 'Running!'
256
+ # end
257
+ # end
258
+ #
259
+ # $ abid foo
260
+ # ... (:bar is executed)
261
+ # Setup!
262
+ # Running!
263
+ define_action :setup
264
+
265
+ # @!method action(&block)
266
+ # Register main action.
267
+ #
268
+ # play :foo do
269
+ # action { |args| ... }
270
+ # end
271
+ #
272
+ # `action` block is not executed in dryrun mode nor preview mode.
273
+ #
274
+ # Main actions of mixis are inherited to play, while `run` method is
275
+ # overwritten.
276
+ #
277
+ # @yieldparam args [Rake::TaskArguments]
278
+ define_action :action
279
+
280
+ # @!method safe_action(&block)
281
+ # Register safe action.
282
+ # `safe_action` is similar to `action`, but this block is executed
283
+ # in preview mode.
284
+ #
285
+ # You should guard dangerous operations in a safe_action block.
286
+ # This is useful to preview detail behavior of play.
287
+ #
288
+ # @yieldparam args [Rake::TaskArguments]
289
+ define_action :safe_action
290
+
291
+ # @!method after(&block)
292
+ # Register _after_ action.
293
+ #
294
+ # After action is called after #run.
295
+ #
296
+ # play :foo do
297
+ # def run
298
+ # ...
299
+ # end
300
+ #
301
+ # after do |error|
302
+ # next if error.nil?
303
+ # $syserr.puts "[ERROR] #{task.name} failed:"
304
+ # $syserr.puts "[ERROR] #{error}"
305
+ # end
306
+ # end
307
+ #
308
+ # `after` block is not executed in dryrun mode nor preview mode.
309
+ #
310
+ # @yieldparam error [StandardError, nil] if run method failed,
311
+ # otherwise nil.
312
+ define_action :after
313
+
314
+ # Include mixins.
315
+ #
316
+ # All methods, actions, settings and params_spec are inherited.
317
+ #
318
+ # mixin :foo do
319
+ # param :country
320
+ # end
321
+ #
322
+ # play :bar do
323
+ # include :bar
324
+ # params_spec #=> { country: {} }
325
+ # end
326
+ #
327
+ # When Module objects are given, it includes them as usual.
328
+ #
329
+ # @param mod [Array<Symbol, String, Module>] mixin name or module.
330
+ def include(*mod)
331
+ ms = mod.map { |m| resolve_mixin(m) }
332
+ super(*ms)
333
+ end
334
+ private :include
335
+
336
+ # @!visibility private
337
+ def resolve_mixin(mod)
338
+ return mod if mod.is_a? Module
339
+
340
+ mixin_task = task.application[mod.to_s, task.scope]
341
+ raise "#{mod} is not a mixin" unless mixin_task.is_a? MixinTask
342
+
343
+ mixin_task.internal
344
+ end
345
+ private :resolve_mixin
346
+
347
+ # Return a list of Mixin objects included.
348
+ def superplays
349
+ ancestors.select { |o| o.is_a? PlayCore::ClassMethods }
350
+ end
351
+ end
352
+ end
353
+ end
354
+ end