aspera-cli 4.26.0 → 4.26.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 (47) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +17 -3
  4. data/lib/aspera/api/aoc.rb +2 -1
  5. data/lib/aspera/api/node.rb +2 -2
  6. data/lib/aspera/ascp/installation.rb +7 -4
  7. data/lib/aspera/assert.rb +17 -13
  8. data/lib/aspera/cli/extended_value.rb +6 -2
  9. data/lib/aspera/cli/formatter.rb +65 -60
  10. data/lib/aspera/cli/main.rb +69 -10
  11. data/lib/aspera/cli/manager.rb +130 -76
  12. data/lib/aspera/cli/options.schema.yaml +82 -0
  13. data/lib/aspera/cli/plugins/aoc.rb +36 -11
  14. data/lib/aspera/cli/plugins/base.rb +46 -37
  15. data/lib/aspera/cli/plugins/config.rb +9 -9
  16. data/lib/aspera/cli/plugins/faspex.rb +1 -1
  17. data/lib/aspera/cli/plugins/faspex5.rb +4 -5
  18. data/lib/aspera/cli/plugins/node.rb +1 -1
  19. data/lib/aspera/cli/sync_actions.rb +1 -1
  20. data/lib/aspera/cli/transfer_agent.rb +17 -15
  21. data/lib/aspera/cli/version.rb +1 -1
  22. data/lib/aspera/command_line_builder.rb +22 -18
  23. data/lib/aspera/environment.rb +3 -3
  24. data/lib/aspera/formatter_interface.rb +14 -0
  25. data/lib/aspera/hash_ext.rb +6 -0
  26. data/lib/aspera/log.rb +4 -3
  27. data/lib/aspera/markdown.rb +4 -1
  28. data/lib/aspera/oauth/factory.rb +1 -1
  29. data/lib/aspera/proxy_auto_config.rb +3 -0
  30. data/lib/aspera/rest.rb +1 -1
  31. data/lib/aspera/schema/IBM Aspera Faspex API-5.0-enhanced.yaml +62801 -0
  32. data/lib/aspera/schema/IBM Aspera on Cloud API-0.2.6-enhanced.yaml +8898 -0
  33. data/lib/aspera/schema/documentation.rb +107 -0
  34. data/lib/aspera/schema/reader.rb +75 -0
  35. data/lib/aspera/schema/registry.rb +63 -0
  36. data/lib/aspera/sync/conf.schema.yaml +0 -26
  37. data/lib/aspera/sync/operations.rb +9 -5
  38. data/lib/aspera/transfer/faux_file.rb +1 -1
  39. data/lib/aspera/transfer/resumer.rb +1 -1
  40. data/lib/aspera/transfer/spec.rb +3 -3
  41. data/lib/aspera/transfer/spec.schema.yaml +1 -1
  42. data/lib/aspera/uri_reader.rb +1 -1
  43. data/lib/aspera/yaml.rb +4 -2
  44. data.tar.gz.sig +0 -0
  45. metadata +9 -3
  46. metadata.gz.sig +0 -0
  47. data/lib/aspera/transfer/spec_doc.rb +0 -76
@@ -12,6 +12,8 @@ require 'aspera/cli/hints'
12
12
  require 'aspera/secret_hider'
13
13
  require 'aspera/log'
14
14
  require 'aspera/assert'
15
+ require 'aspera/schema/documentation'
16
+ require 'aspera/schema/registry'
15
17
  require 'net/ssh/errors'
16
18
  require 'openssl'
17
19
 
@@ -19,6 +21,8 @@ module Aspera
19
21
  module Cli
20
22
  # Global objects shared with plugins
21
23
  class Context
24
+ # @type [Array<Symbol>]
25
+ MEMBERS = %i[options transfer config formatter persistency man_header].freeze
22
26
  # @!attribute [rw] options
23
27
  # @return [Manager] the command line options manager
24
28
  # @!attribute [rw] transfer
@@ -31,15 +35,17 @@ module Aspera
31
35
  # @return [Object] # whatever the type is
32
36
  # @!attribute [rw] man_header
33
37
  # @return [Boolean] whether to display the manual header in plugin help
34
- MEMBERS = %i[options transfer config formatter persistency man_header].freeze
35
38
  attr_accessor(*MEMBERS)
36
39
 
37
40
  # Initialize all members to nil, so that they are defined and can be validated later
41
+ # @return [nil]
38
42
  def initialize
39
43
  MEMBERS.each{ |i| instance_variable_set(:"@#{i}", nil)}
40
44
  end
41
45
 
42
46
  # Validate that all members are set, raise exception if not
47
+ # @raise [Aspera::AssertionError] if any member is not set
48
+ # @return [nil]
43
49
  def validate
44
50
  MEMBERS.each do |i|
45
51
  Aspera.assert(instance_variable_defined?(:"@#{i}"))
@@ -47,10 +53,14 @@ module Aspera
47
53
  end
48
54
  end
49
55
 
56
+ # Check if the context is in manual-only mode
57
+ # @return [Boolean] true if in manual-only mode
50
58
  def only_manual?
51
59
  transfer.eql?(:only_manual)
52
60
  end
53
61
 
62
+ # Set the context to manual-only mode
63
+ # @return [Symbol] :only_manual
54
64
  def only_manual!
55
65
  @transfer = :only_manual
56
66
  end
@@ -69,26 +79,37 @@ module Aspera
69
79
  private_constant :COMMAND_CONFIG, :COMMAND_HELP, :SCALAR_TYPES, :USER_INTERFACES
70
80
 
71
81
  class << self
72
- def result_special(how); {type: :special, data: how}; end
82
+ # Create a special result type (only used internally here)
83
+ # @param special_sym [Symbol] the special result type
84
+ # @return [Hash] result hash with type :special
85
+ def result_special(special_sym); {type: :special, data: special_sym}; end
73
86
 
74
87
  # Expect some list, but nothing to display
88
+ # @return [Hash] result hash for empty list
75
89
  def result_empty; result_special(:empty); end
76
90
 
77
91
  # Nothing expected
92
+ # @return [Hash] result hash for nothing
78
93
  def result_nothing; result_special(:nothing); end
79
94
 
80
95
  # Result is some status, such as "complete", "deleted"...
81
96
  # @param status [String] The status
97
+ # @return [Hash] result hash with type :status
82
98
  def result_status(status); return {type: :status, data: status}; end
83
99
 
84
100
  # Text result coming from command result
101
+ # @param data [String, Integer, Symbol] the text data to display
102
+ # @return [Hash] result hash with type :text
85
103
  def result_text(data); return {type: :text, data: data}; end
86
104
 
105
+ # Create a success result
106
+ # @return [Hash] result hash with status 'complete'
87
107
  def result_success; return result_status('complete'); end
88
108
 
89
109
  # Process statuses of finished transfer sessions
90
- # @raise exception if there is one error
91
- # else returns an empty status
110
+ # @param statuses [Array] array of transfer session statuses
111
+ # @raise [Symbol] exception if there is one error
112
+ # @return [Hash] empty status result if all transfers succeeded
92
113
  def result_transfer(statuses)
93
114
  worst = TransferAgent.session_status(statuses)
94
115
  raise worst unless worst.eql?(:success)
@@ -112,26 +133,33 @@ module Aspera
112
133
  end
113
134
 
114
135
  # Display image for that URL or directly blob
115
- #
116
136
  # @param url_or_blob [String] URL or blob to display as image
137
+ # @return [Hash] result hash with type :image
117
138
  def result_image(url_or_blob)
118
139
  return {type: :image, data: url_or_blob}
119
140
  end
120
141
 
121
142
  # A single object, must be Hash
143
+ # @param data [Hash] the object data
144
+ # @param fields [Array<String>, nil] optional list of fields to display
145
+ # @return [Hash] result hash with type :single_object
122
146
  def result_single_object(data, fields: nil)
123
147
  return {type: :single_object, data: data, fields: fields}
124
148
  end
125
149
 
126
150
  # An Array of Hash
151
+ # @param data [Array<Hash>] array of objects
152
+ # @param fields [Array<String>, nil] optional list of fields to display
153
+ # @param total [Integer, nil] optional total count
154
+ # @return [Hash] result hash with type :object_list
127
155
  def result_object_list(data, fields: nil, total: nil)
128
156
  return {type: :object_list, data: data, fields: fields, total: total}
129
157
  end
130
158
 
131
159
  # A list of values
132
- #
133
160
  # @param data [Array] The list of values
134
161
  # @param name [String] The name of the list (used for display)
162
+ # @return [Hash] result hash with type :value_list
135
163
  def result_value_list(data, name: 'id')
136
164
  Aspera.assert_type(data, Array)
137
165
  Aspera.assert_type(name, String)
@@ -139,6 +167,8 @@ module Aspera
139
167
  end
140
168
 
141
169
  # Determines type of result based on data
170
+ # @param data [Object] the data to analyze and format
171
+ # @return [Hash] result hash with appropriate type based on data
142
172
  def result_auto(data)
143
173
  case data
144
174
  when NilClass
@@ -159,6 +189,8 @@ module Aspera
159
189
  end
160
190
 
161
191
  # Minimum initialization, no exception raised
192
+ # @param argv [Array<String>] command line arguments
193
+ # @return [nil]
162
194
  def initialize(argv)
163
195
  @argv = argv
164
196
  Log.dump(:argv, @argv, level: :trace2)
@@ -169,6 +201,8 @@ module Aspera
169
201
  end
170
202
 
171
203
  # This is the main function called by initial script just after constructor
204
+ # Processes command line arguments, executes commands, and handles exceptions
205
+ # @return [nil]
172
206
  def process_command_line
173
207
  # Catch exception information , if any
174
208
  exception_info = nil
@@ -239,6 +273,7 @@ module Aspera
239
273
  rescue Cli::BadArgument => e; exception_info = {e: e, t: 'Argument', usage: true}
240
274
  rescue Cli::MissingArgument => e; exception_info = {e: e, t: 'Missing', usage: true}
241
275
  rescue Cli::BadIdentifier => e; exception_info = {e: e, t: 'Identifier'}
276
+ rescue Cli::SchemaRequest => e; exception_info = {e: e, t: 'Schema'}
242
277
  rescue Cli::Error => e; exception_info = {e: e, t: 'Tool', usage: true}
243
278
  rescue Transfer::Error => e; exception_info = {e: e, t: 'Transfer'}
244
279
  rescue RestCallError => e; exception_info = {e: e, t: 'Rest'}
@@ -251,11 +286,22 @@ module Aspera
251
286
  # 1- processing of error condition
252
287
  unless exception_info.nil?
253
288
  Log.log.warn(exception_info[:e].message) if Log.instance.logger_type.eql?(:syslog) && exception_info[:security]
254
- Log.log.error{"#{exception_info[:t]}: #{exception_info[:e].message}"}
289
+ Log.log.error{"#{exception_info[:t]}: #{exception_info[:e].message}"} unless exception_info[:e].is_a?(Cli::SchemaRequest)
255
290
  Log.log.debug{(['Backtrace:'] + exception_info[:e].backtrace).join("\n")} if exception_info[:debug]
256
291
  @context.formatter.display_message(:error, 'Use option -h to get help.') if exception_info[:usage]
257
292
  # Is that a known error condition with proposal for remediation ?
258
293
  Hints.hint_for(exception_info[:e], @context.formatter)
294
+ # Requested help for a Hash parameter/option ?
295
+ if exception_info[:e].is_a?(Cli::SchemaRequest)
296
+ Log.log.info{"#{exception_info[:t]}: #{exception_info[:e].message}"}
297
+ schema_path = exception_info[:e].path
298
+ if schema_path.nil?
299
+ Log.log.warn{'Sorry, no schema provided yet. Please refer to the manual or API.'}
300
+ else
301
+ builder = Schema::Documentation.new(TerminalFormatter, Schema::Registry.instance.reader(schema_path)).build
302
+ @context.formatter.display_results(**Main.result_object_list(builder.rows, fields: builder.columns))
303
+ end
304
+ end
259
305
  end
260
306
  # 2- processing of command not processed (due to exception or bad command line)
261
307
  if execute_command || @option_show_config
@@ -276,6 +322,10 @@ module Aspera
276
322
  return
277
323
  end
278
324
 
325
+ # Display usage information and help
326
+ # @param all [Boolean] if true, show help for all plugins; if false, show only current plugin
327
+ # @param exit [Boolean] if true, exit the process after displaying help
328
+ # @return [nil]
279
329
  def show_usage(all: true, exit: true)
280
330
  # Display main plugin options (+config)
281
331
  @context.formatter.display_message(:error, @context.options.parser)
@@ -298,7 +348,10 @@ module Aspera
298
348
 
299
349
  private
300
350
 
351
+ # Initialize agents and options
301
352
  # This can throw exception if there is a problem with the environment, needs to be caught by execute method
353
+ # @raise [StandardError] if there is a problem with the environment
354
+ # @return [nil]
302
355
  def init_agents_and_options
303
356
  @context.man_header = true
304
357
  # Create formatter, in case there is an exception, it is used to display.
@@ -328,6 +381,8 @@ module Aspera
328
381
  @context.options.parser.banner = app_banner
329
382
  end
330
383
 
384
+ # Generate the application banner for help display
385
+ # @return [String] formatted banner text
331
386
  def app_banner
332
387
  t = ' ' * 8
333
388
  return <<~END_OF_BANNER
@@ -362,7 +417,8 @@ module Aspera
362
417
  END_OF_BANNER
363
418
  end
364
419
 
365
- # Define header for manual
420
+ # Define header for manual and declare all global options
421
+ # @return [nil]
366
422
  def declare_global_options
367
423
  Log.log.debug('declare_global_options')
368
424
  @context.options.declare(:help, 'Show this message', allowed: Allowed::TYPES_NONE, short: 'h'){@option_help = true}
@@ -397,9 +453,10 @@ module Aspera
397
453
  @context.options.parse_options!
398
454
  end
399
455
 
400
- # @return the plugin instance, based on name
456
+ # Get the plugin instance based on name
401
457
  # Also loads the plugin options, and default values from conf file
402
- # @param plugin_name_sym : symbol for plugin name
458
+ # @param plugin_name_sym [Symbol] symbol for plugin name
459
+ # @return [Plugins::Base] the plugin instance
403
460
  def get_plugin_instance_with_options(plugin_name_sym)
404
461
  Log.log.debug{"get_plugin_instance_with_options(#{plugin_name_sym})"}
405
462
  # Load default params only if no param already loaded before plugin instantiation
@@ -408,6 +465,8 @@ module Aspera
408
465
  return command_plugin
409
466
  end
410
467
 
468
+ # Generate bash completion suggestions
469
+ # @return [nil]
411
470
  def generate_bash_completion
412
471
  if @context.options.get_next_argument('', multiple: true, mandatory: false).nil?
413
472
  Plugins::Factory.instance.plugin_list.each{ |p| puts p}