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
@@ -1,5 +1,9 @@
1
+ require 'morpheus/cli/option_parser'
1
2
  require 'morpheus/cli/cli_registry'
2
3
  require 'morpheus/cli/mixins/print_helper'
4
+ require 'morpheus/cli/credentials'
5
+ require 'morpheus/api/api_client'
6
+ require 'morpheus/cli/remote'
3
7
 
4
8
  module Morpheus
5
9
  module Cli
@@ -7,9 +11,9 @@ module Morpheus
7
11
  module CliCommand
8
12
 
9
13
  def self.included(klass)
10
- Morpheus::Cli::CliRegistry.add(klass)
11
14
  klass.send :include, Morpheus::Cli::PrintHelper
12
15
  klass.extend ClassMethods
16
+ Morpheus::Cli::CliRegistry.add(klass, klass.command_name)
13
17
  end
14
18
 
15
19
  def build_common_options(opts, options, includes=[])
@@ -26,9 +30,10 @@ module Morpheus
26
30
  end
27
31
 
28
32
  when :options
29
- opts.on( '-O', '--option OPTION', "Option" ) do |option|
33
+ options[:options] ||= {}
34
+ opts.on( '-O', '--option OPTION', "Option in the format var=\"value\"" ) do |option|
30
35
  custom_option_args = option.split('=')
31
- custom_options = options[:options] || {}
36
+ custom_options = options[:options]
32
37
  option_name_args = custom_option_args[0].split('.')
33
38
  if option_name_args.count > 1
34
39
  nested_options = custom_options
@@ -43,7 +48,6 @@ module Morpheus
43
48
  else
44
49
  custom_options[custom_option_args[0]] = custom_option_args[1]
45
50
  end
46
-
47
51
  options[:options] = custom_options
48
52
  end
49
53
  opts.on('-N','--no-prompt', "Skip prompts. Use default values for all optional fields.") do |val|
@@ -52,8 +56,8 @@ module Morpheus
52
56
  options[:options] ||= {}
53
57
  options[:options][:no_prompt] = true
54
58
  end
59
+
55
60
  when :list
56
-
57
61
  opts.on( '-m', '--max MAX', "Max Results" ) do |max|
58
62
  options[:max] = max.to_i
59
63
  end
@@ -75,10 +79,26 @@ module Morpheus
75
79
  end
76
80
 
77
81
  when :remote
78
- opts.on( '-r', '--remote REMOTE', "Remote Appliance" ) do |remote|
79
- options[:remote] = remote
82
+
83
+ # this is the only option now...
84
+ # first, you must do `remote use [appliance]`
85
+ opts.on( '-r', '--remote REMOTE', "Remote Appliance Name to use for this command. The active appliance is used by default." ) do |val|
86
+ options[:remote] = val
87
+ end
88
+
89
+ # todo: also require this for talking to plain old HTTP
90
+ opts.on('-I','--insecure', "Allow for insecure HTTPS communication i.e. bad SSL certificate") do |val|
91
+ Morpheus::RestClient.enable_ssl_verification = false
80
92
  end
81
93
 
94
+ # skipping the rest of this for now..
95
+
96
+ next
97
+
98
+ # opts.on( '-r', '--remote REMOTE', "Remote Appliance" ) do |remote|
99
+ # options[:remote] = remote
100
+ # end
101
+
82
102
  opts.on( '-U', '--url REMOTE', "API Url" ) do |remote|
83
103
  options[:remote_url] = remote
84
104
  end
@@ -94,36 +114,39 @@ module Morpheus
94
114
  opts.on( '-T', '--token ACCESS_TOKEN', "Access Token" ) do |remote|
95
115
  options[:remote_token] = remote
96
116
  end
97
-
98
- when :auto_confirm
117
+ when :auto_confirm
99
118
  opts.on( '-y', '--yes', "Auto Confirm" ) do
100
119
  options[:yes] = true
101
120
  end
102
-
103
- when :json
121
+ when :json
104
122
  opts.on('-j','--json', "JSON Output") do |json|
105
123
  options[:json] = true
106
124
  end
107
125
 
108
126
  when :dry_run
109
- opts.on('-d','--dry-run', "Dry Run, print json without making the actual request.") do |json|
127
+ opts.on('-d','--dry-run', "Dry Run, print the API request instead of executing it") do |json|
110
128
  options[:dry_run] = true
111
129
  end
112
-
130
+ when :quiet
131
+ opts.on('-q','--quiet', "No Output, when successful") do |json|
132
+ options[:quiet] = true
133
+ end
134
+
113
135
  else
114
136
  raise "Unknown common_option key: #{option_key}"
115
137
  end
116
138
  end
117
139
 
118
140
  # options that are always included
119
- opts.on('-C','--nocolor', "ANSI") do
141
+
142
+ # disable ANSI coloring
143
+ opts.on('-C','--nocolor', "Disable ANSI coloring") do
120
144
  Term::ANSIColor::coloring = false
121
145
  end
122
146
 
123
147
  opts.on('-V','--debug', "Print extra output for debugging. ") do |json|
124
148
  options[:debug] = true
125
- # this is handled upstream for now...
126
- # Morpheus::Logging.set_log_level(Morpheus::Logging::Logger::DEBUG)
149
+ Morpheus::Logging.set_log_level(Morpheus::Logging::Logger::DEBUG)
127
150
  # perhaps...
128
151
  # create a new logger instance just for this command instance
129
152
  # this way we don't elevate the global level for subsequent commands in a shell
@@ -132,21 +155,166 @@ module Morpheus
132
155
  # @logger.log_level = Morpheus::Logging::Logger::DEBUG
133
156
  # end
134
157
  end
135
-
158
+
136
159
  opts.on('-h', '--help', "Prints this help" ) do
137
160
  puts opts
138
161
  exit
139
162
  end
140
163
 
141
164
  end
142
-
165
+
166
+ def command_name
167
+ self.class.command_name
168
+ end
169
+
170
+ def subcommands
171
+ self.class.subcommands
172
+ end
173
+
174
+ def subcommand_aliases
175
+ self.class.subcommand_aliases
176
+ end
177
+
178
+ def default_subcommand
179
+ self.class.default_subcommand
180
+ end
181
+
182
+ def usage
183
+ if !subcommands.empty?
184
+ "Usage: morpheus #{command_name} [command] [options]"
185
+ else
186
+ "Usage: morpheus #{command_name} [options]"
187
+ end
188
+ end
189
+
190
+ def subcommand_usage(*extra)
191
+ calling_method = caller[0][/`([^']*)'/, 1].to_s.sub('block in ', '')
192
+ subcommand_name = subcommands.key(calling_method)
193
+ extra = extra.flatten
194
+ if !subcommand_name.empty? && extra.first == subcommand_name
195
+ extra.shift
196
+ end
197
+ #extra = ["[options]"] if extra.empty?
198
+ "Usage: morpheus #{command_name} #{subcommand_name} #{extra.join(' ')}".squeeze(' ').strip
199
+ end
200
+
201
+ def print_usage()
202
+ puts usage
203
+ if !subcommands.empty?
204
+ puts "Commands:"
205
+ subcommands.sort.each {|cmd, method|
206
+ puts "\t#{cmd.to_s}"
207
+ }
208
+ end
209
+ end
210
+
211
+ # a default handler
212
+ def handle_subcommand(args)
213
+ commands = subcommands
214
+ if subcommands.empty?
215
+ raise "#{self.class} has no available subcommands"
216
+ end
217
+ # meh, could deprecate and make subcommand define handle() itself
218
+ if args.count == 0 && default_subcommand
219
+ # p "using default subcommand #{default_subcommand}"
220
+ return self.send(default_subcommand, args || [])
221
+ end
222
+ cmd_name = args[0]
223
+ if subcommand_aliases[cmd_name]
224
+ cmd_name = subcommand_aliases[cmd_name]
225
+ end
226
+ cmd_method = subcommands[cmd_name]
227
+ if cmd_name && !cmd_method
228
+ #puts "unknown command '#{cmd_name}'"
229
+ end
230
+ if !cmd_method
231
+ print_usage
232
+ exit 127
233
+ end
234
+ self.send(cmd_method, args[1..-1])
235
+ end
236
+
237
+ def handle(args)
238
+ raise "#{self} has not defined handle()!"
239
+ end
240
+
241
+ # This supports the simple remote option eg. `instances add --remote "qa"`
242
+ # It will establish a connection to the pre-configured appliance named "qa"
243
+ # The calling command needs to populate @appliances and/or @appliance_name
244
+ # This returns a new instance of Morpheus::APIClient (and sets @access_token, and @appliance)
245
+ # Your command should be ready to make api requests after this.
246
+ # todo: probably don't exit here, just return nil or raise
247
+ def establish_remote_appliance_connection(options)
248
+ @appliances ||= ::Morpheus::Cli::Remote.appliances
249
+ if !@appliance_name
250
+ @appliance_name, @appliance_url = Morpheus::Cli::Remote.active_appliance
251
+ end
252
+
253
+ # todo: support old way of accepting --username and --password on the command line
254
+ # it's probably better not to do that tho, just so it stays out of history files
255
+
256
+ # use a specific remote appliance by name
257
+ if options[:remote]
258
+ @appliance_name = options[:remote].to_sym rescue nil
259
+ if !@appliances
260
+ print_red_alert "You have no appliances configured. See the `remote add` command."
261
+ exit 1
262
+ end
263
+ found_appliance = @appliances[@appliance_name.to_sym]
264
+ if !found_appliance
265
+ print_red_alert "You have no appliance named '#{@appliance_name}' configured. See the `remote add` command."
266
+ exit 1
267
+ end
268
+ @appliance = found_appliance
269
+ @appliance_name = @appliance_name
270
+ @appliance_url = @appliance[:host]
271
+ if options[:debug]
272
+ print dark,"# => Using remote appliance [#{@appliance_name}] #{@appliance_url}",reset,"\n" if !options[:quiet]
273
+ end
274
+ else
275
+ #@appliance_name, @appliance_url = Morpheus::Cli::Remote.active_appliance
276
+ end
277
+
278
+ if !@appliance_name
279
+ print_red_alert "You must specify a remote appliance with --remote, or see the `remote use` command."
280
+ exit 1
281
+ end
282
+
283
+ puts "#{dark} #=> establishing connection to [#{@appliance_name}] #{@appliance_url}#{reset}\n" if options[:debug]
284
+
285
+ # ok, get some credentials.
286
+ # this prompts for username, password without options[:no_prompt]
287
+ @access_token = Morpheus::Cli::Credentials.new(@appliance_name, @appliance_url).request_credentials(options)
288
+
289
+ # bail if we got nothing
290
+ if @access_token.empty?
291
+ print_red_alert "Invalid Credentials. Unable to acquire access token. Please verify your credentials and try again."
292
+ exit 1
293
+ end
294
+
295
+ # ok, connect to the appliance.. actually this just instantiates an ApiClient
296
+ # setup our api client for all including commands to use.
297
+ @api_client = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url)
298
+ return @api_client
299
+ end
143
300
 
144
301
  module ClassMethods
145
- def cli_command_name(cmd_name)
146
- Morpheus::Cli::CliRegistry.add(self, cmd_name)
302
+
303
+ def set_command_name(cmd_name)
304
+ @command_name = cmd_name
305
+ Morpheus::Cli::CliRegistry.add(self, self.command_name)
306
+ end
307
+
308
+ def default_command_name
309
+ Morpheus::Cli::CliRegistry.cli_ize(self.name.split('::')[-1])
310
+ end
311
+
312
+ def command_name
313
+ @command_name ||= default_command_name
314
+ @command_name
147
315
  end
148
316
 
149
- def cli_command_hidden(val=true)
317
+ def set_command_hidden(val=true)
150
318
  @hidden_command = val
151
319
  end
152
320
 
@@ -154,6 +322,76 @@ module Morpheus
154
322
  !!@hidden_command
155
323
  end
156
324
 
325
+ # construct map of command name => instance method
326
+ def register_subcommands(*cmds)
327
+ @subcommands ||= {}
328
+ cmds.flatten.each {|cmd|
329
+ if cmd.is_a?(Hash)
330
+ cmd.each {|k,v|
331
+ # @subcommands[k] = v
332
+ add_subcommand(k.to_s, v.to_s)
333
+ }
334
+ elsif cmd.is_a?(Array)
335
+ cmd.each {|it| register_subcommands(it) }
336
+ elsif cmd.is_a?(String) || cmd.is_a?(Symbol)
337
+ #k = Morpheus::Cli::CliRegistry.cli_ize(cmd)
338
+ k = cmd.to_s.gsub('_', '-')
339
+ v = cmd.to_s.gsub('-', '_')
340
+ register_subcommands({(k) => v})
341
+ else
342
+ raise "Unable to register command of type: #{cmd.class} #{cmd}"
343
+ end
344
+ }
345
+ return
346
+ end
347
+
348
+ def set_default_subcommand(cmd)
349
+ @default_subcommand = cmd
350
+ end
351
+
352
+ def default_subcommand
353
+ @default_subcommand
354
+ end
355
+
356
+ def subcommands
357
+ @subcommands ||= {}
358
+ end
359
+
360
+ def has_subcommand?(cmd_name)
361
+ return false if cmd_name.empty?
362
+ @subcommands && @subcommands[cmd_name.to_s]
363
+ end
364
+
365
+ def add_subcommand(cmd_name, method)
366
+ @subcommands ||= {}
367
+ @subcommands[cmd_name.to_s] = method
368
+ end
369
+
370
+ def remove_subcommand(cmd_name)
371
+ @subcommands ||= {}
372
+ @subcommands.delete(cmd_name.to_s)
373
+ end
374
+
375
+ # register an alias for a command
376
+ def alias_subcommand(alias_cmd_name, cmd_name)
377
+ add_subcommand_alias(alias_cmd_name.to_s, cmd_name.to_s.gsub('_', '-'))
378
+ return
379
+ end
380
+
381
+ def subcommand_aliases
382
+ @subcommand_aliases ||= {}
383
+ end
384
+
385
+ def add_subcommand_alias(alias_cmd_name, cmd_name)
386
+ @subcommand_aliases ||= {}
387
+ @subcommand_aliases[alias_cmd_name.to_s] = cmd_name
388
+ end
389
+
390
+ def remove_subcommand_alias(alias_cmd_name)
391
+ @subcommand_aliases ||= {}
392
+ @subcommand_aliases.delete(alias_cmd_name.to_s)
393
+ end
394
+
157
395
  end
158
396
  end
159
397
  end
@@ -1,36 +1,76 @@
1
-
1
+ require 'term/ansicolor'
2
2
  module Morpheus
3
3
  module Cli
4
4
  class CliRegistry
5
5
 
6
6
  def initialize
7
- @commands = {}
7
+ @commands = {} # this is command => Class that includes ::CliCommand
8
+ @aliases = {} # this is alias => String full input string
8
9
  end
9
-
10
+
10
11
  class << self
12
+ include Term::ANSIColor
11
13
 
14
+ ALIAS_SPLIT_REGEX=/(\;)(?=(?:[^"']|"[^'"]*")*$)/
15
+
12
16
  def instance
13
17
  @instance ||= CliRegistry.new
14
18
  end
15
19
 
20
+ #todo: move execution out of the CliRegistry
16
21
  def exec(command_name, args)
17
- # begin
18
- Term::ANSIColor::coloring = STDOUT.isatty
22
+ exec_command(command_name, args)
23
+ end
24
+
25
+ def exec_command(command_name, args)
26
+ #puts "exec_command(#{command_name}, #{args})"
27
+ found_alias_command = instance.get_alias(command_name)
28
+ if found_alias_command
29
+ exec_alias(command_name, args)
30
+ else
31
+ #puts "running regular command #{command_name} with arguments #{args.join(' ')}"
19
32
  instance.get(command_name).new.handle(args)
20
- # rescue SystemExit, Interrupt
21
- # puts "Interrupted..."
22
- # end
33
+ end
34
+ end
35
+
36
+ def exec_alias(alias_name, args)
37
+ #puts "exec_alias(#{alias_name}, #{args})"
38
+ found_alias_command = instance.get_alias(alias_name)
39
+ # support aliases of multiple commands, semicolon delimiter
40
+ # todo:
41
+ all_commands = found_alias_command.gsub(ALIAS_SPLIT_REGEX, '__ALIAS_SPLIT_REGEX__').split('__ALIAS_SPLIT_REGEX__').collect {|it| it.to_s.strip }.select {|it| !it.empty? }.compact
42
+ print "#{dark} #=> executing alias #{alias_name} as #{all_commands.join('; ')}#{reset}\n" if Morpheus::Logging.debug?
43
+ all_commands.each do |a_command_string|
44
+ alias_args = a_command_string.to_s.split(/\s+/) # or just ' '
45
+ command_name = alias_args.shift
46
+ command_args = alias_args + args
47
+ if command_name == alias_name
48
+ # needs to be better than this
49
+ print Term::ANSIColor.red,"alias '#{alias_name}' is calling itself? '#{found_alias_command}'", Term::ANSIColor.reset, "\n"
50
+ exit 1
51
+ end
52
+ # this allows aliases to use other aliases
53
+ # todo: prevent recursion infinite loop
54
+ if has_alias?(command_name)
55
+ exec_alias(command_name, command_args)
56
+ elsif has_command?(command_name)
57
+ #puts "executing alias #{found_alias_command} as #{command_name} with args #{args.join(' ')}"
58
+ instance.get(command_name).new.handle(alias_args + args)
59
+ else
60
+ # raise UnrecognizedCommandError.new(command_name)
61
+ print Term::ANSIColor.red,"alias '#{alias_name}' uses and unknown command: '#{command_name}'", Term::ANSIColor.reset, "\n"
62
+ exit 1
63
+ end
64
+ end
23
65
  end
24
66
 
25
67
  def add(klass, command_name=nil)
26
68
  klass_command_name = cli_ize(klass.name.split('::')[-1])
27
-
28
- if has_command?(klass_command_name) && !command_name.nil?
69
+ if has_command?(klass_command_name)
29
70
  instance.remove(klass_command_name)
30
- instance.add(command_name, klass)
31
- else
32
- instance.add(klass_command_name, klass)
33
71
  end
72
+ command_name ||= klass_command_name
73
+ instance.add(command_name, klass)
34
74
  end
35
75
 
36
76
  def has_command?(command_name)
@@ -41,11 +81,21 @@ module Morpheus
41
81
  end
42
82
  end
43
83
 
84
+ def has_alias?(alias_name)
85
+ if alias_name.nil? || alias_name == ''
86
+ false
87
+ else
88
+ !instance.get_alias(alias_name).nil?
89
+ end
90
+ end
91
+
44
92
  def all
45
93
  instance.all
46
94
  end
47
95
 
48
- private
96
+ def all_aliases
97
+ instance.all_aliases
98
+ end
49
99
 
50
100
  def cli_ize(klass_name)
51
101
  # borrowed from ActiveSupport
@@ -58,6 +108,18 @@ module Morpheus
58
108
  word.downcase!
59
109
  word.chop.tr('_', '-')
60
110
  end
111
+
112
+ def parse_alias_definition(input)
113
+ # todo: one multi group regex would work
114
+ alias_name, command_string = nil, nil
115
+ chunks = input.to_s.sub(/^alias\s+/, "").split('=')
116
+ alias_name = chunks.shift
117
+ command_string = chunks.compact.reject {|it| it.empty? }.join('=')
118
+ command_string = command_string.strip.sub(/^'/, "").sub(/'\Z/, "").strip
119
+ return alias_name, command_string
120
+ end
121
+
122
+
61
123
  end
62
124
 
63
125
  def all
@@ -75,6 +137,29 @@ module Morpheus
75
137
  def remove(cmd_name)
76
138
  @commands.delete(cmd_name.to_sym)
77
139
  end
140
+
141
+ def all_aliases
142
+ @aliases
143
+ end
144
+
145
+ def get_alias(alias_name)
146
+ @aliases[alias_name.to_sym]
147
+ end
148
+
149
+ def add_alias(alias_name, command_string)
150
+ #return @commands[alias_name.to_sym]
151
+ if self.class.has_command?(alias_name)
152
+ raise "alias name '#{alias_name}' is invalid. That is the name of a morpheus command."
153
+ elsif alias_name.to_s.downcase.strip == command_string.to_s.downcase.strip
154
+ raise "alias #{alias_name}=#{command_string} is invalid..."
155
+ end
156
+ @aliases[alias_name.to_sym] = command_string
157
+ end
158
+
159
+ def remove_alias(alias_name)
160
+ @aliases.delete(alias_name.to_sym)
161
+ end
162
+
78
163
  end
79
164
  end
80
165
  end