aspera-cli 4.14.0 → 4.15.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 (90) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +54 -3
  4. data/CONTRIBUTING.md +7 -7
  5. data/README.md +1457 -880
  6. data/bin/ascli +18 -9
  7. data/bin/asession +12 -14
  8. data/examples/proxy.pac +1 -1
  9. data/lib/aspera/aoc.rb +198 -127
  10. data/lib/aspera/ascmd.rb +24 -14
  11. data/lib/aspera/cli/basic_auth_plugin.rb +9 -6
  12. data/lib/aspera/cli/error.rb +17 -0
  13. data/lib/aspera/cli/extended_value.rb +47 -12
  14. data/lib/aspera/cli/formatter.rb +260 -171
  15. data/lib/aspera/cli/hints.rb +80 -0
  16. data/lib/aspera/cli/main.rb +101 -147
  17. data/lib/aspera/cli/manager.rb +160 -124
  18. data/lib/aspera/cli/plugin.rb +70 -59
  19. data/lib/aspera/cli/plugins/alee.rb +0 -1
  20. data/lib/aspera/cli/plugins/aoc.rb +239 -273
  21. data/lib/aspera/cli/plugins/ats.rb +8 -5
  22. data/lib/aspera/cli/plugins/bss.rb +2 -2
  23. data/lib/aspera/cli/plugins/config.rb +516 -375
  24. data/lib/aspera/cli/plugins/console.rb +40 -0
  25. data/lib/aspera/cli/plugins/cos.rb +4 -5
  26. data/lib/aspera/cli/plugins/faspex.rb +99 -84
  27. data/lib/aspera/cli/plugins/faspex5.rb +179 -148
  28. data/lib/aspera/cli/plugins/node.rb +219 -153
  29. data/lib/aspera/cli/plugins/orchestrator.rb +52 -17
  30. data/lib/aspera/cli/plugins/preview.rb +46 -32
  31. data/lib/aspera/cli/plugins/server.rb +57 -17
  32. data/lib/aspera/cli/plugins/shares.rb +34 -12
  33. data/lib/aspera/cli/sync_actions.rb +68 -0
  34. data/lib/aspera/cli/transfer_agent.rb +45 -55
  35. data/lib/aspera/cli/transfer_progress.rb +74 -0
  36. data/lib/aspera/cli/version.rb +1 -1
  37. data/lib/aspera/colors.rb +3 -1
  38. data/lib/aspera/command_line_builder.rb +14 -11
  39. data/lib/aspera/cos_node.rb +3 -2
  40. data/lib/aspera/environment.rb +17 -6
  41. data/lib/aspera/fasp/agent_aspera.rb +126 -0
  42. data/lib/aspera/fasp/agent_base.rb +31 -77
  43. data/lib/aspera/fasp/agent_connect.rb +21 -22
  44. data/lib/aspera/fasp/agent_direct.rb +88 -102
  45. data/lib/aspera/fasp/agent_httpgw.rb +196 -192
  46. data/lib/aspera/fasp/agent_node.rb +41 -34
  47. data/lib/aspera/fasp/agent_trsdk.rb +75 -34
  48. data/lib/aspera/fasp/error_info.rb +2 -2
  49. data/lib/aspera/fasp/faux_file.rb +52 -0
  50. data/lib/aspera/fasp/installation.rb +43 -184
  51. data/lib/aspera/fasp/management.rb +244 -0
  52. data/lib/aspera/fasp/parameters.rb +59 -26
  53. data/lib/aspera/fasp/parameters.yaml +75 -8
  54. data/lib/aspera/fasp/products.rb +162 -0
  55. data/lib/aspera/fasp/transfer_spec.rb +1 -1
  56. data/lib/aspera/fasp/uri.rb +4 -4
  57. data/lib/aspera/faspex_gw.rb +2 -2
  58. data/lib/aspera/faspex_postproc.rb +2 -2
  59. data/lib/aspera/hash_ext.rb +2 -2
  60. data/lib/aspera/json_rpc.rb +49 -0
  61. data/lib/aspera/line_logger.rb +23 -0
  62. data/lib/aspera/log.rb +57 -16
  63. data/lib/aspera/node.rb +97 -14
  64. data/lib/aspera/oauth.rb +36 -18
  65. data/lib/aspera/open_application.rb +4 -4
  66. data/lib/aspera/persistency_folder.rb +2 -2
  67. data/lib/aspera/preview/file_types.rb +4 -2
  68. data/lib/aspera/preview/generator.rb +22 -35
  69. data/lib/aspera/preview/options.rb +2 -0
  70. data/lib/aspera/preview/terminal.rb +24 -13
  71. data/lib/aspera/preview/utils.rb +19 -26
  72. data/lib/aspera/rest.rb +103 -72
  73. data/lib/aspera/rest_call_error.rb +1 -1
  74. data/lib/aspera/rest_error_analyzer.rb +15 -14
  75. data/lib/aspera/rest_errors_aspera.rb +37 -34
  76. data/lib/aspera/secret_hider.rb +14 -16
  77. data/lib/aspera/ssh.rb +4 -1
  78. data/lib/aspera/sync.rb +128 -122
  79. data/lib/aspera/temp_file_manager.rb +10 -3
  80. data/lib/aspera/web_auth.rb +10 -7
  81. data/lib/aspera/web_server_simple.rb +9 -4
  82. data.tar.gz.sig +0 -0
  83. metadata +33 -15
  84. metadata.gz.sig +0 -0
  85. data/lib/aspera/cli/listener/line_dump.rb +0 -19
  86. data/lib/aspera/cli/listener/logger.rb +0 -22
  87. data/lib/aspera/cli/listener/progress.rb +0 -50
  88. data/lib/aspera/cli/listener/progress_multi.rb +0 -84
  89. data/lib/aspera/cli/plugins/sync.rb +0 -44
  90. data/lib/aspera/fasp/listener.rb +0 -13
@@ -7,6 +7,46 @@ module Aspera
7
7
  module Cli
8
8
  module Plugins
9
9
  class Console < Aspera::Cli::BasicAuthPlugin
10
+ STANDARD_PATH = '/aspera/console'
11
+ class << self
12
+ def detect(address_or_url)
13
+ address_or_url = "https://#{address_or_url}" unless address_or_url.match?(%r{^[a-z]{1,6}://})
14
+ urls = [address_or_url]
15
+ urls.push("#{address_or_url}#{STANDARD_PATH}") unless address_or_url.end_with?(STANDARD_PATH)
16
+
17
+ urls.each do |base_url|
18
+ next unless base_url.start_with?('https://')
19
+ api = Rest.new(base_url: base_url, redirect_max: 2)
20
+ test_endpoint = 'login'
21
+ test_page = api.call({operation: 'GET', subpath: test_endpoint, url_params: {local: true}})
22
+ next unless test_page[:http].body.include?('Aspera Console')
23
+ version = 'unknown'
24
+ if (m = test_page[:http].body.match(/\(v([1-9]\..*)\)/))
25
+ version = m[1]
26
+ end
27
+ url = test_page[:http].uri.to_s
28
+ return {
29
+ version: version,
30
+ url: url[0..url.index(test_endpoint) - 2]
31
+ }
32
+ rescue StandardError => e
33
+ Log.log.debug{"detect error: #{e}"}
34
+ end
35
+ return nil
36
+ end
37
+
38
+ def wizard(object:, private_key_path: nil, pub_key_pem: nil)
39
+ options = object.options
40
+ return {
41
+ preset_value: {
42
+ url: options.get_option(:url, mandatory: true),
43
+ username: options.get_option(:username, mandatory: true),
44
+ password: options.get_option(:password, mandatory: true)
45
+ },
46
+ test_args: 'transfer list'
47
+ }
48
+ end
49
+ end
10
50
  DEFAULT_FILTER_AGE_SECONDS = 3 * 3600
11
51
  private_constant :DEFAULT_FILTER_AGE_SECONDS
12
52
  def initialize(env)
@@ -10,7 +10,6 @@ module Aspera
10
10
  class Cos < Aspera::Cli::Plugin
11
11
  def initialize(env)
12
12
  super(env)
13
- @service_creds = nil
14
13
  options.declare(:bucket, 'Bucket name')
15
14
  options.declare(:endpoint, 'Storage endpoint url')
16
15
  options.declare(:apikey, 'Storage API key')
@@ -31,19 +30,19 @@ module Aspera
31
30
  # get service credentials, Hash, e.g. @json:@file:...
32
31
  service_credentials = options.get_option(:service_credentials)
33
32
  storage_endpoint = options.get_option(:endpoint)
34
- raise CliBadArgument, 'one of: endpoint or service_credentials is required' if service_credentials.nil? && storage_endpoint.nil?
35
- raise CliBadArgument, 'endpoint and service_credentials are mutually exclusive' unless service_credentials.nil? || storage_endpoint.nil?
33
+ raise Cli::BadArgument, 'one of: endpoint or service_credentials is required' if service_credentials.nil? && storage_endpoint.nil?
34
+ raise Cli::BadArgument, 'endpoint and service_credentials are mutually exclusive' unless service_credentials.nil? || storage_endpoint.nil?
36
35
  if service_credentials.nil?
37
36
  service_api_key = options.get_option(:apikey, mandatory: true)
38
37
  instance_id = options.get_option(:crn, mandatory: true)
39
38
  else
40
- params = CosNode.parameters_from_svc_creds(service_credentials, options.get_option(:region, mandatory: true))
39
+ params = CosNode.parameters_from_svc_credentials(service_credentials, options.get_option(:region, mandatory: true))
41
40
  storage_endpoint = params[:storage_endpoint]
42
41
  service_api_key = params[:service_api_key]
43
42
  instance_id = params[:instance_id]
44
43
  end
45
44
  api_node = CosNode.new(bucket_name, storage_endpoint, instance_id, service_api_key, options.get_option(:identity, mandatory: true))
46
- node_plugin = Node.new(@agents.merge(skip_basic_auth_options: true, node_api: api_node))
45
+ node_plugin = Node.new(@agents, api: api_node)
47
46
  command = options.get_next_command(Node::COMMANDS_COS)
48
47
  return node_plugin.execute_action(command)
49
48
  end
@@ -1,14 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # cspell:ignore passcode xrds workgroups dmembership wmembership
3
4
  require 'aspera/cli/basic_auth_plugin'
4
5
  require 'aspera/cli/plugins/node'
5
6
  require 'aspera/cli/plugins/config'
6
7
  require 'aspera/cli/extended_value'
7
8
  require 'aspera/cli/transfer_agent'
8
- require 'aspera/persistency_action_once'
9
- require 'aspera/open_application'
10
9
  require 'aspera/fasp/uri'
11
10
  require 'aspera/fasp/transfer_spec'
11
+ require 'aspera/persistency_action_once'
12
+ require 'aspera/open_application'
12
13
  require 'aspera/nagios'
13
14
  require 'aspera/id_generator'
14
15
  require 'xmlsimple'
@@ -32,45 +33,68 @@ module Aspera
32
33
  ATOM_EXT_PARAMS = [MAX_ITEMS, MAX_PAGES].concat(ATOM_PARAMS).freeze
33
34
  # sub path in url for public link delivery
34
35
  PUB_LINK_EXTERNAL_MATCH = 'external_deliveries/'
36
+ STANDARD_PATH = '/aspera/faspex'
35
37
  private_constant(*%i[KEY_NODE KEY_PATH PACKAGE_MATCH_FIELD ATOM_MAILBOXES ATOM_PARAMS ATOM_EXT_PARAMS PUB_LINK_EXTERNAL_MATCH])
36
38
 
37
39
  class << self
38
- def detect(base_url)
39
- api = Rest.new(base_url: base_url)
40
- result = api.call(
41
- operation: 'POST',
42
- subpath: 'aspera/faspex',
43
- headers: {'Accept' => 'application/xrds+xml', 'Content-type' => 'text/plain'},
44
- text_body_params: '')
45
- # 4.x
46
- if result[:http].body.start_with?('<?xml')
40
+ def detect(address_or_url)
41
+ address_or_url = "https://#{address_or_url}" unless address_or_url.match?(%r{^[a-z]{1,6}://})
42
+ urls = [address_or_url]
43
+ urls.push("#{address_or_url}#{STANDARD_PATH}") unless address_or_url.end_with?(STANDARD_PATH)
44
+
45
+ urls.each do |base_url|
46
+ next unless base_url.start_with?('https://')
47
+ api = Rest.new(base_url: base_url, redirect_max: 1)
48
+ result = api.call(
49
+ operation: 'POST',
50
+ subpath: '',
51
+ headers: {'Accept' => 'application/xrds+xml', 'Content-type' => 'text/plain'},
52
+ text_body_params: '')
53
+ # 4.x
54
+ next unless result[:http].body.start_with?('<?xml')
47
55
  res_s = XmlSimple.xml_in(result[:http].body, {'ForceArray' => false})
56
+ Log.log.debug{"version: #{result[:http]['X-IBM-Aspera']}"}
48
57
  version = res_s['XRD']['application']['version']
49
- return {version: version, url: result[:http].uri}
58
+ # take redirect if any
59
+ return {version: version, url: result[:http].uri.to_s}
60
+ rescue StandardError => e
61
+ Log.log.debug{"detect error: #{e}"}
50
62
  end
51
63
  return nil
52
64
  end
53
65
 
66
+ def wizard(object:, private_key_path: nil, pub_key_pem: nil)
67
+ options = object.options
68
+ return {
69
+ preset_value: {
70
+ url: options.get_option(:url, mandatory: true),
71
+ username: options.get_option(:username, mandatory: true),
72
+ password: options.get_option(:password, mandatory: true)
73
+ },
74
+ test_args: 'me'
75
+ }
76
+ end
77
+
54
78
  # extract elements from anonymous faspex link
55
79
  def get_link_data(public_url)
56
80
  public_uri = URI.parse(public_url)
57
- raise CliBadArgument, 'Public link does not match Faspex format' unless (m = public_uri.path.match(%r{^(.*)/(external.*)$}))
81
+ raise Cli::BadArgument, 'Public link does not match Faspex format' unless (m = public_uri.path.match(%r{^(.*)/(external.*)$}))
58
82
  base = m[1]
59
83
  subpath = m[2]
60
84
  port_add = public_uri.port.eql?(public_uri.default_port) ? '' : ":#{public_uri.port}"
61
85
  result = {
62
86
  base_url: "#{public_uri.scheme}://#{public_uri.host}#{port_add}#{base}",
63
87
  subpath: subpath,
64
- query: URI.decode_www_form(public_uri.query).each_with_object({}){|v, h|h[v.first] = v.last; }
88
+ query: Rest.decode_query(public_uri.query)
65
89
  }
66
- Log.dump('link data', result)
90
+ Log.log.debug{Log.dump('link data', result)}
67
91
  return result
68
92
  end
69
93
 
70
- # get faspe: URI from entry in xml, and fix problems..
94
+ # get Fasp::Uri::SCHEME URI from entry in xml, and fix problems..
71
95
  def get_fasp_uri_from_entry(entry, raise_no_link: true)
72
96
  unless entry.key?('link')
73
- raise CliBadArgument, 'package has no link (deleted?)' if raise_no_link
97
+ raise Cli::BadArgument, 'package has no link (deleted?)' if raise_no_link
74
98
  return nil
75
99
  end
76
100
  result = entry['link'].find{|e| e['rel'].eql?('package')}['href']
@@ -80,21 +104,11 @@ module Aspera
80
104
  return result
81
105
  end
82
106
 
83
- def textify_package_list(table_data)
84
- return table_data.map do |e|
85
- e.each_key {|k| e[k] = e[k].first if e[k].is_a?(Array) && (e[k].length == 1)}
86
- e['items'] = e.key?('link') ? e['link'].length : 0
87
- e
88
- end
89
- end
90
-
91
- # field_sym : :id or :name
92
- def get_source_id(source_list, source_name)
93
- source_ids = source_list.select { |i| i['name'].eql?(source_name) }
94
- if source_ids.empty?
95
- raise CliError, %Q(No such Faspex source "#{source_name}" in [#{source_list.map{|i| %Q("#{i['name']}")}.join(', ')}])
96
- end
97
- return source_ids.first['id']
107
+ # @return [Integer] identifier of source
108
+ def get_source_id_by_name(source_name, source_list)
109
+ match_source = source_list.find { |i| i['name'].eql?(source_name) }
110
+ return match_source['id'] unless match_source.nil?
111
+ raise Cli::Error, %Q(No such Faspex source: "#{source_name}" in [#{source_list.map{|i| %Q("#{i['name']}")}.join(', ')}])
98
112
  end
99
113
  end
100
114
 
@@ -104,8 +118,8 @@ module Aspera
104
118
  super(env)
105
119
  options.declare(:link, 'Public link for specific operation')
106
120
  options.declare(:delivery_info, 'Package delivery information', types: Hash)
107
- options.declare(:source_name, 'Create package from remote source (by name)')
108
- options.declare(:storage, 'Faspex local storage definition')
121
+ options.declare(:remote_source, 'Remote source for package send (id or %name:)')
122
+ options.declare(:storage, 'Faspex local storage definition (for browsing source)')
109
123
  options.declare(:recipient, 'Use if recipient is a dropbox (with *)')
110
124
  options.declare(:box, 'Package box', values: ATOM_MAILBOXES, default: :inbox)
111
125
  options.parse_options!
@@ -160,8 +174,8 @@ module Aspera
160
174
  # get a batch of package information
161
175
  # order: first batch is latest packages, and then in a batch ids are increasing
162
176
  atom_xml = api_v3.call({operation: 'GET', subpath: "#{mailbox}.atom", headers: {'Accept' => 'application/xml'}, url_params: mailbox_query})[:http].body
163
- box_data = XmlSimple.xml_in(atom_xml, {'ForceArray' => true})
164
- Log.dump(:box_data, box_data)
177
+ box_data = XmlSimple.xml_in(atom_xml, {'ForceArray' => %w[entry field link to]})
178
+ Log.log.debug{Log.dump(:box_data, box_data)}
165
179
  items = box_data.key?('entry') ? box_data['entry'] : []
166
180
  Log.log.debug{"new items: #{items.count}"}
167
181
  # it is the end if page is empty
@@ -173,11 +187,14 @@ module Aspera
173
187
  package[PACKAGE_MATCH_FIELD] =
174
188
  case mailbox
175
189
  when :inbox, :archive
176
- recipient = package['to'].find{|i|recipient_names.include?(i['name'].first)}
177
- recipient.nil? ? nil : recipient['recipient_delivery_id'].first
190
+ recipient = package['to'].find{|i|recipient_names.include?(i['name'])}
191
+ recipient.nil? ? nil : recipient['recipient_delivery_id']
178
192
  else # :sent
179
- package['delivery_id'].first
193
+ package['delivery_id']
180
194
  end
195
+ # add special key
196
+ package['items'] = package['link'].is_a?(Array) ? package['link'].length : 0
197
+ package['metadata'] = package['metadata']['field'].each_with_object({}){|i, m| m[i['name']] = i['content'] }
181
198
  # if we look for a specific package
182
199
  stop_condition = true if !stop_at_id.nil? && stop_at_id.eql?(package[PACKAGE_MATCH_FIELD])
183
200
  # keep only those for the specified recipient
@@ -197,7 +214,7 @@ module Aspera
197
214
  break if link.nil?
198
215
  # replace parameters with the ones from next link
199
216
  params = CGI.parse(URI.parse(link['href']).query)
200
- mailbox_query = params.keys.each_with_object({}){|i, m|; m[i] = params[i].first; }
217
+ mailbox_query = params.keys.each_with_object({}){|i, m| m[i] = params[i].first }
201
218
  Log.log.debug{"query: #{mailbox_query}"}
202
219
  break if !max_pages.nil? && (mailbox_query['page'].to_i > max_pages)
203
220
  end
@@ -210,7 +227,7 @@ module Aspera
210
227
  # pub link user
211
228
  link_data = self.class.get_link_data(public_link_url)
212
229
  if !['external/submissions/new', 'external/dropbox_submissions/new'].include?(link_data[:subpath])
213
- raise CliBadArgument, "pub link is #{link_data[:subpath]}, expecting external/submissions/new"
230
+ raise Cli::BadArgument, "pub link is #{link_data[:subpath]}, expecting external/submissions/new"
214
231
  end
215
232
  create_path = link_data[:subpath].split('/')[0..-2].join('/')
216
233
  package_create_params[:passcode] = link_data[:query]['passcode']
@@ -225,11 +242,11 @@ module Aspera
225
242
  subpath: create_path,
226
243
  json_params: package_create_params,
227
244
  headers: {'Accept' => 'text/javascript'}})[:http].body
228
- # get args of function call
245
+ # get arguments of function call
229
246
  package_creation_data.delete!("\n") # one line
230
247
  package_creation_data.gsub!(/^[^"]+\("\{/, '{') # delete header
231
248
  package_creation_data.gsub!(/"\);[^"]+$/, '"') # delete trailer
232
- package_creation_data.gsub!(/\}", *"/, '},"') # between two args
249
+ package_creation_data.gsub!(/\}", *"/, '},"') # between two arguments
233
250
  package_creation_data.gsub!('\\"', '"') # remove protecting quote
234
251
  begin
235
252
  package_creation_data = JSON.parse("[#{package_creation_data}]")
@@ -254,18 +271,20 @@ module Aspera
254
271
  end
255
272
  return nagios.result
256
273
  when :package
257
- command_pkg = options.get_next_command(%i[send recv list])
274
+ command_pkg = options.get_next_command(%i[send recv list show])
258
275
  case command_pkg
276
+ when :show
277
+ delivery_id = instance_identifier
278
+ return {type: :single_object, data: mailbox_filtered_entries(stop_at_id: delivery_id).find{|p|p[PACKAGE_MATCH_FIELD].eql?(delivery_id)} }
259
279
  when :list
260
280
  return {
261
- type: :object_list,
262
- data: mailbox_filtered_entries,
263
- fields: [PACKAGE_MATCH_FIELD, 'title', 'items'],
264
- textify: lambda {|table_data|Faspex.textify_package_list(table_data)}
281
+ type: :object_list,
282
+ data: mailbox_filtered_entries,
283
+ fields: [PACKAGE_MATCH_FIELD, 'title', 'items']
265
284
  }
266
285
  when :send
267
286
  delivery_info = options.get_option(:delivery_info, mandatory: true)
268
- raise CliBadArgument, 'delivery_info must be hash, refer to doc' unless delivery_info.is_a?(Hash)
287
+ raise Cli::BadArgument, 'delivery_info must be hash, refer to doc' unless delivery_info.is_a?(Hash)
269
288
  # actual parameter to faspex API
270
289
  package_create_params = {'delivery' => delivery_info}
271
290
  public_link_url = options.get_option(:link)
@@ -274,30 +293,30 @@ module Aspera
274
293
  delivery_info['sources'] ||= [{'paths' => []}]
275
294
  first_source = delivery_info['sources'].first
276
295
  first_source['paths'].push(*transfer.source_list)
277
- source_name = options.get_option(:source_name)
278
- if !source_name.nil?
296
+ source_id = instance_identifier(as_option: :remote_source) do |field, value|
297
+ raise Cli::BadArgument, 'only name as selector, or give id' unless field.eql?('name')
279
298
  source_list = api_v3.call({operation: 'GET', subpath: 'source_shares', headers: {'Accept' => 'application/json'}})[:data]['items']
280
- source_id = self.class.get_source_id(source_list, source_name)
281
- first_source['id'] = source_id
299
+ self.class.get_source_id_by_name(value, source_list)
282
300
  end
301
+ first_source['id'] = source_id.to_i unless source_id.nil?
283
302
  pkg_created = api_v3.call({
284
303
  operation: 'POST',
285
304
  subpath: 'send',
286
305
  json_params: package_create_params,
287
306
  headers: {'Accept' => 'application/json'}
288
307
  })[:data]
289
- if !source_name.nil?
290
- # no transfer spec if remote source
308
+ if first_source.key?('id')
309
+ # no transfer spec if remote source: handled by faspex
291
310
  return {data: [pkg_created['links']['status']], type: :value_list, name: 'link'}
292
311
  end
293
- raise CliBadArgument, 'expecting one session exactly' if pkg_created['xfer_sessions'].length != 1
312
+ raise Cli::BadArgument, 'expecting one session exactly' if pkg_created['xfer_sessions'].length != 1
294
313
  transfer_spec = pkg_created['xfer_sessions'].first
295
314
  # use source from cmd line, this one only contains destination (already in dest root)
296
315
  transfer_spec.delete('paths')
297
316
  else # public link
298
317
  transfer_spec = send_public_link_to_ts(public_link_url, package_create_params)
299
318
  end
300
- # Log.dump('transfer_spec',transfer_spec)
319
+ # Log.log.debug{Log.dump('transfer_spec',transfer_spec)}
301
320
  return Main.result_transfer(transfer.start(transfer_spec))
302
321
  when :recv
303
322
  link_url = options.get_option(:link)
@@ -322,11 +341,11 @@ module Aspera
322
341
  delivery_id = instance_identifier
323
342
  raise 'empty id' if delivery_id.empty?
324
343
  recipient = options.get_option(:recipient)
325
- if VAL_ALL.eql?(delivery_id)
344
+ if ExtendedValue::ALL.eql?(delivery_id)
326
345
  pkg_id_uri = mailbox_filtered_entries.map{|i|{id: i[PACKAGE_MATCH_FIELD], uri: self.class.get_fasp_uri_from_entry(i, raise_no_link: false)}}
327
346
  elsif !recipient.nil? && recipient.start_with?('*')
328
347
  found_package_link = mailbox_filtered_entries(stop_at_id: delivery_id).find{|p|p[PACKAGE_MATCH_FIELD].eql?(delivery_id)}['link'].first['href']
329
- raise 'Not Found. Dropbox and Workgroup packages can use the link option with faspe:' if found_package_link.nil?
348
+ raise "Not Found. Dropbox and Workgroup packages can use the link option with #{Fasp::Uri::SCHEME}" if found_package_link.nil?
330
349
  pkg_id_uri = [{id: delivery_id, uri: found_package_link}]
331
350
  else
332
351
  # TODO: delivery id is the right one if package was receive by workgroup
@@ -339,12 +358,12 @@ module Aspera
339
358
  package_entry = XmlSimple.xml_in(entry_xml, {'ForceArray' => true})
340
359
  pkg_id_uri = [{id: delivery_id, uri: self.class.get_fasp_uri_from_entry(package_entry)}]
341
360
  end
342
- when /^faspe:/
361
+ when /^#{Fasp::Uri::SCHEME}:/o
343
362
  pkg_id_uri = [{id: 'package', uri: link_url}]
344
363
  else
345
364
  link_data = self.class.get_link_data(link_url)
346
365
  if !link_data[:subpath].start_with?(PUB_LINK_EXTERNAL_MATCH)
347
- raise CliBadArgument, "Pub link is #{link_data[:subpath]}. Expecting #{PUB_LINK_EXTERNAL_MATCH}"
366
+ raise Cli::BadArgument, "Pub link is #{link_data[:subpath]}. Expecting #{PUB_LINK_EXTERNAL_MATCH}"
348
367
  end
349
368
  # NOTE: unauthenticated API (authorization is in url params)
350
369
  api_public_link = Rest.new({base_url: link_data[:base_url]})
@@ -355,10 +374,10 @@ module Aspera
355
374
  headers: {'Accept' => 'application/xml'})
356
375
  if !package_creation_data[:http].body.start_with?('<?xml ')
357
376
  OpenApplication.instance.uri(link_url)
358
- raise CliError, 'Unexpected response: package not found ?'
377
+ raise Cli::Error, 'Unexpected response: package not found ?'
359
378
  end
360
379
  package_entry = XmlSimple.xml_in(package_creation_data[:http].body, {'ForceArray' => false})
361
- Log.dump(:package_entry, package_entry)
380
+ Log.log.debug{Log.dump(:package_entry, package_entry)}
362
381
  transfer_uri = self.class.get_fasp_uri_from_entry(package_entry)
363
382
  pkg_id_uri = [{id: package_entry['id'], uri: transfer_uri}]
364
383
  end # public link
@@ -366,7 +385,7 @@ module Aspera
366
385
  # TODO : remove ids from skip not present in inbox to avoid growing too big
367
386
  # skip_ids_data.select!{|id|pkg_id_uri.select{|p|p[:id].eql?(id)}}
368
387
  pkg_id_uri.reject!{|i|skip_ids_data.include?(i[:id])}
369
- Log.dump(:pkg_id_uri, pkg_id_uri)
388
+ Log.log.debug{Log.dump(:pkg_id_uri, pkg_id_uri)}
370
389
  return Main.result_status('no new package') if pkg_id_uri.empty?
371
390
  result_transfer = []
372
391
  pkg_id_uri.each do |id_uri|
@@ -375,7 +394,7 @@ module Aspera
375
394
  statuses = [:success]
376
395
  else
377
396
  transfer_spec = Fasp::Uri.new(id_uri[:uri]).transfer_spec
378
- # NOTE: only external users have token in faspe: link !
397
+ # NOTE: only external users have token in Fasp::Uri::SCHEME link !
379
398
  if !transfer_spec.key?('token')
380
399
  sanitized = id_uri[:uri].gsub('&', '&amp;')
381
400
  xml_payload =
@@ -397,41 +416,37 @@ module Aspera
397
416
  return Main.result_transfer_multiple(result_transfer)
398
417
  end
399
418
  when :source
400
- command_source = options.get_next_command(%i[list id name])
419
+ command_source = options.get_next_command(%i[list info node])
401
420
  source_list = api_v3.call({operation: 'GET', subpath: 'source_shares', headers: {'Accept' => 'application/json'}})[:data]['items']
402
421
  case command_source
403
422
  when :list
404
423
  return {type: :object_list, data: source_list}
405
- else # :id or :name
406
- source_match_val = options.get_next_argument('source id or name')
407
- source_ids = source_list.select { |i| i[command_source.to_s].to_s.eql?(source_match_val) }
408
- if source_ids.empty?
409
- raise CliError, "No such Faspex source #{command_source}: #{source_match_val} in [#{source_list.map{|i| i[command_source.to_s]}.join(', ')}]"
410
- end
411
- # get id and name
412
- source_name = source_ids.first['name']
413
- # source_id=source_ids.first['id']
424
+ else # :info :node
425
+ source_id = instance_identifier do |field, value|
426
+ raise Cli::BadArgument, 'only name as selector, or give id' unless field.eql?('name')
427
+ self.class.get_source_id_by_name(value, source_list)
428
+ end.to_i
429
+ source_name = source_list.find{|i|i['id'].eql?(source_id)}['name']
414
430
  source_hash = options.get_option(:storage, mandatory: true)
415
431
  # check value of option
416
- raise CliError, 'storage option must be a Hash' unless source_hash.is_a?(Hash)
432
+ raise Cli::Error, 'storage option must be a Hash' unless source_hash.is_a?(Hash)
417
433
  source_hash.each do |name, storage|
418
- raise CliError, "storage '#{name}' must be a Hash" unless storage.is_a?(Hash)
434
+ raise Cli::Error, "storage '#{name}' must be a Hash" unless storage.is_a?(Hash)
419
435
  [KEY_NODE, KEY_PATH].each do |key|
420
- raise CliError, "storage '#{name}' must have a '#{key}'" unless storage.key?(key)
436
+ raise Cli::Error, "storage '#{name}' must have a '#{key}'" unless storage.key?(key)
421
437
  end
422
438
  end
423
439
  if !source_hash.key?(source_name)
424
- raise CliError, "No such storage in config file: \"#{source_name}\" in [#{source_hash.keys.join(', ')}]"
440
+ raise Cli::Error, "No such storage in config file: \"#{source_name}\" in [#{source_hash.keys.join(', ')}]"
425
441
  end
426
442
  source_info = source_hash[source_name]
427
- Log.log.debug{"source_info: #{source_info}"}
428
- command_node = options.get_next_command(%i[info node])
429
- case command_node
443
+ Log.log.debug{Log.dump(:source_info, source_info)}
444
+ case command_source
430
445
  when :info
431
446
  return {data: source_info, type: :single_object}
432
447
  when :node
433
448
  node_config = ExtendedValue.instance.evaluate(source_info[KEY_NODE])
434
- raise CliError, "bad type for: \"#{source_info[KEY_NODE]}\"" unless node_config.is_a?(Hash)
449
+ raise Cli::Error, "bad type for: \"#{source_info[KEY_NODE]}\"" unless node_config.is_a?(Hash)
435
450
  Log.log.debug{"node=#{node_config}"}
436
451
  api_node = Rest.new({
437
452
  base_url: node_config['url'],
@@ -440,7 +455,7 @@ module Aspera
440
455
  username: node_config['username'],
441
456
  password: node_config['password']}})
442
457
  command = options.get_next_command(Node::COMMANDS_FASPEX)
443
- return Node.new(@agents.merge(skip_basic_auth_options: true, node_api: api_node)).execute_action(command, source_info[KEY_PATH])
458
+ return Node.new(@agents, api: api_node).execute_action(command, source_info[KEY_PATH])
444
459
  end
445
460
  end
446
461
  when :me