morpheus-cli 3.3.1.4 → 3.3.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/lib/morpheus/api/api_client.rb +28 -0
  3. data/lib/morpheus/api/instance_types_interface.rb +12 -10
  4. data/lib/morpheus/api/instances_interface.rb +4 -0
  5. data/lib/morpheus/api/library_container_scripts_interface.rb +49 -0
  6. data/lib/morpheus/api/library_container_templates_interface.rb +49 -0
  7. data/lib/morpheus/api/library_container_types_interface.rb +65 -0
  8. data/lib/morpheus/api/library_container_upgrades_interface.rb +66 -0
  9. data/lib/morpheus/api/library_instance_types_interface.rb +59 -0
  10. data/lib/morpheus/api/library_layouts_interface.rb +65 -0
  11. data/lib/morpheus/api/servers_interface.rb +4 -0
  12. data/lib/morpheus/api/user_sources_interface.rb +120 -0
  13. data/lib/morpheus/api/virtual_images_interface.rb +7 -0
  14. data/lib/morpheus/cli.rb +12 -1
  15. data/lib/morpheus/cli/accounts.rb +35 -9
  16. data/lib/morpheus/cli/cli_command.rb +82 -2
  17. data/lib/morpheus/cli/curl_command.rb +1 -1
  18. data/lib/morpheus/cli/echo_command.rb +1 -1
  19. data/lib/morpheus/cli/hosts.rb +40 -14
  20. data/lib/morpheus/cli/instance_types.rb +106 -64
  21. data/lib/morpheus/cli/instances.rb +39 -15
  22. data/lib/morpheus/cli/library.rb +1 -1184
  23. data/lib/morpheus/cli/library_container_scripts_command.rb +437 -0
  24. data/lib/morpheus/cli/library_container_templates_command.rb +397 -0
  25. data/lib/morpheus/cli/library_container_types_command.rb +653 -0
  26. data/lib/morpheus/cli/library_instance_types_command.rb +491 -0
  27. data/lib/morpheus/cli/library_layouts_command.rb +650 -0
  28. data/lib/morpheus/cli/library_option_lists_command.rb +476 -0
  29. data/lib/morpheus/cli/library_option_types_command.rb +549 -0
  30. data/lib/morpheus/cli/library_upgrades_command.rb +604 -0
  31. data/lib/morpheus/cli/mixins/library_helper.rb +123 -0
  32. data/lib/morpheus/cli/mixins/print_helper.rb +21 -22
  33. data/lib/morpheus/cli/mixins/provisioning_helper.rb +56 -11
  34. data/lib/morpheus/cli/network_services_command.rb +1 -1
  35. data/lib/morpheus/cli/option_types.rb +12 -2
  36. data/lib/morpheus/cli/power_scheduling_command.rb +1 -1
  37. data/lib/morpheus/cli/shell.rb +120 -22
  38. data/lib/morpheus/cli/sleep_command.rb +45 -0
  39. data/lib/morpheus/cli/user_sources_command.rb +963 -0
  40. data/lib/morpheus/cli/users.rb +33 -2
  41. data/lib/morpheus/cli/version.rb +1 -1
  42. data/lib/morpheus/cli/version_command.rb +1 -1
  43. data/lib/morpheus/cli/virtual_images.rb +93 -39
  44. data/lib/morpheus/formatters.rb +37 -27
  45. data/lib/morpheus/terminal.rb +1 -1
  46. metadata +20 -2
@@ -0,0 +1,123 @@
1
+ require 'morpheus/cli/mixins/print_helper'
2
+ require 'morpheus/cli/option_types'
3
+ # Mixin for Morpheus::Cli command classes
4
+ # Provides common methods for library management commands
5
+ module Morpheus::Cli::LibraryHelper
6
+
7
+ def self.included(klass)
8
+ klass.send :include, Morpheus::Cli::PrintHelper
9
+ end
10
+
11
+ def api_client
12
+ raise "#{self.class} has not defined @api_client" if @api_client.nil?
13
+ @api_client
14
+ end
15
+
16
+ def find_instance_type_by_name_or_id(val)
17
+ if val.to_s =~ /\A\d{1,}\Z/
18
+ return find_instance_type_by_id(val)
19
+ else
20
+ return find_instance_type_by_name(val)
21
+ end
22
+ end
23
+
24
+ def find_instance_type_by_id(id)
25
+ begin
26
+ json_response = @library_instance_types_interface.get(id.to_i)
27
+ return json_response['instanceType']
28
+ rescue RestClient::Exception => e
29
+ if e.response && e.response.code == 404
30
+ print_red_alert "Instance Type not found by id #{id}"
31
+ else
32
+ raise e
33
+ end
34
+ end
35
+ end
36
+
37
+ def find_instance_type_by_name(name)
38
+ json_response = @library_instance_types_interface.list({name: name.to_s})
39
+ instance_types = json_response['instanceTypes']
40
+ if instance_types.empty?
41
+ print_red_alert "Instance Type not found by name #{name}"
42
+ return nil
43
+ elsif instance_types.size > 1
44
+ print_red_alert "#{instance_types.size} instance types found by name #{name}"
45
+ print_instance_types_table(instance_types, {color: red})
46
+ print_red_alert "Try using ID instead"
47
+ print reset,"\n"
48
+ return nil
49
+ else
50
+ return instance_types[0]
51
+ end
52
+ end
53
+
54
+ def print_instance_types_table(instance_types, opts={})
55
+ columns = [
56
+ {"ID" => lambda {|instance_type| instance_type['id'] } },
57
+ {"NAME" => lambda {|instance_type| instance_type['name'] } },
58
+ {"CODE" => lambda {|instance_type| instance_type['code'] } },
59
+ {"TECHNOLOGY" => lambda {|instance_type| format_instance_type_technology(instance_type) } },
60
+ {"CATEGORY" => lambda {|instance_type| instance_type['category'].to_s.capitalize } },
61
+ {"FEATURED" => lambda {|instance_type| format_boolean instance_type['featured'] } },
62
+ {"OWNER" => lambda {|instance_type| instance_type['account'] ? instance_type['account']['name'] : '' } },
63
+ ]
64
+ if opts[:include_fields]
65
+ columns = opts[:include_fields]
66
+ end
67
+ print as_pretty_table(instance_types, columns, opts)
68
+ end
69
+
70
+ def format_instance_type_technology(instance_type)
71
+ if instance_type
72
+ instance_type['provisionTypeCode'].to_s.capitalize
73
+ else
74
+ ""
75
+ end
76
+ end
77
+
78
+ def load_balance_protocols_dropdown
79
+ [
80
+ {'name' => 'None', 'value' => ''},
81
+ {'name' => 'HTTP', 'value' => 'HTTP'},
82
+ {'name' => 'HTTPS', 'value' => 'HTTPS'},
83
+ {'name' => 'TCP', 'value' => 'TCP'}
84
+ ]
85
+ end
86
+
87
+ # Prompts user for exposed ports array
88
+ # returns array of port objects
89
+ def prompt_exposed_ports(options={}, api_client=nil, api_params={})
90
+ #puts "Configure ports:"
91
+ no_prompt = (options[:no_prompt] || (options[:options] && options[:options][:no_prompt]))
92
+
93
+ ports = []
94
+ port_index = 0
95
+ has_another_port = options[:options] && options[:options]["exposedPort#{port_index}"]
96
+ add_another_port = has_another_port || (!no_prompt && Morpheus::Cli::OptionTypes.confirm("Add an exposed port?"))
97
+ while add_another_port do
98
+ field_context = "exposedPort#{port_index}"
99
+
100
+ port = {}
101
+ #port['name'] ||= "Port #{port_index}"
102
+ port_label = port_index == 0 ? "Port" : "Port [#{port_index+1}]"
103
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'name', 'type' => 'text', 'fieldLabel' => "#{port_label} Name", 'required' => false, 'description' => 'Choose a name for this port.', 'defaultValue' => port['name']}], options[:options])
104
+ port['name'] = v_prompt[field_context]['name']
105
+
106
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'port', 'type' => 'number', 'fieldLabel' => "#{port_label} Number", 'required' => true, 'description' => 'A port number. eg. 8001', 'defaultValue' => (port['port'] ? port['port'].to_i : nil)}], options[:options])
107
+ port['port'] = v_prompt[field_context]['port']
108
+
109
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'loadBalanceProtocol', 'type' => 'select', 'fieldLabel' => "#{port_label} LB", 'selectOptions' => load_balance_protocols_dropdown, 'required' => false, 'skipSingleOption' => true, 'description' => 'Choose a load balance protocol.', 'defaultValue' => port['loadBalanceProtocol']}], options[:options])
110
+ port['loadBalanceProtocol'] = v_prompt[field_context]['loadBalanceProtocol']
111
+
112
+ ports << port
113
+ port_index += 1
114
+ has_another_port = options[:options] && options[:options]["exposedPort#{port_index}"]
115
+ add_another_port = has_another_port || (!no_prompt && Morpheus::Cli::OptionTypes.confirm("Add another exposed port?"))
116
+
117
+ end
118
+
119
+
120
+ return ports
121
+ end
122
+
123
+ end
@@ -58,7 +58,7 @@ module Morpheus::Cli::PrintHelper
58
58
  out << "\n"
59
59
  out << "#{color}#{bold}#{title}#{reset}"
60
60
  if !subtitles.empty?
61
- out << "#{color} - #{subtitles.join(', ')}#{reset}"
61
+ out << "#{color} | #{subtitles.join(', ')}#{reset}"
62
62
  end
63
63
  out << "\n"
64
64
  out << "#{color}#{bold}==================#{reset}"
@@ -574,8 +574,15 @@ module Morpheus::Cli::PrintHelper
574
574
  columns.each do |col|
575
575
  # determine label
576
576
  if col.is_a?(String)
577
- k = col
578
- v = col
577
+ # supports "field as Label"
578
+ field_key, field_label = col.split(/\s+as\s+/)
579
+ if field_key && field_label
580
+ k = field_label.strip
581
+ v = field_key.strip
582
+ else
583
+ k = col.strip
584
+ v = col.strip
585
+ end
579
586
  build_column_definitions([{(k) => v}]).each do |r|
580
587
  results << r if r
581
588
  end
@@ -684,15 +691,13 @@ module Morpheus::Cli::PrintHelper
684
691
  newline = opts[:csv_newline] || opts[:newline] || "\n"
685
692
  include_header = opts[:csv_no_header] ? false : true
686
693
  do_quotes = opts[:csv_quotes] || opts[:quotes]
687
- # allow passing a single hash instead of an array of hashes
688
- # todo: stop doing this, always pass an array!
689
- if columns.is_a?(Hash)
690
- columns = columns.collect {|k,v| {(k) => v} }
691
- end
692
- columns = columns.flatten.compact
694
+
695
+ column_defs = build_column_definitions(columns)
696
+ #columns = columns.flatten.compact
693
697
  data_array = [data].flatten.compact
698
+
694
699
  if include_header
695
- headers = columns.collect {|column_def| column_def.is_a?(Hash) ? column_def.keys[0].to_s : column_def.to_s }
700
+ headers = column_defs.collect {|column_def| column_def.label }
696
701
  if do_quotes
697
702
  headers = headers.collect {|it| quote_csv_value(it) }
698
703
  end
@@ -703,8 +708,10 @@ module Morpheus::Cli::PrintHelper
703
708
  data_array.each do |obj|
704
709
  if obj
705
710
  cells = []
706
- columns.each do |column_def|
707
- value = get_object_value(obj, column_def)
711
+ column_defs.each do |column_def|
712
+ label = column_def.label
713
+ value = column_def.display_method.call(obj)
714
+ # value = get_object_value(obj, column_def)
708
715
  if do_quotes
709
716
  cells << quote_csv_value(value)
710
717
  else
@@ -718,6 +725,7 @@ module Morpheus::Cli::PrintHelper
718
725
  out << lines.join(newline)
719
726
  #out << delim
720
727
  out
728
+
721
729
  end
722
730
 
723
731
  def records_as_csv(records, opts={}, default_columns=nil)
@@ -748,16 +756,7 @@ module Morpheus::Cli::PrintHelper
748
756
  if !data
749
757
  return "null" # "No data"
750
758
  end
751
-
752
- # include_fields = options[:include_fields]
753
- # if include_fields
754
- # json_fields_for = options[:json_fields_for] || options[:fields_for] || options[:root_field]
755
- # if json_fields_for && data[json_fields_for]
756
- # data[json_fields_for] = filter_data(data[json_fields_for], include_fields)
757
- # else
758
- # data = filter_data(data, include_fields)
759
- # end
760
- # end
759
+
761
760
  do_pretty = options.key?(:pretty_json) ? options[:pretty_json] : true
762
761
  if do_pretty
763
762
  out << JSON.pretty_generate(data)
@@ -117,24 +117,63 @@ module Morpheus::Cli::ProvisioningHelper
117
117
  return find_cloud_by_name_for_provisioning(group_id, val)
118
118
  end
119
119
  end
120
+
121
+ def find_instance_type_by_id(id)
122
+ begin
123
+ json_response = instance_types_interface.get(id.to_i)
124
+ return json_response['instanceType']
125
+ rescue RestClient::Exception => e
126
+ if e.response && e.response.code == 404
127
+ print_red_alert "Instance Type not found by id #{id}"
128
+ return nil
129
+ else
130
+ raise e
131
+ end
132
+ end
133
+ end
134
+
120
135
  def find_instance_type_by_code(code)
121
- results = instance_types_interface.get({code: code})
122
- if results['instanceTypes'].empty?
136
+ results = instance_types_interface.list({code: code})
137
+ instance_types = results['instanceTypes']
138
+ if instance_types.empty?
123
139
  print_red_alert "Instance Type not found by code #{code}"
124
- # return nil
125
- exit 1
140
+ return nil
126
141
  end
127
- return results['instanceTypes'][0]
142
+ if instance_types.size() > 1
143
+ print as_pretty_table(instance_types, [:id,:name,:code], {color:red})
144
+ print_red_alert "Try using ID instead"
145
+ return nil
146
+ end
147
+ # return instance_types[0]
148
+ # fetch by ID to get full details
149
+ # could also use ?details-true with search
150
+ return find_instance_type_by_id(instance_types[0]['id'])
128
151
  end
129
152
 
130
153
  def find_instance_type_by_name(name)
131
- results = instance_types_interface.get({name: name})
132
- if results['instanceTypes'].empty?
154
+ results = instance_types_interface.list({name: name})
155
+ instance_types = results['instanceTypes']
156
+ if instance_types.empty?
133
157
  print_red_alert "Instance Type not found by name #{name}"
134
- # return nil
135
- exit 1
158
+ return nil
159
+ end
160
+ if instance_types.size() > 1
161
+ print as_pretty_table(instance_types, [:id,:name,:code], {color:red})
162
+ print_red_alert "Try using ID instead"
163
+ return nil
164
+ end
165
+ # return instance_types[0]
166
+ # fetch by ID to get full details
167
+ # could also use ?details-true with search
168
+ return find_instance_type_by_id(instance_types[0]['id'])
169
+ end
170
+
171
+ def find_instance_type_by_name_or_id(val)
172
+ if val.to_s =~ /\A\d{1,}\Z/
173
+ return find_instance_type_by_id(val)
174
+ else
175
+ return find_instance_type_by_name(val)
136
176
  end
137
- return results['instanceTypes'][0]
138
177
  end
139
178
 
140
179
  def find_instance_by_name_or_id(val)
@@ -205,6 +244,7 @@ module Morpheus::Cli::ProvisioningHelper
205
244
  instance_type_code = instance_type_prompt['type']
206
245
  end
207
246
  instance_type = find_instance_type_by_code(instance_type_code)
247
+ exit 1 if !instance_type
208
248
 
209
249
  # Instance Name
210
250
 
@@ -269,7 +309,12 @@ module Morpheus::Cli::ProvisioningHelper
269
309
  service_plans = service_plans_json["plans"]
270
310
  service_plans_dropdown = service_plans.collect {|sp| {'name' => sp["name"], 'value' => sp["id"]} } # already sorted
271
311
  plan_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'servicePlan', 'type' => 'select', 'fieldLabel' => 'Plan', 'selectOptions' => service_plans_dropdown, 'required' => true, 'description' => 'Choose the appropriately sized plan for this instance'}],options[:options])
272
- service_plan = service_plans.find {|sp| sp["id"] == plan_prompt['servicePlan'].to_i }
312
+ plan_id = plan_prompt['servicePlan']
313
+ service_plan = service_plans.find {|sp| sp["id"] == plan_id.to_i }
314
+ if !service_plan
315
+ print_red_alert "Plan not found by id #{plan_id}"
316
+ exit 1
317
+ end
273
318
  payload['instance']['plan'] = {'id' => service_plan["id"]}
274
319
 
275
320
  # prompt for volumes
@@ -77,7 +77,7 @@ class Morpheus::Cli::NetworkServicesCommand
77
77
  row = {
78
78
  id: network_service['id'],
79
79
  name: network_service['name'],
80
- type: network_service['type'] ? network_service['type']['name'] : '',
80
+ type: network_service['typeName'] || network_service['type'],
81
81
  }
82
82
  row
83
83
  }
@@ -233,7 +233,12 @@ module Morpheus
233
233
  else
234
234
  print Term::ANSIColor.red, "\nInvalid Option #{option_type['fieldLabel']}: [#{use_value}]\n\n", Term::ANSIColor.reset
235
235
  print Term::ANSIColor.red, " * #{option_type['fieldLabel']} [-O #{option_type['fieldContext'] ? (option_type['fieldContext']+'.') : ''}#{option_type['fieldName']}=] - #{option_type['description']}\n", Term::ANSIColor.reset
236
- display_select_options(opt, select_options)
236
+ if select_options && select_options.size > 10
237
+ display_select_options(option_type, select_options.first(10))
238
+ puts " (#{select_options.size-1} more)"
239
+ else
240
+ display_select_options(option_type, select_options)
241
+ end
237
242
  print "\n"
238
243
  exit 1
239
244
  end
@@ -247,7 +252,12 @@ module Morpheus
247
252
  if option_type['required']
248
253
  print Term::ANSIColor.red, "\nMissing Required Option\n\n", Term::ANSIColor.reset
249
254
  print Term::ANSIColor.red, " * #{option_type['fieldLabel']} [-O #{option_type['fieldContext'] ? (option_type['fieldContext']+'.') : ''}#{option_type['fieldName']}=] - #{option_type['description']}\n", Term::ANSIColor.reset
250
- display_select_options(option_type, select_options)
255
+ if select_options && select_options.size > 10
256
+ display_select_options(option_type, select_options.first(10))
257
+ puts " (#{select_options.size-1} more)"
258
+ else
259
+ display_select_options(option_type, select_options)
260
+ end
251
261
  print "\n"
252
262
  exit 1
253
263
  else
@@ -797,7 +797,7 @@ class Morpheus::Cli::PowerSchedulingCommand
797
797
  end
798
798
 
799
799
  def find_server_by_name(name)
800
- servers = @servers_interface.get({name: name.to_s})['servers']
800
+ servers = @servers_interface.list({name: name.to_s})['servers']
801
801
  if servers.empty?
802
802
  print_red_alert "Host not found by name #{name}"
803
803
  return nil
@@ -118,7 +118,7 @@ class Morpheus::Cli::Shell
118
118
  opts.on('-C','--nocolor', "Disable ANSI coloring") do
119
119
  Term::ANSIColor::coloring = false
120
120
  end
121
- opts.on('-V','--debug', "Print extra output for debugging. ") do |json|
121
+ opts.on('-V','--debug', "Print extra output for debugging.") do |json|
122
122
  Morpheus::Logging.set_log_level(Morpheus::Logging::Logger::DEBUG)
123
123
  ::RestClient.log = Morpheus::Logging.debug? ? Morpheus::Logging::DarkPrinter.instance : nil
124
124
  end
@@ -174,13 +174,103 @@ class Morpheus::Cli::Shell
174
174
  # all_commands = input.gsub(/(\;)(?=(?:[^"]|"[^"]*")*$)/, '__CMDDELIM__').split('__CMDDELIM__').collect {|it| it.to_s.strip }.select {|it| !it.empty? }.compact
175
175
  all_commands = input.gsub(/(\;)(?=(?:[^"']|"[^'"]*")*$)/, '__CMDDELIM__').split('__CMDDELIM__').collect {|it| it.to_s.strip }.select {|it| !it.empty? }.compact
176
176
  #puts "executing #{all_commands.size} commands: #{all_commands}"
177
+ final_command_result = nil
177
178
  all_commands.each do |cmd|
178
- execute_command(cmd)
179
+ flow = parse_commands_and_operators(cmd)
180
+ if flow.size > 1
181
+ last_command_result = nil
182
+ if ['&&','||', '|'].include?(flow.first)
183
+ puts_error "invalid command format, begins with an operator: #{cmd}"
184
+ return 9
185
+ elsif ['&&','||', '|'].include?(flow.last)
186
+ puts_error "invalid command format, ends with an operator: #{cmd}"
187
+ return 9
188
+ # elsif ['&&','||', '|'].include?(flow.last)
189
+ # puts_error "invalid command format, consecutive operators: #{cmd}"
190
+ else
191
+ #Morpheus::Logging::DarkPrinter.puts "Executing command flow: #{flow.inspect}" if Morpheus::Logging.debug?
192
+ previous_command = nil
193
+ previous_command_result = nil
194
+ current_operator = nil
195
+ still_executing = true
196
+ flow.each do |flow_cmd|
197
+ if still_executing
198
+ if flow_cmd == '&&'
199
+ # AND operator
200
+ current_operator = flow_cmd
201
+ if previous_command_result.to_i != 0
202
+ still_executing = false
203
+ end
204
+ elsif flow_cmd == '||' # or with previous command
205
+ current_operator = flow_cmd
206
+ if previous_command_result.to_i == 0
207
+ still_executing = false
208
+ end
209
+ elsif flow_cmd == '|' # or with previous command
210
+ puts_error "The PIPE (|) operator is not yet supported =["
211
+ previous_command_result = nil
212
+ still_executing = false
213
+ # or just continue?
214
+ else # it's a command, not an operator
215
+ current_operator = nil
216
+ previous_command_result = execute_command(flow_cmd)
217
+ end
218
+ previous_command = flow_cmd
219
+ else
220
+ #Morpheus::Logging::DarkPrinter.puts "operator skipped command: #{flow_cmd}" if Morpheus::Logging.debug?
221
+ end
222
+ # previous_command = flow_cmd
223
+ end
224
+ final_command_result = previous_command_result
225
+ end
226
+ else
227
+ # just one command, this else is not needed tho
228
+ final_command_result = execute_command(cmd)
229
+ end
179
230
  end
180
231
  # skip logging of exit and !cmd
181
232
  unless input.strip.empty? || (["exit", "history"].include?(input.strip)) || input.strip[0].to_s.chr == "!"
182
233
  log_history_command(input.strip)
183
234
  end
235
+ return final_command_result
236
+ end
237
+
238
+ # returns Array of strings like [command1, operator, command2, operator, command3]
239
+ # eg. ["instances get 555", "||", "echo '%redInstance 555 is missing!'"]
240
+ def parse_commands_and_operators(input)
241
+ cmd = input
242
+ cmd_flow = []
243
+ begin
244
+ and_regex = /\s+\&\&\s+/
245
+ or_regex = /\s+\|\|\s+/
246
+ pipe_regex = /\s+\|\s+/
247
+ still_parsing = true
248
+ while still_parsing
249
+ and_index = cmd.index(and_regex)
250
+ or_index = cmd.index(or_regex)
251
+ pipe_index = cmd.index(pipe_regex)
252
+ if and_index # && (or_index == nil || or_index > and_index) && (pipe_index == nil || pipe_index > and_index)
253
+ cmd_flow << cmd[0..and_index-1]
254
+ cmd_flow << "&&"
255
+ cmd = cmd[and_index..-1].sub(and_regex, '')
256
+ elsif or_index && (and_index == nil || and_index > or_index) && (pipe_index == nil || pipe_index > or_index)
257
+ cmd_flow << cmd[0..or_index-1]
258
+ cmd_flow << "||"
259
+ cmd = cmd[or_index..-1].sub(or_regex, '')
260
+ elsif pipe_index && (and_index == nil || and_index > pipe_index) && (or_index == nil || or_index > pipe_index)
261
+ cmd_flow << cmd[0..pipe_index-1]
262
+ cmd_flow << "|"
263
+ cmd = cmd[pipe_index..-1].sub(pipe_regex, '')
264
+ else
265
+ cmd_flow << cmd
266
+ still_parsing = false
267
+ end
268
+ end
269
+ return cmd_flow
270
+ rescue => ex
271
+ puts_error "error parsing command flow: #{ex.message}"
272
+ return [input]
273
+ end
184
274
  end
185
275
 
186
276
  def execute_command(input)
@@ -219,21 +309,22 @@ class Morpheus::Cli::Shell
219
309
  elsif input =~ /^\s*#/
220
310
  Morpheus::Logging::DarkPrinter.puts "comment ignored" if Morpheus::Logging.debug?
221
311
  return 0
222
- elsif input =~ /^sleep/
223
- sleep_sec = input.sub("sleep ", "").to_f
224
- if (!(sleep_sec > 0))
225
- # raise_command_error "sleep requires the argument [seconds]. eg. sleep 3.14"
226
- puts_error "sleep requires argument [seconds]. eg. sleep 3.14"
227
- return false
228
- end
229
- log_history_command(input)
230
- Morpheus::Logging::DarkPrinter.puts "sleeping for #{sleep_sec}s ... zzzZzzzZ" if Morpheus::Logging.debug?
231
- begin
232
- sleep(sleep_sec)
233
- rescue Interrupt
234
- Morpheus::Logging::DarkPrinter.puts "\nInterrupt. waking up from sleep early"
235
- end
236
- return 0
312
+ # this is a full blown command now
313
+ # elsif input =~ /^sleep/
314
+ # sleep_sec = input.sub("sleep ", "").to_f
315
+ # if (!(sleep_sec > 0))
316
+ # # raise_command_error "sleep requires the argument [seconds]. eg. sleep 3.14"
317
+ # puts_error "sleep requires argument [seconds]. eg. sleep 3.14"
318
+ # return false
319
+ # end
320
+ # log_history_command(input)
321
+ # Morpheus::Logging::DarkPrinter.puts "sleeping for #{sleep_sec}s ... zzzZzzzZ" if Morpheus::Logging.debug?
322
+ # begin
323
+ # sleep(sleep_sec)
324
+ # rescue Interrupt
325
+ # Morpheus::Logging::DarkPrinter.puts "\nInterrupt. waking up from sleep early"
326
+ # end
327
+ # return 0
237
328
  elsif input =~ /^history/
238
329
  n_commands = input.sub(/^history\s?/, '').sub(/\-n\s?/, '')
239
330
  n_commands = n_commands.empty? ? 25 : n_commands.to_i
@@ -374,28 +465,30 @@ class Morpheus::Cli::Shell
374
465
  log_history_command(input)
375
466
  return Morpheus::Cli::SourceCommand.new.handle(input.split[1..-1])
376
467
  end
377
-
468
+ cmd_result = nil
378
469
  begin
379
470
  argv = Shellwords.shellsplit(input)
380
471
  cmd_name = argv[0]
381
472
  cmd_args = argv[1..-1]
382
473
  if Morpheus::Cli::CliRegistry.has_command?(cmd_name) || Morpheus::Cli::CliRegistry.has_alias?(cmd_name)
383
474
  #log_history_command(input)
384
- Morpheus::Cli::CliRegistry.exec(cmd_name, cmd_args)
475
+ cmd_result = Morpheus::Cli::CliRegistry.exec(cmd_name, cmd_args)
385
476
  else
386
477
  puts_error "#{Morpheus::Terminal.angry_prompt}'#{cmd_name}' is not a morpheus command. Use 'help' to see the list of available commands."
387
478
  @history_logger.warn "Unrecognized Command #{cmd_name}" if @history_logger
479
+ cmd_result = -1
388
480
  end
389
481
  rescue Interrupt
390
482
  # nothing to do
391
483
  @history_logger.warn "shell interrupt" if @history_logger
392
484
  print "\nInterrupt. aborting command '#{input}'\n"
393
- rescue SystemExit
485
+ rescue SystemExit => cmdexit
394
486
  # nothing to do
395
487
  # print "\n"
488
+ cmd_result = cmdexit.status
396
489
  rescue => e
397
490
  @history_logger.error "#{e.message}" if @history_logger
398
- Morpheus::Cli::ErrorHandler.new(my_terminal.stderr).handle_error(e) # lol
491
+ cmd_result = Morpheus::Cli::ErrorHandler.new(my_terminal.stderr).handle_error(e) # lol
399
492
  # exit 1
400
493
  end
401
494
 
@@ -404,7 +497,12 @@ class Morpheus::Cli::Shell
404
497
  ::RestClient.log = Morpheus::Logging.debug? ? Morpheus::Logging::DarkPrinter.instance : nil
405
498
  @return_to_log_level = nil
406
499
  end
407
-
500
+
501
+ # commands should be a number or nil (treated as 0)
502
+ if cmd_result == true
503
+ cmd_result = 0
504
+ end
505
+ return cmd_result
408
506
  end
409
507
 
410
508
  end