morpheus-cli 4.2.14 → 4.2.19
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/Dockerfile +1 -1
- data/README.md +8 -6
- data/lib/morpheus/api/api_client.rb +32 -14
- data/lib/morpheus/api/auth_interface.rb +4 -2
- data/lib/morpheus/api/backup_jobs_interface.rb +9 -0
- data/lib/morpheus/api/backups_interface.rb +16 -0
- data/lib/morpheus/api/deploy_interface.rb +25 -56
- data/lib/morpheus/api/deployments_interface.rb +44 -55
- data/lib/morpheus/api/doc_interface.rb +57 -0
- data/lib/morpheus/api/instances_interface.rb +5 -0
- data/lib/morpheus/api/rest_interface.rb +40 -0
- data/lib/morpheus/api/user_sources_interface.rb +0 -15
- data/lib/morpheus/api/users_interface.rb +2 -3
- data/lib/morpheus/benchmarking.rb +2 -2
- data/lib/morpheus/cli.rb +4 -1
- data/lib/morpheus/cli/access_token_command.rb +27 -10
- data/lib/morpheus/cli/apps.rb +21 -15
- data/lib/morpheus/cli/backup_jobs_command.rb +276 -0
- data/lib/morpheus/cli/backups_command.rb +271 -0
- data/lib/morpheus/cli/blueprints_command.rb +27 -61
- data/lib/morpheus/cli/boot_scripts_command.rb +1 -1
- data/lib/morpheus/cli/cli_command.rb +183 -45
- data/lib/morpheus/cli/cli_registry.rb +3 -0
- data/lib/morpheus/cli/clouds.rb +7 -10
- data/lib/morpheus/cli/clusters.rb +0 -18
- data/lib/morpheus/cli/commands/standard/benchmark_command.rb +23 -20
- data/lib/morpheus/cli/commands/standard/man_command.rb +1 -1
- data/lib/morpheus/cli/credentials.rb +13 -9
- data/lib/morpheus/cli/deploy.rb +374 -0
- data/lib/morpheus/cli/deployments.rb +521 -197
- data/lib/morpheus/cli/deploys.rb +271 -126
- data/lib/morpheus/cli/doc.rb +182 -0
- data/lib/morpheus/cli/error_handler.rb +23 -8
- data/lib/morpheus/cli/errors.rb +3 -2
- data/lib/morpheus/cli/image_builder_command.rb +2 -2
- data/lib/morpheus/cli/instances.rb +136 -17
- data/lib/morpheus/cli/invoices_command.rb +339 -225
- data/lib/morpheus/cli/jobs_command.rb +2 -2
- data/lib/morpheus/cli/library_layouts_command.rb +1 -1
- data/lib/morpheus/cli/library_option_lists_command.rb +61 -125
- data/lib/morpheus/cli/library_option_types_command.rb +32 -37
- data/lib/morpheus/cli/login.rb +9 -3
- data/lib/morpheus/cli/mixins/accounts_helper.rb +158 -100
- data/lib/morpheus/cli/mixins/backups_helper.rb +115 -0
- data/lib/morpheus/cli/mixins/deployments_helper.rb +135 -0
- data/lib/morpheus/cli/mixins/library_helper.rb +32 -0
- data/lib/morpheus/cli/mixins/option_source_helper.rb +1 -1
- data/lib/morpheus/cli/mixins/print_helper.rb +149 -84
- data/lib/morpheus/cli/mixins/provisioning_helper.rb +2 -2
- data/lib/morpheus/cli/mixins/whoami_helper.rb +19 -6
- data/lib/morpheus/cli/network_routers_command.rb +1 -1
- data/lib/morpheus/cli/option_parser.rb +48 -5
- data/lib/morpheus/cli/option_types.rb +46 -10
- data/lib/morpheus/cli/price_sets_command.rb +1 -1
- data/lib/morpheus/cli/projects_command.rb +7 -7
- data/lib/morpheus/cli/remote.rb +3 -2
- data/lib/morpheus/cli/roles.rb +49 -92
- data/lib/morpheus/cli/security_groups.rb +7 -1
- data/lib/morpheus/cli/service_plans_command.rb +10 -10
- data/lib/morpheus/cli/setup.rb +1 -1
- data/lib/morpheus/cli/shell.rb +7 -6
- data/lib/morpheus/cli/subnets_command.rb +1 -1
- data/lib/morpheus/cli/tasks.rb +24 -10
- data/lib/morpheus/cli/tenants_command.rb +133 -163
- data/lib/morpheus/cli/user_groups_command.rb +20 -65
- data/lib/morpheus/cli/user_settings_command.rb +115 -13
- data/lib/morpheus/cli/user_sources_command.rb +57 -24
- data/lib/morpheus/cli/users.rb +210 -186
- data/lib/morpheus/cli/version.rb +1 -1
- data/lib/morpheus/cli/whitelabel_settings_command.rb +29 -5
- data/lib/morpheus/cli/whoami.rb +113 -6
- data/lib/morpheus/cli/workflows.rb +11 -8
- data/lib/morpheus/ext/hash.rb +21 -0
- data/lib/morpheus/formatters.rb +7 -19
- data/lib/morpheus/terminal.rb +1 -0
- metadata +12 -3
- data/lib/morpheus/cli/auth_command.rb +0 -105
@@ -0,0 +1,115 @@
|
|
1
|
+
require 'morpheus/cli/mixins/print_helper'
|
2
|
+
# Mixin for Morpheus::Cli command classes
|
3
|
+
# Provides common methods for infrastructure management
|
4
|
+
module Morpheus::Cli::BackupsHelper
|
5
|
+
|
6
|
+
def self.included(klass)
|
7
|
+
klass.send :include, Morpheus::Cli::PrintHelper
|
8
|
+
end
|
9
|
+
|
10
|
+
def backups_interface
|
11
|
+
# @api_client.groups
|
12
|
+
raise "#{self.class} has not defined @backups_interface" if @backups_interface.nil?
|
13
|
+
@backups_interface
|
14
|
+
end
|
15
|
+
|
16
|
+
def backup_jobs_interface
|
17
|
+
# @api_client.groups
|
18
|
+
raise "#{self.class} has not defined @backup_jobs_interface" if @backup_jobs_interface.nil?
|
19
|
+
@backup_jobs_interface
|
20
|
+
end
|
21
|
+
|
22
|
+
def backup_object_key
|
23
|
+
'backup'
|
24
|
+
end
|
25
|
+
|
26
|
+
def backup_list_key
|
27
|
+
'backups'
|
28
|
+
end
|
29
|
+
|
30
|
+
def find_backup_by_name_or_id(val)
|
31
|
+
if val.to_s =~ /\A\d{1,}\Z/
|
32
|
+
return find_backup_by_id(val)
|
33
|
+
else
|
34
|
+
return find_backup_by_name(val)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def find_backup_by_id(id)
|
39
|
+
begin
|
40
|
+
json_response = backups_interface.get(id.to_i)
|
41
|
+
return json_response[backup_object_key]
|
42
|
+
rescue RestClient::Exception => e
|
43
|
+
if e.response && e.response.code == 404
|
44
|
+
print_red_alert "Backup not found by id '#{id}'"
|
45
|
+
else
|
46
|
+
raise e
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def find_backup_by_name(name)
|
52
|
+
json_response = backups_interface.list({name: name.to_s})
|
53
|
+
backups = json_response[backup_list_key]
|
54
|
+
if backups.empty?
|
55
|
+
print_red_alert "Backup not found by name '#{name}'"
|
56
|
+
return nil
|
57
|
+
elsif backups.size > 1
|
58
|
+
print_red_alert "#{backups.size} backups found by name '#{name}'"
|
59
|
+
puts_error as_pretty_table(backups, [:id, :name], {color:red})
|
60
|
+
print_red_alert "Try using ID instead"
|
61
|
+
print reset,"\n"
|
62
|
+
return nil
|
63
|
+
else
|
64
|
+
return backups[0]
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def backup_job_object_key
|
69
|
+
# 'backupJob'
|
70
|
+
'job'
|
71
|
+
end
|
72
|
+
|
73
|
+
def backup_job_list_key
|
74
|
+
# 'backupJobs'
|
75
|
+
'jobs'
|
76
|
+
end
|
77
|
+
|
78
|
+
def find_backup_job_by_name_or_id(val)
|
79
|
+
if val.to_s =~ /\A\d{1,}\Z/
|
80
|
+
return find_backup_job_by_id(val)
|
81
|
+
else
|
82
|
+
return find_backup_job_by_name(val)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def find_backup_job_by_id(id)
|
87
|
+
begin
|
88
|
+
json_response = backup_jobs_interface.get(id.to_i)
|
89
|
+
return json_response[backup_job_object_key]
|
90
|
+
rescue RestClient::Exception => e
|
91
|
+
if e.response && e.response.code == 404
|
92
|
+
print_red_alert "Backup job not found by id '#{id}'"
|
93
|
+
else
|
94
|
+
raise e
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def find_backup_job_by_name(name)
|
100
|
+
json_response = backup_jobs_interface.list({name: name.to_s})
|
101
|
+
backup_jobs = json_response[backup_job_list_key]
|
102
|
+
if backup_jobs.empty?
|
103
|
+
print_red_alert "Backup job not found by name '#{name}'"
|
104
|
+
return nil
|
105
|
+
elsif backup_jobs.size > 1
|
106
|
+
print_red_alert "#{backup_jobs.size} backup jobs found by name '#{name}'"
|
107
|
+
puts_error as_pretty_table(backup_jobs, [:id, :name], {color:red})
|
108
|
+
print_red_alert "Try using ID instead"
|
109
|
+
print reset,"\n"
|
110
|
+
return nil
|
111
|
+
else
|
112
|
+
return backup_jobs[0]
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
require 'morpheus/cli/mixins/print_helper'
|
2
|
+
# Mixin for Morpheus::Cli command classes
|
3
|
+
# Provides common methods for infrastructure management
|
4
|
+
module Morpheus::Cli::DeploymentsHelper
|
5
|
+
|
6
|
+
def self.included(klass)
|
7
|
+
klass.send :include, Morpheus::Cli::PrintHelper
|
8
|
+
end
|
9
|
+
|
10
|
+
## Deployments
|
11
|
+
|
12
|
+
def deployments_interface
|
13
|
+
# @api_client.groups
|
14
|
+
raise "#{self.class} has not defined @deployments_interface" if @deployments_interface.nil?
|
15
|
+
@deployments_interface
|
16
|
+
end
|
17
|
+
|
18
|
+
def deployment_object_key
|
19
|
+
'deployment'
|
20
|
+
end
|
21
|
+
|
22
|
+
def deployment_list_key
|
23
|
+
'deployments'
|
24
|
+
end
|
25
|
+
|
26
|
+
def find_deployment_by_name_or_id(val)
|
27
|
+
if val.to_s =~ /\A\d{1,}\Z/
|
28
|
+
return find_deployment_by_id(val)
|
29
|
+
else
|
30
|
+
return find_deployment_by_name(val)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def find_deployment_by_id(id)
|
35
|
+
begin
|
36
|
+
json_response = deployments_interface.get(id.to_i)
|
37
|
+
return json_response[deployment_object_key]
|
38
|
+
rescue RestClient::Exception => e
|
39
|
+
if e.response && e.response.code == 404
|
40
|
+
print_red_alert "Deployment not found by id '#{id}'"
|
41
|
+
else
|
42
|
+
raise e
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def find_deployment_by_name(name)
|
48
|
+
json_response = deployments_interface.list({name: name.to_s})
|
49
|
+
deployments = json_response[deployment_list_key]
|
50
|
+
if deployments.empty?
|
51
|
+
print_red_alert "Deployment not found by name '#{name}'"
|
52
|
+
return nil
|
53
|
+
elsif deployments.size > 1
|
54
|
+
print_red_alert "#{deployments.size} deployments found by name '#{name}'"
|
55
|
+
puts_error as_pretty_table(deployments, [:id, :name], {color:red})
|
56
|
+
print_red_alert "Try using ID instead"
|
57
|
+
print reset,"\n"
|
58
|
+
return nil
|
59
|
+
else
|
60
|
+
return deployments[0]
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
## Deployment Types
|
66
|
+
|
67
|
+
# unused?
|
68
|
+
def find_deployment_type_by_name(val)
|
69
|
+
raise "find_deployment_type_by_name passed a bad name: #{val.inspect}" if val.to_s == ''
|
70
|
+
results = @deployments_interface.deployment_types(val)
|
71
|
+
result = nil
|
72
|
+
if !results['deploymentTypes'].nil? && !results['deploymentTypes'].empty?
|
73
|
+
result = results['deploymentTypes'][0]
|
74
|
+
elsif val.to_i.to_s == val
|
75
|
+
results = @deployments_interface.deployment_types(val.to_i)
|
76
|
+
result = results['deploymentType']
|
77
|
+
end
|
78
|
+
if result.nil?
|
79
|
+
print_red_alert "Deployment Type not found by '#{val}'"
|
80
|
+
return nil
|
81
|
+
end
|
82
|
+
return result
|
83
|
+
end
|
84
|
+
|
85
|
+
## Deployment Versions
|
86
|
+
|
87
|
+
def deployment_version_object_key
|
88
|
+
# 'deploymentVersion'
|
89
|
+
'version'
|
90
|
+
end
|
91
|
+
|
92
|
+
def deployment_version_list_key
|
93
|
+
# 'deploymentVersions'
|
94
|
+
'versions'
|
95
|
+
end
|
96
|
+
|
97
|
+
def find_deployment_version_by_name_or_id(deployment_id, val)
|
98
|
+
if val.to_s =~ /\A\d{1,}\Z/
|
99
|
+
return find_deployment_version_by_id(deployment_id, val)
|
100
|
+
else
|
101
|
+
return find_deployment_version_by_name(deployment_id, val)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def find_deployment_version_by_id(deployment_id, id)
|
106
|
+
begin
|
107
|
+
json_response = deployments_interface.get_version(deployment_id, id.to_i)
|
108
|
+
return json_response[deployment_version_object_key]
|
109
|
+
rescue RestClient::Exception => e
|
110
|
+
if e.response && e.response.code == 404
|
111
|
+
print_red_alert "Deployment version not found by id '#{id}'"
|
112
|
+
else
|
113
|
+
raise e
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def find_deployment_version_by_name(deployment_id, name)
|
119
|
+
json_response = deployments_interface.list_versions(deployment_id, {userVersion: name.to_s})
|
120
|
+
deployment_versions = json_response[deployment_version_list_key]
|
121
|
+
if deployment_versions.empty?
|
122
|
+
print_red_alert "Deployment version not found by version '#{name}'"
|
123
|
+
return nil
|
124
|
+
elsif deployment_versions.size > 1
|
125
|
+
print_red_alert "#{deployment_versions.size} deployment versions found by version '#{name}'"
|
126
|
+
puts_error as_pretty_table(deployment_versions, {"ID" => 'id', "VERSION" => 'userVersion'}, {color:red})
|
127
|
+
print_red_alert "Try using ID instead"
|
128
|
+
print reset,"\n"
|
129
|
+
return nil
|
130
|
+
else
|
131
|
+
return deployment_versions[0]
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
end
|
@@ -502,4 +502,36 @@ module Morpheus::Cli::LibraryHelper
|
|
502
502
|
return {success:true, data: spec_template_ids}
|
503
503
|
end
|
504
504
|
|
505
|
+
def find_option_type_list_by_name_or_id(val)
|
506
|
+
if val.to_s =~ /\A\d{1,}\Z/
|
507
|
+
return find_option_type_list_by_id(val)
|
508
|
+
else
|
509
|
+
return find_option_type_list_by_name(val)
|
510
|
+
end
|
511
|
+
end
|
512
|
+
|
513
|
+
def find_option_type_list_by_id(id)
|
514
|
+
begin
|
515
|
+
json_response = @option_type_lists_interface.get(id.to_i)
|
516
|
+
return json_response['optionTypeList']
|
517
|
+
rescue RestClient::Exception => e
|
518
|
+
if e.response && e.response.code == 404
|
519
|
+
print_red_alert "Option List not found by id #{id}"
|
520
|
+
exit 1
|
521
|
+
else
|
522
|
+
raise e
|
523
|
+
end
|
524
|
+
end
|
525
|
+
end
|
526
|
+
|
527
|
+
def find_option_type_list_by_name(name)
|
528
|
+
json_results = @option_type_lists_interface.list({name: name.to_s})
|
529
|
+
if json_results['optionTypeLists'].empty?
|
530
|
+
print_red_alert "Option List not found by name #{name}"
|
531
|
+
exit 1
|
532
|
+
end
|
533
|
+
option_type_list = json_results['optionTypeLists'][0]
|
534
|
+
return option_type_list
|
535
|
+
end
|
536
|
+
|
505
537
|
end
|
@@ -75,7 +75,7 @@ module Morpheus::Cli::OptionSourceHelper
|
|
75
75
|
|
76
76
|
def get_cloud_options(refresh=false, api_params={})
|
77
77
|
if !@available_cloud_options || refresh
|
78
|
-
option_results = options_interface.options_for_source('clouds', api_params)
|
78
|
+
option_results = options_interface.options_for_source('clouds', api_params.mege({'default' => 'false'}))
|
79
79
|
@available_cloud_options = option_results['data'].collect {|it|
|
80
80
|
{"name" => it["name"], "value" => it["value"], "id" => it["value"]}
|
81
81
|
}
|
@@ -186,72 +186,49 @@ module Morpheus::Cli::PrintHelper
|
|
186
186
|
payload = api_request[:payload] || api_request[:body]
|
187
187
|
#Morpheus::Logging::DarkPrinter.puts "API payload is: (#{payload.class}) #{payload.inspect}"
|
188
188
|
content_type = (headers && headers['Content-Type']) ? headers['Content-Type'] : 'application/x-www-form-urlencoded'
|
189
|
-
|
189
|
+
# build output, either CURL or REQUEST
|
190
|
+
output = ""
|
191
|
+
if api_request[:curl] || options[:curl]
|
192
|
+
output = format_curl_command(http_method, url, headers, payload, options)
|
193
|
+
else
|
194
|
+
output = format_api_request(http_method, url, headers, payload, options)
|
195
|
+
end
|
196
|
+
# this is an extra scrub, should remove
|
197
|
+
if options[:scrub]
|
198
|
+
output = Morpheus::Logging.scrub_message(output)
|
199
|
+
end
|
190
200
|
# write to a file?
|
191
201
|
if options[:outfile]
|
192
|
-
output = ""
|
193
|
-
if api_request[:curl] || options[:curl]
|
194
|
-
output = format_curl_command(http_method, url, headers, payload, options)
|
195
|
-
else
|
196
|
-
# body payload
|
197
|
-
output = payload
|
198
|
-
if content_type == 'application/json'
|
199
|
-
if payload.is_a?(String)
|
200
|
-
begin
|
201
|
-
payload = JSON.parse(payload)
|
202
|
-
rescue => e
|
203
|
-
#payload = "(unparsable) #{payload}"
|
204
|
-
end
|
205
|
-
end
|
206
|
-
output = JSON.pretty_generate(payload)
|
207
|
-
else
|
208
|
-
if payload.is_a?(File)
|
209
|
-
pretty_size = "#{payload.size} B"
|
210
|
-
output = "File: #{payload.path} (#{pretty_size})"
|
211
|
-
elsif payload.is_a?(String)
|
212
|
-
output = payload
|
213
|
-
else
|
214
|
-
if content_type == 'application/x-www-form-urlencoded'
|
215
|
-
body_str = payload.to_s
|
216
|
-
begin
|
217
|
-
body_str = URI.encode_www_form(payload)
|
218
|
-
rescue => ex
|
219
|
-
# raise ex
|
220
|
-
end
|
221
|
-
output = body_str
|
222
|
-
else
|
223
|
-
begin
|
224
|
-
output = JSON.pretty_generate(payload)
|
225
|
-
rescue
|
226
|
-
output = payload.to_s
|
227
|
-
end
|
228
|
-
end
|
229
|
-
end
|
230
|
-
end
|
231
|
-
end
|
232
|
-
if options[:scrub]
|
233
|
-
output = Morpheus::Logging.scrub_message(output)
|
234
|
-
end
|
235
202
|
print_result = print_to_file(output, options[:outfile], options[:overwrite])
|
236
|
-
|
203
|
+
# with_stdout_to_file(options[:outfile], options[:overwrite]) { print output }
|
204
|
+
print "#{cyan}Wrote output to file #{options[:outfile]} (#{format_bytes File.size(options[:outfile])})\n" unless options[:quiet]
|
205
|
+
#return print_result
|
206
|
+
return
|
237
207
|
end
|
238
|
-
|
239
|
-
# curl output?
|
208
|
+
# print output
|
240
209
|
if api_request[:curl] || options[:curl]
|
241
210
|
print "\n"
|
242
|
-
|
243
|
-
|
211
|
+
print "#{cyan}#{bold}#{dark}CURL COMMAND#{reset}\n"
|
212
|
+
else
|
244
213
|
print "\n"
|
245
|
-
|
214
|
+
print "#{cyan}#{bold}#{dark}REQUEST#{reset}\n"
|
246
215
|
end
|
216
|
+
print output
|
217
|
+
print reset, "\n"
|
218
|
+
print reset
|
219
|
+
return
|
220
|
+
end
|
247
221
|
|
248
|
-
|
249
|
-
|
222
|
+
def format_api_request(http_method, url, headers, payload=nil, options={})
|
223
|
+
out = ""
|
224
|
+
# out << "\n"
|
225
|
+
# out << "#{cyan}#{bold}#{dark}REQUEST#{reset}\n"
|
250
226
|
request_string = "#{http_method.to_s.upcase} #{url}".strip
|
251
|
-
|
252
|
-
|
227
|
+
out << request_string + "\n"
|
228
|
+
out << cyan
|
253
229
|
if payload
|
254
|
-
|
230
|
+
out << "\n"
|
231
|
+
content_type = (headers && headers['Content-Type']) ? headers['Content-Type'] : 'application/x-www-form-urlencoded'
|
255
232
|
if content_type == 'application/json'
|
256
233
|
if payload.is_a?(String)
|
257
234
|
begin
|
@@ -260,23 +237,24 @@ module Morpheus::Cli::PrintHelper
|
|
260
237
|
#payload = "(unparsable) #{payload}"
|
261
238
|
end
|
262
239
|
end
|
263
|
-
|
240
|
+
out << "#{cyan}#{bold}#{dark}JSON#{reset}\n"
|
264
241
|
if options[:scrub]
|
265
|
-
|
242
|
+
out << Morpheus::Logging.scrub_message(JSON.pretty_generate(payload))
|
266
243
|
else
|
267
|
-
|
244
|
+
out << JSON.pretty_generate(payload)
|
268
245
|
end
|
269
246
|
else
|
270
|
-
|
271
|
-
|
247
|
+
out << "Content-Type: #{content_type}" + "\n"
|
248
|
+
out << reset
|
272
249
|
if payload.is_a?(File)
|
273
|
-
pretty_size = "#{payload.size} B"
|
274
|
-
|
250
|
+
#pretty_size = "#{payload.size} B"
|
251
|
+
pretty_size = format_bytes(payload.size)
|
252
|
+
out << "File: #{payload.path} (#{pretty_size})"
|
275
253
|
elsif payload.is_a?(String)
|
276
254
|
if options[:scrub]
|
277
|
-
|
255
|
+
out << Morpheus::Logging.scrub_message(payload)
|
278
256
|
else
|
279
|
-
|
257
|
+
out << payload
|
280
258
|
end
|
281
259
|
else
|
282
260
|
if content_type == 'application/x-www-form-urlencoded'
|
@@ -287,22 +265,24 @@ module Morpheus::Cli::PrintHelper
|
|
287
265
|
# raise ex
|
288
266
|
end
|
289
267
|
if options[:scrub]
|
290
|
-
|
268
|
+
out << Morpheus::Logging.scrub_message(body_str)
|
291
269
|
else
|
292
|
-
|
270
|
+
out << body_str
|
293
271
|
end
|
294
272
|
else
|
295
273
|
if options[:scrub]
|
296
|
-
|
274
|
+
out << Morpheus::Logging.scrub_message(payload)
|
297
275
|
else
|
298
|
-
|
276
|
+
out << payload
|
299
277
|
end
|
300
278
|
end
|
301
279
|
end
|
302
280
|
end
|
281
|
+
out << "\n"
|
303
282
|
end
|
304
|
-
|
305
|
-
|
283
|
+
# out << "\n"
|
284
|
+
out << reset
|
285
|
+
return out
|
306
286
|
end
|
307
287
|
|
308
288
|
# format_curl_command generates a valid curl command for the given api request
|
@@ -550,10 +530,10 @@ module Morpheus::Cli::PrintHelper
|
|
550
530
|
# label_width, justify = 0, "none"
|
551
531
|
out = ""
|
552
532
|
value = value.to_s
|
553
|
-
if do_wrap && value && Morpheus::Cli::PrintHelper.terminal_width
|
533
|
+
if do_wrap && value && value.include?(" ") && Morpheus::Cli::PrintHelper.terminal_width
|
554
534
|
value_width = Morpheus::Cli::PrintHelper.terminal_width - label_width
|
555
535
|
if value_width > 0 && value.gsub(/\e\[(\d+)m/, '').to_s.size > value_width
|
556
|
-
wrap_indent = label_width + 1
|
536
|
+
wrap_indent = label_width + 1
|
557
537
|
value = wrap(value, value_width, wrap_indent)
|
558
538
|
end
|
559
539
|
end
|
@@ -571,7 +551,7 @@ module Morpheus::Cli::PrintHelper
|
|
571
551
|
# truncate_string truncates a string and appends the suffix "..."
|
572
552
|
# @param value [String] the string to pad
|
573
553
|
# @param width [Integer] the length to truncate to
|
574
|
-
# @param
|
554
|
+
# @param suffix [String] the character to pad right side with. Default is '...'
|
575
555
|
def truncate_string(value, width, suffix="...")
|
576
556
|
value = value.to_s
|
577
557
|
# JD: hack alerty.. this sux, but it's a best effort to preserve values containing ascii coloring codes
|
@@ -603,6 +583,41 @@ module Morpheus::Cli::PrintHelper
|
|
603
583
|
end
|
604
584
|
end
|
605
585
|
|
586
|
+
# truncate_string truncates a string and appends the prefix "..."
|
587
|
+
# @param value [String] the string to pad
|
588
|
+
# @param width [Integer] the length to truncate to
|
589
|
+
# @param prefix [String] the character to pad left side with. Default is '...'
|
590
|
+
def truncate_string_right(value, width, prefix="...")
|
591
|
+
value = value.to_s
|
592
|
+
# JD: hack alerty.. this sux, but it's a best effort to preserve values containing ascii coloring codes
|
593
|
+
# it stops working when there are words separated by ascii codes, eg. two diff colors
|
594
|
+
# plus this is probably pretty slow...
|
595
|
+
uncolored_value = Term::ANSIColor.coloring? ? Term::ANSIColor.uncolored(value.to_s) : value.to_s
|
596
|
+
if uncolored_value != value
|
597
|
+
trimmed_value = nil
|
598
|
+
if uncolored_value.size > width
|
599
|
+
if prefix
|
600
|
+
trimmed_value = prefix + uncolored_value[(uncolored_value.size - width - prefix.size)..-1]
|
601
|
+
else
|
602
|
+
trimmed_value = uncolored_value[(uncolored_value.size - width)..-1]
|
603
|
+
end
|
604
|
+
return value.gsub(uncolored_value, trimmed_value)
|
605
|
+
else
|
606
|
+
return value
|
607
|
+
end
|
608
|
+
else
|
609
|
+
if value.size > width
|
610
|
+
if prefix
|
611
|
+
return prefix + value[(value.size - width - prefix.size)..-1]
|
612
|
+
else
|
613
|
+
return value[(value.size - width)..-1]
|
614
|
+
end
|
615
|
+
else
|
616
|
+
return value
|
617
|
+
end
|
618
|
+
end
|
619
|
+
end
|
620
|
+
|
606
621
|
# justified returns a left, center, or right aligned string.
|
607
622
|
# @param value [String] the string to pad
|
608
623
|
# @param width [Integer] the length to truncate to
|
@@ -872,13 +887,7 @@ module Morpheus::Cli::PrintHelper
|
|
872
887
|
out << color if color
|
873
888
|
rows.each do |row|
|
874
889
|
value = row[:value].to_s
|
875
|
-
|
876
|
-
if value_width && value_width < value.size
|
877
|
-
wrap_indent = label_width + 1
|
878
|
-
value = wrap(value, value_width, wrap_indent)
|
879
|
-
end
|
880
|
-
end
|
881
|
-
out << format_dt_dd(row[:label], value, label_width, justify) + "\n"
|
890
|
+
out << format_dt_dd(row[:label], value, label_width, justify, do_wrap) + "\n"
|
882
891
|
end
|
883
892
|
out << reset if color
|
884
893
|
return out
|
@@ -1142,16 +1151,27 @@ module Morpheus::Cli::PrintHelper
|
|
1142
1151
|
out
|
1143
1152
|
end
|
1144
1153
|
|
1145
|
-
def
|
1154
|
+
def format_list(items, conjunction="and", limit=nil)
|
1146
1155
|
items = items ? items.clone : []
|
1156
|
+
if limit
|
1157
|
+
items = items.first(limit)
|
1158
|
+
end
|
1147
1159
|
last_item = items.pop
|
1148
1160
|
if items.empty?
|
1149
1161
|
return "#{last_item}"
|
1150
1162
|
else
|
1151
|
-
return items.join(", ") + "
|
1163
|
+
return items.join(", ") + (conjunction.to_s.empty? ? ", " : " #{conjunction} ") + "#{last_item}" + ((limit && limit < (items.size+1)) ? " ..." : "")
|
1152
1164
|
end
|
1153
1165
|
end
|
1154
1166
|
|
1167
|
+
def anded_list(items, limit=nil)
|
1168
|
+
format_list(items, "and", limit)
|
1169
|
+
end
|
1170
|
+
|
1171
|
+
def ored_list(items, limit=nil)
|
1172
|
+
format_list(items, "or", limit)
|
1173
|
+
end
|
1174
|
+
|
1155
1175
|
def sleep_with_dots(sleep_seconds, dots=3, dot_chr=".")
|
1156
1176
|
dot_interval = (sleep_seconds.to_f / dots.to_i)
|
1157
1177
|
dots.to_i.times do |dot_index|
|
@@ -1161,7 +1181,7 @@ module Morpheus::Cli::PrintHelper
|
|
1161
1181
|
end
|
1162
1182
|
|
1163
1183
|
def print_to_file(txt, filename, overwrite=false, access_mode = 'w+')
|
1164
|
-
Morpheus::Logging::DarkPrinter.puts "Writing #{txt.to_s.bytesize} bytes to file #{filename}
|
1184
|
+
Morpheus::Logging::DarkPrinter.puts "Writing #{txt.to_s.bytesize} bytes to file #{filename}" if Morpheus::Logging.debug?
|
1165
1185
|
outfile = nil
|
1166
1186
|
begin
|
1167
1187
|
full_filename = File.expand_path(filename)
|
@@ -1182,7 +1202,6 @@ module Morpheus::Cli::PrintHelper
|
|
1182
1202
|
end
|
1183
1203
|
outfile = File.open(full_filename, access_mode)
|
1184
1204
|
outfile.print(txt)
|
1185
|
-
print "#{cyan}Wrote #{txt.to_s.bytesize} bytes to file #{filename}\n"
|
1186
1205
|
return 0
|
1187
1206
|
rescue => ex
|
1188
1207
|
# puts_error "Error writing to outfile '#{filename}'. Error: #{ex}"
|
@@ -1193,6 +1212,52 @@ module Morpheus::Cli::PrintHelper
|
|
1193
1212
|
end
|
1194
1213
|
end
|
1195
1214
|
|
1215
|
+
def with_stdout_to_file(filename, overwrite=false, access_mode = 'w+', &block)
|
1216
|
+
Morpheus::Logging::DarkPrinter.puts "Writing output to file #{filename}" if Morpheus::Logging.debug?
|
1217
|
+
previous_stdout = my_terminal.stdout
|
1218
|
+
outfile = nil
|
1219
|
+
begin
|
1220
|
+
full_filename = File.expand_path(filename)
|
1221
|
+
if File.exists?(full_filename)
|
1222
|
+
if !overwrite
|
1223
|
+
print "#{red}Output file '#{filename}' already exists.#{reset}\n"
|
1224
|
+
print "#{red}Use --overwrite to overwrite the existing file.#{reset}\n"
|
1225
|
+
return 1
|
1226
|
+
end
|
1227
|
+
end
|
1228
|
+
if Dir.exists?(full_filename)
|
1229
|
+
print "#{red}Output file '#{filename}' is invalid. It is the name of an existing directory.#{reset}\n"
|
1230
|
+
return 1
|
1231
|
+
end
|
1232
|
+
target_dir = File.dirname(full_filename)
|
1233
|
+
if !Dir.exists?(target_dir)
|
1234
|
+
FileUtils.mkdir_p(target_dir)
|
1235
|
+
end
|
1236
|
+
outfile = File.open(full_filename, access_mode)
|
1237
|
+
# outfile.print(txt)
|
1238
|
+
# ok just redirect stdout to the file
|
1239
|
+
my_terminal.set_stdout(outfile)
|
1240
|
+
result = yield
|
1241
|
+
outfile.close if outfile
|
1242
|
+
my_terminal.set_stdout(previous_stdout)
|
1243
|
+
my_terminal.stdout.flush if my_terminal.stdout
|
1244
|
+
# this does not work here.. i dunno why yet, it works in ensure though...
|
1245
|
+
# print "#{cyan}Wrote #{File.size(full_filename)} bytes to file #{filename}\n"
|
1246
|
+
if result
|
1247
|
+
return result
|
1248
|
+
else
|
1249
|
+
return 0
|
1250
|
+
end
|
1251
|
+
rescue => ex
|
1252
|
+
# puts_error "Error writing to outfile '#{filename}'. Error: #{ex}"
|
1253
|
+
print_error "#{red}Error writing to file '#{filename}'. Error: #{ex}#{reset}\n"
|
1254
|
+
return 1
|
1255
|
+
ensure
|
1256
|
+
outfile.close if outfile
|
1257
|
+
my_terminal.set_stdout(previous_stdout) if previous_stdout != my_terminal.stdout
|
1258
|
+
end
|
1259
|
+
end
|
1260
|
+
|
1196
1261
|
def format_percent(val, sig_dig=2)
|
1197
1262
|
if val.nil?
|
1198
1263
|
return ""
|