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.
- checksums.yaml +4 -4
- data/bin/morpheus +27 -32
- data/lib/morpheus/api/accounts_interface.rb +36 -47
- data/lib/morpheus/api/api_client.rb +141 -110
- data/lib/morpheus/api/app_templates_interface.rb +56 -72
- data/lib/morpheus/api/apps_interface.rb +111 -132
- data/lib/morpheus/api/auth_interface.rb +30 -0
- data/lib/morpheus/api/clouds_interface.rb +71 -76
- data/lib/morpheus/api/custom_instance_types_interface.rb +21 -46
- data/lib/morpheus/api/dashboard_interface.rb +10 -17
- data/lib/morpheus/api/deploy_interface.rb +60 -72
- data/lib/morpheus/api/deployments_interface.rb +53 -71
- data/lib/morpheus/api/groups_interface.rb +55 -45
- data/lib/morpheus/api/instance_types_interface.rb +19 -23
- data/lib/morpheus/api/instances_interface.rb +179 -177
- data/lib/morpheus/api/key_pairs_interface.rb +11 -17
- data/lib/morpheus/api/license_interface.rb +18 -23
- data/lib/morpheus/api/load_balancers_interface.rb +54 -69
- data/lib/morpheus/api/logs_interface.rb +25 -29
- data/lib/morpheus/api/options_interface.rb +13 -17
- data/lib/morpheus/api/provision_types_interface.rb +19 -22
- data/lib/morpheus/api/roles_interface.rb +75 -94
- data/lib/morpheus/api/security_group_rules_interface.rb +28 -37
- data/lib/morpheus/api/security_groups_interface.rb +39 -51
- data/lib/morpheus/api/servers_interface.rb +113 -115
- data/lib/morpheus/api/setup_interface.rb +31 -0
- data/lib/morpheus/api/task_sets_interface.rb +36 -38
- data/lib/morpheus/api/tasks_interface.rb +56 -69
- data/lib/morpheus/api/users_interface.rb +67 -76
- data/lib/morpheus/api/virtual_images_interface.rb +61 -61
- data/lib/morpheus/api/whoami_interface.rb +12 -15
- data/lib/morpheus/cli.rb +71 -60
- data/lib/morpheus/cli/accounts.rb +254 -315
- data/lib/morpheus/cli/alias_command.rb +219 -0
- data/lib/morpheus/cli/app_templates.rb +264 -272
- data/lib/morpheus/cli/apps.rb +608 -671
- data/lib/morpheus/cli/cli_command.rb +259 -21
- data/lib/morpheus/cli/cli_registry.rb +99 -14
- data/lib/morpheus/cli/clouds.rb +599 -372
- data/lib/morpheus/cli/config_file.rb +126 -0
- data/lib/morpheus/cli/credentials.rb +141 -117
- data/lib/morpheus/cli/dashboard_command.rb +48 -56
- data/lib/morpheus/cli/deployments.rb +254 -268
- data/lib/morpheus/cli/deploys.rb +150 -142
- data/lib/morpheus/cli/error_handler.rb +38 -0
- data/lib/morpheus/cli/groups.rb +551 -179
- data/lib/morpheus/cli/hosts.rb +862 -617
- data/lib/morpheus/cli/instance_types.rb +103 -95
- data/lib/morpheus/cli/instances.rb +1335 -1009
- data/lib/morpheus/cli/key_pairs.rb +82 -90
- data/lib/morpheus/cli/library.rb +498 -499
- data/lib/morpheus/cli/license.rb +83 -101
- data/lib/morpheus/cli/load_balancers.rb +314 -300
- data/lib/morpheus/cli/login.rb +66 -44
- data/lib/morpheus/cli/logout.rb +47 -46
- data/lib/morpheus/cli/mixins/accounts_helper.rb +69 -31
- data/lib/morpheus/cli/mixins/infrastructure_helper.rb +106 -0
- data/lib/morpheus/cli/mixins/print_helper.rb +181 -17
- data/lib/morpheus/cli/mixins/provisioning_helper.rb +535 -458
- data/lib/morpheus/cli/mixins/whoami_helper.rb +2 -2
- data/lib/morpheus/cli/option_parser.rb +35 -0
- data/lib/morpheus/cli/option_types.rb +232 -192
- data/lib/morpheus/cli/recent_activity_command.rb +61 -65
- data/lib/morpheus/cli/remote.rb +446 -199
- data/lib/morpheus/cli/roles.rb +884 -906
- data/lib/morpheus/cli/security_group_rules.rb +213 -203
- data/lib/morpheus/cli/security_groups.rb +237 -192
- data/lib/morpheus/cli/shell.rb +338 -231
- data/lib/morpheus/cli/tasks.rb +326 -308
- data/lib/morpheus/cli/users.rb +457 -462
- data/lib/morpheus/cli/version.rb +1 -1
- data/lib/morpheus/cli/version_command.rb +16 -18
- data/lib/morpheus/cli/virtual_images.rb +526 -345
- data/lib/morpheus/cli/whoami.rb +125 -111
- data/lib/morpheus/cli/workflows.rb +338 -185
- data/lib/morpheus/formatters.rb +8 -1
- data/lib/morpheus/logging.rb +1 -1
- data/lib/morpheus/rest_client.rb +17 -8
- metadata +9 -3
- data/lib/morpheus/api/custom_instance_types.rb +0 -55
data/lib/morpheus/cli/shell.rb
CHANGED
@@ -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
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
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
|
-
|
40
|
-
|
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
|
-
|
43
|
-
|
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
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
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
|