morpheus-cli 0.9.9 → 0.9.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/lib/morpheus/api/api_client.rb +4 -0
  3. data/lib/morpheus/api/app_templates_interface.rb +74 -0
  4. data/lib/morpheus/api/instance_types_interface.rb +9 -0
  5. data/lib/morpheus/api/instances_interface.rb +16 -0
  6. data/lib/morpheus/api/roles_interface.rb +37 -1
  7. data/lib/morpheus/cli.rb +4 -1
  8. data/lib/morpheus/cli/accounts.rb +82 -58
  9. data/lib/morpheus/cli/app_templates.rb +908 -0
  10. data/lib/morpheus/cli/apps.rb +226 -187
  11. data/lib/morpheus/cli/cli_command.rb +57 -30
  12. data/lib/morpheus/cli/clouds.rb +50 -65
  13. data/lib/morpheus/cli/deployments.rb +18 -33
  14. data/lib/morpheus/cli/deploys.rb +1 -3
  15. data/lib/morpheus/cli/groups.rb +54 -38
  16. data/lib/morpheus/cli/hosts.rb +86 -80
  17. data/lib/morpheus/cli/instance_types.rb +42 -29
  18. data/lib/morpheus/cli/instances.rb +192 -69
  19. data/lib/morpheus/cli/key_pairs.rb +70 -87
  20. data/lib/morpheus/cli/license.rb +7 -9
  21. data/lib/morpheus/cli/load_balancers.rb +23 -53
  22. data/lib/morpheus/cli/mixins/accounts_helper.rb +7 -8
  23. data/lib/morpheus/cli/mixins/print_helper.rb +67 -0
  24. data/lib/morpheus/cli/mixins/provisioning_helper.rb +461 -0
  25. data/lib/morpheus/cli/option_types.rb +71 -18
  26. data/lib/morpheus/cli/roles.rb +725 -34
  27. data/lib/morpheus/cli/security_group_rules.rb +50 -70
  28. data/lib/morpheus/cli/security_groups.rb +61 -48
  29. data/lib/morpheus/cli/shell.rb +123 -14
  30. data/lib/morpheus/cli/tasks.rb +24 -59
  31. data/lib/morpheus/cli/users.rb +86 -71
  32. data/lib/morpheus/cli/version.rb +1 -1
  33. data/lib/morpheus/cli/virtual_images.rb +21 -51
  34. data/lib/morpheus/cli/workflows.rb +14 -29
  35. data/lib/morpheus/ext/nil_class.rb +5 -0
  36. data/lib/morpheus/formatters.rb +1 -0
  37. metadata +7 -3
  38. data/lib/morpheus/cli/error_handler.rb +0 -44
@@ -1,7 +1,6 @@
1
1
  # require 'yaml'
2
2
  require 'io/console'
3
3
  require 'rest_client'
4
- require 'term/ansicolor'
5
4
  require 'optparse'
6
5
  require 'filesize'
7
6
  require 'table_print'
@@ -9,7 +8,7 @@ require 'morpheus/cli/cli_command'
9
8
 
10
9
  class Morpheus::Cli::SecurityGroupRules
11
10
  include Morpheus::Cli::CliCommand
12
- include Term::ANSIColor
11
+
13
12
  def initialize()
14
13
  @appliance_name, @appliance_url = Morpheus::Cli::Remote.active_appliance
15
14
  @access_token = Morpheus::Cli::Credentials.new(@appliance_name,@appliance_url).request_credentials()
@@ -20,7 +19,7 @@ class Morpheus::Cli::SecurityGroupRules
20
19
 
21
20
  def handle(args)
22
21
  if @access_token.empty?
23
- print red,bold, "\nInvalid Credentials. Unable to acquire access token. Please verify your credentials and try again.\n\n",reset
22
+ print_red_alert "Invalid Credentials. Unable to acquire access token. Please verify your credentials and try again."
24
23
  return 1
25
24
  end
26
25
  if args.empty?
@@ -49,25 +48,22 @@ Usage: morpheus security-group-rules add_custom_rule SOURCE_CIDR PORT_RANGE PROT
49
48
  PORT_RANGE: Port value (i.e. 123) or port range (i.e. 1-65535)
50
49
  PROTOCOL: tcp, udp, icmp\n\n'
51
50
  EOT
52
-
53
- if args.count < 3
54
- puts usage
55
- return
56
- end
57
-
51
+ options = {}
58
52
  security_group_id = nil
59
53
  optparse = OptionParser.new do|opts|
60
- opts.banner = "\nUsage: morpheus security-group-rules add_custom_rule SOURCE_CIDR PORT_RANGE PROTOCOL [options]"
54
+ opts.banner = usage
61
55
  opts.on( '-s', '--secgroup SECGROUP', "Security Group ID (Use will use security as set with 'security-groups use id'" ) do |id|
62
56
  security_group_id = id
63
57
  end
64
- opts.on( '-h', '--help', "Prints this help" ) do
65
- puts opts
66
- exit
67
- end
58
+ build_common_options(opts, options, [])
68
59
  end
69
60
  optparse.parse(args)
70
61
 
62
+ if args.count < 3
63
+ puts "\n#{optparse.banner}\n\n"
64
+ exit 1
65
+ end
66
+
71
67
  if security_group_id.nil?
72
68
  security_group_id = @active_security_group[@appliance_name.to_sym]
73
69
  end
@@ -77,7 +73,7 @@ EOT
77
73
  exit
78
74
  end
79
75
 
80
- options = {
76
+ params = {
81
77
  :rule => {
82
78
  :source => args[0],
83
79
  :portRange => args[1],
@@ -87,17 +83,12 @@ EOT
87
83
  }
88
84
 
89
85
  begin
90
- @security_group_rules_interface.create(security_group_id, options)
91
- rescue => e
92
- if e.response.code == 400
93
- error = JSON.parse(e.response.to_s)
94
- ::Morpheus::Cli::ErrorHandler.new.print_errors(error)
95
- else
96
- puts "Error Communicating with the Appliance. Please try again later. #{e}"
97
- end
98
- return nil
86
+ @security_group_rules_interface.create(security_group_id, params)
87
+ list([])
88
+ rescue RestClient::Exception => e
89
+ print_rest_exception(e, options)
90
+ exit 1
99
91
  end
100
- list([])
101
92
  end
102
93
 
103
94
  def add_instance_rule(args)
@@ -106,24 +97,21 @@ Usage: morpheus security-group-rules add_instance_rule SOURCE_CIDR INSTANCE_TYPE
106
97
  SOURCE_CIDR: CIDR to white-list
107
98
  INSTANCE_TYPE_ID: ID of the Instance Type to access
108
99
  EOT
109
- if args.count < 2
110
- puts usage
111
- return
112
- end
113
100
 
101
+ options = {}
114
102
  security_group_id = nil
115
103
  optparse = OptionParser.new do|opts|
116
- opts.banner = "\nmorpheus security-group-rules add_instance_rule SOURCE_CIDR INSTANCE_TYPE_ID [options]"
104
+ opts.banner = usage
117
105
  opts.on( '-s', '--secgroup secgroup', "Security Group ID (Use will use security as set with 'security-groups use id'" ) do |id|
118
106
  security_group_id = id
119
107
  end
120
- opts.on( '-h', '--help', "Prints this help" ) do
121
- puts opts
122
- exit
123
- end
108
+ build_common_options(opts, options, [])
124
109
  end
125
110
  optparse.parse(args)
126
-
111
+ if args.count < 2
112
+ puts "\n#{optparse.banner}\n\n"
113
+ exit 1
114
+ end
127
115
  if security_group_id.nil?
128
116
  security_group_id = @active_security_group[@appliance_name.to_sym]
129
117
  end
@@ -133,7 +121,7 @@ EOT
133
121
  exit
134
122
  end
135
123
 
136
- options = {
124
+ params = {
137
125
  :rule => {
138
126
  :source => args[0],
139
127
  :instanceTypeId => args[1]
@@ -141,17 +129,12 @@ EOT
141
129
  }
142
130
 
143
131
  begin
144
- @security_group_rules_interface.create(security_group_id, options)
145
- rescue => e
146
- if e.response.code == 400
147
- error = JSON.parse(e.response.to_s)
148
- ::Morpheus::Cli::ErrorHandler.new.print_errors(error)
149
- else
150
- puts "Error Communicating with the Appliance. Please try again later. #{e}"
151
- end
152
- return nil
132
+ @security_group_rules_interface.create(security_group_id, params)
133
+ list([security_group_id])
134
+ rescue RestClient::Exception => e
135
+ print_rest_exception(e, options)
136
+ exit 1
153
137
  end
154
- list([])
155
138
  end
156
139
 
157
140
  def list(args)
@@ -159,7 +142,7 @@ EOT
159
142
  security_group_id = nil
160
143
  optparse = OptionParser.new do|opts|
161
144
  opts.banner = "\nUsage: morpheus security-group-rules list [ID]"
162
- Morpheus::Cli::CliCommand.genericOptions(opts,options)
145
+ build_common_options(opts, options, [:json])
163
146
  end
164
147
  security_group_id = args[0].to_i
165
148
  optparse.parse(args)
@@ -175,7 +158,12 @@ EOT
175
158
 
176
159
  begin
177
160
  params = {}
178
- json_response = @security_group_rules_interface.get(security_group_id, options)
161
+ json_response = @security_group_rules_interface.get(security_group_id, params)
162
+ if options[:json]
163
+ print JSON.pretty_generate(json_response)
164
+ print "\n"
165
+ return
166
+ end
179
167
  rules = json_response['rules']
180
168
  print "\n" ,cyan, bold, "Morpheus Security Group Rules for Security Group ID:#{security_group_id}\n","==================", reset, "\n\n"
181
169
  if rules.empty?
@@ -187,31 +175,28 @@ EOT
187
175
  end
188
176
  print reset,"\n\n"
189
177
 
190
- rescue => e
191
- puts "Error Communicating with the Appliance. Please try again later. #{e}"
192
- return nil
178
+ rescue RestClient::Exception => e
179
+ print_rest_exception(e, options)
180
+ exit 1
193
181
  end
194
182
  end
195
183
 
196
184
  def remove(args)
197
- if args.count < 1
198
- puts "\nUsage: morpheus security-group-rules remove ID [options]\n\n"
199
- return
200
- end
201
-
185
+
186
+ options = {}
202
187
  security_group_id = nil
203
188
  optparse = OptionParser.new do|opts|
204
- opts.banner = "\nUsage: morpheus security-group-rules remove ID [options]"
189
+ opts.banner = "Usage: morpheus security-group-rules remove ID [options]"
205
190
  opts.on( '-s', '--secgroup secgroup', "Security Group ID (Use will use security as set with 'security-groups use id'" ) do |id|
206
191
  security_group_id = id
207
192
  end
208
- opts.on( '-h', '--help', "Prints this help" ) do
209
- puts opts
210
- exit
211
- end
193
+ build_common_options(opts, options, [])
212
194
  end
213
195
  optparse.parse(args)
214
-
196
+ if args.count < 1
197
+ puts "\n#{optparse.banner}\n\n"
198
+ exit 1
199
+ end
215
200
  if security_group_id.nil?
216
201
  security_group_id = @active_security_group[@appliance_name.to_sym]
217
202
  end
@@ -223,15 +208,10 @@ EOT
223
208
 
224
209
  begin
225
210
  @security_group_rules_interface.delete(security_group_id, args[0])
226
- list([])
211
+ list([security_group_id])
227
212
  rescue RestClient::Exception => e
228
- if e.response.code == 400
229
- error = JSON.parse(e.response.to_s)
230
- ::Morpheus::Cli::ErrorHandler.new.print_errors(error)
231
- else
232
- puts "Error Communicating with the Appliance. Please try again later. #{e}"
233
- end
234
- return nil
213
+ print_rest_exception(e, options)
214
+ exit 1
235
215
  end
236
216
  end
237
217
 
@@ -1,7 +1,6 @@
1
1
  # require 'yaml'
2
2
  require 'io/console'
3
3
  require 'rest_client'
4
- require 'term/ansicolor'
5
4
  require 'optparse'
6
5
  require 'filesize'
7
6
  require 'table_print'
@@ -9,7 +8,7 @@ require 'morpheus/cli/cli_command'
9
8
 
10
9
  class Morpheus::Cli::SecurityGroups
11
10
  include Morpheus::Cli::CliCommand
12
- include Term::ANSIColor
11
+
13
12
  def initialize()
14
13
  @appliance_name, @appliance_url = Morpheus::Cli::Remote.active_appliance
15
14
  @access_token = Morpheus::Cli::Credentials.new(@appliance_name,@appliance_url).request_credentials()
@@ -20,7 +19,7 @@ class Morpheus::Cli::SecurityGroups
20
19
 
21
20
  def handle(args)
22
21
  if @access_token.empty?
23
- print red,bold, "\nInvalid Credentials. Unable to acquire access token. Please verify your credentials and try again.\n\n",reset
22
+ print_red_alert "Invalid Credentials. Unable to acquire access token. Please verify your credentials and try again."
24
23
  return 1
25
24
  end
26
25
  if args.empty?
@@ -45,6 +44,12 @@ class Morpheus::Cli::SecurityGroups
45
44
  end
46
45
 
47
46
  def list(args)
47
+ options = {}
48
+ optparse = OptionParser.new do|opts|
49
+ opts.banner = "\nUsage: morpheus security-groups list"
50
+ build_common_options(opts, options, [])
51
+ end
52
+ optparse.parse(args)
48
53
  begin
49
54
  json_response = @security_groups_interface.list()
50
55
  security_groups = json_response['securityGroups']
@@ -53,21 +58,32 @@ class Morpheus::Cli::SecurityGroups
53
58
  puts yellow,"No Security Groups currently configured.",reset
54
59
  else
55
60
  security_groups.each do |security_group|
56
- print cyan, "= #{security_group['id']}: #{security_group['name']} (#{security_group['description']})\n"
61
+
62
+ if @active_security_group[@appliance_name.to_sym] = security_group['id']
63
+ print cyan, "=> #{security_group['id']}: #{security_group['name']} (#{security_group['description']})\n"
64
+ else
65
+ print cyan, "= #{security_group['id']}: #{security_group['name']} (#{security_group['description']})\n"
66
+ end
57
67
  end
58
68
  end
59
69
  print reset,"\n\n"
60
70
 
61
- rescue => e
62
- puts "Error Communicating with the Appliance. Please try again later. #{e}"
63
- return nil
71
+ rescue RestClient::Exception => e
72
+ print_rest_exception(e, options)
73
+ exit 1
64
74
  end
65
75
  end
66
76
 
67
77
  def get(args)
78
+ options = {}
79
+ optparse = OptionParser.new do|opts|
80
+ opts.banner = "Usage: morpheus security-groups get ID"
81
+ build_common_options(opts, options, [])
82
+ end
83
+ optparse.parse(args)
68
84
  if args.count < 1
69
- puts "\nUsage: morpheus security-groups get ID\n\n"
70
- return
85
+ puts "\n#{optparse.banner}\n\n"
86
+ exit 1
71
87
  end
72
88
 
73
89
  begin
@@ -81,49 +97,45 @@ class Morpheus::Cli::SecurityGroups
81
97
  end
82
98
  print reset,"\n\n"
83
99
 
84
- rescue => e
85
- puts "Error Communicating with the Appliance. Please try again later. #{e}"
86
- return nil
100
+ rescue RestClient::Exception => e
101
+ print_rest_exception(e, options)
102
+ exit 1
87
103
  end
88
104
  end
89
105
 
90
106
  def add(args)
91
- if args.count < 1
92
- puts "\nUsage: morpheus security-groups add NAME [options]\n\n"
93
- return
94
- end
95
-
96
- options = {:securityGroup => {:name => args[0]} }
107
+ options = {}
108
+ params = {:securityGroup => {:name => args[0]} }
97
109
  optparse = OptionParser.new do|opts|
98
110
  opts.banner = "\nUsage: morpheus security-groups add NAME [options]"
99
111
  opts.on( '-d', '--description Description', "Description of the security group" ) do |description|
100
- options[:securityGroup][:description] = description
101
- end
102
-
103
- opts.on( '-h', '--help', "Prints this help" ) do
104
- puts opts
105
- exit
112
+ params[:securityGroup][:description] = description
106
113
  end
114
+ build_common_options(opts, options, [])
107
115
  end
108
116
  optparse.parse(args)
109
-
117
+ if args.count < 1
118
+ puts "\n#{optparse.banner}\n\n"
119
+ exit 1
120
+ end
110
121
  begin
111
- @security_groups_interface.create(options)
112
- rescue => e
113
- if e.response.code == 400
114
- error = JSON.parse(e.response.to_s)
115
- ::Morpheus::Cli::ErrorHandler.new.print_errors(error)
116
- else
117
- puts "Error Communicating with the Appliance. Please try again later. #{e}"
118
- end
119
- return nil
122
+ @security_groups_interface.create(params)
123
+ list([])
124
+ rescue RestClient::Exception => e
125
+ print_rest_exception(e, options)
126
+ exit 1
120
127
  end
121
- list([])
122
128
  end
123
129
 
124
130
  def remove(args)
131
+ options = {}
132
+ optparse = OptionParser.new do|opts|
133
+ opts.banner = "\nUsage: morpheus security-groups remove ID"
134
+ build_common_options(opts, options, [])
135
+ end
136
+ optparse.parse(args)
125
137
  if args.count < 1
126
- puts "\nUsage: morpheus security-groups remove ID\n\n"
138
+ puts "\n#{optparse.banner}\n\n"
127
139
  return
128
140
  end
129
141
  begin
@@ -136,19 +148,20 @@ class Morpheus::Cli::SecurityGroups
136
148
  @security_groups_interface.delete(security_group['id'])
137
149
  list([])
138
150
  rescue RestClient::Exception => e
139
- if e.response.code == 400
140
- error = JSON.parse(e.response.to_s)
141
- ::Morpheus::Cli::ErrorHandler.new.print_errors(error)
142
- else
143
- puts "Error Communicating with the Appliance. Please try again later. #{e}"
144
- end
145
- return nil
151
+ print_rest_exception(e, options)
152
+ exit 1
146
153
  end
147
154
  end
148
155
 
149
- def use(args)
156
+ def use(args)
157
+ options = {}
158
+ optparse = OptionParser.new do|opts|
159
+ opts.banner = "Usage: morpheus security-groups use ID"
160
+ build_common_options(opts, options, [])
161
+ end
162
+ optparse.parse(args)
150
163
  if args.length < 1
151
- puts "Usage: morpheus security-groups use ID"
164
+ puts "\n#{optparse.banner}\n\n"
152
165
  return
153
166
  end
154
167
  begin
@@ -161,9 +174,9 @@ class Morpheus::Cli::SecurityGroups
161
174
  else
162
175
  puts "Security Group not found"
163
176
  end
164
- rescue => e
165
- puts "Error Communicating with the Appliance. Please try again later. #{e}"
166
- return nil
177
+ rescue RestClient::Exception => e
178
+ print_rest_exception(e, options)
179
+ exit 1
167
180
  end
168
181
  end
169
182
 
@@ -7,6 +7,8 @@ require 'table_print'
7
7
  require 'morpheus/cli/cli_command'
8
8
  require "shellwords"
9
9
  require 'readline'
10
+ require 'logger'
11
+ require 'fileutils'
10
12
 
11
13
 
12
14
  class Morpheus::Cli::Shell
@@ -15,7 +17,8 @@ class Morpheus::Cli::Shell
15
17
  def initialize()
16
18
  @appliance_name, @appliance_url = Morpheus::Cli::Remote.active_appliance
17
19
  @auto_complete = proc do |s|
18
- command_list = Morpheus::Cli::CliRegistry.all.keys
20
+ command_list = Morpheus::Cli::CliRegistry.all.keys.reject {|k| [:shell].include?(k) }
21
+ command_list += [:clear, :history, :flush_history, :exit]
19
22
  result = command_list.grep(/^#{Regexp.escape(s)}/)
20
23
  if result.nil? || result.empty?
21
24
  Readline::FILENAME_COMPLETION_PROC.call(s)
@@ -24,7 +27,6 @@ class Morpheus::Cli::Shell
24
27
  end
25
28
  end
26
29
 
27
-
28
30
  end
29
31
 
30
32
  def handle(args)
@@ -49,7 +51,10 @@ class Morpheus::Cli::Shell
49
51
  end
50
52
  optparse.parse(args)
51
53
 
52
- history = []
54
+ @history_logger ||= load_history_logger
55
+ @history_logger.info "shell started" if @history_logger
56
+ load_history_from_log_file()
57
+
53
58
  remote_handler = Morpheus::Cli::Remote.new()
54
59
  exit = false
55
60
  while !exit do
@@ -57,28 +62,56 @@ class Morpheus::Cli::Shell
57
62
  Readline.completion_proc = @auto_complete
58
63
  Readline.basic_word_break_characters = "\t\n\"\‘`@$><=;|&{( "
59
64
  input = Readline.readline("#{cyan}morpheus> #{reset}", true).to_s
65
+ input = input.strip
60
66
  # print cyan,"morpheus > ",reset
61
67
  # input = $stdin.gets.chomp!
62
68
  if !input.empty?
63
69
 
64
70
  if input == 'exit'
71
+ @history_logger.info "exit" if @history_logger
65
72
  break
66
- elsif input == 'history'
67
- commands = history.last(100)
68
- puts "Last #{commands.size} commands"
69
- commands.reverse.each do |cmd|
70
- puts "#{cmd}"
73
+ elsif input =~ /^history/
74
+ n_commands = input.sub(/^history\s?/, '').sub(/\-n\s?/, '')
75
+ n_commands = n_commands.empty? ? 25 : n_commands.to_i
76
+ cmd_numbers = @history.keys.last(n_commands)
77
+ puts "Last #{cmd_numbers.size} commands"
78
+ cmd_numbers.each do |cmd_number|
79
+ cmd = @history[cmd_number]
80
+ puts "#{cmd_number.to_s.rjust(3, ' ')} #{cmd}"
71
81
  end
72
82
  next
73
83
  elsif input == 'clear'
74
84
  print "\e[H\e[2J"
75
85
  next
76
- elsif input == '!'
77
- input = history[-1]
86
+ elsif input == 'flush_history'
87
+ file_path = history_file_path
88
+ if File.exists?(file_path)
89
+ File.truncate(file_path, 0)
90
+ end
91
+ @history = {}
92
+ @last_command_number = 0
93
+ @history_logger = load_history_logger
94
+ puts "history cleared!"
95
+ next
96
+ elsif input == '!!'
97
+ cmd_number = @history.keys[-1]
98
+ input = @history[cmd_number]
99
+ if !input
100
+ puts "There is no previous command"
101
+ next
102
+ end
103
+ elsif input =~ /^\!.+/
104
+ cmd_number = input.sub("!", "").to_i
105
+ if cmd_number != 0
106
+ input = @history[cmd_number]
107
+ if !input
108
+ puts "Command not found by number #{cmd_index}"
109
+ next
110
+ end
111
+ end
78
112
  end
79
113
 
80
114
  begin
81
- history << input
82
115
  argv = Shellwords.shellsplit(input)
83
116
  if @command_options[:account_name]
84
117
  argv.push "--account", @command_options[:account_name]
@@ -90,19 +123,31 @@ class Morpheus::Cli::Shell
90
123
  argv.push "--nocolor"
91
124
  end
92
125
  #puts "cmd: #{argv.join(' ')}"
93
- if argv[0] == 'remote'
126
+
127
+ if argv[0] == 'shell'
128
+ puts "Unrecognized Command."
129
+ elsif argv[0] == 'remote'
130
+ log_history_command(input)
94
131
  remote_handler.handle(argv[1..-1])
95
132
  elsif Morpheus::Cli::CliRegistry.has_command?(argv[0])
133
+ log_history_command(input)
96
134
  Morpheus::Cli::CliRegistry.exec(argv[0], argv[1..-1])
97
135
  else
136
+ @history_logger.warn "Unrecognized Command: #{input}" if @history_logger
98
137
  puts "Unrecognized Command."
99
138
  end
100
139
  rescue ArgumentError
101
140
  puts "Argument Syntax Error..."
102
- rescue SystemExit, Interrupt
103
- # nothing to do
141
+ rescue Interrupt
142
+ # nothing to do
143
+ @history_logger.warn "shell interrupt" if @history_logger
144
+ print "\n"
145
+ rescue SystemExit
146
+ # nothing to do
104
147
  print "\n"
105
148
  rescue => e
149
+
150
+ @history_logger.error "#{e.message}" if @history_logger
106
151
  print red, "\n", e.message, "\n", reset
107
152
  print e.backtrace.join("\n"), "\n"
108
153
  end
@@ -125,4 +170,68 @@ class Morpheus::Cli::Shell
125
170
  end
126
171
  return input
127
172
  end
173
+
174
+ def history_file_path
175
+ File.join(Dir.home, '.morpheus', "shell_history")
176
+ end
177
+
178
+ def load_history_logger
179
+ file_path = history_file_path
180
+ if !Dir.exists?(File.dirname(file_path))
181
+ FileUtils.mkdir_p(File.dirname(file_path))
182
+ end
183
+ logger = Logger.new(file_path)
184
+ # logger.formatter = proc do |severity, datetime, progname, msg|
185
+ # "#{msg}\n"
186
+ # end
187
+ return logger
188
+ end
189
+
190
+ def load_history_from_log_file(n_commands=1000)
191
+ @history ||= {}
192
+ @last_command_number ||= 0
193
+
194
+ if Gem.win_platform?
195
+ return @history
196
+ end
197
+
198
+ begin
199
+ file_path = history_file_path
200
+ FileUtils.mkdir_p(File.dirname(file_path))
201
+ # grab extra lines because not all log entries are commands
202
+ n_lines = n_commands + 500
203
+ history_lines = `tail -n #{n_lines} #{file_path}`.split(/\n/)
204
+ command_lines = history_lines.select do |line|
205
+ line.match(/\(cmd (\d+)\) (.+)/)
206
+ end
207
+ command_lines = command_lines.last(n_commands)
208
+ command_lines.each do |line|
209
+ matches = line.match(/\(cmd (\d+)\) (.+)/)
210
+ if matches && matches.size == 3
211
+ cmd_number = matches[1].to_i
212
+ cmd = matches[2]
213
+
214
+ @last_command_number = cmd_number
215
+ @history[@last_command_number] = cmd
216
+
217
+ # for Ctrl+R history searching
218
+ Readline::HISTORY << cmd
219
+ end
220
+ end
221
+ rescue => e
222
+ raise e
223
+ end
224
+
225
+ return @history
226
+ end
227
+
228
+ def log_history_command(cmd)
229
+ @history ||= {}
230
+ @last_command_number ||= 0
231
+ @last_command_number += 1
232
+ @history[@last_command_number] = cmd
233
+ if @history_logger
234
+ @history_logger.info "(cmd #{@last_command_number}) #{cmd}"
235
+ end
236
+ end
128
237
  end