dtk-client 0.6.8 → 0.7.0

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.
Files changed (39) hide show
  1. checksums.yaml +8 -8
  2. data/bin/dtk +5 -1
  3. data/lib/auxiliary.rb +0 -1
  4. data/lib/commands/common/thor/assembly_workspace.rb +20 -1
  5. data/lib/commands/common/thor/inventory_parser.rb +1 -1
  6. data/lib/commands/common/thor/module/import.rb +41 -106
  7. data/lib/commands/common/thor/module.rb +13 -226
  8. data/lib/commands/common/thor/poller.rb +48 -0
  9. data/lib/commands/common/thor/puppet_forge.rb +7 -1
  10. data/lib/commands/common/thor/purge_clone.rb +2 -1
  11. data/lib/commands/common/thor/task_status.rb +15 -14
  12. data/lib/commands/common/thor/test_action_agent.rb +39 -0
  13. data/lib/commands/thor/component_module.rb +2 -2
  14. data/lib/commands/thor/node.rb +55 -14
  15. data/lib/commands/thor/node_group.rb +2 -26
  16. data/lib/commands/thor/service.rb +31 -11
  17. data/lib/commands/thor/service_module.rb +3 -1
  18. data/lib/commands/thor/workspace.rb +13 -3
  19. data/lib/core.rb +16 -6
  20. data/lib/domain/git_adapter.rb +0 -3
  21. data/lib/domain/response.rb +25 -13
  22. data/lib/dtk-client/version.rb +1 -1
  23. data/lib/parser/adapters/thor.rb +8 -5
  24. data/lib/shell/context.rb +8 -19
  25. data/lib/shell/domain/active_context.rb +169 -0
  26. data/lib/shell/domain/context_entity.rb +72 -0
  27. data/lib/shell/domain/context_params.rb +202 -0
  28. data/lib/shell/domain/override_tasks.rb +71 -0
  29. data/lib/shell/domain/shadow_entity.rb +59 -0
  30. data/lib/shell/help_monkey_patch.rb +76 -71
  31. data/lib/shell/message_queue.rb +2 -0
  32. data/lib/shell/status_monitor.rb +5 -3
  33. data/lib/shell.rb +4 -2
  34. data/lib/util/dtk_puppet.rb +8 -6
  35. data/lib/util/os_util.rb +5 -1
  36. data/lib/view_processor/table_print.rb +67 -12
  37. data/spec/lib/spec_thor.rb +5 -2
  38. metadata +9 -3
  39. data/lib/shell/domain.rb +0 -492
@@ -52,17 +52,23 @@ module DTK
52
52
  end
53
53
 
54
54
  def get_label_for_column_name(column, type)
55
- mappings = {
56
- "#{type}_id:" => "ID:",
57
- "#{type}_name:" => "NAME:",
58
- "node_type:" => "TYPE:",
59
- "instance_id:" => "INSTANCE ID:",
60
- "size:" => "SIZE:",
61
- "os_type:" => "OS:",
62
- "op_status:" => "OP STATUS:",
63
- "dns_name:" => "DNS NAME:",
64
- "target:" => "TARGET:"
65
- }
55
+ if type.eql?('node')
56
+ mappings = {
57
+ column => column
58
+ }
59
+ else
60
+ mappings = {
61
+ "#{type}_id:" => "ID:",
62
+ "#{type}_name:" => "NAME:",
63
+ "node_type:" => "TYPE:",
64
+ "instance_id:" => "INSTANCE ID:",
65
+ "size:" => "SIZE:",
66
+ "os_type:" => "OS:",
67
+ "op_status:" => "OP STATUS:",
68
+ "dns_name:" => "DNS NAME:",
69
+ "target:" => "TARGET:"
70
+ }
71
+ end
66
72
 
67
73
  mappings[column]
68
74
  end
@@ -73,7 +79,7 @@ module DTK
73
79
  if type.eql?("component")
74
80
  info_list = ["component_name","component_id","basic_type","description"]
75
81
  else
76
- info_list = ["node_id", "node_name","os_type", "instance_id", "op_status", "size", "target", "dns_name"]
82
+ info_list = ["type", "node_id", "node_name","os_type", "instance_id", "admin_op_status", "size", "target", "dns_name", "image_id", "ec2_public_address", "privete_dns_name", "keypair", "security_groups", "security_group", "security_group_set"]
77
83
  end
78
84
 
79
85
  columns = []
@@ -91,7 +97,13 @@ module DTK
91
97
  end
92
98
  end
93
99
 
94
- columns.sort!()
100
+ if type.eql?('node')
101
+ # move target from first place
102
+ columns.rotate!
103
+ else
104
+ columns.sort!()
105
+ end
106
+
95
107
  columns.each do |column|
96
108
  STDOUT << column
97
109
  end
@@ -1,3 +1,3 @@
1
1
  module DtkClient
2
- VERSION="0.6.8"
2
+ VERSION="0.7.0"
3
3
  end
@@ -10,6 +10,7 @@ dtk_require("../../util/console")
10
10
  dtk_require_common_commands('thor/task_status')
11
11
  dtk_require_from_base("command_helper")
12
12
  dtk_require("../../context_router")
13
+ dtk_require_common_commands('thor/poller')
13
14
 
14
15
  module DTK
15
16
  module Client
@@ -17,10 +18,12 @@ module DTK
17
18
  dtk_nested_require('thor','common_option_defs')
18
19
 
19
20
  include CommandBase
21
+ include CommandHelperMixin
22
+ include Poller
23
+
20
24
  extend CommandBase
21
25
  extend TaskStatusMixin
22
26
  extend Console
23
- include CommandHelperMixin
24
27
  extend CommonOptionDefs::ClassMixin
25
28
 
26
29
  @@cached_response = {}
@@ -74,7 +77,7 @@ module DTK
74
77
  if action['wait_for_complete']
75
78
  entity_id, entity_type = action['wait_for_complete']['id'].to_s, action['wait_for_complete']['type']
76
79
  puts "Waiting for task to complete ..."
77
- task_status_aux(entity_id,entity_type,true)
80
+ task_status_aux(entity_id,entity_type,:wait => true)
78
81
  end
79
82
  else
80
83
  # validation action are being skipped
@@ -326,7 +329,7 @@ module DTK
326
329
  unless response['data'].nil?
327
330
  identifiers = []
328
331
  response['data'].each do |element|
329
- identifiers << { :name => element['display_name'], :identifier => element['id'] }
332
+ identifiers << { :name => element['display_name'], :identifier => element['id'], :shadow_entity => element['dtk_client_type'] }
330
333
  end
331
334
  return identifiers
332
335
  end
@@ -403,7 +406,7 @@ module DTK
403
406
 
404
407
  match = nil
405
408
  response = self.class.get_cached_response(entity_type,list_command_path,subtype)
406
- if response.ok? and response['data']
409
+ if response and response.ok? and response['data']
407
410
  match = response['data'].find{|entity|entity_id == entity['id']}
408
411
  end
409
412
  unless match
@@ -428,7 +431,7 @@ module DTK
428
431
 
429
432
  # removes nil values
430
433
  def post_body(hash)
431
- hash.inject(Hash.new){|h,(k,v)|v.nil? ? h : h.merge(k => v)}
434
+ hash.inject(Hash.new){|h,(k,v)|v.nil? ? h : h.merge(k => v)}
432
435
  end
433
436
 
434
437
  # User input prompt
data/lib/shell/context.rb CHANGED
@@ -351,7 +351,7 @@ module DTK
351
351
  break
352
352
  end
353
353
 
354
- active_context_copy.push_new_context(context_hash_data[:name], command, context_hash_data[:identifier]) if ((i+1) >= ac_size)
354
+ active_context_copy.push_new_context(context_hash_data[:name], command, context_hash_data[:identifier], context_hash_data[:shadow_entity]) if ((i+1) >= ac_size)
355
355
  end
356
356
  end
357
357
 
@@ -512,8 +512,12 @@ module DTK
512
512
  # so getting context for 'public' will not work and we use than library
513
513
  command_name = root? ? 'dtk' : @active_context.last_command_name
514
514
 
515
- # if there is no new context (current) we use old one
516
- @current = current_context_task_names() || @current
515
+ if @active_context.last_context_is_shadow_entity?
516
+ @current = ShadowEntity.resolve_tasks(@active_context.last_context)
517
+ else
518
+ # if there is no new context (current) we use old one
519
+ @current = current_context_task_names() || @current
520
+ end
517
521
 
518
522
  client_commands = CLIENT_COMMANDS
519
523
  client_commands.concat(DEV_COMMANDS) if DTK::Configuration.get(:development_mode)
@@ -530,6 +534,7 @@ module DTK
530
534
  command_name_list = command_context ? command_context.collect { |e| e[:name] } : []
531
535
  @context_commands.concat(command_name_list) if current_command?
532
536
 
537
+
533
538
  # logic behind context loading
534
539
  #Readline.completer_word_break_characters=" "
535
540
  Readline.completion_proc = proc { |input| dynamic_autocomplete_context(input, Readline.respond_to?("line_buffer") ? Readline.line_buffer : [])}
@@ -798,22 +803,6 @@ module DTK
798
803
  candidates
799
804
  end
800
805
 
801
- # changes command and argument if argument is plural of one of
802
- # the possible commands on tier1 e.g. libraries, assemblies
803
- # return 2 values cmd, args
804
- def reverse_commands(cmd, args)
805
- # iterates trough current context available commands
806
- @current.each do |available_commands|
807
- # singulirazes command, e.g. libraries => library
808
- command_singular=args.first.singularize
809
- if available_commands.eql?(command_singular)
810
- cmd, args = command_singular, [cmd]
811
- end
812
- end
813
-
814
- return cmd, args
815
- end
816
-
817
806
  def get_dtk_command_parameters(entity_name, args)
818
807
  method_name, entity_name_id = nil, nil
819
808
  context_params = ContextParams.new
@@ -0,0 +1,169 @@
1
+ module DTK::Shell
2
+ class ActiveContext
3
+
4
+ # special case when we are not able to provide valid identifier but we are
5
+ # using it as such
6
+ NO_IDENTIFIER_PROVIDED = -1
7
+
8
+ # TODO: Remove accessor for debug purpose only
9
+ attr_accessor :context_list
10
+
11
+ def clone_me()
12
+ inst = ActiveContext.new
13
+ inst.context_list = @context_list.clone
14
+ return inst
15
+ end
16
+
17
+ def initialize
18
+ @context_list = []
19
+ end
20
+
21
+ def push_new_context(context_name, entity_name, context_value=nil, shadow_entity=nil)
22
+ @context_list << ContextEntity.create_context(context_name, entity_name, context_value, :id, shadow_entity)
23
+ end
24
+
25
+ def push_new_name_context(context_name, entity_name, context_value=nil)
26
+ @context_list << ContextEntity.create_context(context_name, entity_name, context_value, :name)
27
+ end
28
+
29
+ def pop_context(n)
30
+ return @context_list.pop(n)
31
+ end
32
+
33
+ def find_identifier(entity_name)
34
+ results = @context_list.select { |e| (e.is_identifier? && (e.entity == entity_name.to_sym))}
35
+ return results.first
36
+ end
37
+
38
+ def find_command(entity_name)
39
+ results = @context_list.select { |e| (e.is_command? && (e.entity == entity_name.to_sym))}
40
+ return results.first
41
+ end
42
+
43
+ def name_list()
44
+ @context_list.collect { |e| e.is_alt_identifier? ? e.transform_alt_identifier_name : e.name }
45
+ end
46
+
47
+ def name_list_simple()
48
+ @context_list.collect { |e| e.name }
49
+ end
50
+
51
+
52
+ # returns list of entities that have identifier
53
+ def commands_that_have_identifiers()
54
+ filtered_entities = @context_list.select { |e| e.is_identifier? }
55
+ return filtered_entities.collect { |e| e.entity.to_s }
56
+ end
57
+
58
+ def command_list()
59
+ filtered_entities = @context_list.select { |e| e.is_command? }
60
+ return filtered_entities.collect { |e| e.entity.to_s }
61
+ end
62
+
63
+ # returns id to be used to retrive task list form the cache based on
64
+ # current active context
65
+ def get_task_cache_id()
66
+ identifier = command_list().join('_')
67
+ return 'dtk' if identifier.empty?
68
+ if current_alt_identifier?
69
+ return "#{identifier}_#{current_alt_identifier_name()}".to_sym()
70
+ end
71
+
72
+ return current_identifier? ? "#{identifier}_wid".to_sym : identifier.to_sym
73
+ end
74
+
75
+ def full_path()
76
+ path = name_list().join('/')
77
+ path = Context.enchance_path_with_alias(path, @context_list)
78
+
79
+ return "/#{path}"
80
+ end
81
+
82
+ def clear()
83
+ @context_list.clear
84
+ end
85
+
86
+ def empty?()
87
+ return @context_list.empty?
88
+ end
89
+
90
+ def is_n_context?
91
+ @context_list.size > 2
92
+ end
93
+
94
+ def is_base_context?
95
+ @context_list.size == 1
96
+ end
97
+
98
+ def is_root_context?
99
+ @context_list.size == 0
100
+ end
101
+
102
+ def current_command?
103
+ return @context_list.empty? ? true : @context_list.last.is_command?
104
+ end
105
+
106
+ def current_identifier?
107
+ return @context_list.empty? ? false : @context_list.last.is_identifier?
108
+ end
109
+
110
+ def current_alt_identifier?
111
+ return @context_list.empty? ? false : @context_list.last.is_alt_identifier?
112
+ end
113
+
114
+ def current_alt_identifier_name
115
+ @context_list.last.alt_identifier
116
+ end
117
+
118
+ def first_command_name()
119
+ @context_list.each do |e|
120
+ return e.name if e.is_command?
121
+ end
122
+
123
+ return nil
124
+ end
125
+
126
+ def is_there_identifier_for_first_context?
127
+ @context_list.each { |e| return true if e.is_identifier? }
128
+ return false
129
+ end
130
+
131
+ def last_command_name()
132
+ @context_list.reverse.each do |e|
133
+ return e.name if e.is_command?
134
+ end
135
+
136
+ return nil
137
+ end
138
+
139
+ def last_context_entity_name()
140
+ return @context_list.empty? ? nil : @context_list.last.entity
141
+ end
142
+
143
+ def last_context_name()
144
+ return @context_list.empty? ? nil : @context_list.last.name
145
+ end
146
+
147
+ def first_context_name()
148
+ return @context_list.empty? ? nil : @context_list.first.name
149
+ end
150
+
151
+ def first_context()
152
+ return @context_list.empty? ? nil : @context_list.first
153
+ end
154
+
155
+ def last_context()
156
+ return @context_list.empty? ? nil : @context_list.last
157
+ end
158
+
159
+ def last_context_is_shadow_entity?
160
+ return false if @context_list.empty?
161
+ !!last_context().shadow_entity
162
+ end
163
+
164
+ def shadow_entity()
165
+ return if @context_list.empty?
166
+ last_context().shadow_entity
167
+ end
168
+ end
169
+ end
@@ -0,0 +1,72 @@
1
+ module DTK::Shell
2
+ class ContextEntity
3
+ attr_accessor :entity
4
+ attr_accessor :name
5
+ attr_accessor :identifier
6
+ attr_accessor :alt_identifier
7
+ attr_accessor :shadow_entity
8
+
9
+ SHELL_SEPARATOR = '/'
10
+
11
+ def self.create_context(context_name, entity_name, context_value=nil, type_id=:id, shadow_entity=nil)
12
+ if context_value
13
+ if :id.eql?(type_id)
14
+ return ContextEntity.create_identifier(context_name, entity_name, context_value, shadow_entity)
15
+ else
16
+ return ContextEntity.create_name_identifier(context_name, entity_name, context_value, shadow_entity)
17
+ end
18
+ else
19
+ return ContextEntity.create_command(context_name, entity_name, shadow_entity)
20
+ end
21
+ end
22
+
23
+ def is_identifier?
24
+ return !@identifier.nil?
25
+ end
26
+
27
+ def is_alt_identifier?
28
+ return !@alt_identifier.nil?
29
+ end
30
+
31
+ def is_command?
32
+ return @identifier.nil?
33
+ end
34
+
35
+ def get_identifier(type)
36
+ return (type == 'id' ? self.identifier : self.name)
37
+ end
38
+
39
+ def transform_alt_identifier_name()
40
+ @name.gsub(::DTK::Client::CommandBaseThor::ALT_IDENTIFIER_SEPARATOR, SHELL_SEPARATOR)
41
+ end
42
+
43
+ private
44
+
45
+ def self.create_command(name, entity_name, shadow_entity=nil)
46
+ instance = ContextEntity.new
47
+ instance.name = name
48
+ instance.entity = entity_name.to_sym
49
+ instance.shadow_entity = shadow_entity
50
+ return instance
51
+ end
52
+
53
+ def self.create_name_identifier(name, entity_name, value, shadow_entity=nil)
54
+ instance = self.create_command(name,entity_name)
55
+ instance.name = value
56
+ instance.identifier = value
57
+ instance.alt_identifier = value
58
+ instance.shadow_entity = shadow_entity
59
+
60
+ return instance
61
+ end
62
+
63
+ def self.create_identifier(name, entity_name, value, shadow_entity=nil)
64
+ instance = self.create_command(name,entity_name)
65
+ instance.identifier = value
66
+ alt_identifier_name = name.to_s.split(::DTK::Client::CommandBaseThor::ALT_IDENTIFIER_SEPARATOR)
67
+ instance.alt_identifier = alt_identifier_name.size > 1 ? alt_identifier_name.first : nil
68
+ instance.shadow_entity = shadow_entity
69
+ return instance
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,202 @@
1
+ module DTK::Shell
2
+ class ContextParams
3
+
4
+ attr_accessor :current_context
5
+ attr_accessor :method_arguments
6
+
7
+ def initialize(override_method_arguments = [])
8
+ @current_context = ActiveContext.new
9
+ @method_arguments = override_method_arguments
10
+ @thor_options = Hash.new
11
+ end
12
+
13
+ def add_context_to_params(context_name, entity_name, context_value = nil)
14
+ @current_context.push_new_context(context_name, stand_name(entity_name), context_value)
15
+ end
16
+
17
+ def add_context_name_to_params(context_name, entity_name, context_value = nil)
18
+ @current_context.push_new_name_context(context_name, stand_name(entity_name), context_value)
19
+ end
20
+
21
+ def forward_options(options)
22
+ @thor_options = options
23
+ end
24
+
25
+ def get_forwarded_options()
26
+ @thor_options
27
+ end
28
+
29
+ def get_forwarded_thor_option(option_key)
30
+ return @thor_options ? @thor_options[option_key] : nil
31
+ end
32
+
33
+ def override_method_argument!(key, value)
34
+ id = match_argument_id(key)
35
+ raise DTK::Client::DtkImplementationError, "Wrong identifier used '#{key}', ID not matched!" unless id
36
+ @method_arguments[id] = value
37
+ end
38
+
39
+ # can be class methods but no need, since we have this instance available in each method
40
+ def retrieve_thor_options(mapping, options)
41
+ results = []
42
+ errors = []
43
+
44
+ mapping.each do |key|
45
+ required = key.to_s.match(/.+!$/)
46
+ thor_key = key.to_s.gsub('!','')
47
+
48
+ results << element = options[thor_key]
49
+
50
+ if required && element.nil?
51
+ errors << thor_key
52
+ end
53
+ end
54
+
55
+ unless errors.empty?
56
+ raise DTK::Client::DtkValidationError.new("Missing required option#{errors.size > 1 ? 's' : ''}: #{errors.join(', ')}", true)
57
+ end
58
+
59
+ return ((results.size == 1) ? results.first : results)
60
+ end
61
+
62
+ def retrieve_arguments(mapping, method_info = [])
63
+ results = []
64
+ errors = []
65
+
66
+ # using context_name when have array as key_mapping [:assembly_id, :workspace_id]
67
+ # to determine which context is used
68
+ context_name = method_info.first.split('-').first unless method_info.empty?
69
+
70
+ mapping.each do |key_mapping|
71
+
72
+ is_array = key_mapping.is_a?(Array)
73
+
74
+ selected_key = is_array ? key_mapping.first : key_mapping
75
+
76
+ required = selected_key.to_s.match(/.+!$/)
77
+
78
+ element = nil
79
+ matched = selected_key.to_s.match(/option_([0-9]+)/)
80
+ if matched
81
+ id = matched[1].to_i - 1
82
+ element = @method_arguments[id]
83
+
84
+ # used if last parameter has more than one word
85
+ # e.g. set-attribute attr_name "some value" (thor separates 'some value' as two parameters but we need it as one)
86
+ if(mapping.last.to_s.eql?(key_mapping.to_s))
87
+ new_id = id+1
88
+ while @method_arguments[new_id] do
89
+ element << " #{@method_arguments[new_id]}"
90
+ new_id += 1;
91
+ end
92
+ end
93
+
94
+ unless method_info.empty?
95
+ unless element
96
+ errors << method_info[id] if required
97
+ end
98
+ end
99
+
100
+ else
101
+ # More complex split regex for extracting entitiy name from mapping due to complex context names
102
+ # i.e. assembly-template will have assembly_template_id mapping
103
+ element = check_context_for_element(selected_key)
104
+
105
+ # if we are dealing with array we need to check rest of the keys since it is OR
106
+ # approach if first element not found take second
107
+ if element.nil? && is_array
108
+ key_mapping[1..-1].each do |alternative_key|
109
+ element = check_context_for_element(alternative_key)
110
+ break if element
111
+ if context_name
112
+ if alternative_key.to_s.include?(context_name.downcase)
113
+ required = alternative_key.to_s.match(/.+!$/)
114
+ selected_key = alternative_key
115
+ end
116
+ end
117
+ end
118
+ end
119
+
120
+ unless element
121
+ errors << "#{entity_name(selected_key).upcase} ID/NAME" if required
122
+ end
123
+ end
124
+
125
+ results << element
126
+ end
127
+
128
+ unless errors.empty?
129
+ raise DTK::Client::DtkValidationError.new("Missing required argument#{errors.size > 1 ? 's' : ''}: #{errors.join(', ')}", true)
130
+ end
131
+
132
+ return ((results.size == 1) ? results.first : results)
133
+ end
134
+
135
+ def is_last_command_eql_to?(command_name)
136
+ return @current_context.last_command_name() == command_name.to_s
137
+ end
138
+
139
+ def is_there_identifier?(entity_name)
140
+ return @current_context.find_identifier(entity_name) != nil
141
+ end
142
+
143
+ def is_there_command?(entity_name)
144
+ return @current_context.find_command(entity_name) != nil
145
+ end
146
+ def current_command?
147
+ return @current_context.current_command?
148
+ end
149
+ def root_command_name
150
+ @current_context.first_command_name
151
+ end
152
+ def last_entity_name
153
+ @current_context.last_context_entity_name
154
+ end
155
+ def shadow_entity_name()
156
+ @current_context.shadow_entity()
157
+ end
158
+
159
+ private
160
+
161
+ # matches argument id (integer) from used identifier (symbol)
162
+ #
163
+ # Returns: Integer as ID , or nil if not found
164
+ def match_argument_id(identifier)
165
+ matched = identifier.to_s.match(/option_([0-9]+)/)
166
+ (matched ? matched[1].to_i - 1 : nil)
167
+ end
168
+
169
+ # based on map key binding e.g. assembly_id, assembly_name we will extrace value
170
+ # from our ActiveContext
171
+ def check_context_for_element(key_mapping)
172
+ split_info = split_info(key_mapping)
173
+ entity_name = entity_name(key_mapping,split_info)
174
+ id_type = split_info[1].gsub(/!/,'') # for required elements we remove '!' required marker
175
+ context_identifier = @current_context.find_identifier(entity_name)
176
+ if context_identifier
177
+ return context_identifier.get_identifier(id_type)
178
+ else
179
+ return nil
180
+ end
181
+ end
182
+
183
+ def entity_name(key_mapping,split_info=nil)
184
+ split_info ||= split_info(key_mapping)
185
+ split_info[0].gsub(/_/,'-') # makes sure we are using entity names with '_'
186
+ end
187
+
188
+ #
189
+ # Standardize context name since we are in domain treating :component_module as :'component-module'
190
+ # and need to be careful about these changes
191
+ #
192
+
193
+ def stand_name(name)
194
+ name.to_s.gsub('_','-').to_sym
195
+ end
196
+
197
+ def split_info(key_mapping)
198
+ key_mapping.to_s.split(/_([a-z]+!?$)/)
199
+ end
200
+
201
+ end
202
+ end
@@ -0,0 +1,71 @@
1
+ module DTK
2
+ module Shell
3
+
4
+ class CachedTasks < Hash
5
+ end
6
+
7
+ class OverrideTasks < Hash
8
+
9
+ attr_accessor :completed_tasks
10
+ attr_accessor :always_load_list
11
+
12
+
13
+ # help_item (Thor printable task), structure:
14
+ # [0] => task defintion
15
+ # [1] => task description
16
+ # [2] => task name
17
+
18
+ # overriden_task (DTK override task), structure:
19
+ # [0] => task name
20
+ # [1] => task defintion
21
+ # [2] => task description
22
+
23
+ # using 'always load listed' to skip adding task to completed tasks e.g load utils for workspace and workspace_node
24
+ def initialize(hash=nil, always_load_listed=[])
25
+ super(hash)
26
+ @completed_tasks = []
27
+ @always_load_list = always_load_listed
28
+ self.merge!(hash)
29
+ end
30
+
31
+ # returns true if there are overrides for tasks on first two levels.
32
+ def are_there_self_override_tasks?
33
+ return (self[:all][:self] || self[:command_only][:self] || self[:identifier_only][:self])
34
+ end
35
+
36
+ def check_help_item(help_item, is_command)
37
+ command_tasks, identifier_tasks = get_all_tasks(:self)
38
+ found = []
39
+
40
+ if is_command
41
+ found = command_tasks.select { |o_task| o_task[0].eql?(help_item[2]) }
42
+ else
43
+ found = identifier_tasks.select { |o_task| o_task[0].eql?(help_item[2]) }
44
+ end
45
+
46
+ # if we find self overriden task we remove it
47
+ # [found.first[1],found.first[2],found.first[0]] => we convert from o_task structure to thor help structure
48
+ return found.empty? ? help_item : [found.first[1],found.first[2],found.first[0]]
49
+ end
50
+
51
+ # returns 2 arrays one for commands and next one for identifiers
52
+ def get_all_tasks(child_name)
53
+ command_o_tasks, identifier_o_tasks = [], []
54
+ command_o_tasks = (self[:all][child_name]||[]) + (self[:command_only][child_name]||[])
55
+ identifier_o_tasks = (self[:all][child_name]||[]) + (self[:identifier_only][child_name]||[])
56
+ return command_o_tasks, identifier_o_tasks
57
+ end
58
+
59
+ def is_completed?(child_name)
60
+ # do not add task to completed if explicitly said to always load that task
61
+ return false if @always_load_list.include?(child_name)
62
+ @completed_tasks.include?(child_name)
63
+ end
64
+
65
+ def add_to_completed(child_name)
66
+ @completed_tasks << child_name
67
+ end
68
+ end
69
+
70
+ end
71
+ end