morpheus-cli 3.6.21 → 3.6.22

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 789787ba7a4ccb2132d5bcc90b9a7d56201b16cfba7ea0033e853eeeb82745cb
4
- data.tar.gz: '069c49c5ce79c069e5082fd6cbd18995f603a90e4be7562ddae2057ea9318d9a'
3
+ metadata.gz: ba216506570efee1b756a8b534dc529f006f9f8e939de8a1d4c4d549cd1a03c4
4
+ data.tar.gz: 127050886ebf02507861dfe55ca8e6c705e5404f15bc8c6c8cb25a17068f4589
5
5
  SHA512:
6
- metadata.gz: 9b272c53c874322cdd53ab7b1fa75a53db2961149765bfc69682f9ea35eb4f342df69bb7b98d01d9caafb6ad2e4d7d6433ea5e5e22534a097ae2c5747bee3ece
7
- data.tar.gz: 47e44158f0be09618e8c8285b691fb7a8d0d4aa50bd7452b020ba87259871ffd578172df8ba3dbb02a8f75eff62bde08ce8c6e40cdd06c654f8e389369d702ab
6
+ metadata.gz: 9b9c74b514d944013b7bf7b5086115377ef071fa3b04b27ba6edef9da036d3917c6c69224b53466a755d9df8d91e8a9f063e4a66d252d82055719928831355c2
7
+ data.tar.gz: a8523b27b0db023e3321763718a817d386741164bd04ee88fe8cd4213afd672cbf81440b1915252005fa3e2aa156dbb81b9168e47d21fa96e7151db7c8325ccb
@@ -1,5 +1,6 @@
1
1
  require 'securerandom'
2
2
  require 'morpheus/logging'
3
+ require 'morpheus/cli/cli_registry.rb'
3
4
 
4
5
  # Provides global Benchmarking functionality
5
6
  # This provides a store of benchmarking records which can be looked up by name.
@@ -124,25 +125,16 @@ module Morpheus::Benchmarking
124
125
  start_benchmark(opts)
125
126
  if block_given?
126
127
  result = block.call()
127
- # exit_code, err = Morpheus::Cli.parse_command_result(result)
128
- if result.is_a?(Array)
129
- exit_code = result[0]
130
- err = result[0]
131
- elsif result == true || result == nil
132
- exit_code = 0
133
- elsif result == false
134
- exit_code = 1
135
- else
136
- exit_code = result
137
- end
128
+ exit_code, err = Morpheus::Cli::CliRegistry.parse_command_result(result)
138
129
  end
139
130
  rescue => ex
140
131
  raise ex
141
- # exit_code = 1
142
- # err = ex.msg
132
+ exit_code = 1
133
+ err = ex.msg
143
134
  ensure
144
135
  stop_benchmark(exit_code, err)
145
136
  end
137
+ #return result
146
138
  return exit_code, err
147
139
  end
148
140
 
@@ -25,6 +25,7 @@ module Morpheus
25
25
  end
26
26
  end
27
27
 
28
+ # check if this is a Windows environment.
28
29
  def self.windows?
29
30
  if defined?(@@is_windows)
30
31
  return @@is_windows
@@ -39,36 +40,6 @@ module Morpheus
39
40
  return @@is_windows
40
41
  end
41
42
 
42
- def self.parse_command_result(cmd_result)
43
- exit_code, err = nil, nil
44
- if cmd_result.is_a?(Array)
45
- exit_code, err = cmd_result[0], cmd_result[1]
46
- elsif cmd_result.is_a?(Hash)
47
- exit_code, err = cmd_result[:exit_code], (cmd_result[:error] || cmd_result[:err])
48
- end
49
- if cmd_result == nil || cmd_result == true
50
- exit_code = 0
51
- elsif cmd_result == false
52
- exit_code = 1
53
- elsif cmd_result.is_a?(Integer)
54
- exit_code = cmd_result
55
- elsif cmd_result.is_a?(Float)
56
- exit_code = cmd_result.to_i
57
- elsif cmd_result.is_a?(String)
58
- exit_code = cmd_result.to_i
59
- else
60
- if cmd_result.respond_to?(:to_i)
61
- exit_code = cmd_result.to_i
62
- else
63
- # happens for aliases right now.. and execution flow probably, need to handle Array
64
- # uncomment to track them down, proceed with exit 0 for now
65
- #Morpheus::Logging::DarkPrinter.puts "debug: command #{command_name} produced an unexpected result: (#{cmd_result.class}) #{cmd_result}" if Morpheus::Logging.debug?
66
- exit_code = 0
67
- end
68
- end
69
- return exit_code, err
70
- end
71
-
72
43
  # load all the well known commands and utilties they need
73
44
  def self.load!()
74
45
  # load interfaces
@@ -449,12 +449,6 @@ class Morpheus::Cli::Apps
449
449
  print_green_success "New app '#{payload['name']}' validation passed. #{json_response['msg']}".strip
450
450
  else
451
451
  print_red_alert "New app '#{payload['name']}' validation failed. #{json_response['msg']}".strip
452
- # a default way to print errors
453
- (json_response['errors'] || {}).each do |error_key, error_msg|
454
- if error_key != 'instances'
455
- print_error red, " * #{error_key} : #{error_msg}", reset, "\n"
456
- end
457
- end
458
452
  # looks for special error format like instances.instanceErrors
459
453
  if json_response['errors'] && json_response['errors']['instances']
460
454
  json_response['errors']['instances'].each do |error_obj|
@@ -468,6 +462,13 @@ class Morpheus::Cli::Apps
468
462
  end
469
463
  end
470
464
  end
465
+ else
466
+ # a default way to print errors
467
+ (json_response['errors'] || {}).each do |error_key, error_msg|
468
+ if error_key != 'instances'
469
+ print_error red, " * #{error_key} : #{error_msg}", reset, "\n"
470
+ end
471
+ end
471
472
  end
472
473
  end
473
474
  end
@@ -511,7 +512,35 @@ class Morpheus::Cli::Apps
511
512
  end
512
513
  return 0
513
514
  rescue RestClient::Exception => e
514
- print_rest_exception(e, options)
515
+ #print_rest_exception(e, options)
516
+ json_response = nil
517
+ begin
518
+ json_response = JSON.parse(e.response.to_s)
519
+ rescue TypeError, JSON::ParserError => ex
520
+ print_error red, "Failed to parse JSON response: #{ex}", reset, "\n"
521
+ end
522
+
523
+ # looks for special error format like instances.instanceErrors
524
+ if json_response['errors'] && json_response['errors']['instances']
525
+ json_response['errors']['instances'].each do |error_obj|
526
+ tier_name = error_obj['tier']
527
+ instance_index = error_obj['index']
528
+ instance_errors = error_obj['instanceErrors']
529
+ print_error red, "#{tier_name} : #{instance_index}", reset, "\n"
530
+ if instance_errors
531
+ instance_errors.each do |err_key, err_msg|
532
+ print_error red, " * #{err_key} : #{err_msg}", reset, "\n"
533
+ end
534
+ end
535
+ end
536
+ else
537
+ # a default way to print errors
538
+ (json_response['errors'] || {}).each do |error_key, error_msg|
539
+ if error_key != 'instances'
540
+ print_error red, " * #{error_key} : #{error_msg}", reset, "\n"
541
+ end
542
+ end
543
+ end
515
544
  exit 1
516
545
  end
517
546
  end
@@ -339,12 +339,20 @@ module Morpheus
339
339
  end
340
340
 
341
341
  when :list
342
- opts.on( '-m', '--max MAX', "Max Results" ) do |max|
343
- options[:max] = max.to_i
342
+ opts.on( '-m', '--max MAX', "Max Results" ) do |val|
343
+ max = val.to_i
344
+ if max <= 0
345
+ raise ::OptionParser::InvalidArgument.new("must be a positive integer")
346
+ end
347
+ options[:max] = max
344
348
  end
345
349
 
346
- opts.on( '-o', '--offset OFFSET', "Offset Results" ) do |offset|
347
- options[:offset] = offset.to_i.abs
350
+ opts.on( '-o', '--offset OFFSET', "Offset Results" ) do |val|
351
+ offset = val.to_i
352
+ if offset <= 0
353
+ raise ::OptionParser::InvalidArgument.new("must be a positive integer")
354
+ end
355
+ options[:offset] = offset
348
356
  end
349
357
 
350
358
  opts.on( '-s', '--search PHRASE', "Search Phrase" ) do |phrase|
@@ -719,7 +727,8 @@ module Morpheus
719
727
  cmd_method = subcommands[subcommand_name]
720
728
  if !cmd_method
721
729
  print_error Morpheus::Terminal.angry_prompt
722
- puts_error "'#{subcommand_name}' is not recognized. See '#{my_help_command}'"
730
+ #puts_error "'#{subcommand_name}' is not recognized. See '#{my_help_command}'"
731
+ puts_error "'#{subcommand_name}' is not recognized.\n#{full_command_usage}"
723
732
  return 127
724
733
  end
725
734
  self.send(cmd_method, args[1..-1])
@@ -1,5 +1,10 @@
1
1
  require 'term/ansicolor'
2
+ require 'shellwords'
2
3
  require 'morpheus/logging'
4
+ require 'morpheus/cli/command_error'
5
+ require 'morpheus/cli/error_handler'
6
+ require 'morpheus/cli/expression_parser'
7
+
3
8
  module Morpheus
4
9
  module Cli
5
10
  class CliRegistry
@@ -57,8 +62,6 @@ module Morpheus
57
62
 
58
63
  class << self
59
64
  include Term::ANSIColor
60
-
61
- ALIAS_SPLIT_REGEX=/(\;)(?=(?:[^"']|"[^'"]*")*$)/
62
65
 
63
66
  def instance
64
67
  @instance ||= CliRegistry.new
@@ -72,43 +75,97 @@ module Morpheus
72
75
  def exec_command(command_name, args)
73
76
  #puts "exec_command(#{command_name}, #{args})"
74
77
  found_alias_command = instance.get_alias(command_name)
75
- if found_alias_command
78
+ if has_alias?(command_name)
76
79
  exec_alias(command_name, args)
77
- else
78
- #puts "running regular command #{command_name} with arguments #{args.join(' ')}"
80
+ elsif has_command?(command_name)
79
81
  instance.get(command_name).new.handle(args)
82
+ else
83
+ raise Morpheus::Cli::CommandError.new("'#{command_name}' is not a command. See 'morpheus --help'.")
80
84
  end
81
85
  end
82
86
 
83
87
  def exec_alias(alias_name, args)
84
- #puts "exec_alias(#{alias_name}, #{args})"
85
88
  found_alias_command = instance.get_alias(alias_name)
86
- # support aliases of multiple commands, semicolon delimiter
87
- # todo:
88
- 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
89
- Morpheus::Logging::DarkPrinter.puts "executing alias #{alias_name} as #{all_commands.join('; ')}" if Morpheus::Logging.debug?
90
- all_commands.each do |a_command_string|
91
- alias_args = a_command_string.to_s.split(/\s+/) # or just ' '
92
- command_name = alias_args.shift
93
- command_args = alias_args + args
94
- if command_name == alias_name
95
- # needs to be better than this
96
- print Term::ANSIColor.red,"alias '#{alias_name}' is calling itself? '#{found_alias_command}'", Term::ANSIColor.reset, "\n"
97
- exit 1
89
+ if !found_alias_command
90
+ raise Morpheus::Cli::CommandError.new("'#{alias_name}' is not a defined alias.")
91
+ end
92
+ # if !is_valid_expression(found_alias_command)
93
+ # raise Morpheus::Cli::CommandError.new("alias '#{alias_name}' is not a valid expression: #{found_alias_command}")
94
+ # end
95
+ input = found_alias_command
96
+ if args && !args.empty?
97
+ input = "#{found_alias_command} " + args.collect {|arg| arg.include?(" ") ? "\"#{arg}\"" : "#{arg}" }.join(" ")
98
+ end
99
+ exec_expression(input)
100
+ end
101
+
102
+ def exec_expression(input)
103
+ # puts "exec_expression(#{input})"
104
+ flow = input
105
+ if input.is_a?(String)
106
+ begin
107
+ flow = Morpheus::Cli::ExpressionParser.parse(input)
108
+ rescue Morpheus::Cli::ExpressionParser::InvalidExpression => e
109
+ raise e
98
110
  end
99
- # this allows aliases to use other aliases
100
- # todo: prevent recursion infinite loop
101
- if has_alias?(command_name)
102
- exec_alias(command_name, command_args)
103
- elsif has_command?(command_name)
104
- #puts "executing alias #{found_alias_command} as #{command_name} with args #{args.join(' ')}"
105
- instance.get(command_name).new.handle(alias_args + args)
111
+ end
112
+ # puts "executing flow: #{flow.inspect}"
113
+ final_command_result = nil
114
+ if flow.size == 0
115
+ # no input eh?
116
+ else
117
+ last_command_result = nil
118
+ if ['&&','||', '|'].include?(flow.first)
119
+ raise Morpheus::Cli::ExpressionParser::InvalidExpression.new "#{Morpheus::Terminal.angry_prompt}invalid command format, begins with an operator: #{input}"
120
+ elsif ['&&','||', '|'].include?(flow.last)
121
+ raise Morpheus::Cli::ExpressionParser::InvalidExpression.new "#{Morpheus::Terminal.angry_prompt}invalid command format, ends with an operator: #{input}"
122
+ # elsif ['&&','||', '|'].include?(flow.last)
123
+ # raise Morpheus::Cli::ExpressionParser::InvalidExpression.new "invalid command format, consecutive operators: #{cmd}"
106
124
  else
107
- # raise UnrecognizedCommandError.new(command_name)
108
- print Term::ANSIColor.red,"alias '#{alias_name}' uses and unknown command: '#{command_name}'", Term::ANSIColor.reset, "\n"
109
- exit 1
125
+ #Morpheus::Logging::DarkPrinter.puts "Executing command flow: #{flow.inspect}" if Morpheus::Logging.debug?
126
+ previous_command = nil
127
+ previous_command_result = nil
128
+ current_operator = nil
129
+ still_executing = true
130
+ flow.each do |flow_cmd|
131
+ if still_executing
132
+ if flow_cmd == '&&'
133
+ # AND operator
134
+ current_operator = flow_cmd
135
+ exit_code, cmd_err = parse_command_result(previous_command_result)
136
+ if exit_code != 0
137
+ still_executing = false
138
+ end
139
+ elsif flow_cmd == '||' # or with previous command
140
+ current_operator = flow_cmd
141
+ exit_code, err = parse_command_result(previous_command_result)
142
+ if exit_code == 0
143
+ still_executing = false
144
+ end
145
+ elsif flow_cmd == '|' # or with previous command
146
+ raise Morpheus::Cli::ExpressionParser::InvalidExpression.new "The PIPE (|) operator is not yet supported =["
147
+ previous_command_result = nil
148
+ still_executing = false
149
+ # or just continue?
150
+ elsif flow_cmd.is_a?(Array)
151
+ # this is a subexpression, execute it as such
152
+ current_operator = nil
153
+ previous_command_result = exec_expression(flow_cmd)
154
+ else # it's a command, not an operator
155
+ current_operator = nil
156
+ flow_argv = Shellwords.shellsplit(flow_cmd)
157
+ previous_command_result = exec_command(flow_argv[0], flow_argv[1..-1])
158
+ end
159
+ previous_command = flow_cmd
160
+ else
161
+ #Morpheus::Logging::DarkPrinter.puts "operator skipped command: #{flow_cmd}" if Morpheus::Logging.debug?
162
+ end
163
+ # previous_command = flow_cmd
164
+ end
165
+ final_command_result = previous_command_result
110
166
  end
111
167
  end
168
+ return final_command_result
112
169
  end
113
170
 
114
171
  def add(klass, command_name=nil)
@@ -166,6 +223,42 @@ module Morpheus
166
223
  return alias_name, command_string
167
224
  end
168
225
 
226
+ # parse any object into a command result [exit_code, error]
227
+ # 0 means success.
228
+ # This treats nil, true, or an object success.
229
+ # 0 or
230
+ # @return [Array] exit_code, error. Success returns [0, nil].
231
+ def parse_command_result(cmd_result)
232
+ exit_code, err = nil, nil
233
+ if cmd_result.is_a?(Array)
234
+ exit_code = cmd_result[0] || 0
235
+ err = cmd_result[1]
236
+ elsif cmd_result.is_a?(Hash)
237
+ exit_code = cmd_result[:exit_code] || 0
238
+ err = cmd_result[:error] || cmd_result[:err]
239
+ elsif cmd_result == nil || cmd_result == true
240
+ exit_code = 0
241
+ elsif cmd_result == false
242
+ exit_code = 1
243
+ elsif cmd_result.is_a?(Integer)
244
+ exit_code = cmd_result
245
+ elsif cmd_result.is_a?(Float)
246
+ exit_code = cmd_result.to_i
247
+ elsif cmd_result.is_a?(String)
248
+ exit_code = cmd_result.to_i
249
+ else
250
+ if cmd_result.respond_to?(:to_i)
251
+ exit_code = cmd_result.to_i
252
+ else
253
+ # happens for aliases right now.. and execution flow probably, need to handle Array
254
+ # uncomment to track them down, proceed with exit 0 for now
255
+ #Morpheus::Logging::DarkPrinter.puts "debug: command #{command_name} produced an unexpected result: (#{cmd_result.class}) #{cmd_result}" if Morpheus::Logging.debug?
256
+ exit_code = 0
257
+ end
258
+ end
259
+ return exit_code, err
260
+ end
261
+
169
262
  end
170
263
 
171
264
  end
@@ -1,6 +1,7 @@
1
1
  require 'morpheus/logging'
2
2
  require 'morpheus/benchmarking'
3
3
  require 'morpheus/cli/cli_command'
4
+ require 'morpheus/cli/cli_registry'
4
5
 
5
6
  class Morpheus::Cli::BenchmarkCommand
6
7
  include Morpheus::Cli::CliCommand
@@ -293,10 +294,16 @@ EOT
293
294
  end
294
295
 
295
296
  def execute(args)
297
+ n = 1
296
298
  benchmark_name = nil
297
299
  options = {}
298
300
  optparse = Morpheus::Cli::OptionParser.new do |opts|
299
301
  opts.banner = subcommand_usage("[command...]")
302
+ opts.on('-n', '--iterations NUMBER', Integer, "Number of iterations to run. The default is 1.") do |val|
303
+ if val.to_i > 1
304
+ n = val.to_i
305
+ end
306
+ end
300
307
  opts.on('--name NAME', String, "Name for the benchmark. Default is the command itself.") do |val|
301
308
  benchmark_name = val
302
309
  end
@@ -315,97 +322,88 @@ EOT
315
322
  end
316
323
 
317
324
  cmd = args.join(' ')
325
+ benchmark_name ||= cmd
326
+ if n == 1
327
+ start_benchmark(benchmark_name)
328
+ # exit_code, err = my_terminal.execute(cmd)
329
+ cmd_result = Morpheus::Cli::CliRegistry.exec_expression(cmd)
330
+ exit_code, err = Morpheus::Cli::CliRegistry.parse_command_result(cmd_result)
331
+ benchmark_record = stop_benchmark(exit_code, err)
332
+ Morpheus::Logging::DarkPrinter.puts(cyan + dark + benchmark_record.msg) if benchmark_record
333
+ else
334
+ benchmark_records = []
335
+ n.times do |iteration_index|
336
+ start_benchmark(benchmark_name)
337
+ # exit_code, err = my_terminal.execute(cmd)
338
+ cmd_result = Morpheus::Cli::CliRegistry.exec_expression(cmd)
339
+ exit_code, err = Morpheus::Cli::CliRegistry.parse_command_result(cmd_result)
340
+ benchmark_record = stop_benchmark(exit_code, err)
341
+ Morpheus::Logging::DarkPrinter.puts(cyan + dark + benchmark_record.msg) if Morpheus::Logging.debug?
342
+ benchmark_records << benchmark_record
343
+ end
344
+ # calc total and mean and print it
345
+ # all_durations = benchmark_records.collect {|benchmark_record| benchmark_record.duration }
346
+ # total_duration = all_durations.inject(0.0) {|acc, i| acc + i }
347
+ # avg_duration = total_duration / all_durations.size
348
+ # total_time_str = "#{total_duration.round((total_duration > 0.002) ? 3 : 6)}s"
349
+ # avg_time_str = "#{avg_duration.round((total_duration > 0.002) ? 3 : 6)}s"
318
350
 
319
- #previous_terminal_benchmarking = my_terminal.benchmarking
320
- start_benchmark(benchmark_name || cmd)
321
-
322
- # exit_code, err = my_terminal.execute(cmd)
323
- # do this way until terminal supports expressions
324
- cmd_result = execute_commands_as_expression(cmd)
325
- exit_code, err = Morpheus::Cli.parse_command_result(cmd_result)
326
-
327
- benchmark_record = stop_benchmark(exit_code, err)
328
- Morpheus::Logging::DarkPrinter.puts(cyan + dark + benchmark_record.msg) if benchmark_record
329
-
330
- #my_terminal.benchmarking = previous_terminal_benchmarking
331
- return 0
332
- end
351
+ all_durations = []
352
+ stats = {total: 0, avg: nil, min: nil, max: nil}
353
+ benchmark_records.each do |benchmark_record|
354
+ duration = benchmark_record.duration
355
+ if duration
356
+ all_durations << duration
357
+ stats[:total] += duration
358
+ if stats[:min].nil? || stats[:min] > duration
359
+ stats[:min] = duration
360
+ end
361
+ if stats[:max].nil? || stats[:max] < duration
362
+ stats[:max] = duration
363
+ end
364
+ end
365
+ end
366
+ if all_durations.size > 0
367
+ stats[:avg] = stats[:total].to_f / all_durations.size
368
+ end
333
369
 
334
- protected
370
+ total_time_str = "#{stats[:total].round((stats[:total] > 0.002) ? 3 : 6)}s"
371
+ min_time_str = stats[:min] ? "#{stats[:min].round((stats[:min] > 0.002) ? 3 : 6)}s" : ""
372
+ max_time_str = stats[:max] ? "#{stats[:max].round((stats[:max] > 0.002) ? 3 : 6)}s" : ""
373
+ avg_time_str = stats[:avg] ? "#{stats[:avg].round((stats[:avg] > 0.002) ? 3 : 6)}s" : ""
335
374
 
336
- # copied these over from shell, consolidate to terminal plz
375
+ out = ""
376
+ # <benchmark name or command>
377
+ out << "#{benchmark_name.ljust(30, ' ')}"
378
+ # exit: 0
379
+ exit_str = "0"
380
+ bad_benchmark = benchmark_records.find {|benchmark_record| benchmark_record.exit_code && benchmark_record.exit_code != 0 }
381
+ if bad_benchmark
382
+ bad_benchmark.exit_code.to_s
383
+ out << "\texit: #{bad_benchmark.exit_code.to_s.ljust(2, ' ')}"
384
+ out << "\terror: #{bad_benchmark.error.to_s.ljust(12, ' ')}"
385
+ else
386
+ out << "\texit: 0 "
387
+ end
337
388
 
338
- def execute_command(cmd)
339
- my_terminal.execute(cmd)
340
- end
389
+ out << "\tn: #{n.to_s.ljust(4, ' ')}"
390
+ out << "\ttotal: #{total_time_str.ljust(9, ' ')}"
391
+ out << "\tmin: #{min_time_str.ljust(9, ' ')}"
392
+ out << "\tmax: #{max_time_str.ljust(9, ' ')}"
393
+ out << "\tavg: #{avg_time_str.ljust(9, ' ')}"
341
394
 
342
- def execute_commands_as_expression(input)
343
- flow = input
344
- if input.is_a?(String)
345
- begin
346
- flow = Morpheus::Cli::ExpressionParser.parse(input)
347
- rescue Morpheus::Cli::ExpressionParser::InvalidExpression => e
348
- @history_logger.error "#{e.message}" if @history_logger
349
- return Morpheus::Cli::ErrorHandler.new(my_terminal.stderr).handle_error(e) # lol
350
- end
351
- end
352
- final_command_result = nil
353
- if flow.size == 0
354
- # no input eh?
355
- else
356
- last_command_result = nil
357
- if ['&&','||', '|'].include?(flow.first)
358
- puts_error "#{Morpheus::Terminal.angry_prompt}invalid command format, begins with an operator: #{input}"
359
- return 99
360
- elsif ['&&','||', '|'].include?(flow.last)
361
- puts_error "#{Morpheus::Terminal.angry_prompt}invalid command format, ends with an operator: #{input}"
362
- return 99
363
- # elsif ['&&','||', '|'].include?(flow.last)
364
- # puts_error "invalid command format, consecutive operators: #{cmd}"
395
+
396
+ if bad_benchmark
397
+ print red,out,reset,"\n"
398
+ return 1
365
399
  else
366
- #Morpheus::Logging::DarkPrinter.puts "Executing command flow: #{flow.inspect}" if Morpheus::Logging.debug?
367
- previous_command = nil
368
- previous_command_result = nil
369
- current_operator = nil
370
- still_executing = true
371
- flow.each do |flow_cmd|
372
- if still_executing
373
- if flow_cmd == '&&'
374
- # AND operator
375
- current_operator = flow_cmd
376
- exit_code, cmd_err = Morpheus::Cli.parse_command_result(previous_command_result)
377
- if exit_code != 0
378
- still_executing = false
379
- end
380
- elsif flow_cmd == '||' # or with previous command
381
- current_operator = flow_cmd
382
- exit_code, err = Morpheus::Cli.parse_command_result(previous_command_result)
383
- if exit_code == 0
384
- still_executing = false
385
- end
386
- elsif flow_cmd == '|' # or with previous command
387
- puts_error "The PIPE (|) operator is not yet supported =["
388
- previous_command_result = nil
389
- still_executing = false
390
- # or just continue?
391
- elsif flow_cmd.is_a?(Array)
392
- # this is a subexpression, execute it as such
393
- current_operator = nil
394
- previous_command_result = execute_commands_as_expression(flow_cmd)
395
- else # it's a command, not an operator
396
- current_operator = nil
397
- previous_command_result = execute_command(flow_cmd)
398
- end
399
- previous_command = flow_cmd
400
- else
401
- #Morpheus::Logging::DarkPrinter.puts "operator skipped command: #{flow_cmd}" if Morpheus::Logging.debug?
402
- end
403
- # previous_command = flow_cmd
404
- end
405
- final_command_result = previous_command_result
400
+ print cyan,out,reset,"\n"
401
+ return 0
406
402
  end
403
+
407
404
  end
408
- return final_command_result
405
+
406
+ return 0
409
407
  end
410
408
 
411
409
  end
@@ -122,7 +122,7 @@ class Morpheus::Cli::ContainersCommand
122
122
  if options[:include_available_actions]
123
123
  if (container["availableActions"])
124
124
  print_h2 "Available Actions"
125
- print as_pretty_table(container["availableActions"], [:id, :name])
125
+ print as_pretty_table(container["availableActions"], [:name, :code])
126
126
  print reset, "\n"
127
127
  else
128
128
  print "#{yellow}No available actions#{reset}\n\n"
@@ -53,53 +53,28 @@ class Morpheus::Cli::DotFile
53
53
  next if line.empty?
54
54
  next if line =~ /^\#/ # skip comments
55
55
 
56
- # print "#{dark} #=> executing source file line #{line_num}: #{line}#{reset}\n" if Morpheus::Logging.debug?
57
-
58
- # allow semicolons inside arguments too..
59
- #command_list = line.strip.split(';').compact
60
- command_list = line.split(/(;)(?=(?:[^"']|["|'][^"']*")*$)/).reject {|it| it.to_s.strip.empty? || it.to_s.strip == ";" }
61
- command_list.each do |input|
62
- input = input.strip
63
- if input.empty?
64
- next
65
- end
66
- argv = nil
67
- begin
68
- argv = Shellwords.shellsplit(input)
69
- rescue => err
70
- cmd_result = false
71
- puts "#{red} Unparsable source file: #{@filename} line: #{line_num} '#{input}' #{reset} - #{err}"
72
- end
73
- if argv[0] && Morpheus::Cli::CliRegistry.has_command?(argv[0]) || Morpheus::Cli::CliRegistry.has_alias?(argv[0])
74
- #log_history_command(input)
75
- cmd_result = nil
76
- begin
77
- cmd_result = Morpheus::Cli::CliRegistry.exec(argv[0], argv[1..-1])
78
- rescue SystemExit => err
79
- if err.success?
80
- cmd_result = true
81
- else
82
- puts "#{red} source file: #{@filename} line: #{line_num} command: #{argv[0]}#{reset} error: exited non zero - #{err}"
83
- cmd_result = false
84
- end
85
- rescue => err
86
- # raise err
87
- puts "#{red} source file: #{@filename} line: #{line_num} command: #{argv[0]}#{reset} error: unexpected error - #{err}"
88
- cmd_result = false
89
- end
90
- cmd_results << cmd_result
91
- # next command please!
56
+ cmd_exit_code = 0
57
+ cmd_err = nil
58
+ cmd_result = nil
59
+ begin
60
+ cmd_result = Morpheus::Cli::CliRegistry.exec_expression(line)
61
+ rescue SystemExit => err
62
+ if err.success?
63
+ cmd_result = true
92
64
  else
93
- puts "#{red}Unrecognized source command file: #{@filename} line: #{line_num} command: #{argv[0]}#{reset}"
65
+ puts "#{red} source file: #{@filename} line: #{line_num} command: #{line}#{reset} error: exited non zero - #{err}"
94
66
  cmd_result = false
95
67
  end
96
- if cmd_result == false
97
- if stop_on_failure
98
- return cmd_results
99
- end
68
+ rescue => err
69
+ # raise err
70
+ puts "#{red} source file: #{@filename} line: #{line_num} command: #{line}#{reset} error: unexpected error - #{err}"
71
+ cmd_result = false
72
+ end
73
+ if cmd_result == false
74
+ if stop_on_failure
75
+ return cmd_results
100
76
  end
101
77
  end
102
-
103
78
  end
104
79
  return cmd_results
105
80
  end
@@ -130,6 +105,8 @@ class Morpheus::Cli::DotFile
130
105
  new_config_lines = []
131
106
  existing_alias_definitions = {}
132
107
  header_line_index = config_lines.index {|line| line.strip.include?(EXPORTED_ALIASES_HEADER) }
108
+ # JD: there's some bad bug here where it can clear all your aliases!
109
+ # it would be safer to export to another file at .morpheus/aliases or something.
133
110
  if header_line_index
134
111
  # keep everything before the exported alias section
135
112
  new_config_lines = config_lines[0..header_line_index-1]
@@ -392,8 +392,14 @@ class Morpheus::Cli::Hosts
392
392
  end
393
393
  return
394
394
  end
395
- server = find_host_by_name_or_id(arg)
396
- json_response = @servers_interface.get(server['id'])
395
+ json_response = nil
396
+ if arg.to_s =~ /\A\d{1,}\Z/
397
+ json_response = @servers_interface.get(arg.to_i)
398
+ else
399
+ server = find_host_by_name_or_id(arg)
400
+ json_response = @servers_interface.get(server['id'])
401
+ # json_response = {"server" => server} need stats
402
+ end
397
403
  if options[:json]
398
404
  json_response.delete('stats') if options[:include_fields]
399
405
  puts as_json(json_response, options, "server")
@@ -70,6 +70,9 @@ class Morpheus::Cli::Instances
70
70
  end
71
71
  optparse.parse!(args)
72
72
  connect(options)
73
+ if args.count != 0
74
+ raise_command_error "wrong number of arguments, expected 0 and got (#{args.count}) #{args}\n#{optparse}"
75
+ end
73
76
  begin
74
77
  params = {}
75
78
  params.merge!(parse_list_options(options))
@@ -811,9 +814,11 @@ class Morpheus::Cli::Instances
811
814
  opts.on( nil, '--nodes', "Alias for --containers" ) do
812
815
  options[:include_containers] = true
813
816
  end
817
+ # opts.add_hidden_option('--nodes')
814
818
  opts.on( nil, '--vms', "Alias for --containers" ) do
815
819
  options[:include_containers] = true
816
820
  end
821
+ # opts.add_hidden_option('--vms')
817
822
  opts.on( nil, '--scaling', "Display Instance Scaling Settings" ) do
818
823
  options[:include_scaling] = true
819
824
  end
@@ -6,6 +6,7 @@ require "shellwords"
6
6
  require 'readline'
7
7
  require 'logger'
8
8
  require 'fileutils'
9
+ require 'morpheus/cli/cli_registry'
9
10
  require 'morpheus/cli/cli_command'
10
11
  require 'morpheus/cli/error_handler'
11
12
  require 'morpheus/cli/expression_parser'
@@ -117,7 +118,7 @@ class Morpheus::Cli::Shell
117
118
  optparse = Morpheus::Cli::OptionParser.new do |opts|
118
119
  opts.banner = usage
119
120
  # change to a temporary home directory, delete it afterwards.
120
- opts.on('-e','--exec COMMAND', "Execute the provided morpheus commands and exit.") do |val|
121
+ opts.on('-e','--exec EXPRESSION', "Execute the command(s) expression and exit.") do |val|
121
122
  @execute_mode = true
122
123
  @execute_mode_command = val
123
124
  end
@@ -249,80 +250,6 @@ class Morpheus::Cli::Shell
249
250
  unless input.strip.empty? || input.strip[0] == "!"
250
251
  log_history_command(input.strip)
251
252
  end
252
- result = execute_commands_as_expression(input)
253
- return result
254
- end
255
-
256
- def execute_commands_as_expression(input)
257
- flow = input
258
- if input.is_a?(String)
259
- begin
260
- flow = Morpheus::Cli::ExpressionParser.parse(input)
261
- rescue Morpheus::Cli::ExpressionParser::InvalidExpression => e
262
- @history_logger.error "#{e.message}" if @history_logger
263
- return Morpheus::Cli::ErrorHandler.new(my_terminal.stderr).handle_error(e) # lol
264
- end
265
- end
266
- final_command_result = nil
267
- if flow.size == 0
268
- # no input eh?
269
- else
270
- last_command_result = nil
271
- if ['&&','||', '|'].include?(flow.first)
272
- puts_error "#{Morpheus::Terminal.angry_prompt}invalid command format, begins with an operator: #{input}"
273
- return 99
274
- elsif ['&&','||', '|'].include?(flow.last)
275
- puts_error "#{Morpheus::Terminal.angry_prompt}invalid command format, ends with an operator: #{input}"
276
- return 99
277
- # elsif ['&&','||', '|'].include?(flow.last)
278
- # puts_error "invalid command format, consecutive operators: #{cmd}"
279
- else
280
- #Morpheus::Logging::DarkPrinter.puts "Executing command flow: #{flow.inspect}" if Morpheus::Logging.debug?
281
- previous_command = nil
282
- previous_command_result = nil
283
- current_operator = nil
284
- still_executing = true
285
- flow.each do |flow_cmd|
286
- if still_executing
287
- if flow_cmd == '&&'
288
- # AND operator
289
- current_operator = flow_cmd
290
- exit_code, cmd_err = Morpheus::Cli.parse_command_result(previous_command_result)
291
- if exit_code != 0
292
- still_executing = false
293
- end
294
- elsif flow_cmd == '||' # or with previous command
295
- current_operator = flow_cmd
296
- exit_code, err = Morpheus::Cli.parse_command_result(previous_command_result)
297
- if exit_code == 0
298
- still_executing = false
299
- end
300
- elsif flow_cmd == '|' # or with previous command
301
- puts_error "The PIPE (|) operator is not yet supported =["
302
- previous_command_result = nil
303
- still_executing = false
304
- # or just continue?
305
- elsif flow_cmd.is_a?(Array)
306
- # this is a subexpression, execute it as such
307
- current_operator = nil
308
- previous_command_result = execute_commands_as_expression(flow_cmd)
309
- else # it's a command, not an operator
310
- current_operator = nil
311
- previous_command_result = execute_command(flow_cmd)
312
- end
313
- previous_command = flow_cmd
314
- else
315
- #Morpheus::Logging::DarkPrinter.puts "operator skipped command: #{flow_cmd}" if Morpheus::Logging.debug?
316
- end
317
- # previous_command = flow_cmd
318
- end
319
- final_command_result = previous_command_result
320
- end
321
- end
322
- return final_command_result
323
- end
324
-
325
- def execute_command(input)
326
253
 
327
254
  #Morpheus::Logging::DarkPrinter.puts "Shell command: #{input}"
328
255
  input = input.to_s.strip
@@ -525,7 +452,7 @@ class Morpheus::Cli::Shell
525
452
  @return_to_coloring = ["coloring"].include?(cmd_name) ? nil : Term::ANSIColor::coloring?
526
453
  @return_to_benchmarking = ["benchmark"].include?(cmd_name) ? nil : Morpheus::Benchmarking.enabled?
527
454
 
528
- if Morpheus::Cli::CliRegistry.has_command?(cmd_name) || Morpheus::Cli::CliRegistry.has_alias?(cmd_name)
455
+ #if Morpheus::Cli::CliRegistry.has_command?(cmd_name) || Morpheus::Cli::CliRegistry.has_alias?(cmd_name)
529
456
  #log_history_command(input)
530
457
  # start a benchmark, unless the command is benchmark of course
531
458
  if my_terminal.benchmarking || cmd_args.include?("-B") || cmd_args.include?("--benchmark")
@@ -535,15 +462,16 @@ class Morpheus::Cli::Shell
535
462
  start_benchmark(benchmark_name)
536
463
  end
537
464
  end
538
- cmd_result = Morpheus::Cli::CliRegistry.exec(cmd_name, cmd_args)
539
- cmd_exit_code, cmd_err = Morpheus::Cli.parse_command_result(cmd_result)
465
+ cmd_exit_code, cmd_err = Morpheus::Cli::CliRegistry.exec_expression(input)
466
+ #cmd_result = Morpheus::Cli::CliRegistry.exec(cmd_name, cmd_args)
467
+ #cmd_exit_code, cmd_err = Morpheus::Cli::CliRegistry.parse_command_result(cmd_result)
540
468
  benchmark_record = stop_benchmark(cmd_exit_code, cmd_err) # if benchmarking?
541
469
  Morpheus::Logging::DarkPrinter.puts(cyan + dark + benchmark_record.msg) if benchmark_record
542
- else
543
- puts_error "#{Morpheus::Terminal.angry_prompt}'#{cmd_name}' is not recognized. Use 'help' to see the list of available commands."
544
- @history_logger.warn "Unrecognized Command #{cmd_name}" if @history_logger
545
- cmd_result = -1
546
- end
470
+ # else
471
+ # puts_error "#{Morpheus::Terminal.angry_prompt}'#{cmd_name}' is not recognized. Use 'help' to see the list of available commands."
472
+ # @history_logger.warn "Unrecognized Command #{cmd_name}" if @history_logger
473
+ # cmd_result = -1
474
+ # end
547
475
  rescue Interrupt
548
476
  # nothing to do
549
477
  @history_logger.warn "shell interrupt" if @history_logger
@@ -795,6 +723,8 @@ class Morpheus::Cli::Shell
795
723
  print_results_pagination({:meta => history_result[:meta]}, {:message =>"Viewing most recent %{size} of %{total} %{label}"})
796
724
  end
797
725
  print reset, "\n"
726
+ else
727
+ print reset
798
728
  end
799
729
  end
800
730
  #print "\n"
@@ -1,6 +1,6 @@
1
1
 
2
2
  module Morpheus
3
3
  module Cli
4
- VERSION = "3.6.21"
4
+ VERSION = "3.6.22"
5
5
  end
6
6
  end
@@ -6,6 +6,7 @@ require 'morpheus/rest_client'
6
6
  require 'morpheus/cli/cli_registry'
7
7
  require 'morpheus/cli/dot_file'
8
8
  require 'morpheus/cli/error_handler'
9
+ require 'morpheus/cli/expression_parser'
9
10
  require 'morpheus/logging'
10
11
  require 'morpheus/benchmarking'
11
12
  require 'morpheus/cli'
@@ -48,7 +49,7 @@ module Morpheus
48
49
  end
49
50
 
50
51
  # DEFAULT_TERMINAL_WIDTH = 80
51
-
52
+
52
53
  def self.default_color
53
54
  Term::ANSIColor.cyan
54
55
  end
@@ -216,9 +217,9 @@ module Morpheus
216
217
  # maybe OptionParser's recover() instance method will do the trick
217
218
  optparse = Morpheus::Cli::OptionParser.new do|opts|
218
219
  opts.banner = "Options:" # hack alert
219
- opts.on('-v','--version', "Print the version.") do
220
- @stdout.puts Morpheus::Cli::VERSION
221
- # exit
220
+ opts.on('-e','--exec EXPRESSION', "Execute the command(s) expression. This is an alternative to passing [command] [options]") do |val|
221
+ @execute_mode = true
222
+ @execute_mode_command = val
222
223
  end
223
224
  opts.on('--noprofile','--noprofile', "Do not read and execute the personal initialization script .morpheus_profile") do
224
225
  @noprofile = true
@@ -236,6 +237,10 @@ module Morpheus
236
237
  Morpheus::Logging.set_log_level(Morpheus::Logging::Logger::DEBUG)
237
238
  ::RestClient.log = Morpheus::Logging.debug? ? Morpheus::Logging::DarkPrinter.instance : nil
238
239
  end
240
+ opts.on('-v','--version', "Print the version.") do
241
+ @stdout.puts Morpheus::Cli::VERSION
242
+ # exit
243
+ end
239
244
  opts.on( '-h', '--help', "Print this help" ) do
240
245
  @stdout.puts opts
241
246
  # exit
@@ -317,7 +322,6 @@ module Morpheus
317
322
  end
318
323
  end
319
324
 
320
-
321
325
  # process global options
322
326
 
323
327
  # raise log level right away
@@ -336,7 +340,7 @@ module Morpheus
336
340
  # ok, execute the command (or alias)
337
341
  result = nil
338
342
  begin
339
-
343
+
340
344
  # execute startup script .morpheus_profile unless --noprofile is passed
341
345
  # todo: this should happen in initialize..
342
346
  noprofile = false
@@ -351,38 +355,69 @@ module Morpheus
351
355
  end
352
356
  end
353
357
 
354
- # not enough arguments?
355
- if args.count == 0
356
- @stderr.puts "#{@angry_prompt}[command] argument is required."
357
- #@stderr.puts "No command given, here's some help:"
358
- @stderr.print usage
359
- return 2, nil # CommandError.new("morpheus requires a command")
360
- end
361
-
362
- cmd_name = args[0]
363
- cmd_args = args[1..-1]
364
-
365
- # unknown command?
366
- # all commands should be registered commands or aliases
367
- if !(Morpheus::Cli::CliRegistry.has_command?(cmd_name) || Morpheus::Cli::CliRegistry.has_alias?(cmd_name))
368
- @stderr.puts "#{@angry_prompt}'#{cmd_name}' is not recognized. See 'morpheus --help'."
369
- #@stderr.puts usage
370
- return 127, nil
371
- end
372
-
373
- if @benchmarking || args.include?('-B') || args.include?('--benchmark')
374
- benchmark_name = "morpheus " + args.reject {|it| it == '-B' || it == '--benchmark' }.join(' ')
375
- #benchmark_name = args.reject {|it| it == '-B' || it == '--benchmark' }.join(' ')
376
- start_benchmark(benchmark_name)
358
+ # execute startup script .morpheus_profile unless --noprofile is passed
359
+ # todo: this should happen in initialize..
360
+ @execute_mode = false
361
+ @execute_mode_command = nil
362
+ args.size.times do |i|
363
+ if args[i] == '-e' || args[i] == '--exec'
364
+ @execute_mode = true
365
+ # delete switch and value (command)
366
+ deleted_option = args.delete_at(i)
367
+ @execute_mode_command = args.delete_at(i)
368
+ if @execute_mode_command.nil?
369
+ raise ::OptionParser::MissingArgument.new(deleted_option)
370
+ #@stderr.puts "#{@angry_prompt}missing argument: #{deleted_option}."
371
+ #@stderr.puts "No command given, here's some help:"
372
+ #@stderr.print usage
373
+ return 1
374
+ end
375
+ break
376
+ end
377
377
  end
378
378
 
379
- # shell is a Singleton command class
380
- if args[0] == "shell"
381
- result = Morpheus::Cli::Shell.instance.handle(args[1..-1])
379
+ if @execute_mode_command
380
+ # execute a single command and exit
381
+ result = Morpheus::Cli::CliRegistry.exec_expression(@execute_mode_command)
382
+ @execute_mode_command = nil
382
383
  else
383
- result = Morpheus::Cli::CliRegistry.exec(args[0], args[1..-1])
384
+ # not enough arguments?
385
+ if args.count == 0
386
+ @stderr.puts "#{@angry_prompt}[command] argument is required."
387
+ #@stderr.puts "No command given, here's some help:"
388
+ @stderr.print usage
389
+ return 1, nil # CommandError.new("morpheus requires a command")
390
+ end
391
+
392
+ cmd_name, *cmd_args = args
393
+
394
+ formatted_cmd = args.collect {|arg| arg.include?(' ') ? "\"#{arg}\"" : "#{arg}" }.join(" ")
395
+
396
+ # unknown command?
397
+ # all commands should be registered commands or aliases
398
+ # ahh, but it could support expressions (), use -e for that ..
399
+ # if !(Morpheus::Cli::CliRegistry.has_command?(cmd_name) || Morpheus::Cli::CliRegistry.has_alias?(cmd_name))
400
+ # @stderr.puts "#{@angry_prompt}'#{cmd_name}' is not recognized. See 'morpheus --help'."
401
+ # #@stderr.puts usage
402
+ # return 127, nil
403
+ # end
404
+
405
+ if @benchmarking || args.include?('-B') || args.include?('--benchmark')
406
+ benchmark_name = "morpheus #{formatted_cmd}"
407
+ benchmark_name.sub!(' -B', '')
408
+ benchmark_name.sub!(' --benchmark', '')
409
+ start_benchmark(benchmark_name)
410
+ end
411
+
412
+ # shell is a Singleton command class
413
+ if args[0] == "shell"
414
+ result = Morpheus::Cli::Shell.instance.handle(args[1..-1])
415
+ else
416
+ #result = Morpheus::Cli::CliRegistry.exec_expression(formatted_cmd)
417
+ result = Morpheus::Cli::CliRegistry.exec(args[0], args[1..-1])
418
+ end
384
419
  end
385
- exit_code, err = Morpheus::Cli.parse_command_result(result)
420
+ exit_code, err = Morpheus::Cli::CliRegistry.parse_command_result(result)
386
421
  rescue => e
387
422
  exit_code = Morpheus::Cli::ErrorHandler.new(@stderr).handle_error(e)
388
423
  err = e
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: morpheus-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.6.21
4
+ version: 3.6.22
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Estes
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2019-03-01 00:00:00.000000000 Z
14
+ date: 2019-03-05 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: bundler