morpheus-cli 4.2.16 → 4.2.21
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/budgets_command.rb +4 -4
- data/lib/morpheus/cli/cli_command.rb +99 -41
- data/lib/morpheus/cli/cloud_resource_pools_command.rb +16 -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 +7 -7
- 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 +59 -47
- data/lib/morpheus/cli/jobs_command.rb +2 -2
- data/lib/morpheus/cli/library_instance_types_command.rb +17 -3
- data/lib/morpheus/cli/library_layouts_command.rb +1 -1
- 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/option_source_helper.rb +1 -1
- data/lib/morpheus/cli/mixins/print_helper.rb +110 -74
- 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 +1 -1
- data/lib/morpheus/cli/projects_command.rb +7 -7
- data/lib/morpheus/cli/provisioning_licenses_command.rb +2 -2
- 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/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
|
@@ -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
|
@@ -1171,16 +1151,27 @@ module Morpheus::Cli::PrintHelper
|
|
1171
1151
|
out
|
1172
1152
|
end
|
1173
1153
|
|
1174
|
-
def
|
1154
|
+
def format_list(items, conjunction="and", limit=nil)
|
1175
1155
|
items = items ? items.clone : []
|
1156
|
+
if limit
|
1157
|
+
items = items.first(limit)
|
1158
|
+
end
|
1176
1159
|
last_item = items.pop
|
1177
1160
|
if items.empty?
|
1178
1161
|
return "#{last_item}"
|
1179
1162
|
else
|
1180
|
-
return items.join(", ") + "
|
1163
|
+
return items.join(", ") + (conjunction.to_s.empty? ? ", " : " #{conjunction} ") + "#{last_item}" + ((limit && limit < (items.size+1)) ? " ..." : "")
|
1181
1164
|
end
|
1182
1165
|
end
|
1183
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
|
+
|
1184
1175
|
def sleep_with_dots(sleep_seconds, dots=3, dot_chr=".")
|
1185
1176
|
dot_interval = (sleep_seconds.to_f / dots.to_i)
|
1186
1177
|
dots.to_i.times do |dot_index|
|
@@ -1190,7 +1181,7 @@ module Morpheus::Cli::PrintHelper
|
|
1190
1181
|
end
|
1191
1182
|
|
1192
1183
|
def print_to_file(txt, filename, overwrite=false, access_mode = 'w+')
|
1193
|
-
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?
|
1194
1185
|
outfile = nil
|
1195
1186
|
begin
|
1196
1187
|
full_filename = File.expand_path(filename)
|
@@ -1211,7 +1202,6 @@ module Morpheus::Cli::PrintHelper
|
|
1211
1202
|
end
|
1212
1203
|
outfile = File.open(full_filename, access_mode)
|
1213
1204
|
outfile.print(txt)
|
1214
|
-
print "#{cyan}Wrote #{txt.to_s.bytesize} bytes to file #{filename}\n"
|
1215
1205
|
return 0
|
1216
1206
|
rescue => ex
|
1217
1207
|
# puts_error "Error writing to outfile '#{filename}'. Error: #{ex}"
|
@@ -1222,6 +1212,52 @@ module Morpheus::Cli::PrintHelper
|
|
1222
1212
|
end
|
1223
1213
|
end
|
1224
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
|
+
|
1225
1261
|
def format_percent(val, sig_dig=2)
|
1226
1262
|
if val.nil?
|
1227
1263
|
return ""
|