morpheus-cli 2.10.0 → 2.10.1

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 (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