aspera-cli 4.26.1 → 4.26.2

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 (86) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +19 -1
  4. data/CONTRIBUTING.md +2 -5
  5. data/bin/ascli +2 -2
  6. data/lib/aspera/agent/direct.rb +1 -1
  7. data/lib/aspera/agent/factory.rb +4 -0
  8. data/lib/aspera/agent/httpgw.rb +1 -1
  9. data/lib/aspera/agent/node.rb +2 -2
  10. data/lib/aspera/api/aoc.rb +43 -36
  11. data/lib/aspera/api/cos_node.rb +1 -1
  12. data/lib/aspera/api/faspex.rb +7 -6
  13. data/lib/aspera/api/node.rb +7 -7
  14. data/lib/aspera/ascmd.rb +4 -4
  15. data/lib/aspera/ascp/installation.rb +6 -2
  16. data/lib/aspera/cli/context.rb +58 -0
  17. data/lib/aspera/cli/extended_value.rb +3 -2
  18. data/lib/aspera/cli/formatter.rb +83 -184
  19. data/lib/aspera/cli/http.rb +167 -0
  20. data/lib/aspera/cli/manager.rb +3 -2
  21. data/lib/aspera/cli/plugins/alee.rb +2 -2
  22. data/lib/aspera/cli/plugins/aoc.rb +78 -67
  23. data/lib/aspera/cli/plugins/ats.rb +16 -16
  24. data/lib/aspera/cli/plugins/base.rb +18 -12
  25. data/lib/aspera/cli/plugins/config.rb +166 -438
  26. data/lib/aspera/cli/plugins/console.rb +7 -7
  27. data/lib/aspera/cli/plugins/cos.rb +2 -2
  28. data/lib/aspera/cli/plugins/factory.rb +3 -0
  29. data/lib/aspera/cli/plugins/faspex.rb +21 -21
  30. data/lib/aspera/cli/plugins/faspex5.rb +64 -44
  31. data/lib/aspera/cli/plugins/faspio.rb +1 -1
  32. data/lib/aspera/cli/plugins/httpgw.rb +2 -2
  33. data/lib/aspera/cli/plugins/node.rb +79 -79
  34. data/lib/aspera/cli/plugins/orchestrator.rb +21 -26
  35. data/lib/aspera/cli/plugins/preview.rb +9 -9
  36. data/lib/aspera/cli/plugins/server.rb +7 -7
  37. data/lib/aspera/cli/plugins/shares.rb +2 -2
  38. data/lib/aspera/cli/preset_manager.rb +235 -0
  39. data/lib/aspera/cli/result.rb +310 -0
  40. data/lib/aspera/cli/{main.rb → runner.rb} +14 -155
  41. data/lib/aspera/cli/sync_actions.rb +14 -10
  42. data/lib/aspera/cli/terminal_formatter.rb +65 -0
  43. data/lib/aspera/cli/transfer_progress.rb +6 -6
  44. data/lib/aspera/cli/version.rb +1 -1
  45. data/lib/aspera/cli/wizard.rb +5 -6
  46. data/lib/aspera/command_line_builder.rb +1 -1
  47. data/lib/aspera/data_repository.rb +4 -0
  48. data/lib/aspera/dot_container.rb +1 -1
  49. data/lib/aspera/environment.rb +22 -3
  50. data/lib/aspera/faspex_gw.rb +1 -1
  51. data/lib/aspera/json_rpc.rb +6 -5
  52. data/lib/aspera/keychain/base.rb +1 -1
  53. data/lib/aspera/keychain/encrypted_hash.rb +1 -1
  54. data/lib/aspera/keychain/factory.rb +1 -1
  55. data/lib/aspera/keychain/macos_security.rb +1 -1
  56. data/lib/aspera/log.rb +6 -2
  57. data/lib/aspera/nagios.rb +2 -2
  58. data/lib/aspera/oauth/base.rb +5 -5
  59. data/lib/aspera/oauth/boot.rb +43 -0
  60. data/lib/aspera/oauth/factory.rb +37 -13
  61. data/lib/aspera/oauth/web.rb +2 -2
  62. data/lib/aspera/oauth.rb +1 -0
  63. data/lib/aspera/persistency_action_once.rb +2 -2
  64. data/lib/aspera/preview/file_types.rb +4 -0
  65. data/lib/aspera/products/connect.rb +3 -0
  66. data/lib/aspera/products/transferd.rb +2 -2
  67. data/lib/aspera/proxy_auto_config.rb +3 -3
  68. data/lib/aspera/rest.rb +8 -4
  69. data/lib/aspera/rest_error_analyzer.rb +4 -0
  70. data/lib/aspera/rest_list.rb +10 -3
  71. data/lib/aspera/schema/IBM Aspera Faspex API-5.0-enhanced.yaml +14 -4
  72. data/lib/aspera/schema/IBM Aspera on Cloud API-0.2.6-enhanced.yaml +827 -88
  73. data/lib/aspera/schema/async_tables.yaml +361 -0
  74. data/lib/aspera/schema/reader.rb +1 -1
  75. data/lib/aspera/schema/registry.rb +13 -6
  76. data/lib/aspera/secret_hider.rb +4 -0
  77. data/lib/aspera/sync/database.rb +14 -10
  78. data/lib/aspera/sync/operations.rb +5 -5
  79. data/lib/aspera/temp_file_manager.rb +4 -0
  80. data/lib/aspera/transfer/parameters.rb +4 -4
  81. data/lib/aspera/transfer/resumer.rb +1 -1
  82. data/lib/aspera/transfer/spec.schema.yaml +17 -8
  83. data/lib/aspera/transfer/uri.rb +1 -1
  84. data.tar.gz.sig +0 -0
  85. metadata +21 -14
  86. metadata.gz.sig +0 -0
@@ -42,7 +42,7 @@ module Aspera
42
42
  url = options&.delete(:url)
43
43
  if !url.nil?
44
44
  uri = URI.parse(url)
45
- Aspera.assert(uri.scheme.eql?('https')){'only https'}
45
+ Aspera.assert(uri.scheme.eql?('https'), 'only https')
46
46
  options[:protocol] = 'htps' # cspell: disable-line
47
47
  raise Error, 'host required in URL' if uri.host.nil?
48
48
  options[:server] = uri.host
data/lib/aspera/log.rb CHANGED
@@ -54,6 +54,10 @@ $VERBOSE = old_verbose
54
54
 
55
55
  module Aspera
56
56
  # Singleton object for logging
57
+ #
58
+ # @!method self.instance
59
+ # Returns the singleton instance of Log
60
+ # @return [Log] the singleton instance
57
61
  class Log
58
62
  include Singleton
59
63
 
@@ -80,7 +84,7 @@ module Aspera
80
84
  # @yieldreturn [Object] Computed object to dump (alternative to object parameter)
81
85
  def dump(name, object = nil, level: :debug, &block)
82
86
  return unless instance.logger.send(:"#{level}?")
83
- Aspera.assert(object.nil? || block.nil?){'Use either object, or block, not both'}
87
+ Aspera.assert(object.nil? || block.nil?, 'Use either object, or block, not both')
84
88
  object = yield if block_given?
85
89
  instance.logger.send(level, obj_dump(name, object))
86
90
  end
@@ -168,7 +172,7 @@ module Aspera
168
172
  # Get symbol of debug level of underlying logger
169
173
  # @return [Symbol] One of LEVELS
170
174
  def level
171
- Aspera.assert(Logger::SEVERITY_LABEL.key?(@logger.level))
175
+ Aspera.assert(Logger::SEVERITY_LABEL.key?(@logger.level), 'unexpected logger level value')
172
176
  Logger::SEVERITY_LABEL[@logger.level].downcase
173
177
  end
174
178
 
data/lib/aspera/nagios.rb CHANGED
@@ -24,7 +24,7 @@ module Aspera
24
24
  # Process results of a analysis and display status and exit with code
25
25
  def process(data)
26
26
  Aspera.assert_type(data, Array)
27
- Aspera.assert(!data.empty?){'data is empty'}
27
+ Aspera.assert(!data.empty?, 'data is empty')
28
28
  %w[status component message].each do |c|
29
29
  Aspera.assert(data.first.key?(c)){"result must have #{c}"}
30
30
  end
@@ -79,7 +79,7 @@ module Aspera
79
79
  # Readable status list
80
80
  # @return [Array] of Hash
81
81
  def status_list
82
- Aspera.assert(!@data.empty?){'missing result'}
82
+ Aspera.assert(!@data.empty?, 'missing result')
83
83
  @data.map{ |i| {'status' => LEVELS[i[:code]].to_s, 'component' => i[:comp], 'message' => i[:msg]}}
84
84
  end
85
85
  end
@@ -15,15 +15,15 @@ module Aspera
15
15
  class Base
16
16
  Aspera.require_method!(:create_token)
17
17
  # @param params [Hash] Parameters for token creation (client_id, client_secret, scope, etc...)
18
- # @param use_query [Boolean] Provide parameters in query instead of body
19
18
  # @param path_token [String] API end point to create a token from base URL
19
+ # @param use_query [Boolean] Provide parameters in query instead of body
20
20
  # @param token_field [String] Field in result that contains the token
21
21
  # @param cache_ids [Array] List of unique identifiers for cache id generation
22
22
  # @param **rest_params [Hash] Parameters for REST
23
23
  def initialize(
24
24
  params: {},
25
+ path_token: 'token',
25
26
  use_query: false,
26
- path_token: 'token',
27
27
  token_field: Factory::TOKEN_FIELD,
28
28
  cache_ids: [],
29
29
  **rest_params
@@ -42,10 +42,10 @@ module Aspera
42
42
 
43
43
  # The OAuth API Object
44
44
  attr_reader :api
45
- # Sub path to generate token
46
- attr_reader :path_token
47
45
  # Parameters to generate token
48
46
  attr_reader :params
47
+ # Sub path to generate token
48
+ attr_reader :path_token
49
49
 
50
50
  # Helper method to create token as per RFC
51
51
  # @return [HTTPResponse]
@@ -122,7 +122,7 @@ module Aspera
122
122
  token_data = JSON.parse(json_data)
123
123
  Factory.instance.persist_mgr.put(@token_cache_id, json_data)
124
124
  end
125
- Aspera.assert(token_data.key?(@token_field)){"API error: No such field in answer: #{@token_field}"}
125
+ Aspera.assert(token_data.key?(@token_field)){"API error: No such field in answer: #{@token_field}"} unless token_data.nil?
126
126
  # ok we shall have a token here
127
127
  return token_data[@token_field]
128
128
  end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'aspera/oauth/base'
4
+ require 'aspera/assert'
5
+ require 'json'
6
+
7
+ module Aspera
8
+ module OAuth
9
+ # Token provider bootstrapped from an existing cookie (e.g. AoC browser cookie).
10
+ # Injects the bearer token and optional refresh token directly into the cache.
11
+ # Never generates a new token from scratch — raises if cache+refresh are both exhausted.
12
+ class Boot < Base
13
+ # @param cookie [String, nil] Raw cookie string (--password), nil to rely on existing cache
14
+ # @param username [String, nil] Expected subject; if provided, must match token's `sub` claim
15
+ # @param **base_params Forwarded to Base (base_url:, params: {client_id:, scope:}, etc.)
16
+ def initialize(cookie: nil, username: nil, **base_params)
17
+ if cookie.nil?
18
+ # No cookie: rely on existing cache, identified by username if provided
19
+ Aspera.assert(username, 'Provide --password (cookie) on first use, or --username for cache lookup', type: ParameterError)
20
+ super(**base_params, cache_ids: [username])
21
+ else
22
+ cookies = cookie.split('; ').map{ |p| p.split('=', 2)}.to_h
23
+ Aspera.assert(cookies.key?('aoc.token'), '--password cookie does not contain aoc.token', type: ParameterError)
24
+ token = cookies['aoc.token']
25
+ decoded = Factory.instance.decode_token(token)
26
+ Aspera.assert_type(decoded, Hash){'Boot: token is not a decodable JWT'}
27
+ sub = decoded['sub']
28
+ Aspera.assert(username.nil? || username.eql?(sub)){"Boot: --username #{username} does not match token subject #{sub}"}
29
+ super(**base_params, cache_ids: [sub])
30
+ token_data = {Factory::TOKEN_FIELD => token}
31
+ token_data['refresh_token'] = cookies['aoc.refresh'] if cookies.key?('aoc.refresh')
32
+ Factory.instance.persist_mgr.put(@token_cache_id, JSON.generate(token_data))
33
+ end
34
+ end
35
+
36
+ # Should never be reached: if cache and refresh are both exhausted, re-authenticate via browser
37
+ def create_token
38
+ Aspera.report_error(AssertError, 'Boot: token expired and no refresh available — re-authenticate in browser')
39
+ end
40
+ end
41
+ Factory.instance.register_token_creator(Boot)
42
+ end
43
+ end
@@ -7,10 +7,14 @@ require 'base64'
7
7
  module Aspera
8
8
  module OAuth
9
9
  # Factory to create tokens and manage their cache
10
+ #
11
+ # @!method self.instance
12
+ # Returns the singleton instance of Factory
13
+ # @return [Factory] the singleton instance
10
14
  class Factory
11
15
  include Singleton
12
16
 
13
- # a prefix for persistency of tokens (simplify garbage collect)
17
+ # prefix for persistency of tokens (simplify garbage collect)
14
18
  PERSIST_CATEGORY_TOKEN = 'token'
15
19
  # prefix for bearer authorization when in header
16
20
  SPACE_BEARER_AUTH_SCHEME = 'Bearer '
@@ -19,18 +23,23 @@ module Aspera
19
23
  private_constant :PERSIST_CATEGORY_TOKEN, :SPACE_BEARER_AUTH_SCHEME
20
24
 
21
25
  class << self
26
+ # Format a token for use in Authorization header
22
27
  # @param token [String] The token alone
23
28
  # @return [String] Value suitable for Authorization header
24
29
  def bearer_authorization(token)
25
30
  return "#{SPACE_BEARER_AUTH_SCHEME}#{token}"
26
31
  end
27
32
 
28
- # @return true if the authorization contains a bearer token , i.e. auth scheme is bearer
33
+ # Check if the authorization contains a bearer token
34
+ # @param authorization [String] The authorization header value
35
+ # @return [Boolean] true if the authorization contains a bearer token, i.e. auth scheme is bearer
29
36
  def bearer_auth?(authorization)
30
37
  return authorization.start_with?(SPACE_BEARER_AUTH_SCHEME)
31
38
  end
32
39
 
33
40
  # Extract only token from Authorization (remove scheme)
41
+ # @param authorization [String] The authorization header value
42
+ # @return [String] The bearer token without the scheme prefix
34
43
  def bearer_token(authorization)
35
44
  Aspera.assert(bearer_auth?(authorization)){'not a bearer token, wrong prefix scheme'}
36
45
  return authorization.delete_prefix(SPACE_BEARER_AUTH_SCHEME)
@@ -40,12 +49,14 @@ module Aspera
40
49
  # @param url [String] Base URL of the OAuth server
41
50
  # @param creator_class [Class] Class of the token creator
42
51
  # @param params [Array] List of parameters (can be nested) to uniquely identify the token
43
- # @return a unique cache identifier
52
+ # @return [String] a unique cache identifier
44
53
  def cache_id(url, creator_class, *params)
45
54
  return IdGenerator.from_list(PERSIST_CATEGORY_TOKEN, url, Factory.class_to_id(creator_class), params)
46
55
  end
47
56
 
48
- # @return snake version of class name
57
+ # Convert a class name to snake_case symbol
58
+ # @param creator_class [Class] The class to convert
59
+ # @return [Symbol] snake_case version of class name
49
60
  def class_to_id(creator_class)
50
61
  return creator_class.name.split('::').last.capital_to_snake.to_sym
51
62
  end
@@ -53,6 +64,7 @@ module Aspera
53
64
 
54
65
  private
55
66
 
67
+ # Initialize the factory with default parameters and empty collections
56
68
  def initialize
57
69
  # persistency manager
58
70
  @persist = nil
@@ -73,12 +85,16 @@ module Aspera
73
85
 
74
86
  attr_reader :parameters
75
87
 
88
+ # Set the persistence manager for token caching
89
+ # @param manager [Object] The persistence manager instance
76
90
  def persist_mgr=(manager)
77
91
  @persist = manager
78
92
  # cleanup expired tokens
79
93
  @persist.garbage_collect(PERSIST_CATEGORY_TOKEN, @parameters[:token_cache_max_age])
80
94
  end
81
95
 
96
+ # Get or initialize the persistence manager
97
+ # @return [Object] The persistence manager instance
82
98
  def persist_mgr
83
99
  if @persist.nil?
84
100
  # use OAuth::Factory.instance.persist_mgr=PersistencyFolder.new)
@@ -91,11 +107,14 @@ module Aspera
91
107
  return @persist
92
108
  end
93
109
 
94
- # delete all existing tokens
110
+ # Delete all existing tokens in cache
111
+ # @return [void]
95
112
  def flush_tokens
96
113
  persist_mgr.garbage_collect(PERSIST_CATEGORY_TOKEN)
97
114
  end
98
115
 
116
+ # Retrieve all persisted tokens with their decoded information
117
+ # @return [Array<Hash>] Array of token information hashes
99
118
  def persisted_tokens
100
119
  data = persist_mgr.current_items(PERSIST_CATEGORY_TOKEN)
101
120
  data.each.map do |k, v|
@@ -134,12 +153,16 @@ module Aspera
134
153
  return info
135
154
  end
136
155
 
137
- # register a bearer token decoder, mainly to inspect expiry date
156
+ # Register a bearer token decoder for inspecting token properties
157
+ # @param method [Proc] The decoder lambda/proc to register
158
+ # @return [void]
138
159
  def register_decoder(method)
139
160
  @decoders.push(method)
140
161
  end
141
162
 
142
- # decode token using all registered decoders
163
+ # Decode a token using all registered decoders
164
+ # @param token [String] The token to decode
165
+ # @return [Hash, nil] Decoded token data or nil if no decoder succeeded
143
166
  def decode_token(token)
144
167
  @decoders.each do |decoder|
145
168
  result = decoder.call(token) rescue nil
@@ -148,10 +171,9 @@ module Aspera
148
171
  return
149
172
  end
150
173
 
151
- # register a token creation method
152
- # @param id creation type from field :grant_method in constructor
153
- # @param lambda_create called to create token
154
- # @param id_create called to generate unique id for token, for cache
174
+ # Register a token creation method
175
+ # @param creator_class [Class] The token creator class to register
176
+ # @return [void]
155
177
  def register_token_creator(creator_class)
156
178
  Aspera.assert_type(creator_class, Class)
157
179
  id = Factory.class_to_id(creator_class)
@@ -159,7 +181,9 @@ module Aspera
159
181
  @token_type_classes[id] = creator_class
160
182
  end
161
183
 
162
- # @return one of the registered creators for the given create type
184
+ # Create a token creator instance for the specified grant method
185
+ # @param parameters [Hash] Parameters including :grant_method and creator-specific options
186
+ # @return [Object] An instance of the registered token creator class
163
187
  def create(**parameters)
164
188
  Aspera.assert_type(parameters, Hash)
165
189
  id = parameters[:grant_method]
@@ -169,6 +193,6 @@ module Aspera
169
193
  end
170
194
  end
171
195
  # JSON Web Signature (JWS) compact serialization: https://datatracker.ietf.org/doc/html/rfc7515
172
- Factory.instance.register_decoder(lambda{ |token| parts = token.split('.'); Aspera.assert(parts.length.eql?(3)){'not JWS token'}; JSON.parse(Base64.decode64(parts[1]))}) # rubocop:disable Style/Semicolon
196
+ Factory.instance.register_decoder(lambda{ |token| parts = token.split('.'); Aspera.assert_values(parts.length, [3]){'JWS token parts'}; JSON.parse(Base64.decode64(parts[1]))}) # rubocop:disable Style/Semicolon
173
197
  end
174
198
  end
@@ -22,8 +22,8 @@ module Aspera
22
22
  @redirect_uri = redirect_uri
23
23
  @path_authorize = path_authorize
24
24
  uri = URI.parse(@redirect_uri)
25
- Aspera.assert(%w[http https].include?(uri.scheme)){'redirect_uri scheme must be http or https'}
26
- Aspera.assert(!uri.port.nil?){'redirect_uri must have a port'}
25
+ Aspera.assert_values(uri.scheme, %w[http https]){'redirect_uri scheme must be http or https'}
26
+ Aspera.assert(!uri.port.nil?, 'redirect_uri must have a port')
27
27
  # TODO: we could check that host is localhost or local address, as we are going to listen locally
28
28
  end
29
29
 
data/lib/aspera/oauth.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'aspera/oauth/factory'
4
+ require 'aspera/oauth/boot'
4
5
  require 'aspera/oauth/generic'
5
6
  require 'aspera/oauth/jwt'
6
7
  require 'aspera/oauth/web'
@@ -23,9 +23,9 @@ module Aspera
23
23
  # @param :merge Optional merge data from file to current data
24
24
  def initialize(manager:, data:, id:, delete: DELETE_DEFAULT, parse: PARSE_DEFAULT, format: FORMAT_DEFAULT, merge: MERGE_DEFAULT)
25
25
  Aspera.assert(MANAGER_METHODS.all?{ |i| manager.respond_to?(i)}){"Manager must answer to #{MANAGER_METHODS}"}
26
- Aspera.assert(!data.nil?)
26
+ Aspera.assert(!data.nil?, 'data must not be nil')
27
27
  Aspera.assert_type(id, String)
28
- Aspera.assert(!id.empty?)
28
+ Aspera.assert(!id.empty?, 'id must not be empty')
29
29
  Aspera.assert_type(delete, Proc)
30
30
  Aspera.assert_type(parse, Proc)
31
31
  Aspera.assert_type(format, Proc)
@@ -8,6 +8,10 @@ require 'marcel'
8
8
  module Aspera
9
9
  module Preview
10
10
  # function conversion_type returns one of the types: CONVERSION_TYPES
11
+ #
12
+ # @!method self.instance
13
+ # Returns the singleton instance of FileTypes
14
+ # @return [FileTypes] the singleton instance
11
15
  class FileTypes
12
16
  include Singleton
13
17
 
@@ -5,6 +5,9 @@ require 'singleton'
5
5
 
6
6
  module Aspera
7
7
  module Products
8
+ # @!method self.instance
9
+ # Returns the singleton instance of Connect
10
+ # @return [Connect] the singleton instance
8
11
  class Connect
9
12
  include Singleton
10
13
 
@@ -29,7 +29,7 @@ module Aspera
29
29
 
30
30
  # @return the path to folder where SDK is or should be installed
31
31
  def sdk_directory
32
- Aspera.assert(!@sdk_dir.nil?){'SDK path was not initialized'}
32
+ Aspera.assert(!@sdk_dir.nil?, 'SDK path was not initialized')
33
33
  @sdk_dir
34
34
  end
35
35
 
@@ -52,7 +52,7 @@ module Aspera
52
52
  end
53
53
  end
54
54
  end
55
- Aspera.assert(!result.nil?){'Port not found in daemon logs'}
55
+ Aspera.assert(!result.nil?, 'Port not found in daemon logs')
56
56
  Log.log.debug{"Got port #{result} from log"}
57
57
  return result
58
58
  end
@@ -14,7 +14,7 @@ module URI
14
14
  # @yieldparam url [String] The URL to find proxy for
15
15
  # @yieldreturn [String, nil] Proxy URL or nil to fallback to original method
16
16
  def register_proxy_finder
17
- Aspera.assert(block_given?)
17
+ Aspera.assert(block_given?, 'block required for register_proxy_finder')
18
18
  # overload the method in URI : call user's provided block and fallback to original method
19
19
  define_method(:find_proxy){ |env_vars = ENV| yield(to_s) || find_proxy_orig(env_vars)}
20
20
  end
@@ -116,12 +116,12 @@ END_OF_JAVASCRIPT
116
116
  parts = item.strip.split
117
117
  case parts.shift
118
118
  when 'DIRECT'
119
- Aspera.assert(parts.empty?){'DIRECT has no param'}
119
+ Aspera.assert(parts.empty?, 'DIRECT has no param')
120
120
  Log.log.debug('ignoring proxy DIRECT')
121
121
  when 'PROXY'
122
122
  addr_port = parts.shift
123
123
  Aspera.assert_type(addr_port, String)
124
- Aspera.assert(parts.empty?){'PROXY shall have one param'}
124
+ Aspera.assert(parts.empty?, 'PROXY shall have one param')
125
125
  begin
126
126
  # PAC proxy addresses are <host>:<port>
127
127
  if /:[0-9]+$/.match?(addr_port)
data/lib/aspera/rest.rb CHANGED
@@ -30,6 +30,10 @@ module Aspera
30
30
  # @param download_partial_suffix [String] suffix for partial download
31
31
  # @param session_cb [lambda] lambda called on new HTTP session. Takes the Net::HTTP as arg. Used to change parameters on creation.
32
32
  # @param progress_bar [Object] progress bar object called for file transfer
33
+ #
34
+ # @!method self.instance
35
+ # Returns the singleton instance of RestParameters
36
+ # @return [RestParameters] the singleton instance
33
37
  class RestParameters
34
38
  include Singleton
35
39
 
@@ -102,7 +106,7 @@ module Aspera
102
106
  when Hash
103
107
  URI.encode_www_form(h_to_query_array(query))
104
108
  when Array
105
- Aspera.assert(query.all?{ |i| i.is_a?(Array) && i.length.eql?(2)}){'Query must be array of arrays of 2 elements'}
109
+ Aspera.assert(query.all?{ |i| i.is_a?(Array) && i.length.eql?(2)}, 'Query must be array of arrays of 2 elements')
106
110
  URI.encode_www_form(query) # remove nil values
107
111
  else Aspera.error_unexpected_value(query.class){'query type'}
108
112
  end.gsub('%5B%5D=', '[]=')
@@ -316,7 +320,7 @@ module Aspera
316
320
  # default is no auth
317
321
  @auth_params = auth
318
322
  Aspera.assert_type(@auth_params, Hash)
319
- Aspera.assert(@auth_params.key?(:type)){'no auth type defined'}
323
+ Aspera.assert(@auth_params.key?(:type), 'no auth type defined')
320
324
  @not_auth_codes = not_auth_codes
321
325
  Aspera.assert_type(@not_auth_codes, Array)
322
326
  # persistent session
@@ -333,7 +337,7 @@ module Aspera
333
337
  # @return the OAuth object (create, or cached if already created)
334
338
  def oauth
335
339
  if @oauth.nil?
336
- Aspera.assert(@auth_params[:type].eql?(:oauth2)){'no OAuth defined'}
340
+ Aspera.assert(@auth_params[:type].eql?(:oauth2), 'no OAuth defined')
337
341
  oauth_parameters = @auth_params.reject{ |k, _v| k.eql?(:type)}
338
342
  Log.dump(:oauth_parameters, oauth_parameters)
339
343
  @oauth = OAuth::Factory.instance.create(**oauth_parameters)
@@ -374,7 +378,7 @@ module Aspera
374
378
  Log.dump(:headers, headers, level: :trace1)
375
379
  Aspera.assert_type(subpath, String)
376
380
  # We must have a way to check return code
377
- Aspera.assert(exception || !ret.eql?(:data))
381
+ Aspera.assert(exception || !ret.eql?(:data), 'ret: :data requires exception handler')
378
382
  if headers.nil?
379
383
  headers = @headers.clone
380
384
  else
@@ -7,6 +7,10 @@ require 'net/http'
7
7
 
8
8
  module Aspera
9
9
  # analyze error codes returned by REST calls and raise ruby exception
10
+ #
11
+ # @!method self.instance
12
+ # Returns the singleton instance of RestErrorAnalyzer
13
+ # @return [RestErrorAnalyzer] the singleton instance
10
14
  class RestErrorAnalyzer
11
15
  include Singleton
12
16
 
@@ -50,6 +50,7 @@ module Aspera
50
50
  # @return [Array<(Array<Hash>, Integer)>] items, total_count
51
51
  def list_entities_limit_offset_total_count(
52
52
  entity:,
53
+ operation: 'GET',
53
54
  items_key: nil,
54
55
  query: nil
55
56
  )
@@ -67,9 +68,15 @@ module Aspera
67
68
  # Merge default parameters, by default 100 per page
68
69
  query = {'limit'=> PER_PAGE_DEFAULT}.merge(query)
69
70
  total_count = nil
71
+ call_args = {
72
+ operation: operation,
73
+ subpath: entity,
74
+ query: query,
75
+ headers: {'Accept' => Mime::JSON}
76
+ }
70
77
  loop do
71
78
  query['offset'] = offset
72
- page_result = read(entity, query)
79
+ page_result = call(**call_args)
73
80
  Aspera.assert_type(page_result[items_key], Array)
74
81
  result.concat(page_result[items_key])
75
82
  # Reach the limit set by user ?
@@ -97,7 +104,7 @@ module Aspera
97
104
  # @param query [Hash] Additional query parameters (Default: `:default`)
98
105
  def lookup_entity_by_field(entity:, value:, field: 'name', items_key: nil, query: :default)
99
106
  if query.eql?(:default)
100
- Aspera.assert(field.eql?('name')){'Default query is on name only'}
107
+ Aspera.assert_values(field, ['name']){'Default query field'}
101
108
  query = {'q'=> value}
102
109
  end
103
110
  lookup_entity_generic(entity: entity, field: field, value: value){list_entities_limit_offset_total_count(entity: entity, items_key: items_key, query: query).first}
@@ -113,7 +120,7 @@ module Aspera
113
120
  # @return [Hash] The unique matching object.
114
121
  # @raise [Cli::BadIdentifier] If 0 or >1 matches are found.
115
122
  def lookup_entity_generic(entity:, value:, field: 'name')
116
- Aspera.assert(block_given?)
123
+ Aspera.assert(block_given?, 'block required for lookup_entity_generic')
117
124
  found = yield
118
125
  Aspera.assert_array_all(found, Hash)
119
126
  found = found.select{ |i| i[field].eql?(value)}
@@ -1,3 +1,8 @@
1
+ # DO NOT EDIT THIS FILE MANUALLY
2
+ # This file is automatically downloaded from:
3
+ # https://raw.githubusercontent.com/laurent-martin/aspera-api-examples/refs/heads/main/openapi/IBM%20Aspera%20Faspex%20API-5.0-enhanced.yaml
4
+ # Use 'rake tools:openapi' to update this file
5
+
1
6
  openapi: 3.1.0
2
7
  info:
3
8
  title: IBM Aspera Faspex API
@@ -32646,7 +32651,12 @@ components:
32646
32651
  maxLength: 255
32647
32652
  minLength: 1
32648
32653
  expiration_policy:
32649
- description: The expiration policy for the package. Default is "none" for no expiration policy (a package will not be marked for deletion based on recipient downloads), "delete_after_all_download" for deleting a package after ALL users do a full download of the package (download of all files/folders in the package), "delete_after_any_download" for deleting a package after ANY user fully downloads and "delete_after_expiration_date" for deleting a package after the date set in expiration_date parameter.
32654
+ description: |-
32655
+ The expiration policy for the package.
32656
+ * `none`: Default, for no expiration policy (a package will not be marked for deletion based on recipient downloads).
32657
+ * `delete_after_all_download` for deleting a package after ALL users do a full download of the package (download of all files/folders in the package).
32658
+ * `delete_after_any_download` for deleting a package after ANY user fully downloads.
32659
+ * `delete_after_expiration_date` for deleting a package after the date set in expiration_date parameter.
32650
32660
  type: string
32651
32661
  default: none
32652
32662
  enum:
@@ -40721,9 +40731,9 @@ components:
40721
40731
  type: boolean
40722
40732
  can_have_public_url:
40723
40733
  description: |-
40724
- Specifies whether the user can share public submission submission links.\
40725
- A user can share public submission links to invite external users to \
40726
- send packages to the user.
40734
+ Specifies whether the user can share public submission submission links.
40735
+ A user can share public submission links to invite external users to
40736
+ send packages to the user.
40727
40737
  type: string
40728
40738
  default: default
40729
40739
  enum: