morpheus-cli 0.9.9 → 0.9.10

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