dtk-client 0.6.8 → 0.7.0

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