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.
- checksums.yaml +4 -4
- data/lib/morpheus/api/api_client.rb +28 -0
- data/lib/morpheus/api/instance_types_interface.rb +12 -10
- data/lib/morpheus/api/instances_interface.rb +4 -0
- data/lib/morpheus/api/library_container_scripts_interface.rb +49 -0
- data/lib/morpheus/api/library_container_templates_interface.rb +49 -0
- data/lib/morpheus/api/library_container_types_interface.rb +65 -0
- data/lib/morpheus/api/library_container_upgrades_interface.rb +66 -0
- data/lib/morpheus/api/library_instance_types_interface.rb +59 -0
- data/lib/morpheus/api/library_layouts_interface.rb +65 -0
- data/lib/morpheus/api/servers_interface.rb +4 -0
- data/lib/morpheus/api/user_sources_interface.rb +120 -0
- data/lib/morpheus/api/virtual_images_interface.rb +7 -0
- data/lib/morpheus/cli.rb +12 -1
- data/lib/morpheus/cli/accounts.rb +35 -9
- data/lib/morpheus/cli/cli_command.rb +82 -2
- data/lib/morpheus/cli/curl_command.rb +1 -1
- data/lib/morpheus/cli/echo_command.rb +1 -1
- data/lib/morpheus/cli/hosts.rb +40 -14
- data/lib/morpheus/cli/instance_types.rb +106 -64
- data/lib/morpheus/cli/instances.rb +39 -15
- data/lib/morpheus/cli/library.rb +1 -1184
- data/lib/morpheus/cli/library_container_scripts_command.rb +437 -0
- data/lib/morpheus/cli/library_container_templates_command.rb +397 -0
- data/lib/morpheus/cli/library_container_types_command.rb +653 -0
- data/lib/morpheus/cli/library_instance_types_command.rb +491 -0
- data/lib/morpheus/cli/library_layouts_command.rb +650 -0
- data/lib/morpheus/cli/library_option_lists_command.rb +476 -0
- data/lib/morpheus/cli/library_option_types_command.rb +549 -0
- data/lib/morpheus/cli/library_upgrades_command.rb +604 -0
- data/lib/morpheus/cli/mixins/library_helper.rb +123 -0
- data/lib/morpheus/cli/mixins/print_helper.rb +21 -22
- data/lib/morpheus/cli/mixins/provisioning_helper.rb +56 -11
- data/lib/morpheus/cli/network_services_command.rb +1 -1
- data/lib/morpheus/cli/option_types.rb +12 -2
- data/lib/morpheus/cli/power_scheduling_command.rb +1 -1
- data/lib/morpheus/cli/shell.rb +120 -22
- data/lib/morpheus/cli/sleep_command.rb +45 -0
- data/lib/morpheus/cli/user_sources_command.rb +963 -0
- data/lib/morpheus/cli/users.rb +33 -2
- data/lib/morpheus/cli/version.rb +1 -1
- data/lib/morpheus/cli/version_command.rb +1 -1
- data/lib/morpheus/cli/virtual_images.rb +93 -39
- data/lib/morpheus/formatters.rb +37 -27
- data/lib/morpheus/terminal.rb +1 -1
- 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}
|
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
|
-
|
578
|
-
|
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
|
-
|
688
|
-
|
689
|
-
|
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 =
|
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
|
-
|
707
|
-
|
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.
|
122
|
-
|
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
|
-
|
125
|
-
exit 1
|
140
|
+
return nil
|
126
141
|
end
|
127
|
-
|
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.
|
132
|
-
|
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
|
-
|
135
|
-
|
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
|
-
|
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['
|
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
|
-
|
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
|
-
|
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.
|
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
|
data/lib/morpheus/cli/shell.rb
CHANGED
@@ -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.
|
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
|
-
|
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
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
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
|