morpheus-cli 3.6.21 → 3.6.22

Sign up to get free protection for your applications and to get access to all the features.
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