aspera-cli 4.19.0 → 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 (80) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +20 -0
  4. data/CONTRIBUTING.md +16 -4
  5. data/README.md +344 -164
  6. data/bin/asession +26 -19
  7. data/examples/build_exec +65 -76
  8. data/examples/build_exec_rubyc +40 -0
  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 +2 -18
  12. data/lib/aspera/agent/connect.rb +14 -13
  13. data/lib/aspera/agent/direct.rb +23 -24
  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 +126 -97
  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 +15 -10
  22. data/lib/aspera/api/node.rb +33 -12
  23. data/lib/aspera/ascmd.rb +56 -48
  24. data/lib/aspera/ascp/installation.rb +99 -42
  25. data/lib/aspera/ascp/management.rb +3 -2
  26. data/lib/aspera/ascp/products.rb +12 -0
  27. data/lib/aspera/assert.rb +10 -5
  28. data/lib/aspera/cli/formatter.rb +27 -17
  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 +5 -0
  33. data/lib/aspera/cli/plugin.rb +15 -29
  34. data/lib/aspera/cli/plugins/alee.rb +3 -3
  35. data/lib/aspera/cli/plugins/aoc.rb +222 -194
  36. data/lib/aspera/cli/plugins/ats.rb +16 -14
  37. data/lib/aspera/cli/plugins/config.rb +53 -45
  38. data/lib/aspera/cli/plugins/console.rb +3 -3
  39. data/lib/aspera/cli/plugins/faspex.rb +11 -21
  40. data/lib/aspera/cli/plugins/faspex5.rb +44 -42
  41. data/lib/aspera/cli/plugins/faspio.rb +2 -2
  42. data/lib/aspera/cli/plugins/httpgw.rb +1 -1
  43. data/lib/aspera/cli/plugins/node.rb +153 -95
  44. data/lib/aspera/cli/plugins/orchestrator.rb +14 -13
  45. data/lib/aspera/cli/plugins/preview.rb +8 -9
  46. data/lib/aspera/cli/plugins/server.rb +5 -9
  47. data/lib/aspera/cli/plugins/shares.rb +2 -2
  48. data/lib/aspera/cli/sync_actions.rb +2 -2
  49. data/lib/aspera/cli/transfer_agent.rb +12 -14
  50. data/lib/aspera/cli/transfer_progress.rb +35 -17
  51. data/lib/aspera/cli/version.rb +1 -1
  52. data/lib/aspera/command_line_builder.rb +3 -4
  53. data/lib/aspera/coverage.rb +13 -1
  54. data/lib/aspera/environment.rb +34 -18
  55. data/lib/aspera/faspex_gw.rb +2 -2
  56. data/lib/aspera/json_rpc.rb +1 -1
  57. data/lib/aspera/keychain/macos_security.rb +7 -12
  58. data/lib/aspera/log.rb +3 -4
  59. data/lib/aspera/oauth/base.rb +39 -45
  60. data/lib/aspera/oauth/factory.rb +11 -4
  61. data/lib/aspera/oauth/generic.rb +4 -8
  62. data/lib/aspera/oauth/jwt.rb +3 -3
  63. data/lib/aspera/oauth/url_json.rb +1 -2
  64. data/lib/aspera/oauth/web.rb +5 -2
  65. data/lib/aspera/persistency_action_once.rb +16 -8
  66. data/lib/aspera/preview/utils.rb +5 -16
  67. data/lib/aspera/rest.rb +100 -76
  68. data/lib/aspera/transfer/faux_file.rb +4 -4
  69. data/lib/aspera/transfer/parameters.rb +14 -16
  70. data/lib/aspera/transfer/spec.rb +12 -12
  71. data/lib/aspera/transfer/sync.rb +1 -5
  72. data/lib/aspera/transfer/uri.rb +1 -1
  73. data/lib/aspera/uri_reader.rb +1 -1
  74. data/lib/aspera/web_auth.rb +166 -17
  75. data/lib/aspera/web_server_simple.rb +4 -3
  76. data/lib/transfer_pb.rb +84 -0
  77. data/lib/transfer_services_pb.rb +82 -0
  78. data.tar.gz.sig +0 -0
  79. metadata +24 -5
  80. 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
@@ -394,19 +393,19 @@ module Aspera
394
393
  def check_gem_version
395
394
  latest_version =
396
395
  begin
397
- 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']
398
397
  rescue StandardError
399
398
  Log.log.warn('Could not retrieve latest gem version on rubygems.')
400
399
  '0'
401
400
  end
402
- 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)
403
402
  Log.log.warn do
404
- "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, " \
405
404
  "you are using #{Environment.ruby_version}"
406
405
  end
407
406
  end
408
407
  return {
409
- name: @gem,
408
+ name: Info::GEM_NAME,
410
409
  current: Cli::VERSION,
411
410
  latest: latest_version,
412
411
  need_update: Gem::Version.new(Cli::VERSION) < Gem::Version.new(latest_version)
@@ -522,7 +521,7 @@ module Aspera
522
521
  current = current[name]
523
522
  raise Cli::Error, "No such config preset: #{include_path}" if current.nil?
524
523
  end
525
- current = self.class.protect_presets(current) unless current.is_a?(String)
524
+ current = self.class.deep_clone(current) unless current.is_a?(String)
526
525
  return ExtendedValue.instance.evaluate(current)
527
526
  end
528
527
 
@@ -592,7 +591,7 @@ module Aspera
592
591
  @config_presets[CONF_PRESET_DEFAULTS].delete(true) if @config_presets[CONF_PRESET_DEFAULTS].is_a?(Hash)
593
592
  # ^^^ Place new compatibility code before this line
594
593
  # set version to current
595
- @config_presets[CONF_PRESET_CONFIG][CONF_PRESET_VERSION] = @version
594
+ @config_presets[CONF_PRESET_CONFIG][CONF_PRESET_VERSION] = Cli::VERSION
596
595
  unless files_to_copy.empty?
597
596
  Log.log.warn('Copying referenced files')
598
597
  files_to_copy.each do |file|
@@ -607,7 +606,7 @@ module Aspera
607
606
  Log.log.debug{"-> #{e.class.name} : #{e}"}
608
607
  if File.exist?(@option_config_file)
609
608
  # then there is a problem with that file.
610
- new_name = "#{@option_config_file}.pre#{@version}.manual_conversion_needed"
609
+ new_name = "#{@option_config_file}.pre#{Cli::VERSION}.manual_conversion_needed"
611
610
  File.rename(@option_config_file, new_name)
612
611
  Log.log.warn{"Renamed config file to #{new_name}."}
613
612
  Log.log.warn('Manual Conversion is required. Next time, a new empty file will be created.')
@@ -730,7 +729,7 @@ module Aspera
730
729
  when :install
731
730
  # reset to default location, if older default was used
732
731
  Ascp::Installation.instance.sdk_folder = self.class.default_app_main_folder(app_name: APP_NAME_SDK) if @sdk_default_location
733
- n, v = Ascp::Installation.instance.install_sdk(options.get_option(:sdk_url, mandatory: true))
732
+ n, v = Ascp::Installation.instance.install_sdk(url: options.get_option(:sdk_url, mandatory: true))
734
733
  return Main.result_status("Installed #{n} version #{v}")
735
734
  when :spec
736
735
  return {
@@ -767,9 +766,9 @@ module Aspera
767
766
  return {type: :value_list, data: @config_presets.keys, name: 'name'}
768
767
  when :overview
769
768
  # display process modifies the value (hide secrets): we do not want to save removed secrets
770
- return {type: :config_over, data: self.class.protect_presets(@config_presets)}
769
+ return {type: :config_over, data: self.class.deep_clone(@config_presets)}
771
770
  when :show
772
- 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])}
773
772
  when :delete
774
773
  @config_presets.delete(name)
775
774
  return Main.result_status("Deleted: #{name}")
@@ -872,7 +871,7 @@ module Aspera
872
871
  check_update
873
872
  initdemo
874
873
  vault
875
- throw
874
+ test
876
875
  platform
877
876
  ].freeze
878
877
 
@@ -888,7 +887,7 @@ module Aspera
888
887
  when :documentation
889
888
  section = options.get_next_argument('private key file path', mandatory: false)
890
889
  section = "##{section}" unless section.nil?
891
- Environment.instance.open_uri("#{@help}#{section}")
890
+ Environment.instance.open_uri("#{Info::DOC_URL}#{section}")
892
891
  return Main.result_nothing
893
892
  when :genkey # generate new rsa key
894
893
  private_key_path = options.get_next_argument('private key file path')
@@ -970,7 +969,7 @@ module Aspera
970
969
  case options.get_next_command(%i[path version name])
971
970
  when :path then return Main.result_status(self.class.gem_src_root)
972
971
  when :version then return Main.result_status(Cli::VERSION)
973
- when :name then return Main.result_status(@gem)
972
+ when :name then return Main.result_status(Info::GEM_NAME)
974
973
  end
975
974
  when :folder
976
975
  return Main.result_status(@main_folder)
@@ -1010,14 +1009,7 @@ module Aspera
1010
1009
  end
1011
1010
  return Main.result_status('Done')
1012
1011
  when :vault then execute_vault
1013
- when :throw
1014
- # :type [String]
1015
- options
1016
- exception_class_name = options.get_next_argument('exception class name', mandatory: true)
1017
- exception_text = options.get_next_argument('exception text', mandatory: true)
1018
- exception_class = Object.const_get(exception_class_name)
1019
- Aspera.assert(exception_class <= Exception){"#{exception_class} is not an exception: #{exception_class.class}"}
1020
- raise exception_class, exception_text
1012
+ when :test then return execute_test
1021
1013
  when :platform
1022
1014
  return Main.result_status(Environment.architecture)
1023
1015
  else Aspera.error_unreachable_line
@@ -1112,7 +1104,7 @@ module Aspera
1112
1104
  test_args = "-P#{wiz_preset_name} #{test_args}"
1113
1105
  end
1114
1106
  # TODO: actually test the command
1115
- 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}")
1116
1108
  end
1117
1109
 
1118
1110
  # @return [Hash] email server setting with defaults if not defined
@@ -1141,6 +1133,8 @@ module Aspera
1141
1133
  end
1142
1134
 
1143
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
1144
1138
  def send_email_template(email_template_default: nil, values: {})
1145
1139
  values[:to] ||= options.get_option(:notify_to, mandatory: true)
1146
1140
  notify_template = options.get_option(:notify_template, mandatory: email_template_default.nil?) || email_template_default
@@ -1202,7 +1196,7 @@ module Aspera
1202
1196
  Log.log.error do
1203
1197
  "Default config name [#{default_config_name}] specified for plugin [#{plugin_name_sym}], but it does not exist in config file.\n" \
1204
1198
  'Please fix the issue: either create preset with one parameter: ' \
1205
- "(#{@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})."
1206
1200
  end
1207
1201
  end
1208
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)
@@ -1257,7 +1251,7 @@ module Aspera
1257
1251
  info = options.get_option(:vault) || {}
1258
1252
  info = info.symbolize_keys
1259
1253
  info[:type] ||= 'file'
1260
- info[:name] ||= (info[:type].eql?('file') ? DEFAULT_VAULT_FILENAME : PROGRAM_NAME)
1254
+ info[:name] ||= (info[:type].eql?('file') ? DEFAULT_VAULT_FILENAME : Info::CMD_NAME)
1261
1255
  Aspera.assert(info.keys.sort == %i[name type]) {"vault info shall have exactly keys 'type' and 'name'"}
1262
1256
  Aspera.assert(info.values.all?(String)){'vault info shall have only string values'}
1263
1257
  info[:password] = options.get_option(:vault_password, mandatory: true)
@@ -1289,6 +1283,20 @@ module Aspera
1289
1283
  @vault
1290
1284
  end
1291
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
+
1292
1300
  # version of URL without trailing "/" and removing default port
1293
1301
  def canonical_url(url)
1294
1302
  url.sub(%r{/+$}, '').sub(%r{^(https://[^/]+):443$}, '\1')
@@ -1301,7 +1309,7 @@ module Aspera
1301
1309
  @config_presets.each_value do |v|
1302
1310
  next unless v.is_a?(Hash)
1303
1311
  conf_url = v['url'].is_a?(String) ? canonical_url(v['url']) : nil
1304
- 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)
1305
1313
  end
1306
1314
  nil
1307
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