aspera-cli 4.21.2 → 4.23.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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/BUGS.md +1 -1
- data/CHANGELOG.md +402 -374
- data/CONTRIBUTING.md +6 -10
- data/README.md +1018 -687
- data/lib/aspera/agent/base.rb +9 -5
- data/lib/aspera/agent/connect.rb +30 -28
- data/lib/aspera/agent/desktop.rb +29 -25
- data/lib/aspera/agent/direct.rb +137 -125
- data/lib/aspera/agent/httpgw.rb +22 -26
- data/lib/aspera/agent/node.rb +14 -11
- data/lib/aspera/agent/transferd.rb +6 -2
- data/lib/aspera/api/aoc.rb +15 -18
- data/lib/aspera/api/cos_node.rb +1 -1
- data/lib/aspera/api/httpgw.rb +15 -7
- data/lib/aspera/api/node.rb +6 -4
- data/lib/aspera/ascmd.rb +17 -9
- data/lib/aspera/ascp/installation.rb +21 -19
- data/lib/aspera/ascp/management.rb +1 -1
- data/lib/aspera/assert.rb +14 -5
- data/lib/aspera/cli/error.rb +2 -2
- data/lib/aspera/cli/extended_value.rb +38 -19
- data/lib/aspera/cli/formatter.rb +48 -48
- data/lib/aspera/cli/hints.rb +10 -2
- data/lib/aspera/cli/main.rb +190 -168
- data/lib/aspera/cli/manager.rb +16 -16
- data/lib/aspera/cli/plugin.rb +24 -21
- data/lib/aspera/cli/plugin_factory.rb +1 -1
- data/lib/aspera/cli/plugins/alee.rb +1 -1
- data/lib/aspera/cli/plugins/aoc.rb +173 -126
- data/lib/aspera/cli/plugins/ats.rb +19 -17
- data/lib/aspera/cli/plugins/config.rb +87 -98
- data/lib/aspera/cli/plugins/console.rb +5 -3
- data/lib/aspera/cli/plugins/faspex.rb +39 -35
- data/lib/aspera/cli/plugins/faspex5.rb +104 -80
- data/lib/aspera/cli/plugins/faspio.rb +13 -1
- data/lib/aspera/cli/plugins/httpgw.rb +13 -1
- data/lib/aspera/cli/plugins/node.rb +336 -205
- data/lib/aspera/cli/plugins/orchestrator.rb +34 -40
- data/lib/aspera/cli/plugins/preview.rb +3 -3
- data/lib/aspera/cli/plugins/server.rb +7 -6
- data/lib/aspera/cli/plugins/shares.rb +5 -5
- data/lib/aspera/cli/sync_actions.rb +19 -18
- data/lib/aspera/cli/transfer_agent.rb +11 -15
- data/lib/aspera/cli/transfer_progress.rb +2 -2
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/command_line_builder.rb +116 -95
- data/lib/aspera/coverage.rb +4 -3
- data/lib/aspera/data_repository.rb +1 -0
- data/lib/aspera/environment.rb +7 -6
- data/lib/aspera/faspex_gw.rb +14 -14
- data/lib/aspera/faspex_postproc.rb +7 -6
- data/lib/aspera/hash_ext.rb +2 -2
- data/lib/aspera/json_rpc.rb +1 -1
- data/lib/aspera/keychain/encrypted_hash.rb +47 -34
- data/lib/aspera/keychain/factory.rb +41 -0
- data/lib/aspera/keychain/hashicorp_vault.rb +71 -0
- data/lib/aspera/keychain/macos_security.rb +19 -11
- data/lib/aspera/log.rb +29 -34
- data/lib/aspera/nagios.rb +6 -6
- data/lib/aspera/node_simulator.rb +8 -8
- data/lib/aspera/oauth/base.rb +10 -6
- data/lib/aspera/oauth/factory.rb +6 -6
- data/lib/aspera/oauth/url_json.rb +6 -6
- data/lib/aspera/persistency_action_once.rb +6 -4
- data/lib/aspera/persistency_folder.rb +2 -2
- data/lib/aspera/preview/file_types.rb +40 -33
- data/lib/aspera/preview/generator.rb +1 -1
- data/lib/aspera/preview/options.rb +16 -16
- data/lib/aspera/preview/terminal.rb +3 -3
- data/lib/aspera/preview/utils.rb +11 -13
- data/lib/aspera/products/connect.rb +2 -1
- data/lib/aspera/products/desktop.rb +1 -1
- data/lib/aspera/products/transferd.rb +1 -1
- data/lib/aspera/proxy_auto_config.rb +2 -2
- data/lib/aspera/rest.rb +70 -50
- data/lib/aspera/rest_error_analyzer.rb +1 -0
- data/lib/aspera/rest_errors_aspera.rb +1 -1
- data/lib/aspera/secret_hider.rb +5 -5
- data/lib/aspera/ssh.rb +5 -5
- data/lib/aspera/temp_file_manager.rb +1 -0
- data/lib/aspera/timer_limiter.rb +7 -5
- data/lib/aspera/transfer/async_conf.schema.yaml +716 -0
- data/lib/aspera/transfer/convert.rb +29 -0
- data/lib/aspera/transfer/error_info.rb +66 -66
- data/lib/aspera/transfer/parameters.rb +13 -68
- data/lib/aspera/transfer/spec.rb +5 -6
- data/lib/aspera/transfer/spec.schema.yaml +753 -0
- data/lib/aspera/transfer/spec_doc.rb +62 -0
- data/lib/aspera/transfer/sync.rb +37 -76
- data/lib/aspera/transfer/sync_instance.schema.yaml +20 -0
- data/lib/aspera/transfer/sync_session.schema.yaml +86 -0
- data/lib/aspera/transfer/uri.rb +6 -6
- data/lib/aspera/uri_reader.rb +1 -1
- data/lib/aspera/web_auth.rb +1 -1
- data/lib/aspera/web_server_simple.rb +53 -44
- data.tar.gz.sig +0 -0
- metadata +38 -7
- metadata.gz.sig +0 -0
- data/examples/build_package.sh +0 -28
- data/examples/dascli +0 -30
- data/examples/get_proto_file.rb +0 -8
- data/examples/proxy.pac +0 -60
- data/lib/aspera/transfer/spec.yaml +0 -718
@@ -11,8 +11,10 @@ module Aspera
|
|
11
11
|
module Cli
|
12
12
|
module Plugins
|
13
13
|
class Orchestrator < Cli::BasicAuthPlugin
|
14
|
+
STANDARD_PATH = '/aspera/orchestrator'
|
15
|
+
TEST_ENDPOINT = 'api/remote_node_ping'
|
16
|
+
private_constant :STANDARD_PATH, :TEST_ENDPOINT
|
14
17
|
class << self
|
15
|
-
STANDARD_PATH = '/aspera/orchestrator'
|
16
18
|
def detect(address_or_url)
|
17
19
|
address_or_url = "https://#{address_or_url}" unless address_or_url.match?(%r{^[a-z]{1,6}://})
|
18
20
|
urls = [address_or_url]
|
@@ -21,13 +23,12 @@ module Aspera
|
|
21
23
|
urls.each do |base_url|
|
22
24
|
next unless base_url.match?('https?://')
|
23
25
|
api = Rest.new(base_url: base_url)
|
24
|
-
|
25
|
-
result = api.call(operation: 'GET', subpath: test_endpoint, headers: {'Accept' => 'application/json'}, query: {format: :json})
|
26
|
+
result = api.call(operation: 'GET', subpath: TEST_ENDPOINT, headers: {'Accept' => Rest::MIME_JSON}, query: {format: :json})
|
26
27
|
next unless result[:data]['remote_orchestrator_info']
|
27
28
|
url = result[:http].uri.to_s
|
28
29
|
return {
|
29
30
|
version: result[:data]['remote_orchestrator_info']['orchestrator-version'],
|
30
|
-
url: url[0..url.index(
|
31
|
+
url: url[0..url.index(TEST_ENDPOINT) - 2]
|
31
32
|
}
|
32
33
|
rescue StandardError => e
|
33
34
|
error = e
|
@@ -61,27 +62,22 @@ module Aspera
|
|
61
62
|
|
62
63
|
ACTIONS = %i[health info workflow plugins processes].freeze
|
63
64
|
|
64
|
-
#
|
65
|
-
# @param endpoint
|
66
|
-
# @param
|
67
|
-
# @param
|
68
|
-
# @param
|
69
|
-
# @param format [String] the format to request, 'json', 'xml', nil
|
70
|
-
# @param args [Hash] the arguments to pass
|
65
|
+
# Call orchestrator API, it's a bit special
|
66
|
+
# @param endpoint [String] the endpoint to call
|
67
|
+
# @param ret_style [Symbol] the return style, :header, :arg, :ext(extension)
|
68
|
+
# @param format [String] the format to request, 'json', 'xml', nil
|
69
|
+
# @param args [Hash] the arguments to pass
|
71
70
|
# @param xml_arrays [Boolean] if true, force arrays in xml parsing
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
call_args[:subpath] = "#{prefix}/#{call_args[:subpath]}" unless prefix.nil?
|
77
|
-
# specify id if necessary
|
78
|
-
call_args[:subpath] = "#{call_args[:subpath]}/#{id}" unless id.nil?
|
71
|
+
# @param http [Boolean] if true, returns the HttpResponse, else
|
72
|
+
def call_ao(endpoint, ret_style: nil, format: 'json', args: nil, xml_arrays: true, http: false)
|
73
|
+
# calls are all GET
|
74
|
+
call_args = {operation: 'GET', subpath: "api/#{endpoint}"}
|
79
75
|
ret_style = options.get_option(:ret_style, mandatory: true) if ret_style.nil?
|
80
76
|
call_args[:query] = args unless args.nil?
|
81
77
|
unless format.nil?
|
82
78
|
case ret_style
|
83
79
|
when :header
|
84
|
-
call_args[:headers] = {'Accept' => "application/#{format}"
|
80
|
+
call_args[:headers] = {'Accept' => "application/#{format}"}
|
85
81
|
when :arg
|
86
82
|
call_args[:query] ||= {}
|
87
83
|
call_args[:query][:format] = format
|
@@ -92,9 +88,9 @@ module Aspera
|
|
92
88
|
end
|
93
89
|
result = @api_orch.call(**call_args)
|
94
90
|
return result[:http] if http
|
95
|
-
result
|
96
|
-
Log.log.debug{Log.dump(:data, result
|
97
|
-
return result
|
91
|
+
result = format.eql?('xml') ? XmlSimple.xml_in(result[:http].body, {'ForceArray' => xml_arrays}) : result[:data]
|
92
|
+
Log.log.debug{Log.dump(:data, result)}
|
93
|
+
return result
|
98
94
|
end
|
99
95
|
|
100
96
|
def execute_action
|
@@ -105,7 +101,7 @@ module Aspera
|
|
105
101
|
type: :url,
|
106
102
|
url_query: {
|
107
103
|
'login' => options.get_option(:username, mandatory: true),
|
108
|
-
'password' => options.get_option(:password, mandatory: true)
|
104
|
+
'password' => options.get_option(:password, mandatory: true)}
|
109
105
|
}
|
110
106
|
when :head_basic
|
111
107
|
{
|
@@ -136,47 +132,45 @@ module Aspera
|
|
136
132
|
return nagios.result
|
137
133
|
when :info
|
138
134
|
result = call_ao('remote_node_ping', format: 'xml', xml_arrays: false)
|
139
|
-
return
|
135
|
+
return Main.result_single_object(result)
|
140
136
|
when :processes
|
141
137
|
# TODO: Bug ? API has only XML format
|
142
138
|
result = call_ao('processes_status', format: 'xml')
|
143
|
-
return
|
139
|
+
return Main.result_object_list(result['process'])
|
144
140
|
when :plugins
|
145
141
|
# TODO: Bug ? only json format on url
|
146
142
|
result = call_ao('plugin_version')
|
147
|
-
return
|
143
|
+
return Main.result_object_list(result['Plugin'])
|
148
144
|
when :workflow
|
149
145
|
command = options.get_next_command(%i[list status inputs details start export])
|
150
|
-
unless [:list].include?(command)
|
151
|
-
wf_id = instance_identifier
|
152
|
-
end
|
153
146
|
case command
|
154
147
|
when :status
|
155
|
-
wf_id =
|
156
|
-
result = call_ao('workflows_status'
|
157
|
-
return
|
148
|
+
wf_id = instance_identifier
|
149
|
+
result = call_ao(wf_id.eql?(SpecialValues::ALL) ? 'workflows_status' : "workflows_status/#{wf_id}")
|
150
|
+
return Main.result_object_list(result['workflows']['workflow'])
|
158
151
|
when :list
|
159
|
-
result = call_ao('workflows_list'
|
152
|
+
result = call_ao('workflows_list/0')
|
160
153
|
return {
|
161
154
|
type: :object_list,
|
162
155
|
data: result['workflows']['workflow'],
|
163
156
|
fields: %w[id portable_id name published_status published_revision_id latest_revision_id last_modification]
|
164
157
|
}
|
165
158
|
when :details
|
166
|
-
result = call_ao(
|
167
|
-
return
|
159
|
+
result = call_ao("workflow_details/#{instance_identifier}")
|
160
|
+
return Main.result_object_list(result['workflows']['workflow']['statuses'])
|
168
161
|
when :inputs
|
169
|
-
result = call_ao(
|
170
|
-
return
|
162
|
+
result = call_ao("workflow_inputs_spec/#{instance_identifier}")
|
163
|
+
return Main.result_single_object(result['workflow_inputs_spec'])
|
171
164
|
when :export
|
172
|
-
result = call_ao(
|
173
|
-
return
|
165
|
+
result = call_ao("export_workflow/#{instance_identifier}", format: nil, http: true)
|
166
|
+
return Main.result_text(result.body)
|
174
167
|
when :start
|
175
168
|
result = {
|
176
169
|
type: :single_object,
|
177
170
|
data: nil
|
178
171
|
}
|
179
172
|
call_params = {format: :json}
|
173
|
+
wf_id = instance_identifier
|
180
174
|
# get external parameters if any
|
181
175
|
options.get_next_argument('external_parameters', mandatory: false, validation: Hash, default: {}).each do |name, value|
|
182
176
|
call_params["external_parameters[#{name}]"] = value
|
@@ -197,7 +191,7 @@ module Aspera
|
|
197
191
|
if call_params['synchronous']
|
198
192
|
result[:type] = :text
|
199
193
|
end
|
200
|
-
result[:data] = call_ao(
|
194
|
+
result[:data] = call_ao("initiate/#{wf_id}", args: call_params)
|
201
195
|
return result
|
202
196
|
end
|
203
197
|
else Aspera.error_unexpected_value(command)
|
@@ -126,7 +126,7 @@ module Aspera
|
|
126
126
|
# /files/id/files is normally cached in redis, but we can discard the cache
|
127
127
|
# but /files/id is not cached
|
128
128
|
def get_folder_entries(file_id, request_args=nil)
|
129
|
-
headers = {'Accept' =>
|
129
|
+
headers = {'Accept' => Rest::MIME_JSON}
|
130
130
|
headers['X-Aspera-Cache-Control'] = 'no-cache' if @option_folder_reset_cache.eql?(:header)
|
131
131
|
return @api_node.call(
|
132
132
|
operation: 'GET',
|
@@ -194,7 +194,7 @@ module Aspera
|
|
194
194
|
if event.dig('data', 'type').eql?('file')
|
195
195
|
file_entry = @api_node.read("files/#{event['data']['id']}") rescue nil
|
196
196
|
if !file_entry.nil? &&
|
197
|
-
@option_skip_folders.none?{|d|file_entry['path'].start_with?(d)}
|
197
|
+
@option_skip_folders.none?{ |d| file_entry['path'].start_with?(d)}
|
198
198
|
file_entry['parent_file_id'] = event['data']['parent_file_id']
|
199
199
|
if event['types'].include?('file.deleted')
|
200
200
|
Log.log.error('TODO'.red)
|
@@ -460,7 +460,7 @@ module Aspera
|
|
460
460
|
'id' => @access_key_self['root_file_id'],
|
461
461
|
'name' => '/',
|
462
462
|
'type' => 'folder',
|
463
|
-
'path' => '/'
|
463
|
+
'path' => '/'}
|
464
464
|
else
|
465
465
|
@api_node.read("files/#{scan_id}")
|
466
466
|
end
|
@@ -19,6 +19,7 @@ module Aspera
|
|
19
19
|
# implement basic remote access with FASP/SSH
|
20
20
|
class Server < Cli::BasicAuthPlugin
|
21
21
|
include SyncActions
|
22
|
+
|
22
23
|
SSH_SCHEME = 'ssh'
|
23
24
|
LOCAL_SCHEME = 'local'
|
24
25
|
HTTPS_SCHEME = 'https'
|
@@ -148,7 +149,7 @@ module Aspera
|
|
148
149
|
ssh_key_list = [ssh_key_list] if ssh_key_list.is_a?(String)
|
149
150
|
Aspera.assert_type(ssh_key_list, Array){'ssh_keys'}
|
150
151
|
Aspera.assert(ssh_key_list.all?(String))
|
151
|
-
ssh_key_list.map!{|p|File.expand_path(p)}
|
152
|
+
ssh_key_list.map!{ |p| File.expand_path(p)}
|
152
153
|
Log.log.debug{"SSH keys=#{ssh_key_list}"}
|
153
154
|
if !ssh_key_list.empty?
|
154
155
|
@ssh_opts[:keys] = ssh_key_list
|
@@ -176,7 +177,7 @@ module Aspera
|
|
176
177
|
return Main.result_transfer(transfer.start(transfer_spec))
|
177
178
|
when :sync
|
178
179
|
# lets ignore the arguments provided by execute_sync_action, we just give the transfer spec
|
179
|
-
return execute_sync_action
|
180
|
+
return execute_sync_action{transfer_spec}
|
180
181
|
end
|
181
182
|
end
|
182
183
|
|
@@ -220,7 +221,7 @@ module Aspera
|
|
220
221
|
if TransferAgent.session_status(statuses).eql?(:success)
|
221
222
|
nagios.add_ok('transfer', 'ok')
|
222
223
|
else
|
223
|
-
nagios.add_critical('transfer', statuses.reject{|i|i.eql?(:success)}.first.to_s)
|
224
|
+
nagios.add_critical('transfer', statuses.reject{ |i| i.eql?(:success)}.first.to_s)
|
224
225
|
end
|
225
226
|
else Aspera.error_unexpected_value(command_nagios)
|
226
227
|
end
|
@@ -236,11 +237,11 @@ module Aspera
|
|
236
237
|
when :mkdir, :mv, :cp, :rm
|
237
238
|
return Main.result_success
|
238
239
|
when :ls
|
239
|
-
return
|
240
|
+
return Main.result_object_list(result.map(&:stringify_keys), fields: %w[zmode zuid zgid size mtime name])
|
240
241
|
when :df
|
241
|
-
return
|
242
|
+
return Main.result_object_list(result.map(&:stringify_keys))
|
242
243
|
when :du, :md5sum, :info
|
243
|
-
return
|
244
|
+
return Main.result_single_object(result.stringify_keys)
|
244
245
|
end
|
245
246
|
rescue AsCmd::Error => e
|
246
247
|
raise Cli::BadArgument, e.extended_message
|
@@ -50,7 +50,7 @@ module Aspera
|
|
50
50
|
end
|
51
51
|
end
|
52
52
|
|
53
|
-
def initialize(**
|
53
|
+
def initialize(**_)
|
54
54
|
super
|
55
55
|
end
|
56
56
|
|
@@ -72,14 +72,14 @@ module Aspera
|
|
72
72
|
.call(
|
73
73
|
operation: 'GET',
|
74
74
|
subpath: 'ping',
|
75
|
-
headers: {'content-type':
|
75
|
+
headers: {'content-type': Rest::MIME_JSON})
|
76
76
|
raise 'Shares not detected' unless res[:http].body.eql?(' ')
|
77
77
|
nagios.add_ok('shares api', 'accessible')
|
78
78
|
rescue StandardError => e
|
79
79
|
nagios.add_critical('API', e.to_s)
|
80
80
|
end
|
81
81
|
return nagios.result
|
82
|
-
when :
|
82
|
+
when :files
|
83
83
|
api_shares_node = basic_auth_api(NODE_API_PATH)
|
84
84
|
repo_command = options.get_next_command(Node::COMMANDS_SHARES)
|
85
85
|
return Node
|
@@ -138,9 +138,9 @@ module Aspera
|
|
138
138
|
return entity_action(api_shares_admin, entities_path, is_singleton: !entity_verb.eql?(:share_permissions))
|
139
139
|
when :import # saml
|
140
140
|
return do_bulk_operation(command: entity_verb, descr: 'user information') do |entity_parameters|
|
141
|
-
entity_parameters = entity_parameters.transform_keys{|k|k.gsub(/\s+/, '_').downcase}
|
141
|
+
entity_parameters = entity_parameters.transform_keys{ |k| k.gsub(/\s+/, '_').downcase}
|
142
142
|
Aspera.assert_type(entity_parameters, Hash)
|
143
|
-
SAML_IMPORT_MANDATORY.each{|p|raise "missing mandatory field: #{p}" if entity_parameters[p].nil?}
|
143
|
+
SAML_IMPORT_MANDATORY.each{ |p| raise "missing mandatory field: #{p}" if entity_parameters[p].nil?}
|
144
144
|
entity_parameters.each_key do |p|
|
145
145
|
raise "unsupported field: #{p}, use: #{SAML_IMPORT_ALLOWED.join(',')}" unless SAML_IMPORT_ALLOWED.include?(p)
|
146
146
|
end
|
@@ -7,30 +7,30 @@ module Aspera
|
|
7
7
|
module Cli
|
8
8
|
# Module for sync actions
|
9
9
|
module SyncActions
|
10
|
-
#
|
11
|
-
# in Array to keep
|
10
|
+
# Optional simple command line arguments for sync
|
11
|
+
# in Array to keep order as on command line
|
12
12
|
# conf: key in option --conf
|
13
13
|
# args: key for command line args
|
14
14
|
# values: possible values for argument
|
15
15
|
# type: type for validation
|
16
|
-
|
16
|
+
ARGUMENTS_INFO = [
|
17
17
|
{
|
18
18
|
conf: 'direction',
|
19
19
|
args: 'direction',
|
20
20
|
values: Transfer::Sync::DIRECTIONS
|
21
|
-
}, {
|
22
|
-
conf: 'remote.path',
|
23
|
-
args: 'remote_dir',
|
24
|
-
type: String
|
25
21
|
}, {
|
26
22
|
conf: 'local.path',
|
27
23
|
args: 'local_dir',
|
28
24
|
type: String
|
25
|
+
}, {
|
26
|
+
conf: 'remote.path',
|
27
|
+
args: 'remote_dir',
|
28
|
+
type: String
|
29
29
|
}
|
30
30
|
].freeze
|
31
31
|
# name of minimal arguments required, also used to generate a session name
|
32
|
-
|
33
|
-
private_constant :
|
32
|
+
ARGUMENTS_LIST = ARGUMENTS_INFO.map{ |i| i[:conf]}.freeze
|
33
|
+
private_constant :ARGUMENTS_INFO
|
34
34
|
|
35
35
|
class << self
|
36
36
|
def declare_options(options)
|
@@ -42,7 +42,7 @@ module Aspera
|
|
42
42
|
def sync_args_to_params(async_params)
|
43
43
|
# sync session parameters can be provided on command line instead of sync_info
|
44
44
|
arguments = {}
|
45
|
-
|
45
|
+
ARGUMENTS_INFO.each do |info|
|
46
46
|
value = options.get_next_argument(
|
47
47
|
info[:conf],
|
48
48
|
mandatory: false,
|
@@ -52,9 +52,9 @@ module Aspera
|
|
52
52
|
arguments[info[:conf]] = value.to_s
|
53
53
|
end
|
54
54
|
Log.log.debug{Log.dump('arguments', arguments)}
|
55
|
-
|
56
|
-
|
57
|
-
|
55
|
+
case arguments.keys.length
|
56
|
+
when 0 then nil
|
57
|
+
when 3
|
58
58
|
session_info = async_params
|
59
59
|
param_path = :conf
|
60
60
|
if async_params.key?('sessions') || async_params.key?('instance')
|
@@ -63,7 +63,7 @@ module Aspera
|
|
63
63
|
session_info = async_params['sessions'][0]
|
64
64
|
param_path = :args
|
65
65
|
end
|
66
|
-
|
66
|
+
ARGUMENTS_INFO.each do |info|
|
67
67
|
key_path = info[param_path].split('.')
|
68
68
|
hash_for_key = session_info
|
69
69
|
if key_path.length > 1
|
@@ -76,10 +76,11 @@ module Aspera
|
|
76
76
|
end
|
77
77
|
if !session_info.key?('name')
|
78
78
|
# if no name is specified, generate one from simple arguments
|
79
|
-
session_info['name'] =
|
80
|
-
arguments[arg_name]&.gsub(/[^a-zA-Z0-9]
|
81
|
-
end.reject(&:empty?).join('_')
|
79
|
+
session_info['name'] = ARGUMENTS_LIST.filter_map do |arg_name|
|
80
|
+
arguments[arg_name]&.gsub(/[^a-zA-Z0-9]+/, '_')
|
81
|
+
end.reject(&:empty?).join('_').gsub(/__+/, '_')
|
82
82
|
end
|
83
|
+
else raise Cli::BadArgument, "Provide 0 or 3 arguments, not #{arguments.keys.length} for: #{ARGUMENTS_LIST.join(', ')}"
|
83
84
|
end
|
84
85
|
end
|
85
86
|
|
@@ -100,7 +101,7 @@ module Aspera
|
|
100
101
|
when :status
|
101
102
|
sync_session_name = options.get_next_argument('name of sync session', mandatory: false, validation: String)
|
102
103
|
async_params = options.get_option(:sync_info, mandatory: true)
|
103
|
-
return
|
104
|
+
return Main.result_single_object(Transfer::Sync.admin_status(async_params, sync_session_name))
|
104
105
|
end
|
105
106
|
end
|
106
107
|
end
|
@@ -38,7 +38,7 @@ module Aspera
|
|
38
38
|
# @return :success if all sessions statuses returned by "start" are success
|
39
39
|
# else return the first error exception object
|
40
40
|
def session_status(statuses)
|
41
|
-
error_statuses = statuses.reject{|i|i.eql?(:success)}
|
41
|
+
error_statuses = statuses.reject{ |i| i.eql?(:success)}
|
42
42
|
return :success if error_statuses.empty?
|
43
43
|
return error_statuses.first
|
44
44
|
end
|
@@ -88,14 +88,6 @@ module Aspera
|
|
88
88
|
# add other transfer spec parameters
|
89
89
|
def option_transfer_spec_deep_merge(ts); @transfer_spec_command_line.deep_merge!(ts); end
|
90
90
|
|
91
|
-
# @return [Hash] transfer spec with updated values from command line, including removed values
|
92
|
-
def updated_ts(transfer_spec={})
|
93
|
-
transfer_spec.deep_merge!(@transfer_spec_command_line)
|
94
|
-
# recursively remove values that are nil (user wants to delete)
|
95
|
-
transfer_spec.deep_do { |hash, key, value, _unused| hash.delete(key) if value.nil?}
|
96
|
-
return transfer_spec
|
97
|
-
end
|
98
|
-
|
99
91
|
attr_reader :transfer_info
|
100
92
|
|
101
93
|
# multiple option are merged
|
@@ -173,9 +165,10 @@ module Aspera
|
|
173
165
|
|
174
166
|
# This is how the list of files to be transferred is specified
|
175
167
|
# get paths suitable for transfer spec from command line
|
168
|
+
# @param default [String] if set, used as default file for --sources=@args
|
176
169
|
# @return [Hash] {source: (mandatory), destination: (optional)}
|
177
170
|
# computation is done only once, cache is kept in @transfer_paths
|
178
|
-
def ts_source_paths
|
171
|
+
def ts_source_paths(default: nil)
|
179
172
|
# return cache if set
|
180
173
|
return @transfer_paths unless @transfer_paths.nil?
|
181
174
|
# start with lower priority : get paths from transfer spec on command line
|
@@ -185,8 +178,9 @@ module Aspera
|
|
185
178
|
case file_list
|
186
179
|
when nil, FILE_LIST_FROM_ARGS
|
187
180
|
Log.log.debug('getting file list as parameters')
|
181
|
+
Aspera.assert_type(default, Array) unless default.nil?
|
188
182
|
# get remaining arguments
|
189
|
-
file_list = @opt_mgr.get_next_argument('source file list', multiple: true)
|
183
|
+
file_list = @opt_mgr.get_next_argument('source file list', multiple: true, default: default)
|
190
184
|
raise Cli::BadArgument, 'specify at least one file on command line or use ' \
|
191
185
|
"--sources=#{FILE_LIST_FROM_TRANSFER_SPEC} to use transfer spec" if !file_list.is_a?(Array) || file_list.empty?
|
192
186
|
when FILE_LIST_FROM_TRANSFER_SPEC
|
@@ -199,7 +193,7 @@ module Aspera
|
|
199
193
|
return @transfer_paths
|
200
194
|
when Array
|
201
195
|
Log.log.debug('getting file list as extended value')
|
202
|
-
raise Cli::BadArgument, 'sources must be a Array of String' if !file_list.reject{|f|f.is_a?(String)}.empty?
|
196
|
+
raise Cli::BadArgument, 'sources must be a Array of String' if !file_list.reject{ |f| f.is_a?(String)}.empty?
|
203
197
|
else
|
204
198
|
raise Cli::BadArgument, "sources must be a Array, not #{file_list.class}"
|
205
199
|
end
|
@@ -211,10 +205,10 @@ module Aspera
|
|
211
205
|
case source_type
|
212
206
|
when :list
|
213
207
|
# when providing a list, just specify source
|
214
|
-
@transfer_paths = file_list.map{|i|{'source' => i}}
|
208
|
+
@transfer_paths = file_list.map{ |i| {'source' => i}}
|
215
209
|
when :pair
|
216
210
|
Aspera.assert(file_list.length.even?, exception_class: Cli::BadArgument){"When using pair, provide an even number of paths: #{file_list.length}"}
|
217
|
-
@transfer_paths = file_list.each_slice(2).to_a.map{|s, d|{'source' => s, 'destination' => d}}
|
211
|
+
@transfer_paths = file_list.each_slice(2).to_a.map{ |s, d| {'source' => s, 'destination' => d}}
|
218
212
|
else Aspera.error_unexpected_value(source_type)
|
219
213
|
end
|
220
214
|
Log.log.debug{"paths=#{@transfer_paths}"}
|
@@ -252,7 +246,9 @@ module Aspera
|
|
252
246
|
# update command line paths, unless destination already has one
|
253
247
|
@transfer_spec_command_line['paths'] = transfer_spec['paths'] || ts_source_paths
|
254
248
|
# updated transfer spec with command line
|
255
|
-
|
249
|
+
transfer_spec.deep_merge!(@transfer_spec_command_line)
|
250
|
+
# recursively remove values that are nil (user wants to delete)
|
251
|
+
transfer_spec.deep_do{ |hash, key, value, _unused| hash.delete(key) if value.nil?}
|
256
252
|
# if TS from app has content_protection (e.g. F5), that means content is protected: ask password if not provided
|
257
253
|
if transfer_spec['content_protection'].eql?('decrypt') && !transfer_spec.key?('content_protection_password')
|
258
254
|
transfer_spec['content_protection_password'] = @opt_mgr.prompt_user_input('content protection password', sensitive: true)
|
@@ -32,7 +32,7 @@ module Aspera
|
|
32
32
|
if @progress_bar.nil?
|
33
33
|
@progress_bar = ProgressBar.create(
|
34
34
|
format: '%t %a %B %p%% %r Mbps %E',
|
35
|
-
rate_scale: lambda{|rate|rate / Environment::BYTES_PER_MEBIBIT},
|
35
|
+
rate_scale: lambda{ |rate| rate / Environment::BYTES_PER_MEBIBIT},
|
36
36
|
title: '',
|
37
37
|
total: nil)
|
38
38
|
end
|
@@ -86,7 +86,7 @@ module Aspera
|
|
86
86
|
private
|
87
87
|
|
88
88
|
def total(key)
|
89
|
-
@sessions.values.inject(0){|m, s|m + s[key]}
|
89
|
+
@sessions.values.inject(0){ |m, s| m + s[key]}
|
90
90
|
end
|
91
91
|
end
|
92
92
|
end
|