patriot-workflow-scheduler 0.6.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|