aspera-cli 4.18.1 → 4.20.0

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 +0 -0
  3. data/CHANGELOG.md +33 -0
  4. data/CONTRIBUTING.md +17 -12
  5. data/README.md +396 -185
  6. data/bin/asession +26 -19
  7. data/examples/build_exec +74 -0
  8. data/examples/{rubyc → build_exec_rubyc} +18 -2
  9. data/examples/get_proto_file.rb +7 -0
  10. data/lib/aspera/agent/alpha.rb +8 -8
  11. data/lib/aspera/agent/base.rb +4 -18
  12. data/lib/aspera/agent/connect.rb +14 -13
  13. data/lib/aspera/agent/direct.rb +123 -120
  14. data/lib/aspera/agent/httpgw.rb +2 -3
  15. data/lib/aspera/agent/node.rb +10 -10
  16. data/lib/aspera/agent/trsdk.rb +17 -20
  17. data/lib/aspera/api/alee.rb +15 -0
  18. data/lib/aspera/api/aoc.rb +128 -99
  19. data/lib/aspera/api/ats.rb +1 -1
  20. data/lib/aspera/api/cos_node.rb +1 -1
  21. data/lib/aspera/api/httpgw.rb +104 -64
  22. data/lib/aspera/api/node.rb +33 -12
  23. data/lib/aspera/ascmd.rb +56 -48
  24. data/lib/aspera/ascp/installation.rb +142 -70
  25. data/lib/aspera/ascp/management.rb +7 -3
  26. data/lib/aspera/ascp/products.rb +13 -7
  27. data/lib/aspera/assert.rb +10 -5
  28. data/lib/aspera/cli/formatter.rb +42 -26
  29. data/lib/aspera/cli/hints.rb +2 -1
  30. data/lib/aspera/cli/info.rb +12 -10
  31. data/lib/aspera/cli/main.rb +16 -13
  32. data/lib/aspera/cli/manager.rb +15 -10
  33. data/lib/aspera/cli/plugin.rb +17 -31
  34. data/lib/aspera/cli/plugin_factory.rb +10 -1
  35. data/lib/aspera/cli/plugins/alee.rb +3 -3
  36. data/lib/aspera/cli/plugins/aoc.rb +222 -194
  37. data/lib/aspera/cli/plugins/ats.rb +16 -14
  38. data/lib/aspera/cli/plugins/config.rb +66 -53
  39. data/lib/aspera/cli/plugins/console.rb +3 -3
  40. data/lib/aspera/cli/plugins/faspex.rb +11 -21
  41. data/lib/aspera/cli/plugins/faspex5.rb +44 -42
  42. data/lib/aspera/cli/plugins/faspio.rb +2 -2
  43. data/lib/aspera/cli/plugins/httpgw.rb +1 -1
  44. data/lib/aspera/cli/plugins/node.rb +155 -96
  45. data/lib/aspera/cli/plugins/orchestrator.rb +14 -13
  46. data/lib/aspera/cli/plugins/preview.rb +8 -9
  47. data/lib/aspera/cli/plugins/server.rb +6 -10
  48. data/lib/aspera/cli/plugins/shares.rb +13 -9
  49. data/lib/aspera/cli/sync_actions.rb +72 -31
  50. data/lib/aspera/cli/transfer_agent.rb +13 -14
  51. data/lib/aspera/cli/transfer_progress.rb +36 -18
  52. data/lib/aspera/cli/version.rb +1 -1
  53. data/lib/aspera/command_line_builder.rb +3 -4
  54. data/lib/aspera/coverage.rb +13 -1
  55. data/lib/aspera/environment.rb +59 -10
  56. data/lib/aspera/faspex_gw.rb +3 -3
  57. data/lib/aspera/json_rpc.rb +1 -1
  58. data/lib/aspera/keychain/encrypted_hash.rb +2 -0
  59. data/lib/aspera/keychain/macos_security.rb +7 -12
  60. data/lib/aspera/log.rb +4 -4
  61. data/lib/aspera/node_simulator.rb +1 -1
  62. data/lib/aspera/oauth/base.rb +39 -45
  63. data/lib/aspera/oauth/factory.rb +11 -4
  64. data/lib/aspera/oauth/generic.rb +4 -8
  65. data/lib/aspera/oauth/jwt.rb +4 -4
  66. data/lib/aspera/oauth/url_json.rb +3 -2
  67. data/lib/aspera/oauth/web.rb +10 -6
  68. data/lib/aspera/persistency_action_once.rb +16 -8
  69. data/lib/aspera/preview/utils.rb +5 -16
  70. data/lib/aspera/rest.rb +100 -76
  71. data/lib/aspera/secret_hider.rb +3 -2
  72. data/lib/aspera/ssh.rb +1 -1
  73. data/lib/aspera/transfer/faux_file.rb +7 -5
  74. data/lib/aspera/transfer/parameters.rb +41 -35
  75. data/lib/aspera/transfer/spec.rb +16 -18
  76. data/lib/aspera/transfer/sync.rb +51 -50
  77. data/lib/aspera/transfer/uri.rb +1 -1
  78. data/lib/aspera/uri_reader.rb +1 -1
  79. data/lib/aspera/web_auth.rb +166 -18
  80. data/lib/aspera/web_server_simple.rb +27 -15
  81. data/lib/transfer_pb.rb +84 -0
  82. data/lib/transfer_services_pb.rb +82 -0
  83. data.tar.gz.sig +0 -0
  84. metadata +25 -6
  85. metadata.gz.sig +0 -0
@@ -5,6 +5,7 @@
5
5
  require 'aspera/cli/plugins/node'
6
6
  require 'aspera/api/ats'
7
7
  require 'aspera/api/aoc'
8
+ require 'aspera/api/alee'
8
9
  require 'aspera/assert'
9
10
 
10
11
  module Aspera
@@ -24,13 +25,14 @@ module Aspera
24
25
  options.declare(:cloud, 'Cloud provider')
25
26
  options.declare(:region, 'Cloud region')
26
27
  options.parse_options!
28
+ Node.declare_options(options)
27
29
  end
28
30
 
29
31
  def server_by_cloud_region
30
32
  # TODO: provide list ?
31
33
  cloud = options.get_option(:cloud, mandatory: true).upcase
32
34
  region = options.get_option(:region, mandatory: true)
33
- return @ats_api_pub.read("servers/#{cloud}/#{region}")[:data]
35
+ return @ats_api_pub.read("servers/#{cloud}/#{region}")
34
36
  end
35
37
 
36
38
  # require api key only if needed
@@ -84,29 +86,29 @@ module Aspera
84
86
  end
85
87
  end
86
88
  res = ats_api_pub_v1.create('access_keys', params)
87
- return {type: :single_object, data: res[:data]}
89
+ return {type: :single_object, data: res}
88
90
  # TODO : action : modify, with "PUT"
89
91
  when :list
90
92
  params = options.get_option(:params) || {'offset' => 0, 'max_results' => 1000}
91
93
  res = ats_api_pub_v1.read('access_keys', params)
92
- return {type: :object_list, data: res[:data]['data'], fields: ['name', 'id', 'created.at', 'modified.at']}
94
+ return {type: :object_list, data: res['data'], fields: ['name', 'id', 'created.at', 'modified.at']}
93
95
  when :show
94
96
  res = ats_api_pub_v1.read("access_keys/#{access_key_id}")
95
- return {type: :single_object, data: res[:data]}
97
+ return {type: :single_object, data: res}
96
98
  when :modify
97
99
  params = value_create_modify(command: command)
98
100
  params['id'] = access_key_id
99
101
  ats_api_pub_v1.update("access_keys/#{access_key_id}", params)
100
102
  return Main.result_status('modified')
101
103
  when :entitlement
102
- ak = ats_api_pub_v1.read("access_keys/#{access_key_id}")[:data]
104
+ ak = ats_api_pub_v1.read("access_keys/#{access_key_id}")
103
105
  api_bss = Api::Alee.new(ak['license']['entitlement_id'], ak['license']['customer_id'])
104
- return {type: :single_object, data: api_bss.read('entitlement')[:data]}
106
+ return {type: :single_object, data: api_bss.read('entitlement')}
105
107
  when :delete
106
108
  ats_api_pub_v1.delete("access_keys/#{access_key_id}")
107
109
  return Main.result_status("deleted #{access_key_id}")
108
110
  when :node
109
- ak_data = ats_api_pub_v1.read("access_keys/#{access_key_id}")[:data]
111
+ ak_data = ats_api_pub_v1.read("access_keys/#{access_key_id}")
110
112
  server_data = @ats_api_pub.all_servers.find {|i| i['id'].start_with?(ak_data['transfer_server_id'])}
111
113
  raise Cli::Error, 'no such server found' if server_data.nil?
112
114
  node_url = server_data['transfer_setup_url']
@@ -128,7 +130,7 @@ module Aspera
128
130
  username: access_key_id,
129
131
  password: config.lookup_secret(url: ats_url, username: access_key_id)
130
132
  })
131
- return {type: :single_object, data: api_ak_auth.read('servers')[:data]}
133
+ return {type: :single_object, data: api_ak_auth.read('servers')}
132
134
  else Aspera.error_unexpected_value(command)
133
135
  end
134
136
  end
@@ -177,7 +179,7 @@ module Aspera
177
179
  instance = options.get_option(:instance)
178
180
  if instance.nil?
179
181
  # Take the first Aspera on Cloud transfer service instance ID if not provided by user
180
- instance = ats_api_v2_auth_ibm.read('instances')[:data]['data'].first
182
+ instance = ats_api_v2_auth_ibm.read('instances')['data'].first
181
183
  formatter.display_status("using first instance: #{instance}")
182
184
  end
183
185
  rest_add_header = {'X-ATS-Service-Instance-Id' => instance}
@@ -185,18 +187,18 @@ module Aspera
185
187
  ats_ibm_api = ats_api_v2_auth_ibm(rest_add_header)
186
188
  case command
187
189
  when :instances
188
- instances = ats_ibm_api.read('instances')[:data]
190
+ instances = ats_ibm_api.read('instances')
189
191
  Log.log.warn{"more instances remaining: #{instances['remaining']}"} unless instances['remaining'].to_i.eql?(0)
190
192
  return {type: :value_list, data: instances['data'], name: 'instance'}
191
193
  when :create
192
- created_key = ats_ibm_api.create('api_keys', value_create_modify(command: command, default: {}))[:data]
194
+ created_key = ats_ibm_api.create('api_keys', value_create_modify(command: command, default: {}))
193
195
  return {type: :single_object, data: created_key}
194
196
  when :list # list known api keys in ATS (this require an api_key ...)
195
197
  res = ats_ibm_api.read('api_keys', {'offset' => 0, 'max_results' => 1000})
196
- return {type: :value_list, data: res[:data]['data'], name: 'ats_id'}
198
+ return {type: :value_list, data: res['data'], name: 'ats_id'}
197
199
  when :show # show one of api_key in ATS
198
200
  res = ats_ibm_api.read("api_keys/#{concerned_id}")
199
- return {type: :single_object, data: res[:data]}
201
+ return {type: :single_object, data: res}
200
202
  when :delete
201
203
  ats_ibm_api.delete("api_keys/#{concerned_id}")
202
204
  return Main.result_status("deleted #{concerned_id}")
@@ -222,7 +224,7 @@ module Aspera
222
224
  when :api_key # manage credential to access ATS API
223
225
  return execute_action_api_key
224
226
  when :aws_trust_policy
225
- res = ats_api_pub_v1.read('aws/trustpolicy', {region: options.get_option(:region, mandatory: true)})[:data]
227
+ res = ats_api_pub_v1.read('aws/trustpolicy', {region: options.get_option(:region, mandatory: true)})
226
228
  return {type: :single_object, data: res}
227
229
  else Aspera.error_unexpected_value(command)
228
230
  end
@@ -57,15 +57,14 @@ module Aspera
57
57
  APP_NAME_SDK = 'sdk'
58
58
  CONNECT_WEB_URL = 'https://d3gcli72yxqn2z.cloudfront.net/connect'
59
59
  CONNECT_VERSIONS = 'connectversions.js' # cspell: disable-line
60
- TRANSFER_SDK_ARCHIVE_URL = 'https://ibm.biz/aspera_transfer_sdk'
61
60
  DEMO_SERVER = 'demo'
62
61
  DEMO_PRESET = 'demoserver' # cspell: disable-line
63
62
  EMAIL_TEST_TEMPLATE = <<~END_OF_TEMPLATE
64
63
  From: <%=from_name%> <<%=from_email%>>
65
64
  To: <<%=to%>>
66
- Subject: #{GEM_NAME} email test
65
+ Subject: #{Info::GEM_NAME} email test
67
66
 
68
- This email was sent to test #{PROGRAM_NAME}.
67
+ This email was sent to test #{Info::CMD_NAME}.
69
68
  END_OF_TEMPLATE
70
69
  # special extended values
71
70
  EXTEND_PRESET = :preset
@@ -86,7 +85,6 @@ module Aspera
86
85
  :CONF_PRESET_GLOBAL,
87
86
  :ASPERA_PLUGINS_FOLDERNAME,
88
87
  :ASPERA,
89
- :TRANSFER_SDK_ARCHIVE_URL,
90
88
  :DEMO_SERVER,
91
89
  :DEMO_PRESET,
92
90
  :EMAIL_TEST_TEMPLATE,
@@ -126,8 +124,8 @@ module Aspera
126
124
  end
127
125
 
128
126
  # deep clone hash so that it does not get modified in case of display and secret hide
129
- def protect_presets(val)
130
- return JSON.parse(JSON.generate(val))
127
+ def deep_clone(val)
128
+ return Marshal.load(Marshal.dump(val))
131
129
  end
132
130
 
133
131
  # return product family folder (~/.aspera)
@@ -145,13 +143,9 @@ module Aspera
145
143
  end
146
144
  end
147
145
 
148
- def initialize(gem:, name:, help:, version:, **env)
146
+ def initialize(**env)
149
147
  # we need to defer parsing of options until we have the config file, so we can use @extend with @preset
150
148
  super(**env)
151
- @gem = gem
152
- @name = name
153
- @help = help
154
- @version = version
155
149
  @use_plugin_defaults = true
156
150
  @config_presets = nil
157
151
  @config_checksum_on_disk = nil
@@ -177,9 +171,9 @@ module Aspera
177
171
  :home, 'Home folder for tool',
178
172
  handler: {o: self, m: :main_folder},
179
173
  types: String,
180
- default: self.class.default_app_main_folder(app_name: @name))
174
+ default: self.class.default_app_main_folder(app_name: Info::CMD_NAME))
181
175
  options.parse_options!
182
- Log.log.debug{"#{@name} folder: #{@main_folder}"}
176
+ Log.log.debug{"#{Info::CMD_NAME} folder: #{@main_folder}"}
183
177
  # data persistency manager, created by config plugin
184
178
  @persistency = PersistencyFolder.new(File.join(@main_folder, PERSISTENCY_FOLDER))
185
179
  # set folders for plugin lookup
@@ -218,7 +212,7 @@ module Aspera
218
212
  # Transfer SDK options
219
213
  options.declare(:ascp_path, 'Path to ascp', handler: {o: Ascp::Installation.instance, m: :ascp_path})
220
214
  options.declare(:use_product, 'Use ascp from specified product', handler: {o: self, m: :option_use_product})
221
- options.declare(:sdk_url, 'URL to get SDK', default: TRANSFER_SDK_ARCHIVE_URL)
215
+ options.declare(:sdk_url, 'URL to get SDK', default: SpecialValues::DEF)
222
216
  options.declare(:sdk_folder, 'SDK folder path', handler: {o: Ascp::Installation.instance, m: :sdk_folder})
223
217
  options.declare(:progress_bar, 'Display progress bar', values: :bool, default: Environment.terminal?)
224
218
  # email options
@@ -234,7 +228,7 @@ module Aspera
234
228
  options.declare(:http_proxy, 'URL for HTTP proxy with optional credentials', types: String, handler: {o: self, m: :option_http_proxy})
235
229
  options.declare(:cache_tokens, 'Save and reuse OAuth tokens', values: :bool, handler: {o: self, m: :option_cache_tokens})
236
230
  options.declare(:fpac, 'Proxy auto configuration script')
237
- options.declare(:proxy_credentials, 'HTTP proxy credentials for fpac. Array: user,password', types: Array)
231
+ options.declare(:proxy_credentials, 'HTTP proxy credentials for fpac: user, password', types: Array)
238
232
  options.parse_options!
239
233
  @progress_bar = TransferProgress.new if options.get_option(:progress_bar)
240
234
  # Check SDK folder is set or not, for compatibility, we check in two places
@@ -248,7 +242,7 @@ module Aspera
248
242
  if !Dir.exist?(sdk_folder)
249
243
  Log.log.debug{"not exists: #{sdk_folder}"}
250
244
  # former location
251
- former_sdk_folder = File.join(self.class.default_app_main_folder(app_name: @name), APP_NAME_SDK)
245
+ former_sdk_folder = File.join(self.class.default_app_main_folder(app_name: Info::CMD_NAME), APP_NAME_SDK)
252
246
  Log.log.debug{"checking: #{former_sdk_folder}"}
253
247
  sdk_folder = former_sdk_folder if Dir.exist?(former_sdk_folder)
254
248
  end
@@ -266,11 +260,16 @@ module Aspera
266
260
  @pac_exec.proxy_pass = proxy_user_pass[1]
267
261
  end
268
262
  end
269
- Rest.set_parameters(
270
- user_agent: PROGRAM_NAME,
271
- session_cb: lambda{|http_session|update_http_session(http_session)},
272
- progress_bar: @progress_bar)
263
+ RestParameters.instance.user_agent = Info::CMD_NAME
264
+ RestParameters.instance.progress_bar = @progress_bar
265
+ RestParameters.instance.session_cb = lambda{|http_session|update_http_session(http_session)}
266
+ @option_http_options.keys.select{|i|RestParameters.instance.respond_to?(i)}.each do |k|
267
+ method = "#{k}=".to_sym
268
+ RestParameters.instance.send(method, @option_http_options[k])
269
+ @option_http_options.delete(k)
270
+ end
273
271
  OAuth::Factory.instance.persist_mgr = persistency if @option_cache_tokens
272
+ OAuth::Web.additionnal_info = "#{Info::CMD_NAME} v#{Cli::VERSION}"
274
273
  Transfer::Parameters.file_list_folder = File.join(@main_folder, 'filelists')
275
274
  RestErrorAnalyzer.instance.log_file = File.join(@main_folder, 'rest_exceptions.log')
276
275
  # register aspera REST call error handlers
@@ -281,6 +280,8 @@ module Aspera
281
280
  attr_reader :option_ignore_cert_host_port, :progress_bar
282
281
 
283
282
  # add files, folders or default locations to the certificate store
283
+ # @param path_list [Array<String>] list of paths to add
284
+ # @return the list of paths
284
285
  def trusted_cert_locations=(path_list)
285
286
  path_list = [path_list] unless path_list.is_a?(Array)
286
287
  Aspera.assert_type(path_list, Array){'cert locations'}
@@ -296,10 +297,10 @@ module Aspera
296
297
  Log.log.debug{"Adding cert location: #{path}"}
297
298
  if path.eql?(SpecialValues::DEF)
298
299
  @certificate_store.set_default_paths
299
- paths_to_add = [
300
- OpenSSL::X509::DEFAULT_CERT_DIR,
301
- OpenSSL::X509::DEFAULT_CERT_FILE
302
- ].select{|f|File.exist?(f)}
300
+ paths_to_add = [OpenSSL::X509::DEFAULT_CERT_DIR]
301
+ # JRuby cert file seems not to be PEM
302
+ paths_to_add.push(OpenSSL::X509::DEFAULT_CERT_FILE) unless defined?(JRUBY_VERSION)
303
+ paths_to_add.select!{|f|File.exist?(f)}
303
304
  elsif File.file?(path)
304
305
  @certificate_store.add_file(path)
305
306
  elsif File.directory?(path)
@@ -392,19 +393,19 @@ module Aspera
392
393
  def check_gem_version
393
394
  latest_version =
394
395
  begin
395
- Rest.new(base_url: 'https://rubygems.org/api/v1').read("versions/#{@gem}/latest.json")[:data]['version']
396
+ Rest.new(base_url: 'https://rubygems.org/api/v1').read("versions/#{Info::GEM_NAME}/latest.json")['version']
396
397
  rescue StandardError
397
398
  Log.log.warn('Could not retrieve latest gem version on rubygems.')
398
399
  '0'
399
400
  end
400
- if Gem::Version.new(Environment.ruby_version) < Gem::Version.new(RUBY_FUTURE_MINIMUM_VERSION)
401
+ if Gem::Version.new(Environment.ruby_version) < Gem::Version.new(Info::RUBY_FUTURE_MINIMUM_VERSION)
401
402
  Log.log.warn do
402
- "Note that a future version will require Ruby version #{RUBY_FUTURE_MINIMUM_VERSION} at minimum, " \
403
+ "Note that a future version will require Ruby version #{Info::RUBY_FUTURE_MINIMUM_VERSION} at minimum, " \
403
404
  "you are using #{Environment.ruby_version}"
404
405
  end
405
406
  end
406
407
  return {
407
- name: @gem,
408
+ name: Info::GEM_NAME,
408
409
  current: Cli::VERSION,
409
410
  latest: latest_version,
410
411
  need_update: Gem::Version.new(Cli::VERSION) < Gem::Version.new(latest_version)
@@ -520,7 +521,7 @@ module Aspera
520
521
  current = current[name]
521
522
  raise Cli::Error, "No such config preset: #{include_path}" if current.nil?
522
523
  end
523
- current = self.class.protect_presets(current) unless current.is_a?(String)
524
+ current = self.class.deep_clone(current) unless current.is_a?(String)
524
525
  return ExtendedValue.instance.evaluate(current)
525
526
  end
526
527
 
@@ -578,7 +579,7 @@ module Aspera
578
579
  @config_checksum_on_disk = config_checksum
579
580
  end
580
581
  files_to_copy = []
581
- Log.log.debug{Log.dump('Available_presets', @config_presets)}
582
+ Log.log.trace1{Log.dump('Available_presets', @config_presets)}
582
583
  Aspera.assert_type(@config_presets, Hash){'config file YAML'}
583
584
  # check there is at least the config section
584
585
  Aspera.assert(@config_presets.key?(CONF_PRESET_CONFIG)){"Cannot find key: #{CONF_PRESET_CONFIG}"}
@@ -590,7 +591,7 @@ module Aspera
590
591
  @config_presets[CONF_PRESET_DEFAULTS].delete(true) if @config_presets[CONF_PRESET_DEFAULTS].is_a?(Hash)
591
592
  # ^^^ Place new compatibility code before this line
592
593
  # set version to current
593
- @config_presets[CONF_PRESET_CONFIG][CONF_PRESET_VERSION] = @version
594
+ @config_presets[CONF_PRESET_CONFIG][CONF_PRESET_VERSION] = Cli::VERSION
594
595
  unless files_to_copy.empty?
595
596
  Log.log.warn('Copying referenced files')
596
597
  files_to_copy.each do |file|
@@ -605,7 +606,7 @@ module Aspera
605
606
  Log.log.debug{"-> #{e.class.name} : #{e}"}
606
607
  if File.exist?(@option_config_file)
607
608
  # then there is a problem with that file.
608
- new_name = "#{@option_config_file}.pre#{@version}.manual_conversion_needed"
609
+ new_name = "#{@option_config_file}.pre#{Cli::VERSION}.manual_conversion_needed"
609
610
  File.rename(@option_config_file, new_name)
610
611
  Log.log.warn{"Renamed config file to #{new_name}."}
611
612
  Log.log.warn('Manual Conversion is required. Next time, a new empty file will be created.')
@@ -699,8 +700,7 @@ module Aspera
699
700
  return execute_connect_action
700
701
  when :use
701
702
  ascp_path = options.get_next_argument('path to ascp')
702
- ascp_version = Ascp::Installation.instance.get_ascp_version(ascp_path)
703
- formatter.display_status("ascp version: #{ascp_version}")
703
+ formatter.display_status("ascp version: #{Ascp::Installation.instance.get_ascp_version(ascp_path)}")
704
704
  set_global_default(:ascp_path, ascp_path)
705
705
  return Main.result_nothing
706
706
  when :show
@@ -729,8 +729,8 @@ module Aspera
729
729
  when :install
730
730
  # reset to default location, if older default was used
731
731
  Ascp::Installation.instance.sdk_folder = self.class.default_app_main_folder(app_name: APP_NAME_SDK) if @sdk_default_location
732
- v = Ascp::Installation.instance.install_sdk(options.get_option(:sdk_url, mandatory: true))
733
- return Main.result_status("Installed version #{v}")
732
+ n, v = Ascp::Installation.instance.install_sdk(url: options.get_option(:sdk_url, mandatory: true))
733
+ return Main.result_status("Installed #{n} version #{v}")
734
734
  when :spec
735
735
  return {
736
736
  type: :object_list,
@@ -766,9 +766,9 @@ module Aspera
766
766
  return {type: :value_list, data: @config_presets.keys, name: 'name'}
767
767
  when :overview
768
768
  # display process modifies the value (hide secrets): we do not want to save removed secrets
769
- return {type: :config_over, data: self.class.protect_presets(@config_presets)}
769
+ return {type: :config_over, data: self.class.deep_clone(@config_presets)}
770
770
  when :show
771
- return {type: :single_object, data: self.class.protect_presets(@config_presets[name])}
771
+ return {type: :single_object, data: self.class.deep_clone(@config_presets[name])}
772
772
  when :delete
773
773
  @config_presets.delete(name)
774
774
  return Main.result_status("Deleted: #{name}")
@@ -871,7 +871,9 @@ module Aspera
871
871
  check_update
872
872
  initdemo
873
873
  vault
874
- throw].freeze
874
+ test
875
+ platform
876
+ ].freeze
875
877
 
876
878
  # Main action procedure for plugin
877
879
  def execute_action
@@ -885,7 +887,7 @@ module Aspera
885
887
  when :documentation
886
888
  section = options.get_next_argument('private key file path', mandatory: false)
887
889
  section = "##{section}" unless section.nil?
888
- Environment.instance.open_uri("#{@help}#{section}")
890
+ Environment.instance.open_uri("#{Info::DOC_URL}#{section}")
889
891
  return Main.result_nothing
890
892
  when :genkey # generate new rsa key
891
893
  private_key_path = options.get_next_argument('private key file path')
@@ -967,7 +969,7 @@ module Aspera
967
969
  case options.get_next_command(%i[path version name])
968
970
  when :path then return Main.result_status(self.class.gem_src_root)
969
971
  when :version then return Main.result_status(Cli::VERSION)
970
- when :name then return Main.result_status(@gem)
972
+ when :name then return Main.result_status(Info::GEM_NAME)
971
973
  end
972
974
  when :folder
973
975
  return Main.result_status(@main_folder)
@@ -1007,14 +1009,9 @@ module Aspera
1007
1009
  end
1008
1010
  return Main.result_status('Done')
1009
1011
  when :vault then execute_vault
1010
- when :throw
1011
- # :type [String]
1012
- options
1013
- exception_class_name = options.get_next_argument('exception class name', mandatory: true)
1014
- exception_text = options.get_next_argument('exception text', mandatory: true)
1015
- exception_class = Object.const_get(exception_class_name)
1016
- Aspera.assert(exception_class <= Exception){"#{exception_class} is not an exception: #{exception_class.class}"}
1017
- raise exception_class, exception_text
1012
+ when :test then return execute_test
1013
+ when :platform
1014
+ return Main.result_status(Environment.architecture)
1018
1015
  else Aspera.error_unreachable_line
1019
1016
  end
1020
1017
  end
@@ -1107,7 +1104,7 @@ module Aspera
1107
1104
  test_args = "-P#{wiz_preset_name} #{test_args}"
1108
1105
  end
1109
1106
  # TODO: actually test the command
1110
- return Main.result_status("You can test with:\n#{@name} #{identification[:product]} #{test_args}")
1107
+ return Main.result_status("You can test with:\n#{Info::CMD_NAME} #{identification[:product]} #{test_args}")
1111
1108
  end
1112
1109
 
1113
1110
  # @return [Hash] email server setting with defaults if not defined
@@ -1136,6 +1133,8 @@ module Aspera
1136
1133
  end
1137
1134
 
1138
1135
  # send email using ERB template
1136
+ # @param email_template_default [String] default template, can be overriden by option
1137
+ # @param values [Hash] values to be used in template, keys with default: to, from_name, from_email
1139
1138
  def send_email_template(email_template_default: nil, values: {})
1140
1139
  values[:to] ||= options.get_option(:notify_to, mandatory: true)
1141
1140
  notify_template = options.get_option(:notify_template, mandatory: email_template_default.nil?) || email_template_default
@@ -1197,7 +1196,7 @@ module Aspera
1197
1196
  Log.log.error do
1198
1197
  "Default config name [#{default_config_name}] specified for plugin [#{plugin_name_sym}], but it does not exist in config file.\n" \
1199
1198
  'Please fix the issue: either create preset with one parameter: ' \
1200
- "(#{@name} config id #{default_config_name} init @json:'{}') or remove default (#{@name} config id default remove #{plugin_name_sym})."
1199
+ "(#{Info::CMD_NAME} config id #{default_config_name} init @json:'{}') or remove default (#{Info::CMD_NAME} config id default remove #{plugin_name_sym})."
1201
1200
  end
1202
1201
  end
1203
1202
  raise Cli::Error, "Config name [#{default_config_name}] must be a hash, check config file." if !@config_presets[default_config_name].is_a?(Hash)
@@ -1252,7 +1251,7 @@ module Aspera
1252
1251
  info = options.get_option(:vault) || {}
1253
1252
  info = info.symbolize_keys
1254
1253
  info[:type] ||= 'file'
1255
- info[:name] ||= (info[:type].eql?('file') ? DEFAULT_VAULT_FILENAME : PROGRAM_NAME)
1254
+ info[:name] ||= (info[:type].eql?('file') ? DEFAULT_VAULT_FILENAME : Info::CMD_NAME)
1256
1255
  Aspera.assert(info.keys.sort == %i[name type]) {"vault info shall have exactly keys 'type' and 'name'"}
1257
1256
  Aspera.assert(info.values.all?(String)){'vault info shall have only string values'}
1258
1257
  info[:password] = options.get_option(:vault_password, mandatory: true)
@@ -1284,6 +1283,20 @@ module Aspera
1284
1283
  @vault
1285
1284
  end
1286
1285
 
1286
+ def execute_test
1287
+ case options.get_next_command(%i[throw web])
1288
+ when :throw
1289
+ # :type [String]
1290
+ # options
1291
+ exception_class_name = options.get_next_argument('exception class name', mandatory: true)
1292
+ exception_text = options.get_next_argument('exception text', mandatory: true)
1293
+ exception_class = Object.const_get(exception_class_name)
1294
+ Aspera.assert(exception_class <= Exception){"#{exception_class} is not an exception: #{exception_class.class}"}
1295
+ raise exception_class, exception_text
1296
+ when :web
1297
+ end
1298
+ end
1299
+
1287
1300
  # version of URL without trailing "/" and removing default port
1288
1301
  def canonical_url(url)
1289
1302
  url.sub(%r{/+$}, '').sub(%r{^(https://[^/]+):443$}, '\1')
@@ -1296,7 +1309,7 @@ module Aspera
1296
1309
  @config_presets.each_value do |v|
1297
1310
  next unless v.is_a?(Hash)
1298
1311
  conf_url = v['url'].is_a?(String) ? canonical_url(v['url']) : nil
1299
- return self.class.protect_presets(v) if conf_url.eql?(url) && v['username'].eql?(username)
1312
+ return self.class.deep_clone(v) if conf_url.eql?(url) && v['username'].eql?(username)
1300
1313
  end
1301
1314
  nil
1302
1315
  end
@@ -84,11 +84,11 @@ module Aspera
84
84
  command = options.get_next_command(%i[list submit])
85
85
  case command
86
86
  when :list
87
- return {type: :object_list, data: api_console.read('smart_transfers')[:data]}
87
+ return {type: :object_list, data: api_console.read('smart_transfers')}
88
88
  when :submit
89
89
  smart_id = options.get_next_argument('smart_id')
90
90
  params = options.get_next_argument('transfer parameters')
91
- return {type: :object_list, data: api_console.create("smart_transfers/#{smart_id}", params)[:data]}
91
+ return {type: :object_list, data: api_console.create("smart_transfers/#{smart_id}", params)}
92
92
  end
93
93
  when :current
94
94
  command = options.get_next_command([:list])
@@ -99,7 +99,7 @@ module Aspera
99
99
  data: api_console.read('transfers', {
100
100
  'from' => options.get_option(:filter_from, mandatory: true),
101
101
  'to' => options.get_option(:filter_to, mandatory: true)
102
- })[:data],
102
+ }),
103
103
  fields: %w[id contact name status]}
104
104
  end
105
105
  end
@@ -37,7 +37,8 @@ module Aspera
37
37
  # sub path in url for public link delivery
38
38
  PUB_LINK_EXTERNAL_MATCH = 'external_deliveries/'
39
39
  STANDARD_PATH = '/aspera/faspex'
40
- private_constant(*%i[KEY_NODE KEY_PATH PACKAGE_MATCH_FIELD ATOM_MAILBOXES ATOM_PARAMS ATOM_EXT_PARAMS PUB_LINK_EXTERNAL_MATCH])
40
+ HEADER_FASPEX_VERSION = 'X-IBM-Aspera'
41
+ private_constant(*%i[KEY_NODE KEY_PATH PACKAGE_MATCH_FIELD ATOM_MAILBOXES ATOM_PARAMS ATOM_EXT_PARAMS PUB_LINK_EXTERNAL_MATCH HEADER_FASPEX_VERSION])
41
42
 
42
43
  class << self
43
44
  def detect(address_or_url)
@@ -58,7 +59,7 @@ module Aspera
58
59
  # 4.x
59
60
  next unless result[:http].body.start_with?('<?xml')
60
61
  res_s = XmlSimple.xml_in(result[:http].body, {'ForceArray' => false})
61
- Log.log.debug{"version: #{result[:http]['X-IBM-Aspera']}"}
62
+ Log.log.debug{"version: #{result[:http][HEADER_FASPEX_VERSION]}"}
62
63
  version = res_s['XRD']['application']['version']
63
64
  # take redirect if any
64
65
  return {
@@ -95,7 +96,7 @@ module Aspera
95
96
  result = {
96
97
  base_url: "#{public_uri.scheme}://#{public_uri.host}#{port_add}#{base}",
97
98
  subpath: subpath,
98
- query: Rest.decode_query(public_uri.query)
99
+ query: Rest.query_to_h(public_uri.query)
99
100
  }
100
101
  Log.log.debug{Log.dump('link data', result)}
101
102
  return result
@@ -246,7 +247,7 @@ module Aspera
246
247
  delivery_info[:source_paths_list] = transfer.source_list.join("\r\n")
247
248
  api_public_link = Rest.new(base_url: link_data[:base_url])
248
249
  # Hum, as this does not always work (only user, but not dropbox), we get the javascript and need hack
249
- # pkg_created=api_public_link.create(create_path,package_create_params)[:data]
250
+ # pkg_created=api_public_link.create(create_path,package_create_params)
250
251
  # so extract data from javascript
251
252
  package_creation_data = api_public_link.call(
252
253
  operation: 'POST',
@@ -307,17 +308,11 @@ module Aspera
307
308
  first_source['paths'].push(*transfer.source_list)
308
309
  source_id = instance_identifier(as_option: :remote_source) do |field, value|
309
310
  Aspera.assert(field.eql?('name'), exception_class: Cli::BadArgument){'only name as selector, or give id'}
310
- source_list = api_v3.call(operation: 'GET', subpath: 'source_shares', headers: {'Accept' => 'application/json'})[:data]['items']
311
+ source_list = api_v3.read('source_shares')['items']
311
312
  self.class.get_source_id_by_name(value, source_list)
312
313
  end
313
314
  first_source['id'] = source_id.to_i unless source_id.nil?
314
- pkg_created = api_v3.call(
315
- operation: 'POST',
316
- subpath: 'send',
317
- headers: {'Accept' => 'application/json'},
318
- body: package_create_params,
319
- body_type: :json
320
- )[:data]
315
+ pkg_created = api_v3.create('send', package_create_params)
321
316
  if first_source.key?('id')
322
317
  # no transfer spec if remote source: handled by faspex
323
318
  return {data: [pkg_created['links']['status']], type: :value_list, name: 'link'}
@@ -437,7 +432,7 @@ module Aspera
437
432
  end
438
433
  when :source
439
434
  command_source = options.get_next_command(%i[list info node])
440
- source_list = api_v3.call(operation: 'GET', subpath: 'source_shares', headers: {'Accept' => 'application/json'})[:data]['items']
435
+ source_list = api_v3.read('source_shares')['items']
441
436
  case command_source
442
437
  when :list
443
438
  return {type: :object_list, data: source_list}
@@ -479,13 +474,13 @@ module Aspera
479
474
  end
480
475
  end
481
476
  when :me
482
- my_info = api_v3.call(operation: 'GET', subpath: 'me', headers: {'Accept' => 'application/json'})[:data]
477
+ my_info = api_v3.read('me')
483
478
  return {data: my_info, type: :single_object}
484
479
  when :dropbox
485
480
  command_pkg = options.get_next_command([:list])
486
481
  case command_pkg
487
482
  when :list
488
- dropbox_list = api_v3.call(operation: 'GET', subpath: 'dropboxes', headers: {'Accept' => 'application/json'})[:data]
483
+ dropbox_list = api_v3.read('dropboxes')
489
484
  return {type: :object_list, data: dropbox_list['items'], fields: %w[name id description can_read can_write]}
490
485
  end
491
486
  when :v4
@@ -509,12 +504,7 @@ module Aspera
509
504
  return entity_action(api_v4, "#{pkg_box_type}/#{pkg_box_id}/packages")
510
505
  end
511
506
  when :address_book
512
- result = api_v3.call(
513
- operation: 'GET',
514
- subpath: 'address-book',
515
- headers: {'Accept' => 'application/json'},
516
- query: {'format' => 'json', 'count' => 100_000}
517
- )[:data]
507
+ result = api_v3.read('address-book', {'format' => 'json', 'count' => 100_000})
518
508
  formatter.display_status("users: #{result['itemsPerPage']}/#{result['totalResults']}, start:#{result['startIndex']}")
519
509
  users = result['entry']
520
510
  # add missing entries