Class: DTK::Client::CommandBaseThor
- Extended by:
- CommandBase, CommonOptionDefs::ClassMixin, Console, TaskStatusMixin
- Includes:
- CommandBase, CommandHelperMixin, Poller
- Defined in:
- lib/parser/adapters/thor.rb,
lib/parser/adapters/thor/common_option_defs.rb
Direct Known Subclasses
Account, Assembly, Attribute, Component, ComponentModule, ComponentTemplate, Dependency, Developer, Dtk, Library, Node, NodeTemplate, Project, Provider, Remotes, Service, ServiceModule, StateChange, Target, Task, TestModule, Utils, Workspace
Defined Under Namespace
Modules: CommonOptionDefs
Constant Summary collapse
- TIME_DIFF =
second(s)
60
- EXTENDED_TIMEOUT =
second(s)
360
- HIDE_FROM_BASE_CONTEXT =
"HIDE_FROM_BASE"
- ALT_IDENTIFIER_SEPARATOR =
thor command specific constants
':::'
- @@cached_response =
{}
- @@invalidate_map =
[]
Constants included from CommandHelperMixin
DTK::Client::CommandHelperMixin::Loaded
Constants included from ReparseMixin
ReparseMixin::YamlDTKMetaFiles
Constants included from Poller
Constants inherited from Thor
Thor::HIDE_FROM_BASE_CONTEXT_HELP
Class Method Summary collapse
-
.action_on_revalidation_response(validation_response, conn, method_name, context_params, thor_options, shell_execution) ⇒ Object
TODO: Make sure that server responds with new format of ARGVS.
-
.basename ⇒ Object
This is fix where we wanna exclude basename print when using dtk-shell.
- .create_context_arguments(params) ⇒ Object
- .execute_from_cli(conn, method_name, context_params, thor_options, shell_execution = false) ⇒ Object
- .generate_cached_id(subtype) ⇒ Object
-
.get_cached_response(entity_name, url, subtype = {}) ⇒ Object
we take current timestamp and compare it to timestamp stored in @@cached_response if difference is greater than TIME_DIFF we send request again, if not we use response from cache.
- .get_identifiers(conn, context_params) ⇒ Object
- .get_usage_info(entity_name, method) ⇒ Object
- .invalidate_entities(*array_of_entites) ⇒ Object
-
.invisible_context_list(sufix = 'identifier') ⇒ Object
Returns list of invisible contexts with sufix provided (if any).
- .list_method_supported? ⇒ Boolean
-
.task_names ⇒ Object
returns all task names for given thor class with use friendly names (with ‘-’ instead ‘_’).
-
.tiered_task_names ⇒ Object
caches all the taks names for each possible tier and each thor class returnes it, executes only once and only on dtk-shell start.
-
.valid_id?(value, conn, context_params) ⇒ Boolean
we make valid methods to make sure that when context changing we allow change only for valid ID/NAME.
Instance Method Summary collapse
- #help(*args) ⇒ Object
-
#initialize(args, opts, config) ⇒ CommandBaseThor
constructor
A new instance of CommandBaseThor.
Methods included from CommandBase
get, get_connection, handle_argument_error, post, post_file, rest_url, rotate_args
Methods included from TaskStatusMixin
list_task_info_aux, task_status_aux, task_status_stream
Methods included from Console
confirmation_prompt, confirmation_prompt_additional_options, confirmation_prompt_multiple_choice, confirmation_prompt_simple, unix_shell, wait_animation
Methods included from CommandHelperMixin
Methods included from ReparseMixin
Methods included from PushCloneChangesMixin
Methods included from CommonOptionDefs::ClassMixin
Methods included from Poller
#poller_response, #print_response, #resolve_type
Methods inherited from Thor
get_alternative_identifiers, help, match_help_item_changes, overriden_help, printable_tasks, replace_if_matched!, set_context
Constructor Details
#initialize(args, opts, config) ⇒ CommandBaseThor
Returns a new instance of CommandBaseThor.
55 56 57 58 |
# File 'lib/parser/adapters/thor.rb', line 55 def initialize(args, opts, config) @conn = config[:conn] super end |
Class Method Details
.action_on_revalidation_response(validation_response, conn, method_name, context_params, thor_options, shell_execution) ⇒ Object
TODO: Make sure that server responds with new format of ARGVS
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
# File 'lib/parser/adapters/thor.rb', line 80 def self.action_on_revalidation_response(validation_response, conn, method_name, context_params, , shell_execution) puts "[NOTICE] #{validation_response.}" actions = validation_response.validation_actions actions.each_with_index do |action, i| if Console.confirmation_prompt("Pre-action '#{action['action']}' needed, execute"+"?") # we have hash map with values { :assembly_id => 2123123123, :option_1 => true } # we translate to array of values, with action as first element # def self.execute_from_cli(conn,method_name,context_params,options_args,shell_execution=false) response = self.execute_from_cli(conn, action['action'], create_context_arguments(action['params']),[],shell_execution) # we abort if error happens ResponseErrorHandler.check(response) if action['wait_for_complete'] entity_id, entity_type = action['wait_for_complete']['id'].to_s, action['wait_for_complete']['type'] puts "Waiting for task to complete ..." task_status_aux(entity_id,entity_type,:wait => true) end else # validation action are being skipped return "" end end puts "Executing original action: '#{method_name}' ..." # if all executed correctly we run original action return self.execute_from_cli(conn,method_name, context_params,,shell_execution) end |
.basename ⇒ Object
This is fix where we wanna exclude basename print when using dtk-shell. Thor has banner method, representing row when help is invoked. As such banner will print out basename first. e.g.
dtk-shell assembly list [library|target] # List asssemblies in library or target
Basename is derived from name of file, as such can be overriden to serve some other logic.
517 518 519 520 521 |
# File 'lib/parser/adapters/thor.rb', line 517 def self.basename basename = super basename = '' if basename == 'dtk-shell' return basename end |
.create_context_arguments(params) ⇒ Object
177 178 179 180 181 182 183 |
# File 'lib/parser/adapters/thor.rb', line 177 def self.create_context_arguments(params) context_params = DTK::Shell::ContextParams.new params.each do |k,v| context_params.add_context_to_params(k,k,v) end return context_params end |
.execute_from_cli(conn, method_name, context_params, thor_options, shell_execution = false) ⇒ Object
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
# File 'lib/parser/adapters/thor.rb', line 60 def self.execute_from_cli(conn,method_name,context_params,,shell_execution=false) @@shell_execution = shell_execution if method_name == 'help' ret = start([method_name] + context_params.method_arguments,:conn => conn) else ret = start([method_name, context_params] + (||[]),:conn => conn) end # special case where we have validation reply if ret.kind_of?(Response) if ret.validation_response? ret = action_on_revalidation_response(ret, conn, method_name, context_params, , shell_execution) end end ret.kind_of?(Response) ? ret : Response::NoOp.new end |
.generate_cached_id(subtype) ⇒ Object
164 165 166 167 168 169 170 171 172 173 174 175 |
# File 'lib/parser/adapters/thor.rb', line 164 def self.generate_cached_id(subtype) values = '' # subtype.sort.map do |key,value| # removed sort since subtype is hash where keys are symbols, # sort method uses the <=> comparison operator to put things into order but # symbols don't have a <=> comparison operator in ruby 1.8.7 subtype.map do |key,value| values += value.to_s end Digest::SHA1.hexdigest(values) end |
.get_cached_response(entity_name, url, subtype = {}) ⇒ Object
we take current timestamp and compare it to timestamp stored in @@cached_response if difference is greater than TIME_DIFF we send request again, if not we use response from cache
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 |
# File 'lib/parser/adapters/thor.rb', line 122 def self.get_cached_response(entity_name, url, subtype={}) subtype ||= {} current_ts = Time.now.to_i cache_id = (subtype.empty? ? :response : generate_cached_id(subtype)) # if @@cache_response is empty return true if not than return time difference between # current_ts and ts stored in cache time_difference = @@cached_response[entity_name].nil? ? true : ((current_ts - @@cached_response[entity_name][:ts]) > TIME_DIFF) if (@@cached_response[entity_name]) time_difference = true if @@cached_response[entity_name][cache_id].nil? end if (time_difference || @@invalidate_map.include?(entity_name)) response = post rest_url(url), subtype # we do not want to catch is if it is not valid if response.nil? || response.empty? DtkLogger.instance.debug("Response was nil or empty for that reason we did not cache it.") return response end if response.ok? response_hash = {cache_id => response, :ts => current_ts} @@invalidate_map.delete(entity_name) if @@invalidate_map.include?(entity_name) if @@cached_response[entity_name] @@cached_response[entity_name].merge!(response_hash) else @@cached_response.store(entity_name, response_hash) end end end if @@cached_response[entity_name] return @@cached_response[entity_name][cache_id] else return nil end end |
.get_identifiers(conn, context_params) ⇒ Object
330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 |
# File 'lib/parser/adapters/thor.rb', line 330 def self.get_identifiers(conn, context_params) @conn = conn if @conn.nil? # we force raw output # options = Thor::CoreExt::HashWithIndifferentAccess.new({'list' => true}) 3.downto(1) do # get list data from one of the methods if respond_to?(:validation_list) response = validation_list(context_params) else clazz, endpoint, opts = whoami() response = get_cached_response(clazz, endpoint, opts) end unless (response.nil? || response.empty?) unless response['data'].nil? identifiers = [] response['data'].each do |element| # special flag to filter out data not needed here next if element['dtk_context_hidden'] identifiers << { :name => element['display_name'], :identifier => element['id'], :shadow_entity => element['dtk_client_type'] } end return identifiers end end unless response.nil? break if response["status"].eql?('ok') end sleep(1) end DtkLogger.instance.warn("[WARNING] We were not able to check cached context, possible errors may occur.") return [] end |
.get_usage_info(entity_name, method) ⇒ Object
194 195 196 197 198 199 200 201 |
# File 'lib/parser/adapters/thor.rb', line 194 def self.get_usage_info(entity_name, method) # no need for nil checks since task will be found # [0] element contains desire usage description # [2] element contains method name with '_' result = printable_tasks().select { |help_item| help_item[2].gsub('_','-') == method }.flatten[0] # we add entity name with dashes return result.gsub('dtk', "dtk #{entity_name.gsub('_','-')}") end |
.invalidate_entities(*array_of_entites) ⇒ Object
110 111 112 113 114 115 116 117 |
# File 'lib/parser/adapters/thor.rb', line 110 def self.invalidate_entities(*array_of_entites) # we handle to cases here # n-context invalidation, whole structure @@invalidate_map << array_of_entites.join('_').to_sym # last entity @@invalidate_map << array_of_entites.last.to_sym end |
.invisible_context_list(sufix = 'identifier') ⇒ Object
Returns list of invisible contexts with sufix provided (if any)
527 528 529 |
# File 'lib/parser/adapters/thor.rb', line 527 def self.invisible_context_list(sufix = 'identifier') self.respond_to?(:invisible_context) ? self.invisible_context.collect { |i| "#{i}-#{sufix}" } : [] end |
.list_method_supported? ⇒ Boolean
185 186 187 |
# File 'lib/parser/adapters/thor.rb', line 185 def self.list_method_supported? return (respond_to?(:validation_list) || respond_to?(:whoami)) end |
.task_names ⇒ Object
returns all task names for given thor class with use friendly names (with ‘-’ instead ‘_’)
190 191 192 |
# File 'lib/parser/adapters/thor.rb', line 190 def self.task_names all_tasks().map(&:first).collect { |item| item.gsub('_','-')} end |
.tiered_task_names ⇒ Object
caches all the taks names for each possible tier and each thor class returnes it, executes only once and only on dtk-shell start
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 |
# File 'lib/parser/adapters/thor.rb', line 205 def self.tiered_task_names # cached data cached_tasks = {} # get command name from namespace (which is derived by thor from file name) command = namespace.split(':').last.gsub('_','-').upcase # first elvel identifier command_sym = command.downcase.to_sym command_id_sym = (command.downcase + '_wid').to_sym cached_tasks.store(command_sym, []) cached_tasks.store(command_id_sym, []) # n-context children all_children = [] children = self.respond_to?(:all_children) ? self.all_children() : nil all_children << children unless children.nil? # some commands have multiple n-level contexts # e.g. workspace_node_component, workspace_utils and workspace_node_utils # we go through all of them and load them to 'all_children' multi_context_children = self.respond_to?(:multi_context_children) ? self.multi_context_children() : nil if multi_context_children multi_context_children.each do |mc| all_children << (mc.is_a?(Array) ? mc : multi_context_children) end end # n-context-override task, special case which override_task_obj = self.respond_to?(:override_allowed_methods) ? self.override_allowed_methods.dup : nil # we seperate tier 1 and tier 2 tasks all_tasks().each do |task| # noralize task name with '-' since it will be displayed to user that way task_name = task[0].gsub('_','-') usage = task[1].usage # we will match those commands that require identifiers (NAME/ID) # e.g. ASSEMBLY-NAME/ID list ... => MATCH # e.g. [ASSEMBLY-NAME/ID] list ... => MATCH matched_data = task[1].usage.match(/\[?#{command}.?(NAME\/ID|ID\/NAME)\]?/) matched_alt_identifiers_data = nil # we chance alternate providers if respond_to?(:alternate_identifiers) alternate_identifiers = self.alternate_identifiers() alternate_identifiers.each do |a_provider| if matched_alt_identifiers_data = task[1].usage.match(/\[?#{a_provider}.?(NAME\/ID|ID\/NAME)\]?/) command_alt_sym = "#{command}_#{a_provider}".downcase.to_sym cached_tasks[command_alt_sym] = cached_tasks.fetch(command_alt_sym,[]) cached_tasks[command_alt_sym] << task_name # when found break break end end end # only if not matched alt data found continue with caching of task unless matched_alt_identifiers_data if matched_data.nil? # no match it means it is tier 1 task, tier 1 => dtk:\assembly> # using HIDE_FROM_BASE_CONTEXT to hide command from base context (e.g from dtk:/assembly>) ... # ... but to be able to use that command in other context # (e.g get-netstats removed from dtk:/assembly> but used in dtk:/assembly/assembly_id/utils) cached_tasks[command_sym] << task_name unless usage.include?(HIDE_FROM_BASE_CONTEXT) else # match means it is tier 2 taks, tier 2 => dtk:\assembly\231312345> cached_tasks[command_id_sym] << task_name # if there are '[' it means it is optinal identifiers so it is tier 1 and tier 2 task cached_tasks[command_sym] << task_name if matched_data[0].include?('[') end # n-level matching all_children.each do |child| current_children = [] child.each do |c| current_children << c.to_s # create entry e.g. assembly_node_id child_id_sym = (command.downcase + '_' + current_children.join('_') + '_wid').to_sym # n-context matching matched_data = task[1].usage.match(/^\[?#{c.to_s.upcase}.?(NAME\/ID|ID\/NAME|ID|NAME)(\-?PATTERN)?\]?/) if matched_data cached_tasks[child_id_sym] = cached_tasks.fetch(child_id_sym,[]) << task_name end # override method list, we add these methods only once if override_task_obj && !override_task_obj.is_completed?(c) command_o_tasks, identifier_o_tasks = override_task_obj.get_all_tasks(c) child_sym = (command.downcase + '_' + current_children.join('_')).to_sym command_o_tasks.each do |o_task| cached_tasks[child_sym] = cached_tasks.fetch(child_sym,[]) << o_task[0] end identifier_o_tasks.each do |o_task| cached_tasks[child_id_sym] = cached_tasks.fetch(child_id_sym,[]) << o_task[0] end override_task_obj.add_to_completed(c) end end end end end # there is always help, and in all cases this is exception to the rule cached_tasks[command_id_sym] << 'help' return cached_tasks end |
.valid_id?(value, conn, context_params) ⇒ Boolean
we make valid methods to make sure that when context changing we allow change only for valid ID/NAME
322 323 324 325 326 327 328 |
# File 'lib/parser/adapters/thor.rb', line 322 def self.valid_id?(value, conn, context_params) context_list = self.get_identifiers(conn, context_params) results = context_list.select { |e| e[:name].eql?(value) || e[:identifier].eql?(value.to_i)} return results.empty? ? nil : results.first end |
Instance Method Details
#help(*args) ⇒ Object
532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 |
# File 'lib/parser/adapters/thor.rb', line 532 def help(*args) puts # pretty print not_dtk_clazz = true if defined?(DTK::Client::Dtk) not_dtk_clazz = !self.class.eql?(DTK::Client::Dtk) end # not_dtk_clazz - we don't use subcommand print in case of root DTK class # for other classes Assembly, Node, etc. we print subcommand # this gives us console output: dtk assembly converge ASSEMBLY-ID # # @@shell_execution - if we run from shell we don't want subcommand output # super(args.empty? ? nil : args.first, not_dtk_clazz && !@@shell_execution) # we will print error in case configuration has reported error @conn.print_warning if @conn.connection_error? puts # pretty print end |