patriot-workflow-scheduler 0.6.1
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.
- checksums.yaml +15 -0
- data/bin/patriot +8 -0
- data/bin/patriot-init +35 -0
- data/lib/patriot.rb +11 -0
- data/lib/patriot/command.rb +71 -0
- data/lib/patriot/command/base.rb +199 -0
- data/lib/patriot/command/command_group.rb +43 -0
- data/lib/patriot/command/command_macro.rb +141 -0
- data/lib/patriot/command/composite.rb +49 -0
- data/lib/patriot/command/parser.rb +78 -0
- data/lib/patriot/command/sh_command.rb +42 -0
- data/lib/patriot/controller.rb +2 -0
- data/lib/patriot/controller/package_controller.rb +81 -0
- data/lib/patriot/controller/worker_admin_controller.rb +159 -0
- data/lib/patriot/job_store.rb +66 -0
- data/lib/patriot/job_store/base.rb +159 -0
- data/lib/patriot/job_store/factory.rb +19 -0
- data/lib/patriot/job_store/in_memory_store.rb +252 -0
- data/lib/patriot/job_store/job.rb +118 -0
- data/lib/patriot/job_store/job_ticket.rb +30 -0
- data/lib/patriot/job_store/rdb_job_store.rb +353 -0
- data/lib/patriot/tool.rb +2 -0
- data/lib/patriot/tool/batch_parser.rb +102 -0
- data/lib/patriot/tool/patriot_command.rb +48 -0
- data/lib/patriot/tool/patriot_commands/execute.rb +92 -0
- data/lib/patriot/tool/patriot_commands/job.rb +62 -0
- data/lib/patriot/tool/patriot_commands/plugin.rb +41 -0
- data/lib/patriot/tool/patriot_commands/register.rb +77 -0
- data/lib/patriot/tool/patriot_commands/upgrade.rb +24 -0
- data/lib/patriot/tool/patriot_commands/validate.rb +84 -0
- data/lib/patriot/tool/patriot_commands/worker.rb +35 -0
- data/lib/patriot/tool/patriot_commands/worker_admin.rb +60 -0
- data/lib/patriot/util.rb +14 -0
- data/lib/patriot/util/config.rb +58 -0
- data/lib/patriot/util/config/base.rb +22 -0
- data/lib/patriot/util/config/inifile_config.rb +63 -0
- data/lib/patriot/util/cron_format_parser.rb +104 -0
- data/lib/patriot/util/date_util.rb +200 -0
- data/lib/patriot/util/db_client.rb +65 -0
- data/lib/patriot/util/db_client/base.rb +142 -0
- data/lib/patriot/util/db_client/hash_record.rb +53 -0
- data/lib/patriot/util/db_client/record.rb +25 -0
- data/lib/patriot/util/logger.rb +24 -0
- data/lib/patriot/util/logger/facade.rb +33 -0
- data/lib/patriot/util/logger/factory.rb +59 -0
- data/lib/patriot/util/logger/log4r_factory.rb +111 -0
- data/lib/patriot/util/logger/webrick_log_factory.rb +47 -0
- data/lib/patriot/util/param.rb +73 -0
- data/lib/patriot/util/retry.rb +30 -0
- data/lib/patriot/util/script.rb +52 -0
- data/lib/patriot/util/system.rb +120 -0
- data/lib/patriot/worker.rb +35 -0
- data/lib/patriot/worker/base.rb +153 -0
- data/lib/patriot/worker/info_server.rb +90 -0
- data/lib/patriot/worker/job_store_server.rb +32 -0
- data/lib/patriot/worker/multi_node_worker.rb +157 -0
- data/lib/patriot/worker/servlet.rb +23 -0
- data/lib/patriot/worker/servlet/job_servlet.rb +128 -0
- data/lib/patriot/worker/servlet/worker_status_servlet.rb +44 -0
- data/skel/batch/sample/daily/test.pbc +4 -0
- data/skel/config/patriot.ini +21 -0
- data/skel/public/css/bootstrap.css +2495 -0
- data/skel/public/css/original.css +54 -0
- data/skel/public/js/bootstrap-alerts.js +124 -0
- data/skel/public/js/bootstrap-buttons.js +64 -0
- data/skel/public/js/bootstrap-dropdown.js +55 -0
- data/skel/public/js/bootstrap-modal.js +260 -0
- data/skel/public/js/bootstrap-popover.js +90 -0
- data/skel/public/js/bootstrap-scrollspy.js +107 -0
- data/skel/public/js/bootstrap-tabs.js +80 -0
- data/skel/public/js/bootstrap-twipsy.js +321 -0
- data/skel/public/js/jquery-1.6.4.min.js +4 -0
- data/skel/public/templates/_jobs.erb +97 -0
- data/skel/public/templates/job.erb +119 -0
- data/skel/public/templates/jobs.erb +21 -0
- data/skel/public/templates/jobs_deleted.erb +6 -0
- data/skel/public/templates/layout.erb +103 -0
- data/skel/public/templates/state_updated.erb +6 -0
- metadata +235 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
MjRlNzEwZGJjMmY4MTRjMDU1NjBhYTg5OTRlNWYzYmUyZjQ5MWE3MQ==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
ZTA3YjNiN2JjMDczMjZkYWEzNTc3NWJhOWZjYmNkOTdhZTU1MzM5ZQ==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
ODY5NzRjNWZjYmU2MzU4N2E4M2U5YThlODRkN2I2NThlZjI3ZTUxYzcwZTg0
|
10
|
+
MDJmOGZhZTE5ZTE4ZWYzNWIwYzkyZmRhYTkwOTBmZWYxYWE0Mjg3YmQ1MWZl
|
11
|
+
ODgyMTljODVjNGU0ZmE5OTJlZGM5ODkxMzQ4MzIxY2I4ZmZjMGY=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
YzMzYmU3YzU3ZGQ5YWUxNGRmNTYyNmM0NTMwMzI4OWVhNDgyODFiNDZkZTI5
|
14
|
+
NmExNTNjOGI0NmY3YTNiYzE1MTk4N2NhYTYxNGExNDQyNWM5NzhmNDA3NmU1
|
15
|
+
ZTM1NzIwZmNhMDZlNGIwZmE5NjdkNzczMmM3MzI4Njg4NDcyMDY=
|
data/bin/patriot
ADDED
data/bin/patriot-init
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
target=ARGV[0]
|
5
|
+
unless File.exist?(target)
|
6
|
+
puts "directory #{target} does not exist"
|
7
|
+
Dir.mkdir(target)
|
8
|
+
end
|
9
|
+
base_dir = File.join(File.dirname(File.expand_path(__FILE__)), "..")
|
10
|
+
skel_dir = File.join(base_dir, "skel")
|
11
|
+
Dir.glob(File.join(skel_dir,"*")).each do |d|
|
12
|
+
if File.exist?(File.join(target, File.basename(d)))
|
13
|
+
puts "#{d} already exists"
|
14
|
+
else
|
15
|
+
puts "copy #{d} to #{target}"
|
16
|
+
FileUtils.cp_r(d, target)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
def mkdir_ifnot_exist(dir)
|
22
|
+
if File.exist?(dir)
|
23
|
+
puts "#{dir} already exist"
|
24
|
+
else
|
25
|
+
puts "mkdir #{dir}"
|
26
|
+
FileUtils.mkdir_p(dir)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
mkdir_ifnot_exist(File.join(target, "bin"))
|
31
|
+
FileUtils.cp(File.join(base_dir,"bin","patriot"),File.join(target,"bin","patriot"))
|
32
|
+
mkdir_ifnot_exist(File.join(target, "plugins"))
|
33
|
+
mkdir_ifnot_exist(File.join(target, "run"))
|
34
|
+
|
35
|
+
|
data/lib/patriot.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
# the root name space for this scheduler
|
2
|
+
module Patriot
|
3
|
+
# a name space for commands
|
4
|
+
module Command
|
5
|
+
# a parameter key for command class name (used in jobs)
|
6
|
+
COMMAND_CLASS_KEY = "COMMAND_CLASS"
|
7
|
+
|
8
|
+
# attribute name for required products
|
9
|
+
REQUISITES_ATTR = "requisites"
|
10
|
+
# attribute name for produced products
|
11
|
+
PRODUCTS_ATTR = "products"
|
12
|
+
# attribute name for job state
|
13
|
+
STATE_ATTR = "state"
|
14
|
+
# attribute name for job priority
|
15
|
+
PRIORITY_ATTR = "priority"
|
16
|
+
# attribute name for job execution node constraint
|
17
|
+
EXEC_NODE_ATTR = "exec_node"
|
18
|
+
# attribute name for job execution host constraint
|
19
|
+
EXEC_HOST_ATTR = "exec_host"
|
20
|
+
# attribute name for start time constraint
|
21
|
+
START_DATETIME_ATTR = "start_datetime"
|
22
|
+
# attribute name for the skip on fail marker
|
23
|
+
SKIP_ON_FAIL_ATTR = "skip_on_fail"
|
24
|
+
|
25
|
+
# a list of comman attributes
|
26
|
+
COMMON_ATTRIBUTES = [
|
27
|
+
REQUISITES_ATTR,
|
28
|
+
PRODUCTS_ATTR,
|
29
|
+
STATE_ATTR,
|
30
|
+
PRIORITY_ATTR,
|
31
|
+
EXEC_NODE_ATTR,
|
32
|
+
EXEC_HOST_ATTR,
|
33
|
+
START_DATETIME_ATTR,
|
34
|
+
SKIP_ON_FAIL_ATTR
|
35
|
+
]
|
36
|
+
|
37
|
+
# exit code of a command
|
38
|
+
module ExitCode
|
39
|
+
# successfully finished
|
40
|
+
SUCCEEDED = 0
|
41
|
+
# failed
|
42
|
+
FAILED = 1
|
43
|
+
# failed but skipped (marked skip_on_fail)
|
44
|
+
FAILURE_SKIPPED = 2
|
45
|
+
# skip (e.g., updated elsewhere)
|
46
|
+
SKIPPED = -1
|
47
|
+
|
48
|
+
# @param exit_code [Patriot::Command::ExitCode]
|
49
|
+
# @return [String] string expression of the exit code
|
50
|
+
def name_of(exit_code)
|
51
|
+
exit_code = exit_code.to_i
|
52
|
+
return case exit_code
|
53
|
+
when 0 then "SUCCEEDED"
|
54
|
+
when 1 then "FAILED"
|
55
|
+
when 2 then "FAILURE_SKIPPED"
|
56
|
+
when 4 then "FAILED" # for backward compatibility
|
57
|
+
else raise "unknown exit_code #{exit_code}"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
module_function :name_of
|
61
|
+
end
|
62
|
+
|
63
|
+
require 'patriot/command/parser'
|
64
|
+
require 'patriot/command/command_macro'
|
65
|
+
require 'patriot/command/base'
|
66
|
+
require 'patriot/command/command_group'
|
67
|
+
require 'patriot/command/composite'
|
68
|
+
require 'patriot/command/sh_command'
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
@@ -0,0 +1,199 @@
|
|
1
|
+
require 'active_support/core_ext/hash/deep_merge'
|
2
|
+
module Patriot
|
3
|
+
module Command
|
4
|
+
# The base class of every command.
|
5
|
+
# The command is an executable form of the job.
|
6
|
+
class Base
|
7
|
+
include Patriot::Command::Parser
|
8
|
+
include Patriot::Util::Param
|
9
|
+
include Patriot::Util::DateUtil
|
10
|
+
include Patriot::Util::Logger
|
11
|
+
|
12
|
+
class << self
|
13
|
+
include Patriot::Command::CommandMacro
|
14
|
+
end
|
15
|
+
|
16
|
+
attr_accessor :parser, :test_mode, :target_datetime
|
17
|
+
|
18
|
+
# comman attributes handled distinctively (only effective in top level commands)
|
19
|
+
volatile_attr :requisites, :products, :priority, :start_after, :exec_date, :exec_node, :exec_host, :skip_on_fail
|
20
|
+
|
21
|
+
# @param config [Patriot::Util::Config::Base] configuration for this command
|
22
|
+
def initialize(config)
|
23
|
+
@config = config
|
24
|
+
@logger = create_logger(config)
|
25
|
+
@param = {}
|
26
|
+
@requisites = []
|
27
|
+
@products = []
|
28
|
+
@macros = {}
|
29
|
+
@test_mode = false
|
30
|
+
end
|
31
|
+
|
32
|
+
# convert this to a job so that it can be stored to JobStore
|
33
|
+
# @return [Patriot::JobStore::Job] a job for this command.
|
34
|
+
def to_job
|
35
|
+
job = Patriot::JobStore::Job.new(self.job_id)
|
36
|
+
job.read_command(self)
|
37
|
+
return job
|
38
|
+
end
|
39
|
+
|
40
|
+
# get the value of an attribute
|
41
|
+
# @param attr_name [String] attribute name
|
42
|
+
# @return [Object] the value of the attribute specified with argument
|
43
|
+
def [](attr_name)
|
44
|
+
return instance_variable_get("@#{attr_name}".to_sym)
|
45
|
+
end
|
46
|
+
|
47
|
+
# build the identifier of the job for this command.
|
48
|
+
# This method should be overriden in sub-classes
|
49
|
+
# @return [String] the identifier of the job.
|
50
|
+
def job_id
|
51
|
+
raise NotImplementedError
|
52
|
+
end
|
53
|
+
|
54
|
+
# set default command name
|
55
|
+
# replace :: to handle in JSON format
|
56
|
+
# @return [String] a simplified command namd
|
57
|
+
def command_name
|
58
|
+
return self.class.to_s.split("::").last.downcase.gsub(/command/,"")
|
59
|
+
end
|
60
|
+
|
61
|
+
# add products required by this job.
|
62
|
+
# @param requisites [Array<String>] a list of products required by this job.
|
63
|
+
def require(requisites)
|
64
|
+
return if requisites.nil?
|
65
|
+
@requisites |= requisites.flatten
|
66
|
+
end
|
67
|
+
|
68
|
+
# add products produced by this job.
|
69
|
+
# @param products [Array<String>] a list of products produced by this job
|
70
|
+
def produce(products)
|
71
|
+
return if products.nil?
|
72
|
+
@products |= products.flatten
|
73
|
+
end
|
74
|
+
|
75
|
+
# mark this job to skip execution
|
76
|
+
def skip
|
77
|
+
param 'state' => Patriot::JobStore::JobState::SUCCEEDED
|
78
|
+
end
|
79
|
+
|
80
|
+
# mark this job to suspend execution
|
81
|
+
def suspend
|
82
|
+
param 'state' => Patriot::JobStore::JobState::SUSPEND
|
83
|
+
end
|
84
|
+
|
85
|
+
# mark this job to skip in case of failures
|
86
|
+
def skip_on_fail?
|
87
|
+
return @skip_on_fail == 'true' || @skip_on_fail == true
|
88
|
+
end
|
89
|
+
|
90
|
+
# @return [String] the target month in '%Y-%m'
|
91
|
+
def _month_
|
92
|
+
return @target_datetime.strftime("%Y-%m")
|
93
|
+
end
|
94
|
+
|
95
|
+
# @return [String] the target date in '%Y-%m-%d'
|
96
|
+
def _date_
|
97
|
+
return @target_datetime.strftime("%Y-%m-%d")
|
98
|
+
end
|
99
|
+
|
100
|
+
# @return [Integer] the tergat hour
|
101
|
+
def _hour_
|
102
|
+
return @target_datetime.hour
|
103
|
+
end
|
104
|
+
|
105
|
+
# start datetime of this command.
|
106
|
+
# This command should be executed after the return value of this method
|
107
|
+
# @return [DateTime]
|
108
|
+
def start_date_time
|
109
|
+
return nil if @exec_date.nil? && @start_after.nil?
|
110
|
+
# set tomorrow as default
|
111
|
+
date = (@exec_date || date_add(_date_, 1)).split("-").map(&:to_i)
|
112
|
+
# set midnight as default
|
113
|
+
time = (@start_after || "00:00:00").split(":").map(&:to_i)
|
114
|
+
return DateTime.new(date[0], date[1], date[2], time[0], time[1], time[2])
|
115
|
+
end
|
116
|
+
|
117
|
+
# update parameters with a given hash.
|
118
|
+
# If the hash includes keys which values have already been defined,
|
119
|
+
# the value for the key is replaced with the new value.
|
120
|
+
# @param _param [Hash] a hash from attribute name to its value
|
121
|
+
def param(_param)
|
122
|
+
@param = @param.deep_merge(_param)
|
123
|
+
end
|
124
|
+
|
125
|
+
# build this command as executables
|
126
|
+
# @param _param [Hash] default parameter
|
127
|
+
def build(_param={})
|
128
|
+
@param = _param.deep_merge(@param)
|
129
|
+
init_param
|
130
|
+
@start_datetime = start_date_time
|
131
|
+
cmds = configure()
|
132
|
+
cmds = [cmds] unless cmds.is_a?(Array)
|
133
|
+
cmds.each(&:validate_command_attrs)
|
134
|
+
return cmds.flatten
|
135
|
+
end
|
136
|
+
|
137
|
+
# initialize command attributes
|
138
|
+
def init_param
|
139
|
+
# set parameter value to instance variable
|
140
|
+
@param.each do |k,v|
|
141
|
+
raise "a reserved word #{k} is used as parameter name" if Patriot::Command::COMMAND_CLASS_KEY == k
|
142
|
+
raise "#{k} is already used in #{self.job_id}" unless instance_variable_get("@#{k}".to_sym).nil?
|
143
|
+
# don't evaluate here since all parameters are not set to instance variables
|
144
|
+
instance_variable_set("@#{k}".to_sym,v)
|
145
|
+
end
|
146
|
+
|
147
|
+
# evaluate command attributes using parameters (instance variables)
|
148
|
+
self.class.command_attrs.each { |a, d| configure_attr(a, d) }
|
149
|
+
end
|
150
|
+
protected :init_param
|
151
|
+
|
152
|
+
# configure a command attribute and set as an instance variable
|
153
|
+
# @param attr [String] an attribute name to be configured
|
154
|
+
# @param default_value default value of the attribute
|
155
|
+
def configure_attr(attr, default_value = nil)
|
156
|
+
v = instance_variable_get("@#{attr}".to_sym)
|
157
|
+
v = default_value if v.nil?
|
158
|
+
instance_variable_set("@#{attr}".to_sym, eval_attr(v))
|
159
|
+
end
|
160
|
+
|
161
|
+
# a hook method to implement comand-specific configuration
|
162
|
+
def configure
|
163
|
+
return self
|
164
|
+
end
|
165
|
+
|
166
|
+
# validate values of command attributes
|
167
|
+
# @see Patriot::Command::CommandMacro#validate_attr
|
168
|
+
def validate_command_attrs
|
169
|
+
self.class.validation_logics.each do |attr, logics|
|
170
|
+
val = self.instance_variable_get("@#{attr}".to_sym)
|
171
|
+
logics.each do |l|
|
172
|
+
unless l.call(self, attr, val)
|
173
|
+
raise "validation error : #{attr}=#{val} (#{self.class})"
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
# add a sub command
|
180
|
+
# @raise if sub command is not supported
|
181
|
+
def add_subcommand
|
182
|
+
raise "sub command is not supported"
|
183
|
+
end
|
184
|
+
|
185
|
+
# @return description of this command
|
186
|
+
def description
|
187
|
+
self.job_id
|
188
|
+
end
|
189
|
+
|
190
|
+
# execute this command
|
191
|
+
def execute()
|
192
|
+
raise NotImplementedError
|
193
|
+
end
|
194
|
+
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Patriot
|
2
|
+
module Command
|
3
|
+
# define a group of jobs
|
4
|
+
class CommandGroup < Base
|
5
|
+
declare_command_name :command_group
|
6
|
+
declare_command_name :job_group
|
7
|
+
attr_accessor :subcommands
|
8
|
+
|
9
|
+
# @see Patriot::Command::Base#initialize
|
10
|
+
def initialize(config)
|
11
|
+
super
|
12
|
+
@subcommands = []
|
13
|
+
end
|
14
|
+
|
15
|
+
# add a command to this group
|
16
|
+
# @param cmd [Patriot::Command::Base] a command to be added to this group
|
17
|
+
def add_subcommand(cmd)
|
18
|
+
@subcommands << cmd
|
19
|
+
end
|
20
|
+
|
21
|
+
# configure thie group.
|
22
|
+
# pass the required/produced products and parameters to the commands in this group
|
23
|
+
# @see Patriot::Command::Base#configure
|
24
|
+
# @return [Array<Patriot::Command::Base>] a list of commands in this group
|
25
|
+
def configure
|
26
|
+
return @subcommands.map{|cmd|
|
27
|
+
cmd.require @requisites
|
28
|
+
cmd.produce @products
|
29
|
+
cmd.build(@param)
|
30
|
+
}.flatten
|
31
|
+
end
|
32
|
+
|
33
|
+
# execute each command in this group
|
34
|
+
# @see Patriot::Command::Base#execute
|
35
|
+
def execute
|
36
|
+
@subcommands.each do |k,v|
|
37
|
+
v.execute
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
module Patriot
|
2
|
+
module Command
|
3
|
+
# macros to be used for implmentation of command classes
|
4
|
+
module CommandMacro
|
5
|
+
|
6
|
+
# add module methods to DSL methods
|
7
|
+
# @param command_module [Module] module defines methods for the use in DSL
|
8
|
+
def add_dsl_function(command_module)
|
9
|
+
class_eval{ include command_module }
|
10
|
+
end
|
11
|
+
|
12
|
+
# declare DSL method name for defining the command
|
13
|
+
# @param mth_name [String] the DSL method name
|
14
|
+
# @param parent_cls [Class] parent command to which the new command is added
|
15
|
+
# @param cmd_cls [Class]
|
16
|
+
def declare_command_name(mth_name, parent_cls=Patriot::Command::CommandGroup, cmd_cls=self)
|
17
|
+
parent_cls.class_eval do
|
18
|
+
define_method(mth_name) do |&cmd_def|
|
19
|
+
cmd = new_command(cmd_cls, &cmd_def)
|
20
|
+
add_subcommand(cmd)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# declare command attributes to be able to use in DSL
|
26
|
+
# @param attrs [String|Hash] attribute names or a Hash from attribute name to its default value
|
27
|
+
# @yield block to preprocess attribute values
|
28
|
+
# @yieldparam [Patriot::Command::Base] command instance
|
29
|
+
# @yieldparam [String] attribute name
|
30
|
+
# @yieldparam [String] passed value
|
31
|
+
def command_attr(*attrs, &blk)
|
32
|
+
@command_attrs = {} if @command_attrs.nil?
|
33
|
+
default_values = {}
|
34
|
+
if attrs.size == 1 && attrs[0].is_a?(Hash)
|
35
|
+
default_values = attrs[0]
|
36
|
+
attrs = default_values.keys
|
37
|
+
end
|
38
|
+
attrs.each do |a|
|
39
|
+
raise "a reserved word #{a} is used as parameter name" if Patriot::Command::COMMAND_CLASS_KEY == a
|
40
|
+
raise "#{a} is already defined" if self.instance_methods.include?(a)
|
41
|
+
@command_attrs[a] = default_values[a]
|
42
|
+
define_method(a) do |*args|
|
43
|
+
raise "illegal size of arguments (#{a} with #{args.inspect})" unless args.size == 1
|
44
|
+
val = args[0]
|
45
|
+
if block_given?
|
46
|
+
yield(self, a, val)
|
47
|
+
else
|
48
|
+
self.param a.to_s => val
|
49
|
+
end
|
50
|
+
end
|
51
|
+
attr_writer a
|
52
|
+
end
|
53
|
+
return attrs
|
54
|
+
end
|
55
|
+
|
56
|
+
# declare command attributes for only internal use
|
57
|
+
# @param attrs [String] attribute name
|
58
|
+
def private_command_attr(*attrs)
|
59
|
+
command_attr(*attrs) do |cmd, attr_name, attr_val|
|
60
|
+
raise "only internal call is expected for #{attr_name}"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# declare command attributes to be able to use in DSL
|
65
|
+
# values of thes attributes are supposed to be used in {Patriot::Command::Base#do_configure}
|
66
|
+
# and would not be serialized
|
67
|
+
# @param attrs [String|Hash] attribute names or a Hash from attribute name to its default value
|
68
|
+
# @yield block to preprocess attribute values
|
69
|
+
# @yieldparam [Patriot::Command::Base] command instance
|
70
|
+
# @yieldparam [String] attribute name
|
71
|
+
# @yieldparam [String] passed value
|
72
|
+
def volatile_attr(*attrs, &blk)
|
73
|
+
@volatile_attrs = [] if @volatile_attrs.nil?
|
74
|
+
attrs = command_attr(*attrs, &blk)
|
75
|
+
attrs.each do |a|
|
76
|
+
@volatile_attrs << a
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# @return [Hash] a Hash from attribute name to its value
|
81
|
+
def command_attrs
|
82
|
+
super_attrs = {}
|
83
|
+
if self.superclass.respond_to?(:command_attrs)
|
84
|
+
super_attrs = self.superclass.command_attrs
|
85
|
+
end
|
86
|
+
return super_attrs if @command_attrs.nil?
|
87
|
+
return super_attrs.merge(@command_attrs)
|
88
|
+
end
|
89
|
+
|
90
|
+
# @return [Array] a list of volatile attribute names
|
91
|
+
def volatile_attrs
|
92
|
+
super_attrs = []
|
93
|
+
if self.superclass.respond_to?(:volatile_attrs)
|
94
|
+
super_attrs = self.superclass.volatile_attrs
|
95
|
+
end
|
96
|
+
return super_attrs if @volatile_attrs.nil?
|
97
|
+
return @volatile_attrs | super_attrs
|
98
|
+
end
|
99
|
+
|
100
|
+
# @return [Array] a array of attribute names which should be inclued in Job
|
101
|
+
def serde_attrs
|
102
|
+
return command_attrs.keys - volatile_attrs
|
103
|
+
end
|
104
|
+
|
105
|
+
# validate attriubte value
|
106
|
+
# @param attrs attribute names to be validated
|
107
|
+
# @yield logic which validates the value
|
108
|
+
# @yieldreturn [Boolean] true if the value is valid, otherwise false
|
109
|
+
def validate_attr(*attrs, &blk)
|
110
|
+
raise "validation logic not given" unless block_given?
|
111
|
+
unless blk.arity == 3
|
112
|
+
raise "validation logic arguments should be (cmd, attr_name, attr_val)"
|
113
|
+
end
|
114
|
+
@validation_logics = {} if @validation_logics.nil?
|
115
|
+
attrs.each do |a|
|
116
|
+
raise "#{a} is not command attr" unless command_attrs.include?(a)
|
117
|
+
@validation_logics[a] = [] unless @validation_logics.has_key?(a)
|
118
|
+
@validation_logics[a] << blk
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
# check whether the attribute value is not nil
|
123
|
+
# @see {validate_attribute_value}
|
124
|
+
def validate_existence(*attrs)
|
125
|
+
validate_attr(*attrs) do |cmd, a, v|
|
126
|
+
!v.nil?
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
# @return [Hash] a hash from attribute name to validation logic (Process)
|
131
|
+
def validation_logics
|
132
|
+
super_logics = {}
|
133
|
+
if self.superclass.respond_to?(:volatile_attrs)
|
134
|
+
super_logics = self.superclass.validation_logics
|
135
|
+
end
|
136
|
+
return super_logics if @validation_logics.nil?
|
137
|
+
return super_logics.merge(@validation_logics)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|