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.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/Dockerfile +1 -1
  3. data/README.md +8 -6
  4. data/lib/morpheus/api/api_client.rb +32 -14
  5. data/lib/morpheus/api/auth_interface.rb +4 -2
  6. data/lib/morpheus/api/backup_jobs_interface.rb +9 -0
  7. data/lib/morpheus/api/backups_interface.rb +16 -0
  8. data/lib/morpheus/api/deploy_interface.rb +25 -56
  9. data/lib/morpheus/api/deployments_interface.rb +44 -55
  10. data/lib/morpheus/api/doc_interface.rb +57 -0
  11. data/lib/morpheus/api/instances_interface.rb +5 -0
  12. data/lib/morpheus/api/rest_interface.rb +40 -0
  13. data/lib/morpheus/api/user_sources_interface.rb +0 -15
  14. data/lib/morpheus/api/users_interface.rb +2 -3
  15. data/lib/morpheus/benchmarking.rb +2 -2
  16. data/lib/morpheus/cli.rb +4 -1
  17. data/lib/morpheus/cli/access_token_command.rb +27 -10
  18. data/lib/morpheus/cli/apps.rb +21 -15
  19. data/lib/morpheus/cli/backup_jobs_command.rb +276 -0
  20. data/lib/morpheus/cli/backups_command.rb +271 -0
  21. data/lib/morpheus/cli/blueprints_command.rb +27 -61
  22. data/lib/morpheus/cli/boot_scripts_command.rb +1 -1
  23. data/lib/morpheus/cli/budgets_command.rb +4 -4
  24. data/lib/morpheus/cli/cli_command.rb +99 -41
  25. data/lib/morpheus/cli/cloud_resource_pools_command.rb +16 -0
  26. data/lib/morpheus/cli/clouds.rb +7 -10
  27. data/lib/morpheus/cli/clusters.rb +0 -18
  28. data/lib/morpheus/cli/commands/standard/benchmark_command.rb +7 -7
  29. data/lib/morpheus/cli/commands/standard/man_command.rb +1 -1
  30. data/lib/morpheus/cli/credentials.rb +13 -9
  31. data/lib/morpheus/cli/deploy.rb +374 -0
  32. data/lib/morpheus/cli/deployments.rb +521 -197
  33. data/lib/morpheus/cli/deploys.rb +271 -126
  34. data/lib/morpheus/cli/doc.rb +182 -0
  35. data/lib/morpheus/cli/error_handler.rb +23 -8
  36. data/lib/morpheus/cli/errors.rb +3 -2
  37. data/lib/morpheus/cli/image_builder_command.rb +2 -2
  38. data/lib/morpheus/cli/instances.rb +136 -17
  39. data/lib/morpheus/cli/invoices_command.rb +59 -47
  40. data/lib/morpheus/cli/jobs_command.rb +2 -2
  41. data/lib/morpheus/cli/library_instance_types_command.rb +17 -3
  42. data/lib/morpheus/cli/library_layouts_command.rb +1 -1
  43. data/lib/morpheus/cli/login.rb +9 -3
  44. data/lib/morpheus/cli/mixins/accounts_helper.rb +158 -100
  45. data/lib/morpheus/cli/mixins/backups_helper.rb +115 -0
  46. data/lib/morpheus/cli/mixins/deployments_helper.rb +135 -0
  47. data/lib/morpheus/cli/mixins/option_source_helper.rb +1 -1
  48. data/lib/morpheus/cli/mixins/print_helper.rb +110 -74
  49. data/lib/morpheus/cli/mixins/provisioning_helper.rb +2 -2
  50. data/lib/morpheus/cli/mixins/whoami_helper.rb +19 -6
  51. data/lib/morpheus/cli/network_routers_command.rb +1 -1
  52. data/lib/morpheus/cli/option_parser.rb +48 -5
  53. data/lib/morpheus/cli/option_types.rb +1 -1
  54. data/lib/morpheus/cli/projects_command.rb +7 -7
  55. data/lib/morpheus/cli/provisioning_licenses_command.rb +2 -2
  56. data/lib/morpheus/cli/remote.rb +3 -2
  57. data/lib/morpheus/cli/roles.rb +49 -92
  58. data/lib/morpheus/cli/security_groups.rb +7 -1
  59. data/lib/morpheus/cli/service_plans_command.rb +10 -10
  60. data/lib/morpheus/cli/setup.rb +1 -1
  61. data/lib/morpheus/cli/shell.rb +7 -6
  62. data/lib/morpheus/cli/subnets_command.rb +1 -1
  63. data/lib/morpheus/cli/tasks.rb +24 -10
  64. data/lib/morpheus/cli/tenants_command.rb +133 -163
  65. data/lib/morpheus/cli/user_groups_command.rb +20 -65
  66. data/lib/morpheus/cli/user_settings_command.rb +115 -13
  67. data/lib/morpheus/cli/user_sources_command.rb +57 -24
  68. data/lib/morpheus/cli/users.rb +210 -186
  69. data/lib/morpheus/cli/version.rb +1 -1
  70. data/lib/morpheus/cli/whitelabel_settings_command.rb +29 -5
  71. data/lib/morpheus/cli/whoami.rb +113 -6
  72. data/lib/morpheus/cli/workflows.rb +11 -8
  73. data/lib/morpheus/ext/hash.rb +21 -0
  74. data/lib/morpheus/terminal.rb +1 -0
  75. metadata +12 -3
  76. 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
- return print_result
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
- puts "#{cyan}#{bold}#{dark}CURL COMMAND#{reset}"
243
- print format_curl_command(http_method, url, headers, payload, options)
211
+ print "#{cyan}#{bold}#{dark}CURL COMMAND#{reset}\n"
212
+ else
244
213
  print "\n"
245
- return
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
- print "\n"
249
- puts "#{cyan}#{bold}#{dark}REQUEST#{reset}"
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
- print request_string, "\n"
252
- print cyan
227
+ out << request_string + "\n"
228
+ out << cyan
253
229
  if payload
254
- print "\n"
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
- puts "#{cyan}#{bold}#{dark}JSON#{reset}"
240
+ out << "#{cyan}#{bold}#{dark}JSON#{reset}\n"
264
241
  if options[:scrub]
265
- print Morpheus::Logging.scrub_message(JSON.pretty_generate(payload))
242
+ out << Morpheus::Logging.scrub_message(JSON.pretty_generate(payload))
266
243
  else
267
- print JSON.pretty_generate(payload)
244
+ out << JSON.pretty_generate(payload)
268
245
  end
269
246
  else
270
- print "Content-Type: #{content_type}", "\n"
271
- print reset
247
+ out << "Content-Type: #{content_type}" + "\n"
248
+ out << reset
272
249
  if payload.is_a?(File)
273
- pretty_size = "#{payload.size} B"
274
- print "File: #{payload.path} (#{pretty_size})"
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
- print Morpheus::Logging.scrub_message(payload)
255
+ out << Morpheus::Logging.scrub_message(payload)
278
256
  else
279
- print payload
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
- print Morpheus::Logging.scrub_message(body_str)
268
+ out << Morpheus::Logging.scrub_message(body_str)
291
269
  else
292
- print body_str
270
+ out << body_str
293
271
  end
294
272
  else
295
273
  if options[:scrub]
296
- print Morpheus::Logging.scrub_message(payload)
274
+ out << Morpheus::Logging.scrub_message(payload)
297
275
  else
298
- print payload
276
+ out << payload
299
277
  end
300
278
  end
301
279
  end
302
280
  end
281
+ out << "\n"
303
282
  end
304
- print "\n"
305
- print reset
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 anded_list(items)
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(", ") + " and #{last_item}"
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} ..." if Morpheus::Logging.debug?
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 ""