aspera-cli 4.17.0 → 4.18.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +3 -4
  3. data/CHANGELOG.md +33 -0
  4. data/CONTRIBUTING.md +15 -1
  5. data/README.md +711 -432
  6. data/bin/ascli +5 -0
  7. data/bin/asession +2 -2
  8. data/examples/build_package.sh +28 -0
  9. data/lib/aspera/agent/alpha.rb +10 -8
  10. data/lib/aspera/agent/base.rb +9 -6
  11. data/lib/aspera/agent/connect.rb +7 -8
  12. data/lib/aspera/agent/direct.rb +56 -37
  13. data/lib/aspera/agent/httpgw.rb +23 -324
  14. data/lib/aspera/agent/node.rb +19 -20
  15. data/lib/aspera/agent/trsdk.rb +19 -20
  16. data/lib/aspera/api/aoc.rb +17 -14
  17. data/lib/aspera/api/cos_node.rb +4 -4
  18. data/lib/aspera/api/httpgw.rb +342 -0
  19. data/lib/aspera/api/node.rb +135 -89
  20. data/lib/aspera/ascmd.rb +4 -3
  21. data/lib/aspera/ascp/installation.rb +15 -7
  22. data/lib/aspera/ascp/management.rb +2 -2
  23. data/lib/aspera/ascp/products.rb +1 -1
  24. data/lib/aspera/cli/basic_auth_plugin.rb +5 -9
  25. data/lib/aspera/cli/extended_value.rb +35 -16
  26. data/lib/aspera/cli/formatter.rb +161 -70
  27. data/lib/aspera/cli/hints.rb +18 -0
  28. data/lib/aspera/cli/main.rb +32 -39
  29. data/lib/aspera/cli/manager.rb +151 -119
  30. data/lib/aspera/cli/plugin.rb +27 -21
  31. data/lib/aspera/cli/plugin_factory.rb +31 -20
  32. data/lib/aspera/cli/plugins/alee.rb +14 -2
  33. data/lib/aspera/cli/plugins/aoc.rb +152 -141
  34. data/lib/aspera/cli/plugins/ats.rb +1 -1
  35. data/lib/aspera/cli/plugins/config.rb +72 -65
  36. data/lib/aspera/cli/plugins/console.rb +8 -5
  37. data/lib/aspera/cli/plugins/faspex.rb +32 -23
  38. data/lib/aspera/cli/plugins/faspex5.rb +232 -156
  39. data/lib/aspera/cli/plugins/faspio.rb +85 -0
  40. data/lib/aspera/cli/plugins/httpgw.rb +55 -0
  41. data/lib/aspera/cli/plugins/node.rb +129 -64
  42. data/lib/aspera/cli/plugins/orchestrator.rb +33 -30
  43. data/lib/aspera/cli/plugins/preview.rb +7 -3
  44. data/lib/aspera/cli/plugins/server.rb +6 -6
  45. data/lib/aspera/cli/plugins/shares.rb +16 -14
  46. data/lib/aspera/cli/special_values.rb +13 -0
  47. data/lib/aspera/cli/sync_actions.rb +10 -10
  48. data/lib/aspera/cli/transfer_agent.rb +7 -6
  49. data/lib/aspera/cli/version.rb +1 -1
  50. data/lib/aspera/environment.rb +70 -9
  51. data/lib/aspera/faspex_gw.rb +5 -4
  52. data/lib/aspera/faspex_postproc.rb +2 -2
  53. data/lib/aspera/log.rb +6 -3
  54. data/lib/aspera/node_simulator.rb +2 -2
  55. data/lib/aspera/oauth/base.rb +31 -19
  56. data/lib/aspera/oauth/factory.rb +12 -13
  57. data/lib/aspera/oauth/generic.rb +1 -0
  58. data/lib/aspera/oauth/jwt.rb +18 -15
  59. data/lib/aspera/oauth/url_json.rb +8 -6
  60. data/lib/aspera/oauth/web.rb +2 -2
  61. data/lib/aspera/persistency_folder.rb +2 -2
  62. data/lib/aspera/preview/generator.rb +3 -3
  63. data/lib/aspera/preview/options.rb +3 -3
  64. data/lib/aspera/preview/terminal.rb +4 -4
  65. data/lib/aspera/preview/utils.rb +3 -3
  66. data/lib/aspera/proxy_auto_config.rb +5 -1
  67. data/lib/aspera/rest.rb +105 -88
  68. data/lib/aspera/rest_call_error.rb +1 -1
  69. data/lib/aspera/rest_error_analyzer.rb +2 -2
  70. data/lib/aspera/rest_errors_aspera.rb +1 -1
  71. data/lib/aspera/resumer.rb +1 -1
  72. data/lib/aspera/secret_hider.rb +2 -4
  73. data/lib/aspera/ssh.rb +1 -1
  74. data/lib/aspera/transfer/parameters.rb +39 -36
  75. data/lib/aspera/transfer/spec.rb +2 -0
  76. data/lib/aspera/transfer/sync.rb +2 -1
  77. data/lib/aspera/transfer/uri.rb +1 -1
  78. data/lib/aspera/uri_reader.rb +5 -4
  79. data/lib/aspera/web_auth.rb +1 -1
  80. data/lib/aspera/web_server_simple.rb +4 -3
  81. data.tar.gz.sig +0 -0
  82. metadata +7 -4
  83. metadata.gz.sig +0 -0
  84. data/lib/aspera/cli/plugins/bss.rb +0 -71
  85. data/lib/aspera/open_application.rb +0 -71
@@ -1,11 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # cspell:ignore jsonpp
4
+ require 'aspera/cli/special_values'
5
+ require 'aspera/preview/terminal'
4
6
  require 'aspera/secret_hider'
5
7
  require 'aspera/environment'
6
8
  require 'aspera/log'
7
9
  require 'aspera/assert'
8
10
  require 'terminal-table'
11
+ require 'tty-spinner'
9
12
  require 'yaml'
10
13
  require 'pp'
11
14
 
@@ -14,8 +17,9 @@ module Aspera
14
17
  CONF_OVERVIEW_KEYS = %w[preset parameter value].freeze
15
18
  # This class is used to transform a complex structure into a simple hash
16
19
  class Flattener
17
- def initialize
20
+ def initialize(formatter)
18
21
  @result = nil
22
+ @formatter = formatter
19
23
  end
20
24
 
21
25
  # General method
@@ -48,9 +52,9 @@ module Aspera
48
52
  elsif something.is_a?(Array)
49
53
  flatten_array(something, name)
50
54
  elsif something.is_a?(String) && something.empty?
51
- @result[name] = Formatter.special('empty string')
55
+ @result[name] = @formatter.special_format('empty string')
52
56
  elsif something.nil?
53
- @result[name] = Formatter.special('null')
57
+ @result[name] = @formatter.special_format('null')
54
58
  # elsif something.eql?(true) || something.eql?(false)
55
59
  # @result[name] = something
56
60
  else
@@ -63,7 +67,7 @@ module Aspera
63
67
  # @param name [String] name of englobing key
64
68
  def flatten_array(array, name)
65
69
  if array.empty?
66
- @result[name] = Formatter.special('empty list')
70
+ @result[name] = @formatter.special_format('empty list')
67
71
  elsif array.all?(String)
68
72
  @result[name] = array.join("\n")
69
73
  elsif array.all?{|i| i.is_a?(Hash) && i.keys.eql?(%w[name])}
@@ -85,18 +89,18 @@ module Aspera
85
89
  flatten_any(v, "#{prefix}#{k}")
86
90
  end
87
91
  end
88
- end # class
92
+ end
89
93
 
90
94
  # Take care of output
91
95
  class Formatter
96
+ # remove a fields from the list
92
97
  FIELDS_LESS = '-'
93
98
  CSV_RECORD_SEPARATOR = "\n"
94
99
  CSV_FIELD_SEPARATOR = ','
95
100
  # supported output formats
96
- DISPLAY_FORMATS = %i[text nagios ruby json jsonpp yaml table csv].freeze
101
+ DISPLAY_FORMATS = %i[text nagios ruby json jsonpp yaml table csv image].freeze
97
102
  # user output levels
98
103
  DISPLAY_LEVELS = %i[info data error].freeze
99
- RESULT_PARAMS = %i[type data total fields name].freeze
100
104
 
101
105
  private_constant :DISPLAY_FORMATS, :DISPLAY_LEVELS, :CSV_RECORD_SEPARATOR, :CSV_FIELD_SEPARATOR
102
106
  # prefix to display error messages in user messages (terminal)
@@ -105,27 +109,14 @@ module Aspera
105
109
  HINT_FLASH = 'HINT:'.bg_green.gray.blink.freeze
106
110
 
107
111
  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
112
  def all_but(list)
122
113
  list = [list] unless list.is_a?(Array)
123
- return list.map{|i|"#{FIELDS_LESS}#{i}"}.unshift(ExtendedValue::ALL)
114
+ return list.map{|i|"#{FIELDS_LESS}#{i}"}.unshift(SpecialValues::ALL)
124
115
  end
125
116
 
126
117
  def tick(yes)
127
118
  result =
128
- if Environment.use_unicode?
119
+ if Environment.terminal_supports_unicode?
129
120
  if yes
130
121
  "\u2713"
131
122
  else
@@ -150,24 +141,55 @@ module Aspera
150
141
  end
151
142
  return result
152
143
  end
153
- end # self
144
+ end
154
145
 
155
146
  # initialize the formatter
156
147
  def initialize
157
148
  @options = {}
149
+ @spinner = nil
150
+ end
151
+
152
+ # Highlight special values
153
+ def special_format(what, use_colors: $stdout.isatty)
154
+ result = $stdout.isatty ? "<#{what}>" : "&lt;#{what}&gt;"
155
+ if use_colors
156
+ result = if %w[null empty].any?{|s|what.include?(s)}
157
+ result.dim
158
+ else
159
+ result.reverse_color
160
+ end
161
+ end
162
+ return result
158
163
  end
159
164
 
165
+ # call this after REST calls if several api calls are expected
166
+ def long_operation_running(title = '')
167
+ return unless Environment.terminal?
168
+ if @spinner.nil?
169
+ @spinner = TTY::Spinner.new('[:spinner] :title', format: :classic)
170
+ @spinner.start
171
+ end
172
+ @spinner.update(title: title)
173
+ @spinner.spin
174
+ end
175
+
176
+ # options are: format, output, display, fields, select, table_style, flat_hash, transpose_single
160
177
  def option_handler(option_symbol, operation, value=nil)
161
178
  Aspera.assert_values(operation, %i[set get])
162
179
  case operation
163
180
  when :set
164
181
  @options[option_symbol] = value
165
- if option_symbol.eql?(:output)
182
+ case option_symbol
183
+ when :output
166
184
  $stdout = if value.eql?('-')
167
185
  STDOUT # rubocop:disable Style/GlobalStdStream
168
186
  else
169
187
  File.open(value, 'w')
170
188
  end
189
+ when :image
190
+ allowed_options = Preview::Terminal.method(:build).parameters.select{|i|i[0].eql?(:key)}.map{|i|i[1]}
191
+ unknown_options = value.keys.map(&:to_sym) - allowed_options
192
+ raise "Invalid parameter(s) for option image: #{unknown_options.join(', ')}, use #{allowed_options.join(', ')}" unless unknown_options.empty?
171
193
  end
172
194
  when :get then return @options[option_symbol]
173
195
  else Aspera.error_unreachable_line
@@ -176,18 +198,25 @@ module Aspera
176
198
  end
177
199
 
178
200
  def declare_options(options)
201
+ default_table_style = if Environment.terminal_supports_unicode?
202
+ {border: :unicode_round}
203
+ else
204
+ {}
205
+ end
206
+
179
207
  options.declare(:format, 'Output format', values: DISPLAY_FORMATS, handler: {o: self, m: :option_handler}, default: :table)
180
208
  options.declare(:output, 'Destination for results', types: String, handler: {o: self, m: :option_handler})
181
209
  options.declare(:display, 'Output only some information', values: DISPLAY_LEVELS, handler: {o: self, m: :option_handler}, default: :info)
182
210
  options.declare(
183
- :fields, "Comma separated list of: fields, or #{ExtendedValue::ALL}, or #{ExtendedValue::DEF}", handler: {o: self, m: :option_handler},
211
+ :fields, "Comma separated list of: fields, or #{SpecialValues::ALL}, or #{SpecialValues::DEF}", handler: {o: self, m: :option_handler},
184
212
  types: [String, Array, Regexp, Proc],
185
- default: ExtendedValue::DEF)
213
+ default: SpecialValues::DEF)
186
214
  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: ':.:')
215
+ options.declare(:table_style, 'Table display style', types: [Hash], handler: {o: self, m: :option_handler}, default: default_table_style)
188
216
  options.declare(:flat_hash, 'Display deep values as additional keys', values: :bool, handler: {o: self, m: :option_handler}, default: true)
189
217
  options.declare(:transpose_single, 'Single object fields output vertically', values: :bool, handler: {o: self, m: :option_handler}, default: true)
190
218
  options.declare(:show_secrets, 'Show secrets on command output', values: :bool, handler: {o: self, m: :option_handler}, default: false)
219
+ options.declare(:image, 'Options for image display', types: Hash, handler: {o: self, m: :option_handler}, default: {})
191
220
  end
192
221
 
193
222
  # main output method
@@ -220,14 +249,15 @@ module Aspera
220
249
  data.each_with_object({}){|v, m|v.each_key{|c|m[c] = true}}.keys
221
250
  end
222
251
 
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)
252
+ # @return the list of fields to display
253
+ # @param data [Array<Hash>] data to display
254
+ # @param default [Array<String>, Proc] list of fields to display by default (may contain special values)
226
255
  def compute_fields(data, default)
227
256
  Log.log.debug{"compute_fields: data:#{data.class} default:#{default.class} #{default}"}
257
+ # the requested list of fields, but if can contain special values
228
258
  request =
229
259
  case @options[:fields]
230
- when NilClass then [ExtendedValue::DEF]
260
+ # when NilClass then [SpecialValues::DEF]
231
261
  when String then @options[:fields].split(',')
232
262
  when Array then @options[:fields]
233
263
  when Regexp then return all_fields(data).select{|i|i.match(@options[:fields])}
@@ -243,10 +273,10 @@ module Aspera
243
273
  item = item[1..-1]
244
274
  end
245
275
  case item
246
- when ExtendedValue::ALL
276
+ when SpecialValues::ALL
247
277
  # get the list of all column names used in all lines, not just first one, as all lines may have different columns
248
278
  request.unshift(*all_fields(data))
249
- when ExtendedValue::DEF
279
+ when SpecialValues::DEF
250
280
  default = all_fields(data).select{|i|default.call(i)} if default.is_a?(Proc)
251
281
  default = all_fields(data) if default.nil?
252
282
  request.unshift(*default)
@@ -261,20 +291,39 @@ module Aspera
261
291
  return result
262
292
  end
263
293
 
294
+ # filter the list of items on the fields option
295
+ def filter_list_on_fields(data)
296
+ # by default, keep all data intact
297
+ return data if @options[:fields].eql?(SpecialValues::DEF) && @options[:select].nil?
298
+ Aspera.assert_type(data, Array){'Filtering fields or select requires result is an Array of Hash'}
299
+ Aspera.assert(data.all?(Hash)){'Filtering fields or select requires result is an Array of Hash'}
300
+ filter_columns_on_select(data)
301
+ return data if @options[:fields].eql?(SpecialValues::DEF)
302
+ selected_fields = compute_fields(data, @options[:fields])
303
+ return data.map{|i|i[selected_fields.first]} if selected_fields.length == 1
304
+ return data.map{|i|i.select{|k, _|selected_fields.include?(k)}}
305
+ end
306
+
307
+ # filter the list of items on the select option
308
+ # @param data [Array<Hash>] list of items
309
+ def filter_columns_on_select(data)
310
+ case @options[:select]
311
+ when Proc
312
+ data.select!{|i|@options[:select].call(i)}
313
+ when Hash
314
+ @options[:select].each{|k, v|data.select!{|i|i[k].eql?(v)}}
315
+ end
316
+ end
317
+
264
318
  # this method displays a table
265
319
  # object_array: array of hash
266
320
  # fields: list of column names
267
321
  def display_table(object_array, fields)
268
322
  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
323
+ filter_columns_on_select(object_array)
275
324
  if object_array.empty?
276
325
  # no display for csv
277
- display_message(:info, Formatter.special('empty')) if @options[:format].eql?(:table)
326
+ display_message(:info, special_format('empty')) if @options[:format].eql?(:table)
278
327
  return
279
328
  end
280
329
  if object_array.length == 1 && fields.length == 1
@@ -294,72 +343,114 @@ module Aspera
294
343
  # here : fields : list of column names
295
344
  case @options[:format]
296
345
  when :table
297
- style = @options[:table_style].chars
298
346
  # display the table !
299
347
  display_message(:data, Terminal::Table.new(
300
348
  headings: fields,
301
349
  rows: final_table_rows,
302
- border_x: style[0],
303
- border_y: style[1],
304
- border_i: style[2]))
350
+ style: @options[:table_style]&.symbolize_keys))
305
351
  when :csv
306
352
  display_message(:data, final_table_rows.map{|t| t.join(CSV_FIELD_SEPARATOR)}.join(CSV_RECORD_SEPARATOR))
307
353
  end
308
354
  end
309
355
 
356
+ # @return text suitable to display an image from url
357
+ def status_image(blob)
358
+ begin
359
+ raise URI::InvalidURIError, 'not uri' if !(blob =~ /\A#{URI::DEFAULT_PARSER.make_regexp}\z/)
360
+ # it's a url
361
+ url = blob
362
+ unless Environment.instance.url_method.eql?(:text)
363
+ Environment.instance.open_uri(url)
364
+ return ''
365
+ end
366
+ # remote_image = Rest.new(base_url: url).read('')
367
+ # mime = remote_image[:http]['content-type']
368
+ # blob = remote_image[:http].body
369
+ # Log.log.warn("Image ? #{remote_image[:http]['content-type']}") unless mime.include?('image/')
370
+ blob = UriReader.read(url)
371
+ rescue URI::InvalidURIError
372
+ nil
373
+ end
374
+ # try base64
375
+ begin
376
+ blob = Base64.strict_decode64(blob)
377
+ rescue
378
+ nil
379
+ end
380
+ return Preview::Terminal.build(blob, **@options[:image].symbolize_keys)
381
+ end
382
+
310
383
  # 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)
384
+ # @param type [Symbol] type of data
385
+ # @param data [Object] data to display
386
+ # @param total [Integer] total number of items
387
+ # @param fields [Array<String>] list of fields to display
388
+ # @param name [String] name of the column to display
389
+ def display_results(type:, data: nil, total: nil, fields: nil, name: nil)
390
+ Log.log.debug{"display_results: #{type} class=#{data.class} data=#{data}"}
391
+ Aspera.assert_type(type, Symbol){'result must have type'}
392
+ Aspera.assert(!data.nil? || %i[empty nothing].include?(type)){'result must have data'}
393
+ display_item_count(data.length, total) unless total.nil?
394
+ SecretHider.deep_remove_secret(data) unless @options[:show_secrets] || @options[:display].eql?(:data)
319
395
  case @options[:format]
320
396
  when :text
321
- display_message(:data, results[:data].to_s)
397
+ display_message(:data, data.to_s)
322
398
  when :nagios
323
- Nagios.process(results[:data])
399
+ Nagios.process(data)
324
400
  when :ruby
325
- display_message(:data, PP.pp(results[:data], +''))
401
+ display_message(:data, PP.pp(filter_list_on_fields(data), +''))
326
402
  when :json
327
- display_message(:data, JSON.generate(results[:data]))
403
+ display_message(:data, JSON.generate(filter_list_on_fields(data)))
328
404
  when :jsonpp
329
- display_message(:data, JSON.pretty_generate(results[:data]))
405
+ display_message(:data, JSON.pretty_generate(filter_list_on_fields(data)))
330
406
  when :yaml
331
- display_message(:data, results[:data].to_yaml)
407
+ display_message(:data, YAML.dump(filter_list_on_fields(data)))
408
+ when :image
409
+ # assume it is an url
410
+ url = data
411
+ case type
412
+ when :single_object, :object_list
413
+ url = [url] if type.eql?(:single_object)
414
+ raise 'image display requires a single result' unless url.length == 1
415
+ fields = compute_fields(url, fields)
416
+ raise 'select a field to display' unless fields.length == 1
417
+ url = url.first
418
+ raise 'no such field' unless url.key?(fields.first)
419
+ url = url[fields.first]
420
+ end
421
+ raise "not url: #{url.class} #{url}" unless url.is_a?(String)
422
+ display_message(:data, status_image(url))
332
423
  when :table, :csv
333
- case results[:type]
424
+ case type
334
425
  when :config_over
335
- display_table(Flattener.new.config_over(results[:data]), CONF_OVERVIEW_KEYS)
426
+ display_table(Flattener.new(self).config_over(data), CONF_OVERVIEW_KEYS)
336
427
  when :object_list, :single_object
337
- obj_list = results[:data]
338
- obj_list = [obj_list] if results[:type].eql?(:single_object)
428
+ obj_list = data
429
+ obj_list = [obj_list] if type.eql?(:single_object)
339
430
  Aspera.assert_type(obj_list, Array)
340
431
  Aspera.assert(obj_list.all?(Hash)){"expecting Array of Hash: #{obj_list.inspect}"}
341
432
  # :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]))
433
+ obj_list = obj_list.map{|obj|Flattener.new(self).flatten(obj)} if @options[:flat_hash]
434
+ display_table(obj_list, compute_fields(obj_list, fields))
344
435
  when :value_list
345
436
  # :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]])
437
+ display_table(data.map { |i| { name => i } }, [name])
347
438
  when :empty # no table
348
- display_message(:info, Formatter.special('empty'))
439
+ display_message(:info, special_format('empty'))
349
440
  return
350
441
  when :nothing # no result expected
351
442
  Log.log.debug('no result expected')
352
443
  when :status # no table
353
444
  # :status displays a simple message
354
- display_message(:info, results[:data])
445
+ display_message(:info, data)
355
446
  when :text # no table
356
447
  # :status displays a simple message
357
- display_message(:data, results[:data])
448
+ display_message(:data, data)
358
449
  when :other_struct # no table
359
450
  # :other_struct is any other type of structure
360
- display_message(:data, PP.pp(results[:data], +''))
451
+ display_message(:data, PP.pp(data, +''))
361
452
  else
362
- raise "unknown data type: #{results[:type]}"
453
+ raise "unknown data type: #{type}"
363
454
  end
364
455
  end
365
456
  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,13 +93,11 @@ 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
- @plug_init[:options] = Manager.new(PROGRAM_NAME)
101
- # give command line arguments to option manager
102
- options.parse_command_line(@argv)
96
+ # create command line manager with arguments
97
+ @plug_init[:options] = Manager.new(PROGRAM_NAME, @argv)
103
98
  # formatter adds options
104
- formatter.declare_options(options)
99
+ @plug_init[:formatter].declare_options(options)
100
+ ExtendedValue.instance.default_decoder = options.get_option(:struct_parser)
105
101
  # compare $0 with expected name
106
102
  current_prog_name = File.basename($PROGRAM_NAME)
107
103
  formatter.display_message(
@@ -164,12 +160,11 @@ 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,
171
- handler: {o: OpenApplication.instance, m: :url_method},
172
- default: OpenApplication.default_gui_mode)
165
+ values: Environment::USER_INTERFACES,
166
+ handler: {o: Environment.instance, m: :url_method},
167
+ default: Environment.default_gui_mode)
173
168
  options.declare(:log_level, 'Log level', values: Log.levels, handler: {o: Log.instance, m: :level})
174
169
  options.declare(:logger, 'Logging method', values: Log::LOG_TYPES, handler: {o: Log.instance, m: :logger_type})
175
170
  options.declare(:lock_port, 'Prevent dual execution of a command, e.g. in cron', coerce: Integer, types: Integer)
@@ -187,31 +182,29 @@ 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
- if options.get_next_argument('', expected: :multiple, mandatory: false).nil?
200
- PluginFactory.instance.plugins.each_key{|p|puts p}
192
+ if options.get_next_argument('', multiple: true, mandatory: false).nil?
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
204
197
  Process.exit(0)
205
198
  end
206
199
 
207
- def exit_with_usage(all_plugins)
208
- Log.log.debug('exit_with_usage'.bg_red)
200
+ def exit_with_usage(include_all_plugins)
201
+ Log.log.debug{"exit_with_usage(#{include_all_plugins})".bg_red}
209
202
  # display main plugin options
210
203
  formatter.display_message(:error, options.parser)
211
- if all_plugins
204
+ if include_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