morpheus-cli 2.10.0 → 2.10.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. checksums.yaml +4 -4
  2. data/bin/morpheus +27 -32
  3. data/lib/morpheus/api/accounts_interface.rb +36 -47
  4. data/lib/morpheus/api/api_client.rb +141 -110
  5. data/lib/morpheus/api/app_templates_interface.rb +56 -72
  6. data/lib/morpheus/api/apps_interface.rb +111 -132
  7. data/lib/morpheus/api/auth_interface.rb +30 -0
  8. data/lib/morpheus/api/clouds_interface.rb +71 -76
  9. data/lib/morpheus/api/custom_instance_types_interface.rb +21 -46
  10. data/lib/morpheus/api/dashboard_interface.rb +10 -17
  11. data/lib/morpheus/api/deploy_interface.rb +60 -72
  12. data/lib/morpheus/api/deployments_interface.rb +53 -71
  13. data/lib/morpheus/api/groups_interface.rb +55 -45
  14. data/lib/morpheus/api/instance_types_interface.rb +19 -23
  15. data/lib/morpheus/api/instances_interface.rb +179 -177
  16. data/lib/morpheus/api/key_pairs_interface.rb +11 -17
  17. data/lib/morpheus/api/license_interface.rb +18 -23
  18. data/lib/morpheus/api/load_balancers_interface.rb +54 -69
  19. data/lib/morpheus/api/logs_interface.rb +25 -29
  20. data/lib/morpheus/api/options_interface.rb +13 -17
  21. data/lib/morpheus/api/provision_types_interface.rb +19 -22
  22. data/lib/morpheus/api/roles_interface.rb +75 -94
  23. data/lib/morpheus/api/security_group_rules_interface.rb +28 -37
  24. data/lib/morpheus/api/security_groups_interface.rb +39 -51
  25. data/lib/morpheus/api/servers_interface.rb +113 -115
  26. data/lib/morpheus/api/setup_interface.rb +31 -0
  27. data/lib/morpheus/api/task_sets_interface.rb +36 -38
  28. data/lib/morpheus/api/tasks_interface.rb +56 -69
  29. data/lib/morpheus/api/users_interface.rb +67 -76
  30. data/lib/morpheus/api/virtual_images_interface.rb +61 -61
  31. data/lib/morpheus/api/whoami_interface.rb +12 -15
  32. data/lib/morpheus/cli.rb +71 -60
  33. data/lib/morpheus/cli/accounts.rb +254 -315
  34. data/lib/morpheus/cli/alias_command.rb +219 -0
  35. data/lib/morpheus/cli/app_templates.rb +264 -272
  36. data/lib/morpheus/cli/apps.rb +608 -671
  37. data/lib/morpheus/cli/cli_command.rb +259 -21
  38. data/lib/morpheus/cli/cli_registry.rb +99 -14
  39. data/lib/morpheus/cli/clouds.rb +599 -372
  40. data/lib/morpheus/cli/config_file.rb +126 -0
  41. data/lib/morpheus/cli/credentials.rb +141 -117
  42. data/lib/morpheus/cli/dashboard_command.rb +48 -56
  43. data/lib/morpheus/cli/deployments.rb +254 -268
  44. data/lib/morpheus/cli/deploys.rb +150 -142
  45. data/lib/morpheus/cli/error_handler.rb +38 -0
  46. data/lib/morpheus/cli/groups.rb +551 -179
  47. data/lib/morpheus/cli/hosts.rb +862 -617
  48. data/lib/morpheus/cli/instance_types.rb +103 -95
  49. data/lib/morpheus/cli/instances.rb +1335 -1009
  50. data/lib/morpheus/cli/key_pairs.rb +82 -90
  51. data/lib/morpheus/cli/library.rb +498 -499
  52. data/lib/morpheus/cli/license.rb +83 -101
  53. data/lib/morpheus/cli/load_balancers.rb +314 -300
  54. data/lib/morpheus/cli/login.rb +66 -44
  55. data/lib/morpheus/cli/logout.rb +47 -46
  56. data/lib/morpheus/cli/mixins/accounts_helper.rb +69 -31
  57. data/lib/morpheus/cli/mixins/infrastructure_helper.rb +106 -0
  58. data/lib/morpheus/cli/mixins/print_helper.rb +181 -17
  59. data/lib/morpheus/cli/mixins/provisioning_helper.rb +535 -458
  60. data/lib/morpheus/cli/mixins/whoami_helper.rb +2 -2
  61. data/lib/morpheus/cli/option_parser.rb +35 -0
  62. data/lib/morpheus/cli/option_types.rb +232 -192
  63. data/lib/morpheus/cli/recent_activity_command.rb +61 -65
  64. data/lib/morpheus/cli/remote.rb +446 -199
  65. data/lib/morpheus/cli/roles.rb +884 -906
  66. data/lib/morpheus/cli/security_group_rules.rb +213 -203
  67. data/lib/morpheus/cli/security_groups.rb +237 -192
  68. data/lib/morpheus/cli/shell.rb +338 -231
  69. data/lib/morpheus/cli/tasks.rb +326 -308
  70. data/lib/morpheus/cli/users.rb +457 -462
  71. data/lib/morpheus/cli/version.rb +1 -1
  72. data/lib/morpheus/cli/version_command.rb +16 -18
  73. data/lib/morpheus/cli/virtual_images.rb +526 -345
  74. data/lib/morpheus/cli/whoami.rb +125 -111
  75. data/lib/morpheus/cli/workflows.rb +338 -185
  76. data/lib/morpheus/formatters.rb +8 -1
  77. data/lib/morpheus/logging.rb +1 -1
  78. data/lib/morpheus/rest_client.rb +17 -8
  79. metadata +9 -3
  80. data/lib/morpheus/api/custom_instance_types.rb +0 -55
@@ -2,249 +2,356 @@
2
2
  require 'io/console'
3
3
  require 'rest_client'
4
4
  require 'optparse'
5
- require 'table_print'
6
- require 'morpheus/cli/cli_command'
7
5
  require "shellwords"
8
6
  require 'readline'
9
7
  require 'logger'
10
8
  require 'fileutils'
9
+ require 'morpheus/cli/cli_command'
10
+ require 'morpheus/cli/error_handler'
11
11
 
12
12
 
13
13
  class Morpheus::Cli::Shell
14
- include Morpheus::Cli::CliCommand
15
-
16
- def initialize()
17
- @appliance_name, @appliance_url = Morpheus::Cli::Remote.active_appliance
18
- @auto_complete = proc do |s|
19
- command_list = Morpheus::Cli::CliRegistry.all.keys.reject {|k| [:shell].include?(k) }
20
- command_list += [:clear, :history, :flush_history, :exit]
21
- result = command_list.grep(/^#{Regexp.escape(s)}/)
22
- if result.nil? || result.empty?
23
- Readline::FILENAME_COMPLETION_PROC.call(s)
24
- else
25
- result
26
- end
27
- end
28
-
29
- end
30
-
31
- def handle(args)
32
- usage = "Usage: morpheus shell"
33
- @command_options = {}
34
- optparse = OptionParser.new do|opts|
35
- opts.banner = usage
36
- opts.on('-a','--account ACCOUNT', "Account Name") do |val|
37
- @command_options[:account_name] = val
14
+ include Morpheus::Cli::CliCommand
15
+
16
+ def self.instance
17
+ @@instance
18
+ end
19
+
20
+ def initialize()
21
+ @appliance_name, @appliance_url = Morpheus::Cli::Remote.active_appliance
22
+ #connect()
23
+ #raise "one shell only" if @@instance
24
+ @@instance = self
25
+ recalculate_auto_complete_commands()
26
+ end
27
+
28
+ # def connect(opts)
29
+ # @api_client = establish_remote_appliance_connection(opts)
30
+ # end
31
+
32
+ def recalculate_auto_complete_commands
33
+ @morpheus_commands = Morpheus::Cli::CliRegistry.all.keys.reject {|k| [:shell].include?(k) }
34
+ @shell_commands = [:clear, :history, :'flush-history', :reload!, :help, :exit]
35
+ @alias_commands = Morpheus::Cli::CliRegistry.all_aliases.keys
36
+ @exploded_commands = []
37
+ Morpheus::Cli::CliRegistry.all.each do |cmd, klass|
38
+ @exploded_commands << cmd.to_s
39
+ subcommands = klass.subcommands rescue []
40
+ subcommands.keys.each do |sub_cmd|
41
+ @exploded_commands << "#{cmd} #{sub_cmd}"
38
42
  end
39
- opts.on('-A','--account-id ID', "Account ID") do |val|
40
- @command_options[:account_id] = val
43
+ end
44
+ @auto_complete_commands = (@exploded_commands + @shell_commands + @alias_commands).collect {|it| it.to_s }
45
+ @auto_complete = proc do |s|
46
+ command_list = @auto_complete_commands
47
+ result = command_list.grep(/^#{Regexp.escape(s)}/)
48
+ if result.nil? || result.empty?
49
+ Readline::FILENAME_COMPLETION_PROC.call(s)
50
+ else
51
+ result
41
52
  end
42
- opts.on('-C','--nocolor', "ANSI") do
43
- @command_options[:nocolor] = true
53
+ end
54
+ end
55
+
56
+ def handle(args)
57
+ usage = "Usage: morpheus #{command_name}"
58
+ @command_options = {} # this is a way to curry options to all commands.. but meh
59
+ optparse = OptionParser.new do|opts|
60
+ opts.banner = usage
61
+ opts.on('-C','--nocolor', "ANSI") do
62
+ @command_options[:nocolor] = true
44
63
  Term::ANSIColor::coloring = false
45
64
  end
65
+ opts.on('-V','--debug', "Print extra output for debugging. ") do |json|
66
+ Morpheus::Logging.set_log_level(Morpheus::Logging::Logger::DEBUG)
67
+ @command_options[:debug] = true
68
+ end
46
69
  opts.on( '-h', '--help', "Prints this help" ) do
47
70
  puts opts
48
71
  exit
49
72
  end
50
- end
51
- optparse.parse(args)
52
-
53
- @history_logger ||= load_history_logger
54
- @history_logger.info "shell started" if @history_logger
55
- load_history_from_log_file()
56
-
57
- exit = false
58
- while !exit do
59
- Readline.completion_append_character = " "
60
- Readline.completion_proc = @auto_complete
61
- Readline.basic_word_break_characters = "\t\n\"\‘`@$><=;|&{( "
62
- input = Readline.readline("#{cyan}morpheus> #{reset}", true).to_s
63
- input = input.strip
64
- # print cyan,"morpheus > ",reset
65
- # input = $stdin.gets.chomp!
66
- if !input.empty?
67
-
68
- if input == 'exit'
69
- @history_logger.info "exit" if @history_logger
70
- break
71
- elsif input =~ /^history/
72
- n_commands = input.sub(/^history\s?/, '').sub(/\-n\s?/, '')
73
- n_commands = n_commands.empty? ? 25 : n_commands.to_i
74
- cmd_numbers = @history.keys.last(n_commands)
75
- puts "Last #{cmd_numbers.size} commands"
76
- cmd_numbers.each do |cmd_number|
77
- cmd = @history[cmd_number]
78
- puts "#{cmd_number.to_s.rjust(3, ' ')} #{cmd}"
79
- end
80
- next
81
- elsif input == 'clear'
82
- print "\e[H\e[2J"
83
- next
84
- elsif input == 'flush_history'
85
- file_path = history_file_path
86
- if File.exists?(file_path)
87
- File.truncate(file_path, 0)
88
- end
89
- @history = {}
90
- @last_command_number = 0
91
- @history_logger = load_history_logger
92
- puts "history cleared!"
93
- next
94
- elsif input == '!!'
95
- cmd_number = @history.keys[-1]
96
- input = @history[cmd_number]
97
- if !input
98
- puts "There is no previous command"
99
- next
100
- end
101
- elsif input =~ /^\!.+/
102
- cmd_number = input.sub("!", "").to_i
103
- if cmd_number != 0
104
- input = @history[cmd_number]
105
- if !input
106
- puts "Command not found by number #{cmd_index}"
107
- next
108
- end
109
- end
110
- end
111
-
112
- begin
113
- argv = Shellwords.shellsplit(input)
114
- if @command_options[:account_name]
115
- argv.push "--account", @command_options[:account_name]
116
- end
117
- if @command_options[:account_id]
118
- argv.push "--account-id", @command_options[:account_id]
119
- end
120
- if @command_options[:nocolor]
121
- argv.push "--nocolor"
122
- end
123
-
124
- # set global log level to debug (print stack trace for bubbled exceptions)
125
- if argv.find {|arg| arg == '-V' || arg == '--debug'}
126
- @return_to_log_level = Morpheus::Logging.log_level
127
- Morpheus::Logging.set_log_level(Morpheus::Logging::Logger::DEBUG)
128
- end
129
- argv = argv.find_all {|arg| arg != '-V' && arg != '--debug'}
130
-
131
- #puts "cmd: #{argv.join(' ')}"
132
-
133
- if argv[0] == 'shell'
134
- puts "You are already in a shell."
135
- elsif Morpheus::Cli::CliRegistry.has_command?(argv[0])
136
- log_history_command(input)
137
- Morpheus::Cli::CliRegistry.exec(argv[0], argv[1..-1])
138
- else
139
- @history_logger.warn "Unrecognized Command: #{input}" if @history_logger
140
- puts "Unrecognized Command."
141
- end
142
- rescue ArgumentError
143
- puts "Argument Syntax Error..."
144
- rescue Interrupt
145
- # nothing to do
146
- @history_logger.warn "shell interrupt" if @history_logger
147
- print "\n"
148
- rescue SystemExit
149
- # nothing to do
150
- print "\n"
151
- rescue OptionParser::InvalidOption => e
152
- print Term::ANSIColor.red, "\n", "#{e.message}", "", Term::ANSIColor.reset
153
- print "\n", "Try -h for help with this command.", "\n\n"
154
- rescue => e
155
- @history_logger.error "#{e.message}" if @history_logger
156
- print Term::ANSIColor.red, "\n", "Unexpected Error", "\n\n", Term::ANSIColor.reset
157
- if Morpheus::Logging.print_stacktrace?
158
- print Term::ANSIColor.red, "\n", "#{e.class}: #{e.message}", "\n", Term::ANSIColor.reset
159
- print e.backtrace.join("\n"), "\n\n"
160
- end
161
- end
162
-
163
- if @return_to_log_level
164
- Morpheus::Logging.set_log_level(@return_to_log_level)
165
- @return_to_log_level = nil
166
- end
167
-
168
- end
169
- end
170
- end
171
-
172
-
173
- def get_prompt
174
- input = ''
175
- while char=STDIN.getch do
176
- if char == '\n'
177
- print "\r\n"
178
- puts "executing..."
179
- break
180
- end
181
- print char
182
- input << char
183
- end
184
- return input
185
- end
186
-
187
- def history_file_path
188
- File.join(Dir.home, '.morpheus', "shell_history")
189
- end
190
-
191
- def load_history_logger
192
- file_path = history_file_path
193
- if !Dir.exists?(File.dirname(file_path))
194
- FileUtils.mkdir_p(File.dirname(file_path))
195
- end
196
- logger = Logger.new(file_path)
197
- # logger.formatter = proc do |severity, datetime, progname, msg|
198
- # "#{msg}\n"
199
- # end
200
- return logger
201
- end
202
-
203
- def load_history_from_log_file(n_commands=1000)
204
- @history ||= {}
205
- @last_command_number ||= 0
206
-
207
- if Gem.win_platform?
208
- return @history
209
- end
210
-
211
- begin
212
- file_path = history_file_path
213
- FileUtils.mkdir_p(File.dirname(file_path))
214
- # grab extra lines because not all log entries are commands
215
- n_lines = n_commands + 500
216
- history_lines = `tail -n #{n_lines} #{file_path}`.split(/\n/)
217
- command_lines = history_lines.select do |line|
218
- line.match(/\(cmd (\d+)\) (.+)/)
219
- end
220
- command_lines = command_lines.last(n_commands)
221
- command_lines.each do |line|
222
- matches = line.match(/\(cmd (\d+)\) (.+)/)
223
- if matches && matches.size == 3
224
- cmd_number = matches[1].to_i
225
- cmd = matches[2]
226
-
227
- @last_command_number = cmd_number
228
- @history[@last_command_number] = cmd
229
-
230
- # for Ctrl+R history searching
231
- Readline::HISTORY << cmd
232
- end
233
- end
234
- rescue => e
235
- raise e
236
- end
237
-
238
- return @history
239
- end
240
-
241
- def log_history_command(cmd)
242
- @history ||= {}
243
- @last_command_number ||= 0
244
- @last_command_number += 1
245
- @history[@last_command_number] = cmd
246
- if @history_logger
247
- @history_logger.info "(cmd #{@last_command_number}) #{cmd}"
248
- end
249
- end
250
- end
73
+ end
74
+ optparse.parse!(args)
75
+
76
+ @history_logger ||= load_history_logger rescue nil
77
+ @history_logger.info "shell started" if @history_logger
78
+ load_history_from_log_file()
79
+
80
+ exit = false
81
+ while !exit do
82
+ Readline.completion_append_character = " "
83
+ Readline.completion_proc = @auto_complete
84
+ Readline.basic_word_break_characters = ""
85
+ #Readline.basic_word_break_characters = "\t\n\"\‘`@$><=;|&{( "
86
+ input = Readline.readline("#{cyan}morpheus> #{reset}", true).to_s
87
+ input = input.strip
88
+
89
+ execute_commands(input)
90
+ end
91
+ end
92
+
93
+ def execute_commands(input)
94
+ # split the command on unquoted semicolons.
95
+ # so you can run multiple commands at once! eg hosts list; instances list
96
+ # all_commands = input.gsub(/(\;)(?=(?:[^"]|"[^"]*")*$)/, '__CMDDELIM__').split('__CMDDELIM__').collect {|it| it.to_s.strip }.select {|it| !it.empty? }.compact
97
+ all_commands = input.gsub(/(\;)(?=(?:[^"']|"[^'"]*")*$)/, '__CMDDELIM__').split('__CMDDELIM__').collect {|it| it.to_s.strip }.select {|it| !it.empty? }.compact
98
+ #puts "executing #{all_commands.size} commands: #{all_commands}"
99
+ all_commands.each do |cmd|
100
+ execute_command(cmd)
101
+ end
102
+ # skip logging of exit and !cmd
103
+ unless input.strip.empty? || (["exit"].include?(input.strip)) || input.strip[0].to_s.chr == "!"
104
+ log_history_command(input.strip)
105
+ end
106
+ end
107
+
108
+ def execute_command(input)
109
+ #puts "shell execute_command(#{input})"
110
+ @command_options = {}
111
+
112
+ input = input.to_s.strip
113
+
114
+ # print cyan,"morpheus > ",reset
115
+ # input = $stdin.gets.chomp!
116
+ if !input.empty?
117
+
118
+ if input == 'exit'
119
+ #print cyan,"Goodbye\n",reset
120
+ @history_logger.info "exit" if @history_logger
121
+ exit 0
122
+ elsif input == 'help'
123
+
124
+ puts "You are in a morpheus client shell."
125
+ puts "See the available commands below."
126
+
127
+
128
+ puts "\nCommands:"
129
+ # commands = @morpheus_commands + @shell_commands
130
+ @morpheus_commands.sort.each {|cmd|
131
+ puts "\t#{cmd.to_s}"
132
+ }
133
+ puts "\n"
134
+ puts "\nShell Commands:"
135
+ @shell_commands.each {|cmd|
136
+ puts "\t#{cmd.to_s}"
137
+ }
138
+ puts "\n"
139
+ puts "For more information."
140
+ puts "See https://github.com/gomorpheus/morpheus-cli/wiki"
141
+ print "\n"
142
+ return 0
143
+ elsif input =~ /^history/
144
+ n_commands = input.sub(/^history\s?/, '').sub(/\-n\s?/, '')
145
+ n_commands = n_commands.empty? ? 25 : n_commands.to_i
146
+ cmd_numbers = @history.keys.last(n_commands)
147
+ puts "Last #{cmd_numbers.size} commands"
148
+ cmd_numbers.each do |cmd_number|
149
+ cmd = @history[cmd_number]
150
+ puts "#{cmd_number.to_s.rjust(3, ' ')} #{cmd}"
151
+ end
152
+ return 0
153
+ elsif input == 'clear'
154
+ print "\e[H\e[2J"
155
+ return 0
156
+ elsif input == 'flush-history' || input == 'flush_history'
157
+ file_path = history_file_path
158
+ if File.exists?(file_path)
159
+ File.truncate(file_path, 0)
160
+ end
161
+ @history = {}
162
+ @last_command_number = 0
163
+ @history_logger = load_history_logger
164
+ puts "history cleared!"
165
+ return 0
166
+ elsif input == 'reload' || input == 'reload!'
167
+ #log_history_command(input)
168
+ # could just fork instead?
169
+ Morpheus::Cli.load!
170
+ Morpheus::Cli::ConfigFile.instance.reload_file
171
+ # initialize()
172
+ # gotta reload appliance, groups, credentials
173
+ @appliance_name, @appliance_url = Morpheus::Cli::Remote.active_appliance
174
+ recalculate_auto_complete_commands()
175
+ begin
176
+ load __FILE__
177
+ rescue => err
178
+ print "failed to reload #{__FILE__}. oh well"
179
+ # print err
180
+ end
181
+ print dark," #=> shell has been reloaded",reset,"\n" if Morpheus::Logging.debug?
182
+ return 0
183
+ elsif input == '!!'
184
+ cmd_number = @history.keys[-1]
185
+ input = @history[cmd_number]
186
+ if !input
187
+ puts "There is no previous command"
188
+ return 1
189
+ end
190
+ execute_commands(input)
191
+ elsif input =~ /^\!.+/
192
+ cmd_number = input.sub("!", "").to_i
193
+ if cmd_number != 0
194
+ input = @history[cmd_number]
195
+ if !input
196
+ puts "Command not found by number #{cmd_number}"
197
+ return 0
198
+ end
199
+ #puts "executing history command: (#{cmd_number}) #{input}"
200
+ execute_commands(input)
201
+ return 0
202
+ end
203
+ elsif input =~ /^log_level/ # hidden for now
204
+ log_level = input.sub(/^log_level\s*/, '').strip
205
+ if log_level == ""
206
+ puts "#{Morpheus::Logging.log_level}"
207
+ elsif log_level == "debug"
208
+ #log_history_command(input)
209
+ @command_options[:debug] = true
210
+ Morpheus::Logging.set_log_level(Morpheus::Logging::Logger::DEBUG)
211
+ elsif log_level == "info"
212
+ #log_history_command(input)
213
+ @command_options.delete(:debug)
214
+ Morpheus::Logging.set_log_level(Morpheus::Logging::Logger::INFO)
215
+ elsif log_level.to_s == "0" || (log_level.to_i > 0 && log_level.to_i < 7)
216
+ # other log levels are pointless right now..
217
+ @command_options.delete(:debug)
218
+ Morpheus::Logging.set_log_level(log_level.to_i)
219
+ else
220
+ print_red_alert "unknown log level: #{log_level}"
221
+ end
222
+ return 0
223
+ # lots of hidden commands
224
+ elsif input == "debug"
225
+ @command_options[:debug] = true
226
+ Morpheus::Logging.set_log_level(Morpheus::Logging::Logger::DEBUG)
227
+ return 0
228
+ elsif ["hello","hi","hey","hola"].include?(input.strip.downcase)
229
+ print "#{input.capitalize}, how may I #{cyan}help#{reset} you?\n"
230
+ return
231
+ elsif input == "colorize"
232
+ Term::ANSIColor::coloring = true
233
+ @command_options[:nocolor] = false
234
+ return 0
235
+ elsif input == "uncolorize"
236
+ Term::ANSIColor::coloring = false
237
+ @command_options[:nocolor] = true
238
+ return 0
239
+ elsif input == "shell"
240
+ print "#{cyan}You are already in a shell.#{reset}\n"
241
+ return false
242
+ end
243
+
244
+ begin
245
+ argv = Shellwords.shellsplit(input)
246
+
247
+
248
+ if Morpheus::Cli::CliRegistry.has_command?(argv[0]) || Morpheus::Cli::CliRegistry.has_alias?(argv[0])
249
+ #log_history_command(input)
250
+ Morpheus::Cli::CliRegistry.exec(argv[0], argv[1..-1])
251
+ else
252
+ print_yellow_warning "Unrecognized Command '#{argv[0]}'. Try 'help' to see a list of available commands."
253
+ @history_logger.warn "Unrecognized Command #{argv[0]}" if @history_logger
254
+ #puts optparse
255
+ end
256
+ # rescue ArgumentError
257
+ # puts "Argument Syntax Error..."
258
+ rescue Interrupt
259
+ # nothing to do
260
+ @history_logger.warn "shell interrupt" if @history_logger
261
+ print "\nInterrupt. aborting command '#{input}'\n"
262
+ rescue SystemExit
263
+ # nothing to do
264
+ # print "\n"
265
+ rescue => e
266
+ @history_logger.error "#{e.message}" if @history_logger
267
+ Morpheus::Cli::ErrorHandler.new.handle_error(e, @command_options)
268
+ # exit 1
269
+ end
270
+
271
+ if @return_to_log_level
272
+ Morpheus::Logging.set_log_level(@return_to_log_level)
273
+ @return_to_log_level = nil
274
+ end
275
+
276
+ end
277
+
278
+ end
279
+
280
+ def get_prompt
281
+ input = ''
282
+ while char=$stdin.getch do
283
+ if char == '\n'
284
+ print "\r\n"
285
+ puts "executing..."
286
+ break
287
+ end
288
+ print char
289
+ input << char
290
+ end
291
+ return input
292
+ end
293
+
294
+ def history_file_path
295
+ File.join(Dir.home, '.morpheus', "shell_history")
296
+ end
297
+
298
+ def load_history_logger
299
+ file_path = history_file_path
300
+ if !Dir.exists?(File.dirname(file_path))
301
+ FileUtils.mkdir_p(File.dirname(file_path))
302
+ end
303
+ logger = Logger.new(file_path)
304
+ # logger.formatter = proc do |severity, datetime, progname, msg|
305
+ # "#{msg}\n"
306
+ # end
307
+ return logger
308
+ end
309
+
310
+ def load_history_from_log_file(n_commands=1000)
311
+ @history ||= {}
312
+ @last_command_number ||= 0
313
+
314
+ begin
315
+ if Gem.win_platform?
316
+ return @history
317
+ end
318
+ file_path = history_file_path
319
+ FileUtils.mkdir_p(File.dirname(file_path))
320
+ # grab extra lines because not all log entries are commands
321
+ n_lines = n_commands + 500
322
+ history_lines = `tail -n #{n_lines} #{file_path}`.split(/\n/)
323
+ command_lines = history_lines.select do |line|
324
+ line.match(/\(cmd (\d+)\) (.+)/)
325
+ end
326
+ command_lines = command_lines.last(n_commands)
327
+ command_lines.each do |line|
328
+ matches = line.match(/\(cmd (\d+)\) (.+)/)
329
+ if matches && matches.size == 3
330
+ cmd_number = matches[1].to_i
331
+ cmd = matches[2]
332
+
333
+ @last_command_number = cmd_number
334
+ @history[@last_command_number] = cmd
335
+
336
+ # for Ctrl+R history searching
337
+ Readline::HISTORY << cmd
338
+ end
339
+ end
340
+ rescue => e
341
+ # raise e
342
+ # puts "failed to load history from log"
343
+ @history = {}
344
+ end
345
+ return @history
346
+ end
347
+
348
+ def log_history_command(cmd)
349
+ @history ||= {}
350
+ @last_command_number ||= 0
351
+ @last_command_number += 1
352
+ @history[@last_command_number] = cmd
353
+ if @history_logger
354
+ @history_logger.info "(cmd #{@last_command_number}) #{cmd}"
355
+ end
356
+ end
357
+ end