aspera-cli 4.17.0 → 4.18.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +2 -4
  3. data/CHANGELOG.md +23 -0
  4. data/CONTRIBUTING.md +15 -1
  5. data/README.md +620 -378
  6. data/bin/ascli +5 -0
  7. data/bin/asession +2 -2
  8. data/lib/aspera/agent/alpha.rb +6 -4
  9. data/lib/aspera/agent/base.rb +9 -6
  10. data/lib/aspera/agent/connect.rb +4 -4
  11. data/lib/aspera/agent/direct.rb +56 -37
  12. data/lib/aspera/agent/httpgw.rb +23 -324
  13. data/lib/aspera/agent/node.rb +19 -20
  14. data/lib/aspera/agent/trsdk.rb +19 -20
  15. data/lib/aspera/api/aoc.rb +17 -14
  16. data/lib/aspera/api/cos_node.rb +4 -4
  17. data/lib/aspera/api/httpgw.rb +339 -0
  18. data/lib/aspera/api/node.rb +34 -21
  19. data/lib/aspera/ascmd.rb +4 -3
  20. data/lib/aspera/ascp/installation.rb +15 -7
  21. data/lib/aspera/ascp/management.rb +2 -2
  22. data/lib/aspera/cli/basic_auth_plugin.rb +5 -9
  23. data/lib/aspera/cli/extended_value.rb +12 -6
  24. data/lib/aspera/cli/formatter.rb +155 -65
  25. data/lib/aspera/cli/hints.rb +18 -0
  26. data/lib/aspera/cli/main.rb +22 -29
  27. data/lib/aspera/cli/manager.rb +53 -36
  28. data/lib/aspera/cli/plugin.rb +26 -17
  29. data/lib/aspera/cli/plugin_factory.rb +31 -20
  30. data/lib/aspera/cli/plugins/alee.rb +14 -2
  31. data/lib/aspera/cli/plugins/aoc.rb +141 -131
  32. data/lib/aspera/cli/plugins/ats.rb +1 -1
  33. data/lib/aspera/cli/plugins/config.rb +52 -46
  34. data/lib/aspera/cli/plugins/console.rb +8 -5
  35. data/lib/aspera/cli/plugins/faspex.rb +27 -19
  36. data/lib/aspera/cli/plugins/faspex5.rb +222 -149
  37. data/lib/aspera/cli/plugins/faspio.rb +85 -0
  38. data/lib/aspera/cli/plugins/httpgw.rb +55 -0
  39. data/lib/aspera/cli/plugins/node.rb +86 -29
  40. data/lib/aspera/cli/plugins/orchestrator.rb +31 -29
  41. data/lib/aspera/cli/plugins/preview.rb +6 -2
  42. data/lib/aspera/cli/plugins/server.rb +5 -5
  43. data/lib/aspera/cli/plugins/shares.rb +16 -14
  44. data/lib/aspera/cli/sync_actions.rb +6 -6
  45. data/lib/aspera/cli/transfer_agent.rb +5 -4
  46. data/lib/aspera/cli/version.rb +1 -1
  47. data/lib/aspera/environment.rb +7 -6
  48. data/lib/aspera/faspex_gw.rb +5 -4
  49. data/lib/aspera/faspex_postproc.rb +2 -2
  50. data/lib/aspera/log.rb +6 -3
  51. data/lib/aspera/node_simulator.rb +2 -2
  52. data/lib/aspera/oauth/base.rb +31 -19
  53. data/lib/aspera/oauth/factory.rb +12 -13
  54. data/lib/aspera/oauth/generic.rb +1 -0
  55. data/lib/aspera/oauth/jwt.rb +18 -15
  56. data/lib/aspera/oauth/url_json.rb +8 -6
  57. data/lib/aspera/open_application.rb +5 -7
  58. data/lib/aspera/persistency_folder.rb +2 -2
  59. data/lib/aspera/preview/generator.rb +3 -3
  60. data/lib/aspera/preview/options.rb +3 -3
  61. data/lib/aspera/preview/terminal.rb +4 -4
  62. data/lib/aspera/preview/utils.rb +3 -3
  63. data/lib/aspera/proxy_auto_config.rb +5 -1
  64. data/lib/aspera/rest.rb +60 -74
  65. data/lib/aspera/rest_call_error.rb +1 -1
  66. data/lib/aspera/rest_error_analyzer.rb +2 -2
  67. data/lib/aspera/rest_errors_aspera.rb +1 -1
  68. data/lib/aspera/resumer.rb +1 -1
  69. data/lib/aspera/secret_hider.rb +2 -4
  70. data/lib/aspera/ssh.rb +1 -1
  71. data/lib/aspera/transfer/parameters.rb +39 -36
  72. data/lib/aspera/transfer/spec.rb +2 -0
  73. data/lib/aspera/transfer/sync.rb +2 -1
  74. data/lib/aspera/transfer/uri.rb +1 -1
  75. data/lib/aspera/uri_reader.rb +5 -4
  76. data/lib/aspera/web_auth.rb +1 -1
  77. data/lib/aspera/web_server_simple.rb +4 -3
  78. data.tar.gz.sig +0 -0
  79. metadata +5 -3
  80. metadata.gz.sig +0 -0
  81. data/lib/aspera/cli/plugins/bss.rb +0 -71
@@ -1,11 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # cspell:ignore jsonpp
4
+ require 'aspera/preview/terminal'
4
5
  require 'aspera/secret_hider'
5
6
  require 'aspera/environment'
6
7
  require 'aspera/log'
7
8
  require 'aspera/assert'
8
9
  require 'terminal-table'
10
+ require 'tty-spinner'
9
11
  require 'yaml'
10
12
  require 'pp'
11
13
 
@@ -14,8 +16,9 @@ module Aspera
14
16
  CONF_OVERVIEW_KEYS = %w[preset parameter value].freeze
15
17
  # This class is used to transform a complex structure into a simple hash
16
18
  class Flattener
17
- def initialize
19
+ def initialize(formatter)
18
20
  @result = nil
21
+ @formatter = formatter
19
22
  end
20
23
 
21
24
  # General method
@@ -48,9 +51,9 @@ module Aspera
48
51
  elsif something.is_a?(Array)
49
52
  flatten_array(something, name)
50
53
  elsif something.is_a?(String) && something.empty?
51
- @result[name] = Formatter.special('empty string')
54
+ @result[name] = @formatter.special_format('empty string')
52
55
  elsif something.nil?
53
- @result[name] = Formatter.special('null')
56
+ @result[name] = @formatter.special_format('null')
54
57
  # elsif something.eql?(true) || something.eql?(false)
55
58
  # @result[name] = something
56
59
  else
@@ -63,7 +66,7 @@ module Aspera
63
66
  # @param name [String] name of englobing key
64
67
  def flatten_array(array, name)
65
68
  if array.empty?
66
- @result[name] = Formatter.special('empty list')
69
+ @result[name] = @formatter.special_format('empty list')
67
70
  elsif array.all?(String)
68
71
  @result[name] = array.join("\n")
69
72
  elsif array.all?{|i| i.is_a?(Hash) && i.keys.eql?(%w[name])}
@@ -85,18 +88,18 @@ module Aspera
85
88
  flatten_any(v, "#{prefix}#{k}")
86
89
  end
87
90
  end
88
- end # class
91
+ end
89
92
 
90
93
  # Take care of output
91
94
  class Formatter
95
+ # remove a fields from the list
92
96
  FIELDS_LESS = '-'
93
97
  CSV_RECORD_SEPARATOR = "\n"
94
98
  CSV_FIELD_SEPARATOR = ','
95
99
  # supported output formats
96
- DISPLAY_FORMATS = %i[text nagios ruby json jsonpp yaml table csv].freeze
100
+ DISPLAY_FORMATS = %i[text nagios ruby json jsonpp yaml table csv image].freeze
97
101
  # user output levels
98
102
  DISPLAY_LEVELS = %i[info data error].freeze
99
- RESULT_PARAMS = %i[type data total fields name].freeze
100
103
 
101
104
  private_constant :DISPLAY_FORMATS, :DISPLAY_LEVELS, :CSV_RECORD_SEPARATOR, :CSV_FIELD_SEPARATOR
102
105
  # prefix to display error messages in user messages (terminal)
@@ -105,19 +108,6 @@ module Aspera
105
108
  HINT_FLASH = 'HINT:'.bg_green.gray.blink.freeze
106
109
 
107
110
  class << self
108
- # Highlight special values
109
- def special(what, use_colors: $stdout.isatty)
110
- result = $stdout.isatty ? "<#{what}>" : "&lt;#{what}&gt;"
111
- if use_colors
112
- result = if %w[null empty].any?{|s|what.include?(s)}
113
- result.dim
114
- else
115
- result.reverse_color
116
- end
117
- end
118
- return result
119
- end
120
-
121
111
  def all_but(list)
122
112
  list = [list] unless list.is_a?(Array)
123
113
  return list.map{|i|"#{FIELDS_LESS}#{i}"}.unshift(ExtendedValue::ALL)
@@ -125,7 +115,7 @@ module Aspera
125
115
 
126
116
  def tick(yes)
127
117
  result =
128
- if Environment.use_unicode?
118
+ if Environment.terminal_supports_unicode?
129
119
  if yes
130
120
  "\u2713"
131
121
  else
@@ -150,24 +140,55 @@ module Aspera
150
140
  end
151
141
  return result
152
142
  end
153
- end # self
143
+ end
154
144
 
155
145
  # initialize the formatter
156
146
  def initialize
157
147
  @options = {}
148
+ @spinner = nil
149
+ end
150
+
151
+ # Highlight special values
152
+ def special_format(what, use_colors: $stdout.isatty)
153
+ result = $stdout.isatty ? "<#{what}>" : "&lt;#{what}&gt;"
154
+ if use_colors
155
+ result = if %w[null empty].any?{|s|what.include?(s)}
156
+ result.dim
157
+ else
158
+ result.reverse_color
159
+ end
160
+ end
161
+ return result
158
162
  end
159
163
 
164
+ # call this after REST calls if several api calls are expected
165
+ def long_operation_running(title = '')
166
+ return unless Environment.terminal?
167
+ if @spinner.nil?
168
+ @spinner = TTY::Spinner.new('[:spinner] :title', format: :classic)
169
+ @spinner.start
170
+ end
171
+ @spinner.update(title: title)
172
+ @spinner.spin
173
+ end
174
+
175
+ # options are: format, output, display, fields, select, table_style, flat_hash, transpose_single
160
176
  def option_handler(option_symbol, operation, value=nil)
161
177
  Aspera.assert_values(operation, %i[set get])
162
178
  case operation
163
179
  when :set
164
180
  @options[option_symbol] = value
165
- if option_symbol.eql?(:output)
181
+ case option_symbol
182
+ when :output
166
183
  $stdout = if value.eql?('-')
167
184
  STDOUT # rubocop:disable Style/GlobalStdStream
168
185
  else
169
186
  File.open(value, 'w')
170
187
  end
188
+ when :image
189
+ allowed_options = Preview::Terminal.method(:build).parameters.select{|i|i[0].eql?(:key)}.map{|i|i[1]}
190
+ unknown_options = value.keys.map(&:to_sym) - allowed_options
191
+ raise "Invalid parameter(s) for option image: #{unknown_options.join(', ')}, use #{allowed_options.join(', ')}" unless unknown_options.empty?
171
192
  end
172
193
  when :get then return @options[option_symbol]
173
194
  else Aspera.error_unreachable_line
@@ -176,6 +197,12 @@ module Aspera
176
197
  end
177
198
 
178
199
  def declare_options(options)
200
+ default_table_style = if Environment.terminal_supports_unicode?
201
+ {border: :unicode_round}
202
+ else
203
+ {}
204
+ end
205
+
179
206
  options.declare(:format, 'Output format', values: DISPLAY_FORMATS, handler: {o: self, m: :option_handler}, default: :table)
180
207
  options.declare(:output, 'Destination for results', types: String, handler: {o: self, m: :option_handler})
181
208
  options.declare(:display, 'Output only some information', values: DISPLAY_LEVELS, handler: {o: self, m: :option_handler}, default: :info)
@@ -184,10 +211,11 @@ module Aspera
184
211
  types: [String, Array, Regexp, Proc],
185
212
  default: ExtendedValue::DEF)
186
213
  options.declare(:select, 'Select only some items in lists: column, value', types: [Hash, Proc], handler: {o: self, m: :option_handler})
187
- options.declare(:table_style, 'Table display style', handler: {o: self, m: :option_handler}, default: ':.:')
214
+ options.declare(:table_style, 'Table display style', types: [Hash], handler: {o: self, m: :option_handler}, default: default_table_style)
188
215
  options.declare(:flat_hash, 'Display deep values as additional keys', values: :bool, handler: {o: self, m: :option_handler}, default: true)
189
216
  options.declare(:transpose_single, 'Single object fields output vertically', values: :bool, handler: {o: self, m: :option_handler}, default: true)
190
217
  options.declare(:show_secrets, 'Show secrets on command output', values: :bool, handler: {o: self, m: :option_handler}, default: false)
218
+ options.declare(:image, 'Options for image display', types: Hash, handler: {o: self, m: :option_handler}, default: {})
191
219
  end
192
220
 
193
221
  # main output method
@@ -220,14 +248,15 @@ module Aspera
220
248
  data.each_with_object({}){|v, m|v.each_key{|c|m[c] = true}}.keys
221
249
  end
222
250
 
223
- # this method computes the list of fields to display
224
- # data: array of hash
225
- # default: list of fields to display by default (may contain special values)
251
+ # @return the list of fields to display
252
+ # @param data [Array<Hash>] data to display
253
+ # @param default [Array<String>, Proc] list of fields to display by default (may contain special values)
226
254
  def compute_fields(data, default)
227
255
  Log.log.debug{"compute_fields: data:#{data.class} default:#{default.class} #{default}"}
256
+ # the requested list of fields, but if can contain special values
228
257
  request =
229
258
  case @options[:fields]
230
- when NilClass then [ExtendedValue::DEF]
259
+ # when NilClass then [ExtendedValue::DEF]
231
260
  when String then @options[:fields].split(',')
232
261
  when Array then @options[:fields]
233
262
  when Regexp then return all_fields(data).select{|i|i.match(@options[:fields])}
@@ -261,20 +290,39 @@ module Aspera
261
290
  return result
262
291
  end
263
292
 
293
+ # filter the list of items on the fields option
294
+ def filter_list_on_fields(data)
295
+ # by default, keep all data intact
296
+ return data if @options[:fields].eql?(ExtendedValue::DEF) && @options[:select].nil?
297
+ Aspera.assert_type(data, Array){'Filtering fields or select requires result is an Array of Hash'}
298
+ Aspera.assert(data.all?(Hash)){'Filtering fields or select requires result is an Array of Hash'}
299
+ filter_columns_on_select(data)
300
+ return data if @options[:fields].eql?(ExtendedValue::DEF)
301
+ selected_fields = compute_fields(data, @options[:fields])
302
+ return data.map{|i|i[selected_fields.first]} if selected_fields.length == 1
303
+ return data.map{|i|i.select{|k, _|selected_fields.include?(k)}}
304
+ end
305
+
306
+ # filter the list of items on the select option
307
+ # @param data [Array<Hash>] list of items
308
+ def filter_columns_on_select(data)
309
+ case @options[:select]
310
+ when Proc
311
+ data.select!{|i|@options[:select].call(i)}
312
+ when Hash
313
+ @options[:select].each{|k, v|data.select!{|i|i[k].eql?(v)}}
314
+ end
315
+ end
316
+
264
317
  # this method displays a table
265
318
  # object_array: array of hash
266
319
  # fields: list of column names
267
320
  def display_table(object_array, fields)
268
321
  Aspera.assert(!fields.nil?){'missing fields parameter'}
269
- case @options[:select]
270
- when Proc
271
- object_array.select!{|i|@options[:select].call(i)}
272
- when Hash
273
- @options[:select].each{|k, v|object_array.select!{|i|i[k].eql?(v)}}
274
- end
322
+ filter_columns_on_select(object_array)
275
323
  if object_array.empty?
276
324
  # no display for csv
277
- display_message(:info, Formatter.special('empty')) if @options[:format].eql?(:table)
325
+ display_message(:info, special_format('empty')) if @options[:format].eql?(:table)
278
326
  return
279
327
  end
280
328
  if object_array.length == 1 && fields.length == 1
@@ -294,72 +342,114 @@ module Aspera
294
342
  # here : fields : list of column names
295
343
  case @options[:format]
296
344
  when :table
297
- style = @options[:table_style].chars
298
345
  # display the table !
299
346
  display_message(:data, Terminal::Table.new(
300
347
  headings: fields,
301
348
  rows: final_table_rows,
302
- border_x: style[0],
303
- border_y: style[1],
304
- border_i: style[2]))
349
+ style: @options[:table_style]&.symbolize_keys))
305
350
  when :csv
306
351
  display_message(:data, final_table_rows.map{|t| t.join(CSV_FIELD_SEPARATOR)}.join(CSV_RECORD_SEPARATOR))
307
352
  end
308
353
  end
309
354
 
355
+ # @return text suitable to display an image from url
356
+ def status_image(blob)
357
+ begin
358
+ raise URI::InvalidURIError, 'not uri' if !(blob =~ /\A#{URI::DEFAULT_PARSER.make_regexp}\z/)
359
+ # it's a url
360
+ url = blob
361
+ unless OpenApplication.instance.url_method.eql?(:text)
362
+ OpenApplication.instance.uri(url)
363
+ return ''
364
+ end
365
+ # remote_image = Rest.new(base_url: url).read('')
366
+ # mime = remote_image[:http]['content-type']
367
+ # blob = remote_image[:http].body
368
+ # Log.log.warn("Image ? #{remote_image[:http]['content-type']}") unless mime.include?('image/')
369
+ blob = UriReader.read(url)
370
+ rescue URI::InvalidURIError
371
+ nil
372
+ end
373
+ # try base64
374
+ begin
375
+ blob = Base64.strict_decode64(blob)
376
+ rescue
377
+ nil
378
+ end
379
+ return Preview::Terminal.build(blob, **@options[:image].symbolize_keys)
380
+ end
381
+
310
382
  # this method displays the results, especially the table format
311
- def display_results(results)
312
- Aspera.assert_type(results, Hash)
313
- Aspera.assert((results.keys - RESULT_PARAMS).empty?){"result unsupported key: #{results.keys - RESULT_PARAMS}"}
314
- Aspera.assert(results.key?(:type)){"result must have type (#{results})"}
315
- Aspera.assert(results.key?(:data) || %i[empty nothing].include?(results[:type])){'result must have data'}
316
- Log.log.debug{"display_results: #{results[:data].class} #{results[:type]}"}
317
- display_item_count(results[:data].length, results[:total]) if results.key?(:total)
318
- SecretHider.deep_remove_secret(results[:data]) unless @options[:show_secrets] || @options[:display].eql?(:data)
383
+ # @param type [Symbol] type of data
384
+ # @param data [Object] data to display
385
+ # @param total [Integer] total number of items
386
+ # @param fields [Array<String>] list of fields to display
387
+ # @param name [String] name of the column to display
388
+ def display_results(type:, data: nil, total: nil, fields: nil, name: nil)
389
+ Log.log.debug{"display_results: #{type} class=#{data.class} data=#{data}"}
390
+ Aspera.assert_type(type, Symbol){'result must have type'}
391
+ Aspera.assert(!data.nil? || %i[empty nothing].include?(type)){'result must have data'}
392
+ display_item_count(data.length, total) unless total.nil?
393
+ SecretHider.deep_remove_secret(data) unless @options[:show_secrets] || @options[:display].eql?(:data)
319
394
  case @options[:format]
320
395
  when :text
321
- display_message(:data, results[:data].to_s)
396
+ display_message(:data, data.to_s)
322
397
  when :nagios
323
- Nagios.process(results[:data])
398
+ Nagios.process(data)
324
399
  when :ruby
325
- display_message(:data, PP.pp(results[:data], +''))
400
+ display_message(:data, PP.pp(filter_list_on_fields(data), +''))
326
401
  when :json
327
- display_message(:data, JSON.generate(results[:data]))
402
+ display_message(:data, JSON.generate(filter_list_on_fields(data)))
328
403
  when :jsonpp
329
- display_message(:data, JSON.pretty_generate(results[:data]))
404
+ display_message(:data, JSON.pretty_generate(filter_list_on_fields(data)))
330
405
  when :yaml
331
- display_message(:data, results[:data].to_yaml)
406
+ display_message(:data, YAML.dump(filter_list_on_fields(data)))
407
+ when :image
408
+ # assume it is an url
409
+ url = data
410
+ case type
411
+ when :single_object, :object_list
412
+ url = [url] if type.eql?(:single_object)
413
+ raise 'image display requires a single result' unless url.length == 1
414
+ fields = compute_fields(url, fields)
415
+ raise 'select a field to display' unless fields.length == 1
416
+ url = url.first
417
+ raise 'no such field' unless url.key?(fields.first)
418
+ url = url[fields.first]
419
+ end
420
+ raise "not url: #{url.class} #{url}" unless url.is_a?(String)
421
+ display_message(:data, status_image(url))
332
422
  when :table, :csv
333
- case results[:type]
423
+ case type
334
424
  when :config_over
335
- display_table(Flattener.new.config_over(results[:data]), CONF_OVERVIEW_KEYS)
425
+ display_table(Flattener.new(self).config_over(data), CONF_OVERVIEW_KEYS)
336
426
  when :object_list, :single_object
337
- obj_list = results[:data]
338
- obj_list = [obj_list] if results[:type].eql?(:single_object)
427
+ obj_list = data
428
+ obj_list = [obj_list] if type.eql?(:single_object)
339
429
  Aspera.assert_type(obj_list, Array)
340
430
  Aspera.assert(obj_list.all?(Hash)){"expecting Array of Hash: #{obj_list.inspect}"}
341
431
  # :object_list is an array of hash tables, where key=colum name
342
- obj_list = obj_list.map{|obj|Flattener.new.flatten(obj)} if @options[:flat_hash]
343
- display_table(obj_list, compute_fields(obj_list, results[:fields]))
432
+ obj_list = obj_list.map{|obj|Flattener.new(self).flatten(obj)} if @options[:flat_hash]
433
+ display_table(obj_list, compute_fields(obj_list, fields))
344
434
  when :value_list
345
435
  # :value_list is a simple array of values, name of column provided in the :name
346
- display_table(results[:data].map { |i| { results[:name] => i } }, [results[:name]])
436
+ display_table(data.map { |i| { name => i } }, [name])
347
437
  when :empty # no table
348
- display_message(:info, Formatter.special('empty'))
438
+ display_message(:info, special_format('empty'))
349
439
  return
350
440
  when :nothing # no result expected
351
441
  Log.log.debug('no result expected')
352
442
  when :status # no table
353
443
  # :status displays a simple message
354
- display_message(:info, results[:data])
444
+ display_message(:info, data)
355
445
  when :text # no table
356
446
  # :status displays a simple message
357
- display_message(:data, results[:data])
447
+ display_message(:data, data)
358
448
  when :other_struct # no table
359
449
  # :other_struct is any other type of structure
360
- display_message(:data, PP.pp(results[:data], +''))
450
+ display_message(:data, PP.pp(data, +''))
361
451
  else
362
- raise "unknown data type: #{results[:type]}"
452
+ raise "unknown data type: #{type}"
363
453
  end
364
454
  end
365
455
  end
@@ -47,6 +47,24 @@ module Aspera
47
47
  'if you provide a path: prefix with @file:',
48
48
  'e.g. --private-key=@file:/path/to/key.pem'
49
49
  ]
50
+ },
51
+ {
52
+ exception: RuntimeError,
53
+ match: /unexpected last event type: INIT/,
54
+ remediation: [
55
+ 'ascp exited unexpectedly',
56
+ 'it might be due to SSH handshake failure',
57
+ 'one can check SSH connection using ssh command'
58
+ ]
59
+ },
60
+ {
61
+ exception: RuntimeError,
62
+ match: /Wrong remote host:/,
63
+ remediation: [
64
+ 'If remote node is Cloud Pak For Integration',
65
+ 'Make sure that a LoadBalancer is active on cluster',
66
+ 'Check the external address of Aspera tcp-proxy pod'
67
+ ]
50
68
  }
51
69
  ]
52
70
 
@@ -9,7 +9,6 @@ require 'aspera/cli/transfer_agent'
9
9
  require 'aspera/cli/version'
10
10
  require 'aspera/cli/info'
11
11
  require 'aspera/cli/hints'
12
- require 'aspera/preview/terminal'
13
12
  require 'aspera/secret_hider'
14
13
  require 'aspera/log'
15
14
  require 'aspera/assert'
@@ -20,9 +19,10 @@ module Aspera
20
19
  class Main
21
20
  # Plugins store transfer result using this key and use result_transfer_multiple()
22
21
  STATUS_FIELD = 'status'
23
- CONF_PLUGIN_SYM = :config
22
+ COMMAND_CONFIG = :config
23
+ COMMAND_HELP = :help
24
24
 
25
- private_constant :CONF_PLUGIN_SYM
25
+ private_constant :COMMAND_CONFIG, :COMMAND_HELP
26
26
 
27
27
  class << self
28
28
  # expect some list, but nothing to display
@@ -60,14 +60,10 @@ module Aspera
60
60
  return {type: :object_list, data: status_table}
61
61
  end
62
62
 
63
- def result_picture_in_terminal(options, blob)
64
- terminal_options = options.get_option(:query, default: {}).symbolize_keys
65
- allowed_options = Preview::Terminal.method(:build).parameters.select{|i|i[0].eql?(:key)}.map{|i|i[1]}
66
- unknown_options = terminal_options.keys - allowed_options
67
- raise "invalid options: #{unknown_options.join(', ')}, use #{allowed_options.join(', ')}" unless unknown_options.empty?
68
- return Main.result_status(Preview::Terminal.build(blob, **terminal_options))
63
+ def result_image(blob, formatter:)
64
+ return Main.result_status(formatter.status_image(blob))
69
65
  end
70
- end # self
66
+ end
71
67
 
72
68
  private
73
69
 
@@ -88,6 +84,8 @@ module Aspera
88
84
  @option_help = false
89
85
  @option_show_config = false
90
86
  @bash_completion = false
87
+ early_debug_setup
88
+ Log.log.trace2{Log.dump(:argv, @argv)}
91
89
  end
92
90
 
93
91
  # This can throw exception if there is a problem with the environment, needs to be caught by execute method
@@ -95,8 +93,6 @@ module Aspera
95
93
  @plug_init[:only_manual] = false
96
94
  # create formatter, in case there is an exception, it is used to display.
97
95
  @plug_init[:formatter] = Formatter.new
98
- # second : manage debug level (allows debugging of option parser)
99
- early_debug_setup
100
96
  @plug_init[:options] = Manager.new(PROGRAM_NAME)
101
97
  # give command line arguments to option manager
102
98
  options.parse_command_line(@argv)
@@ -164,10 +160,9 @@ module Aspera
164
160
  options.declare(:bash_comp, 'Generate bash completion for command', values: :none) { @bash_completion = true }
165
161
  options.declare(:show_config, 'Display parameters used for the provided action', values: :none) { @option_show_config = true }
166
162
  options.declare(:version, 'Display version', values: :none, short: 'v') { formatter.display_message(:data, Cli::VERSION); Process.exit(0) } # rubocop:disable Style/Semicolon, Layout/LineLength
167
- options.declare(:warnings, 'Check for language warnings', values: :none, short: 'w') { $VERBOSE = true }
168
163
  options.declare(
169
164
  :ui, 'Method to start browser',
170
- values: OpenApplication.user_interfaces,
165
+ values: OpenApplication::USER_INTERFACES,
171
166
  handler: {o: OpenApplication.instance, m: :url_method},
172
167
  default: OpenApplication.default_gui_mode)
173
168
  options.declare(:log_level, 'Log level', values: Log.levels, handler: {o: Log.instance, m: :level})
@@ -187,17 +182,15 @@ module Aspera
187
182
  def get_plugin_instance_with_options(plugin_name_sym, env=nil)
188
183
  env ||= @plug_init
189
184
  Log.log.debug{"get_plugin_instance_with_options(#{plugin_name_sym})"}
190
- require PluginFactory.instance.plugins[plugin_name_sym][:require_stanza]
191
185
  # load default params only if no param already loaded before plugin instantiation
192
186
  env[:config].add_plugin_default_preset(plugin_name_sym)
193
187
  command_plugin = PluginFactory.instance.create(plugin_name_sym, **env)
194
- Log.log.debug{"got #{command_plugin.class}"}
195
188
  return command_plugin
196
189
  end
197
190
 
198
191
  def generate_bash_completion
199
192
  if options.get_next_argument('', expected: :multiple, mandatory: false).nil?
200
- PluginFactory.instance.plugins.each_key{|p|puts p}
193
+ PluginFactory.instance.plugin_list.each{|p|puts p}
201
194
  else
202
195
  Log.log.warn('only first level completion so far')
203
196
  end
@@ -210,8 +203,8 @@ module Aspera
210
203
  formatter.display_message(:error, options.parser)
211
204
  if all_plugins
212
205
  # list plugins that have a "require" field, i.e. all but main plugin
213
- PluginFactory.instance.plugins.each_key do |plugin_name_sym|
214
- next if plugin_name_sym.eql?(CONF_PLUGIN_SYM)
206
+ PluginFactory.instance.plugin_list.each do |plugin_name_sym|
207
+ next if plugin_name_sym.eql?(COMMAND_CONFIG)
215
208
  # override main option parser with a brand new, to avoid having global options
216
209
  plugin_env = @plug_init.clone
217
210
  plugin_env[:only_manual] = true # force declaration of all options
@@ -261,17 +254,17 @@ module Aspera
261
254
  config.periodic_check_newer_gem_version
262
255
  command_sym =
263
256
  if @option_show_config && options.command_or_arg_empty?
264
- CONF_PLUGIN_SYM
257
+ COMMAND_CONFIG
265
258
  else
266
- options.get_next_command(PluginFactory.instance.plugins.keys.dup.unshift(:help))
259
+ options.get_next_command(PluginFactory.instance.plugin_list.unshift(COMMAND_HELP))
267
260
  end
268
261
  # command will not be executed, but we need manual
269
262
  options.fail_on_missing_mandatory = false if @option_help || @option_show_config
270
263
  # main plugin is not dynamically instantiated
271
264
  case command_sym
272
- when :help
265
+ when COMMAND_HELP
273
266
  exit_with_usage(true)
274
- when CONF_PLUGIN_SYM
267
+ when COMMAND_CONFIG
275
268
  command_plugin = config
276
269
  else
277
270
  # get plugin, set options, etc
@@ -282,7 +275,7 @@ module Aspera
282
275
  # help requested for current plugin
283
276
  exit_with_usage(false) if @option_help
284
277
  if @option_show_config
285
- formatter.display_results({type: :single_object, data: options.known_options(only_defined: true).stringify_keys})
278
+ formatter.display_results(type: :single_object, data: options.known_options(only_defined: true).stringify_keys)
286
279
  execute_command = false
287
280
  end
288
281
  # locking for single execution (only after "per plugin" option, in case lock port is there)
@@ -304,7 +297,7 @@ module Aspera
304
297
  at_exit{File.delete(pid_file)}
305
298
  end
306
299
  # execute and display (if not exclusive execution)
307
- formatter.display_results(command_plugin.execute_action) if execute_command
300
+ formatter.display_results(**command_plugin.execute_action) if execute_command
308
301
  # save config file if command modified it
309
302
  config.save_config_file_if_needed
310
303
  # finish
@@ -347,7 +340,7 @@ module Aspera
347
340
  Process.exit(1)
348
341
  end
349
342
  return nil
350
- end # process_command_line
351
- end # Main
352
- end # Cli
353
- end # Aspera
343
+ end
344
+ end
345
+ end
346
+ end