morpheus-cli 3.3.1.4 → 3.3.2

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 (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