aspera-cli 4.20.0 → 4.21.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/CHANGELOG.md +20 -2
- data/README.md +281 -156
- data/bin/asession +2 -2
- data/lib/aspera/agent/alpha.rb +7 -12
- data/lib/aspera/agent/connect.rb +19 -1
- data/lib/aspera/agent/direct.rb +20 -29
- data/lib/aspera/agent/node.rb +1 -11
- data/lib/aspera/agent/trsdk.rb +4 -25
- data/lib/aspera/api/aoc.rb +5 -0
- data/lib/aspera/api/node.rb +45 -28
- data/lib/aspera/ascp/installation.rb +69 -38
- data/lib/aspera/ascp/management.rb +27 -6
- data/lib/aspera/cli/formatter.rb +149 -141
- data/lib/aspera/cli/info.rb +1 -1
- data/lib/aspera/cli/manager.rb +1 -0
- data/lib/aspera/cli/plugin.rb +2 -2
- data/lib/aspera/cli/plugins/aoc.rb +27 -17
- data/lib/aspera/cli/plugins/config.rb +31 -21
- data/lib/aspera/cli/plugins/faspex.rb +1 -1
- data/lib/aspera/cli/plugins/faspex5.rb +11 -3
- data/lib/aspera/cli/plugins/node.rb +44 -38
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/command_line_builder.rb +1 -1
- data/lib/aspera/environment.rb +5 -6
- data/lib/aspera/node_simulator.rb +228 -112
- data/lib/aspera/oauth/base.rb +31 -42
- data/lib/aspera/oauth/factory.rb +41 -2
- data/lib/aspera/persistency_folder.rb +20 -2
- data/lib/aspera/preview/generator.rb +1 -1
- data/lib/aspera/preview/utils.rb +1 -1
- data/lib/aspera/products/alpha.rb +30 -0
- data/lib/aspera/products/connect.rb +48 -0
- data/lib/aspera/products/other.rb +82 -0
- data/lib/aspera/products/trsdk.rb +54 -0
- data/lib/aspera/rest.rb +18 -13
- data/lib/aspera/ssh.rb +28 -24
- data/lib/aspera/transfer/spec.yaml +22 -20
- data.tar.gz.sig +0 -0
- metadata +21 -4
- metadata.gz.sig +0 -0
- data/lib/aspera/ascp/products.rb +0 -168
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'aspera/environment'
|
4
|
+
|
5
|
+
module Aspera
|
6
|
+
module Products
|
7
|
+
class Connect
|
8
|
+
APP_NAME = 'IBM Aspera Connect'
|
9
|
+
class << self
|
10
|
+
# standard folder locations
|
11
|
+
def locations
|
12
|
+
case Aspera::Environment.os
|
13
|
+
when Aspera::Environment::OS_WINDOWS then [{
|
14
|
+
app_root: File.join(ENV.fetch('LOCALAPPDATA', nil), 'Programs', 'Aspera', 'Aspera Connect'),
|
15
|
+
log_root: File.join(ENV.fetch('LOCALAPPDATA', nil), 'Aspera', 'Aspera Connect', 'var', 'log'),
|
16
|
+
run_root: File.join(ENV.fetch('LOCALAPPDATA', nil), 'Aspera', 'Aspera Connect')
|
17
|
+
}]
|
18
|
+
when Aspera::Environment::OS_MACOS then [{
|
19
|
+
app_root: File.join(Dir.home, 'Applications', 'Aspera Connect.app'),
|
20
|
+
log_root: File.join(Dir.home, 'Library', 'Logs', 'Aspera_Connect'),
|
21
|
+
run_root: File.join(Dir.home, 'Library', 'Application Support', 'Aspera', 'Aspera Connect'),
|
22
|
+
sub_bin: File.join('Contents', 'Resources')
|
23
|
+
}, {
|
24
|
+
app_root: File.join('', 'Applications', 'Aspera Connect.app'),
|
25
|
+
log_root: File.join(Dir.home, 'Library', 'Logs', 'Aspera_Connect'),
|
26
|
+
run_root: File.join(Dir.home, 'Library', 'Application Support', 'Aspera', 'Aspera Connect'),
|
27
|
+
sub_bin: File.join('Contents', 'Resources')
|
28
|
+
}, {
|
29
|
+
app_root: File.join(Dir.home, 'Applications', 'IBM Aspera Connect.app'),
|
30
|
+
log_root: File.join(Dir.home, 'Library', 'Logs', 'Aspera_Connect'),
|
31
|
+
run_root: File.join(Dir.home, 'Library', 'Application Support', 'Aspera', 'Aspera Connect'),
|
32
|
+
sub_bin: File.join('Contents', 'Resources')
|
33
|
+
}, {
|
34
|
+
app_root: File.join('', 'Applications', 'IBM Aspera Connect.app'),
|
35
|
+
log_root: File.join(Dir.home, 'Library', 'Logs', 'Aspera_Connect'),
|
36
|
+
run_root: File.join(Dir.home, 'Library', 'Application Support', 'Aspera', 'Aspera Connect'),
|
37
|
+
sub_bin: File.join('Contents', 'Resources')
|
38
|
+
}]
|
39
|
+
else [{ # other: Linux and Unix family
|
40
|
+
app_root: File.join(Dir.home, '.aspera', 'connect'),
|
41
|
+
run_root: File.join(Dir.home, '.aspera', 'connect')
|
42
|
+
}]
|
43
|
+
end.map { |i| i.merge({ expected: APP_NAME }) }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# cspell:ignore LOCALAPPDATA
|
4
|
+
require 'aspera/environment'
|
5
|
+
|
6
|
+
module Aspera
|
7
|
+
# Location of Aspera products, for which an Agent is not proposed
|
8
|
+
module Products
|
9
|
+
# other Aspera products with ascp
|
10
|
+
class Other
|
11
|
+
CLI_V3 = 'Aspera CLI (deprecated)'
|
12
|
+
DRIVE = 'Aspera Drive (deprecated)'
|
13
|
+
HSTS = 'IBM Aspera High-Speed Transfer Server'
|
14
|
+
|
15
|
+
private_constant :CLI_V3, :DRIVE, :HSTS
|
16
|
+
# product information manifest: XML (part of aspera product)
|
17
|
+
INFO_META_FILE = 'product-info.mf'
|
18
|
+
|
19
|
+
# :expected M app name is taken from the manifest if present, else defaults to this value
|
20
|
+
# :app_root M main folder for the application
|
21
|
+
# :log_root O location of log files (Linux uses syslog)
|
22
|
+
# :run_root O only for Connect Client, location of http port file
|
23
|
+
# :sub_bin O subfolder with executables, default : bin
|
24
|
+
LOCATION_ON_THIS_OS = case Aspera::Environment.os
|
25
|
+
when Aspera::Environment::OS_WINDOWS then [{
|
26
|
+
expected: CLI_V3,
|
27
|
+
app_root: File.join('C:', 'Program Files', 'Aspera', 'cli'),
|
28
|
+
log_root: File.join('C:', 'Program Files', 'Aspera', 'cli', 'var', 'log')
|
29
|
+
}, {
|
30
|
+
expected: HSTS,
|
31
|
+
app_root: File.join('C:', 'Program Files', 'Aspera', 'Enterprise Server'),
|
32
|
+
log_root: File.join('C:', 'Program Files', 'Aspera', 'Enterprise Server', 'var', 'log')
|
33
|
+
}]
|
34
|
+
when Aspera::Environment::OS_MACOS then [{
|
35
|
+
expected: CLI_V3,
|
36
|
+
app_root: File.join(Dir.home, 'Applications', 'Aspera CLI'),
|
37
|
+
log_root: File.join(Dir.home, 'Library', 'Logs', 'Aspera')
|
38
|
+
}, {
|
39
|
+
expected: HSTS,
|
40
|
+
app_root: File.join('', 'Library', 'Aspera'),
|
41
|
+
log_root: File.join(Dir.home, 'Library', 'Logs', 'Aspera')
|
42
|
+
}, {
|
43
|
+
expected: DRIVE,
|
44
|
+
app_root: File.join('', 'Applications', 'Aspera Drive.app'),
|
45
|
+
log_root: File.join(Dir.home, 'Library', 'Logs', 'Aspera_Drive'),
|
46
|
+
sub_bin: File.join('Contents', 'Resources')
|
47
|
+
}]
|
48
|
+
else [{ # other: Linux and Unix family
|
49
|
+
expected: CLI_V3,
|
50
|
+
app_root: File.join(Dir.home, '.aspera', 'cli')
|
51
|
+
}, {
|
52
|
+
expected: HSTS,
|
53
|
+
app_root: File.join('', 'opt', 'aspera')
|
54
|
+
}]
|
55
|
+
end
|
56
|
+
class << self
|
57
|
+
def find(scan_locations)
|
58
|
+
scan_locations.select do |item|
|
59
|
+
# skip if not main folder
|
60
|
+
Log.log.trace1{"Checking #{item[:app_root]}"}
|
61
|
+
next false unless Dir.exist?(item[:app_root])
|
62
|
+
Log.log.debug{"Found #{item[:expected]}"}
|
63
|
+
sub_bin = item[:sub_bin] || 'bin'
|
64
|
+
item[:ascp_path] = File.join(item[:app_root], sub_bin, Environment.exe_file('ascp'))
|
65
|
+
# skip if no ascp
|
66
|
+
next false unless File.exist?(item[:ascp_path])
|
67
|
+
# read info from product info file if present
|
68
|
+
product_info_file = "#{item[:app_root]}/#{INFO_META_FILE}"
|
69
|
+
if File.exist?(product_info_file)
|
70
|
+
res_s = XmlSimple.xml_in(File.read(product_info_file), {'ForceArray' => false})
|
71
|
+
item[:name] = res_s['name']
|
72
|
+
item[:version] = res_s['version']
|
73
|
+
else
|
74
|
+
item[:name] = item[:expected]
|
75
|
+
end
|
76
|
+
true # select this version
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Aspera
|
4
|
+
module Products
|
5
|
+
class Trsdk
|
6
|
+
APP_NAME = 'IBM Aspera Transfer Daemon'
|
7
|
+
class << self
|
8
|
+
# standard folder locations
|
9
|
+
def locations
|
10
|
+
[{
|
11
|
+
app_root: sdk_directory,
|
12
|
+
sub_bin: ''
|
13
|
+
}].map { |i| i.merge({ expected: APP_NAME }) }
|
14
|
+
end
|
15
|
+
|
16
|
+
# location of SDK files
|
17
|
+
def sdk_directory=(v)
|
18
|
+
Log.log.debug{"sdk_directory=#{v}"}
|
19
|
+
@sdk_dir = v
|
20
|
+
sdk_directory
|
21
|
+
end
|
22
|
+
|
23
|
+
# @return the path to folder where SDK is installed
|
24
|
+
def sdk_directory
|
25
|
+
Aspera.assert(!@sdk_dir.nil?){'SDK path was not initialized'}
|
26
|
+
FileUtils.mkdir_p(@sdk_dir)
|
27
|
+
@sdk_dir
|
28
|
+
end
|
29
|
+
|
30
|
+
def transferd_path
|
31
|
+
return File.join(sdk_directory, Environment.exe_file('asperatransferd')) # cspell:disable-line
|
32
|
+
end
|
33
|
+
|
34
|
+
# Well, the port number is only in log file
|
35
|
+
def daemon_port_from_log(log_file)
|
36
|
+
result = nil
|
37
|
+
# if port is zero, a dynamic port was created, get it
|
38
|
+
File.open(log_file, 'r') do |file|
|
39
|
+
file.each_line do |line|
|
40
|
+
# Well, it's tricky to depend on log
|
41
|
+
if (m = line.match(/Info: API Server: Listening on ([^:]+):(\d+) /))
|
42
|
+
result = m[2].to_i
|
43
|
+
# no "break" , need to read last matching log line
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
raise 'Port not found in daemon logs' if result.nil?
|
48
|
+
Log.log.debug{"Got port #{result} from log"}
|
49
|
+
return result
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
data/lib/aspera/rest.rb
CHANGED
@@ -10,7 +10,6 @@ require 'net/http'
|
|
10
10
|
require 'net/https'
|
11
11
|
require 'json'
|
12
12
|
require 'base64'
|
13
|
-
require 'cgi'
|
14
13
|
require 'singleton'
|
15
14
|
require 'securerandom'
|
16
15
|
|
@@ -22,11 +21,13 @@ class Net::HTTP::Cancel < Net::HTTPRequest # rubocop:disable Style/ClassAndModul
|
|
22
21
|
end
|
23
22
|
|
24
23
|
module Aspera
|
25
|
-
# Global settings
|
24
|
+
# Global settings for Rest object
|
25
|
+
# For example to remove certificate verification globally:
|
26
|
+
# `RestParameters.instance.session_cb = lambda{|http|http.verify_mode=OpenSSL::SSL::VERIFY_NONE}`
|
26
27
|
# @param user_agent [String] HTTP request header: 'User-Agent'
|
27
28
|
# @param download_partial_suffix [String] suffix for partial download
|
28
29
|
# @param session_cb [lambda] lambda called on new HTTP session. Takes the Net::HTTP as arg. Used to change parameters on creation.
|
29
|
-
# @param progress_bar [Object] progress bar object
|
30
|
+
# @param progress_bar [Object] progress bar object called for file transfer
|
30
31
|
class RestParameters
|
31
32
|
include Singleton
|
32
33
|
|
@@ -200,6 +201,9 @@ module Aspera
|
|
200
201
|
}
|
201
202
|
end
|
202
203
|
|
204
|
+
# Create a REST object for API calls
|
205
|
+
# HTTP sessions parameters can be modified using global parameters in RestParameters
|
206
|
+
# For example, TLS verification can be skipped.
|
203
207
|
# @param base_url [String] base URL of REST API
|
204
208
|
# @param auth [Hash] authentication parameters:
|
205
209
|
# :type (:none, :basic, :url, :oauth2)
|
@@ -207,14 +211,15 @@ module Aspera
|
|
207
211
|
# :password [:basic]
|
208
212
|
# :url_query [:url] a hash
|
209
213
|
# :* [:oauth2] see OAuth::Factory class
|
210
|
-
# @param not_auth_codes [Array]
|
211
|
-
# @param redirect_max
|
214
|
+
# @param not_auth_codes [Array] codes that trigger a refresh/regeneration of bearer token
|
215
|
+
# @param redirect_max [Integer] max redirection allowed
|
216
|
+
# @param headers [Hash] default headers to include in all calls
|
212
217
|
def initialize(
|
213
218
|
base_url:,
|
214
|
-
auth:
|
215
|
-
not_auth_codes:
|
219
|
+
auth: {type: :none},
|
220
|
+
not_auth_codes: ['401'],
|
216
221
|
redirect_max: 0,
|
217
|
-
headers:
|
222
|
+
headers: {}
|
218
223
|
)
|
219
224
|
Aspera.assert_type(base_url, String)
|
220
225
|
# base url with no trailing slashes (note: string may be frozen)
|
@@ -224,20 +229,20 @@ module Aspera
|
|
224
229
|
@base_url = @base_url.gsub(/:80$/, '') if @base_url.start_with?('http://')
|
225
230
|
Log.log.debug{"Rest.new(#{@base_url})"}
|
226
231
|
# default is no auth
|
227
|
-
@auth_params = auth
|
232
|
+
@auth_params = auth
|
228
233
|
Aspera.assert_type(@auth_params, Hash)
|
229
234
|
Aspera.assert(@auth_params.key?(:type)){'no auth type defined'}
|
230
|
-
@not_auth_codes = not_auth_codes
|
235
|
+
@not_auth_codes = not_auth_codes
|
231
236
|
Aspera.assert_type(@not_auth_codes, Array)
|
232
237
|
# persistent session
|
233
238
|
@http_session = nil
|
234
|
-
# OAuth object (created on demand)
|
235
|
-
@oauth = nil
|
236
239
|
@redirect_max = redirect_max
|
237
240
|
Aspera.assert_type(@redirect_max, Integer)
|
238
|
-
@headers = headers
|
241
|
+
@headers = headers
|
239
242
|
Aspera.assert_type(@headers, Hash)
|
240
243
|
@headers['User-Agent'] ||= RestParameters.instance.user_agent
|
244
|
+
# OAuth object (created on demand)
|
245
|
+
@oauth = nil
|
241
246
|
end
|
242
247
|
|
243
248
|
# @return the OAuth object (create, or cached if already created)
|
data/lib/aspera/ssh.rb
CHANGED
@@ -1,33 +1,38 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'net/ssh'
|
4
|
-
|
5
|
-
if ENV.fetch('ASCLI_ENABLE_ED25519', 'false').eql?('false')
|
6
|
-
# HACK: deactivate ed25519 and ecdsa private keys from SSH identities, as it usually causes problems
|
7
|
-
old_verbose = $VERBOSE
|
8
|
-
$VERBOSE = nil
|
9
|
-
begin
|
10
|
-
module Net; module SSH; module Authentication; class Session; private; def default_keys; %w[~/.ssh/id_dsa ~/.ssh/id_rsa ~/.ssh2/id_dsa ~/.ssh2/id_rsa]; end; end; end; end; end # rubocop:disable Layout/AccessModifierIndentation, Layout/EmptyLinesAroundAccessModifier, Layout/LineLength, Style/Semicolon
|
11
|
-
rescue StandardError
|
12
|
-
# ignore errors
|
13
|
-
end
|
14
|
-
$VERBOSE = old_verbose
|
15
|
-
end
|
16
|
-
|
17
|
-
if defined?(JRUBY_VERSION) && ENV.fetch('ASCLI_ENABLE_ECDSHA2', 'false').eql?('false')
|
18
|
-
Net::SSH::Transport::Algorithms::ALGORITHMS.each_value { |a| a.reject! { |a| a =~ /^ecd(sa|h)-sha2/ } }
|
19
|
-
Net::SSH::KnownHosts::SUPPORTED_TYPE.reject! { |t| t =~ /^ecd(sa|h)-sha2/ }
|
20
|
-
end
|
4
|
+
require 'aspera/assert'
|
21
5
|
|
22
6
|
module Aspera
|
23
7
|
# A simple wrapper around Net::SSH
|
24
8
|
# executes one command and get its result from stdout
|
25
9
|
class Ssh
|
10
|
+
class << self
|
11
|
+
def disable_ed25519_keys
|
12
|
+
old_verbose = $VERBOSE
|
13
|
+
$VERBOSE = nil
|
14
|
+
Net::SSH::Authentication::Session.class_eval do
|
15
|
+
define_method(:default_keys) do
|
16
|
+
%w[~/.ssh/id_dsa ~/.ssh/id_rsa ~/.ssh2/id_dsa ~/.ssh2/id_rsa].freeze
|
17
|
+
end
|
18
|
+
private(:default_keys)
|
19
|
+
end rescue nil
|
20
|
+
$VERBOSE = old_verbose
|
21
|
+
end
|
22
|
+
|
23
|
+
def disable_ecd_sha2_algorithms
|
24
|
+
Net::SSH::Transport::Algorithms::ALGORITHMS.each_value { |a| a.reject! { |a| a =~ /^ecd(sa|h)-sha2/ } }
|
25
|
+
Net::SSH::KnownHosts::SUPPORTED_TYPE.reject! { |t| t =~ /^ecd(sa|h)-sha2/ }
|
26
|
+
end
|
27
|
+
end
|
26
28
|
# ssh_options: same as Net::SSH.start
|
27
29
|
# see: https://net-ssh.github.io/net-ssh/classes/Net/SSH.html#method-c-start
|
28
30
|
def initialize(host, username, ssh_options)
|
29
31
|
Log.log.debug{"ssh:#{username}@#{host}"}
|
30
32
|
Log.log.debug{"ssh_options:#{ssh_options}"}
|
33
|
+
Aspera.assert_type(host, String)
|
34
|
+
Aspera.assert_type(username, String)
|
35
|
+
Aspera.assert_type(ssh_options, Hash)
|
31
36
|
@host = host
|
32
37
|
@username = username
|
33
38
|
@ssh_options = ssh_options
|
@@ -35,10 +40,7 @@ module Aspera
|
|
35
40
|
end
|
36
41
|
|
37
42
|
def execute(cmd, input=nil)
|
38
|
-
|
39
|
-
# concatenate arguments, enclose in double quotes
|
40
|
-
cmd = cmd.map{|v|%Q("#{v}")}.join(' ')
|
41
|
-
end
|
43
|
+
Aspera.assert_type(cmd, String)
|
42
44
|
Log.log.debug{"cmd=#{cmd}"}
|
43
45
|
response = []
|
44
46
|
Net::SSH.start(@host, @username, @ssh_options) do |session|
|
@@ -49,9 +51,7 @@ module Aspera
|
|
49
51
|
channel.on_extended_data do |_chan, _type, data|
|
50
52
|
error_message = "#{cmd}: [#{data.chomp}]"
|
51
53
|
# Happens when windows user hasn't logged in and created home account.
|
52
|
-
if data.include?('Could not chdir to home directory')
|
53
|
-
error_message += "\nHint: home not created in Windows?"
|
54
|
-
end
|
54
|
+
error_message += "\nHint: home not created in Windows?" if data.include?('Could not chdir to home directory')
|
55
55
|
raise error_message
|
56
56
|
end
|
57
57
|
# send command to SSH channel (execute) cspell: disable-next-line
|
@@ -67,3 +67,7 @@ module Aspera
|
|
67
67
|
end
|
68
68
|
end
|
69
69
|
end
|
70
|
+
|
71
|
+
# HACK: deactivate ed25519 and ecdsa private keys from SSH identities, as it usually causes problems
|
72
|
+
Aspera::Ssh.disable_ed25519_keys if ENV.fetch('ASCLI_ENABLE_ED25519', 'false').eql?('false')
|
73
|
+
Aspera::Ssh.disable_ecd_sha2_algorithms if defined?(JRUBY_VERSION) && ENV.fetch('ASCLI_ENABLE_ECDSHA2', 'false').eql?('false')
|
@@ -1,13 +1,13 @@
|
|
1
|
-
# desc
|
2
|
-
# accepted_types
|
3
|
-
# default
|
4
|
-
# enum
|
5
|
-
# agents
|
6
|
-
# required
|
7
|
-
# cli.type
|
8
|
-
# cli.switch
|
9
|
-
# cli.convert
|
10
|
-
# cli.variable
|
1
|
+
# desc [String] description
|
2
|
+
# accepted_types [Symbol, Array(Symbol)] accepted types for non-enum
|
3
|
+
# default [String] default value if not specified
|
4
|
+
# enum [Array] set with list of values for enum types accepted in transfer spec
|
5
|
+
# agents [Array] supported agents (for doc only), if not specified: all
|
6
|
+
# required [bool] optional, default: false
|
7
|
+
# cli.type [Symbol] ascp: type of parameter, one of CLI_OPTION_TYPES (opt_without_arg opt_with_arg special ignore envvar)
|
8
|
+
# cli.switch [String] ascp: switch for ascp command line
|
9
|
+
# cli.convert [String] ascp: transform value: either a Hash with conversion values, or name of class
|
10
|
+
# cli.variable [String] ascp: name of env var
|
11
11
|
# cspell:words dgram dnat dnats faspmgr asperanoded xattrs keepalive datagram
|
12
12
|
---
|
13
13
|
cipher:
|
@@ -102,17 +102,13 @@ direction:
|
|
102
102
|
receive: recv
|
103
103
|
send: send
|
104
104
|
exclude_newer_than:
|
105
|
-
:desc:
|
106
|
-
:accepted_types: :
|
107
|
-
:agents:
|
108
|
-
- :direct
|
105
|
+
:desc: Exclude files, but not directories, from the transfer if they are newer than the specified number of seconds added to the source computer's epoch. e.g. "-86400" for newer than a day back.
|
106
|
+
:accepted_types: :string
|
109
107
|
:cli:
|
110
108
|
:type: :opt_with_arg
|
111
109
|
exclude_older_than:
|
112
|
-
:desc:
|
113
|
-
:accepted_types: :
|
114
|
-
:agents:
|
115
|
-
- :direct
|
110
|
+
:desc: Exclude files, but not directories, from the transfer if they are older than the specified number of seconds added to the source computer's epoch. e.g. "-86400" for older than a day back.
|
111
|
+
:accepted_types: :string
|
116
112
|
:cli:
|
117
113
|
:type: :opt_with_arg
|
118
114
|
fasp_port:
|
@@ -213,7 +209,6 @@ password:
|
|
213
209
|
Windows only, node api only.
|
214
210
|
|
215
211
|
|
216
|
-
:required: false
|
217
212
|
:accepted_types: :string
|
218
213
|
:agents:
|
219
214
|
- :node
|
@@ -419,7 +414,7 @@ symlink_policy:
|
|
419
414
|
:type: :opt_with_arg
|
420
415
|
:switch: "--symbolic-links"
|
421
416
|
tags:
|
422
|
-
:desc: Metadata for transfer as JSON
|
417
|
+
:desc: Metadata for transfer as JSON. Key `aspera` is reserved. Key `aspera.xfer_retry` specified a retry timeout for node api initiated transfers.
|
423
418
|
:accepted_types: :hash
|
424
419
|
:cli:
|
425
420
|
:type: :opt_with_arg
|
@@ -714,3 +709,10 @@ write_threads:
|
|
714
709
|
- :unknown
|
715
710
|
:cli:
|
716
711
|
:type: :ignore
|
712
|
+
xfer_max_retries:
|
713
|
+
:desc: maximum number of retries, for node API initiated transfers. Shall not exceed aspera.conf `transfer_manager_max_retries` (default 5).
|
714
|
+
:accepted_types: :int
|
715
|
+
:agents:
|
716
|
+
- :node
|
717
|
+
:cli:
|
718
|
+
:type: :ignore
|
data.tar.gz.sig
CHANGED
Binary file
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: aspera-cli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.
|
4
|
+
version: 4.21.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Laurent Martin
|
@@ -37,7 +37,7 @@ cert_chain:
|
|
37
37
|
eTf9kxhVM40wGQOECVNA8UsEEZHD48eF+csUYZtAJOF5oxTI8UyV9T/o6CgO0c9/
|
38
38
|
Gzz+Qm5ULOUcPiJLjSpaiTrkiIVYiDGnqNSr6R1Hb1c=
|
39
39
|
-----END CERTIFICATE-----
|
40
|
-
date: 2025-
|
40
|
+
date: 2025-02-26 00:00:00.000000000 Z
|
41
41
|
dependencies:
|
42
42
|
- !ruby/object:Gem::Dependency
|
43
43
|
name: blankslate
|
@@ -123,6 +123,20 @@ dependencies:
|
|
123
123
|
- - "~>"
|
124
124
|
- !ruby/object:Gem::Version
|
125
125
|
version: '7.0'
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: openssl
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
requirements:
|
130
|
+
- - "~>"
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
version: 3.3.0
|
133
|
+
type: :runtime
|
134
|
+
prerelease: false
|
135
|
+
version_requirements: !ruby/object:Gem::Requirement
|
136
|
+
requirements:
|
137
|
+
- - "~>"
|
138
|
+
- !ruby/object:Gem::Version
|
139
|
+
version: 3.3.0
|
126
140
|
- !ruby/object:Gem::Dependency
|
127
141
|
name: rainbow
|
128
142
|
requirement: !ruby/object:Gem::Requirement
|
@@ -426,7 +440,6 @@ files:
|
|
426
440
|
- lib/aspera/ascmd.rb
|
427
441
|
- lib/aspera/ascp/installation.rb
|
428
442
|
- lib/aspera/ascp/management.rb
|
429
|
-
- lib/aspera/ascp/products.rb
|
430
443
|
- lib/aspera/assert.rb
|
431
444
|
- lib/aspera/cli/basic_auth_plugin.rb
|
432
445
|
- lib/aspera/cli/error.rb
|
@@ -496,6 +509,10 @@ files:
|
|
496
509
|
- lib/aspera/preview/terminal.rb
|
497
510
|
- lib/aspera/preview/utils.rb
|
498
511
|
- lib/aspera/preview/video_error.png
|
512
|
+
- lib/aspera/products/alpha.rb
|
513
|
+
- lib/aspera/products/connect.rb
|
514
|
+
- lib/aspera/products/other.rb
|
515
|
+
- lib/aspera/products/trsdk.rb
|
499
516
|
- lib/aspera/proxy_auto_config.js
|
500
517
|
- lib/aspera/proxy_auto_config.rb
|
501
518
|
- lib/aspera/rest.rb
|
@@ -538,7 +555,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
538
555
|
requirements:
|
539
556
|
- - ">="
|
540
557
|
- !ruby/object:Gem::Version
|
541
|
-
version: '2.
|
558
|
+
version: '2.7'
|
542
559
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
543
560
|
requirements:
|
544
561
|
- - ">="
|
metadata.gz.sig
CHANGED
Binary file
|
data/lib/aspera/ascp/products.rb
DELETED
@@ -1,168 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# cspell:ignore LOCALAPPDATA
|
4
|
-
require 'aspera/environment'
|
5
|
-
|
6
|
-
module Aspera
|
7
|
-
module Ascp
|
8
|
-
# find Aspera standard products installation in standard paths
|
9
|
-
class Products
|
10
|
-
# known product names
|
11
|
-
CONNECT = 'IBM Aspera Connect'
|
12
|
-
ASPERA = 'IBM Aspera (Client)'
|
13
|
-
CLI_V1 = 'Aspera CLI (deprecated)'
|
14
|
-
DRIVE = 'Aspera Drive (deprecated)'
|
15
|
-
HSTS = 'IBM Aspera High-Speed Transfer Server'
|
16
|
-
# product information manifest: XML (part of aspera product)
|
17
|
-
INFO_META_FILE = 'product-info.mf'
|
18
|
-
BIN_SUBFOLDER = 'bin'
|
19
|
-
ETC_SUBFOLDER = 'etc'
|
20
|
-
VAR_RUN_SUBFOLDER = File.join('var', 'run')
|
21
|
-
|
22
|
-
@@found_products = nil # rubocop:disable Style/ClassVars
|
23
|
-
class << self
|
24
|
-
# @return product folders depending on OS fields
|
25
|
-
# :expected M app name is taken from the manifest if present, else defaults to this value
|
26
|
-
# :app_root M main folder for the application
|
27
|
-
# :log_root O location of log files (Linux uses syslog)
|
28
|
-
# :run_root O only for Connect Client, location of http port file
|
29
|
-
# :sub_bin O subfolder with executables, default : bin
|
30
|
-
def product_locations_on_current_os
|
31
|
-
result =
|
32
|
-
case Aspera::Environment.os
|
33
|
-
when Aspera::Environment::OS_WINDOWS then [{
|
34
|
-
expected: CONNECT,
|
35
|
-
app_root: File.join(ENV.fetch('LOCALAPPDATA', nil), 'Programs', 'Aspera', 'Aspera Connect'),
|
36
|
-
log_root: File.join(ENV.fetch('LOCALAPPDATA', nil), 'Aspera', 'Aspera Connect', 'var', 'log'),
|
37
|
-
run_root: File.join(ENV.fetch('LOCALAPPDATA', nil), 'Aspera', 'Aspera Connect')
|
38
|
-
}, {
|
39
|
-
expected: CLI_V1,
|
40
|
-
app_root: File.join('C:', 'Program Files', 'Aspera', 'cli'),
|
41
|
-
log_root: File.join('C:', 'Program Files', 'Aspera', 'cli', 'var', 'log')
|
42
|
-
}, {
|
43
|
-
expected: HSTS,
|
44
|
-
app_root: File.join('C:', 'Program Files', 'Aspera', 'Enterprise Server'),
|
45
|
-
log_root: File.join('C:', 'Program Files', 'Aspera', 'Enterprise Server', 'var', 'log')
|
46
|
-
}]
|
47
|
-
when Aspera::Environment::OS_MACOS then [{
|
48
|
-
expected: CONNECT,
|
49
|
-
app_root: File.join(Dir.home, 'Applications', 'Aspera Connect.app'),
|
50
|
-
log_root: File.join(Dir.home, 'Library', 'Logs', 'Aspera_Connect'),
|
51
|
-
run_root: File.join(Dir.home, 'Library', 'Application Support', 'Aspera', 'Aspera Connect'),
|
52
|
-
sub_bin: File.join('Contents', 'Resources')
|
53
|
-
}, {
|
54
|
-
expected: CONNECT,
|
55
|
-
app_root: File.join('', 'Applications', 'Aspera Connect.app'),
|
56
|
-
log_root: File.join(Dir.home, 'Library', 'Logs', 'Aspera_Connect'),
|
57
|
-
run_root: File.join(Dir.home, 'Library', 'Application Support', 'Aspera', 'Aspera Connect'),
|
58
|
-
sub_bin: File.join('Contents', 'Resources')
|
59
|
-
}, {
|
60
|
-
expected: CONNECT,
|
61
|
-
app_root: File.join(Dir.home, 'Applications', 'IBM Aspera Connect.app'),
|
62
|
-
log_root: File.join(Dir.home, 'Library', 'Logs', 'Aspera_Connect'),
|
63
|
-
run_root: File.join(Dir.home, 'Library', 'Application Support', 'Aspera', 'Aspera Connect'),
|
64
|
-
sub_bin: File.join('Contents', 'Resources')
|
65
|
-
}, {
|
66
|
-
expected: CONNECT,
|
67
|
-
app_root: File.join('', 'Applications', 'IBM Aspera Connect.app'),
|
68
|
-
log_root: File.join(Dir.home, 'Library', 'Logs', 'Aspera_Connect'),
|
69
|
-
run_root: File.join(Dir.home, 'Library', 'Application Support', 'Aspera', 'Aspera Connect'),
|
70
|
-
sub_bin: File.join('Contents', 'Resources')
|
71
|
-
}, {
|
72
|
-
expected: CLI_V1,
|
73
|
-
app_root: File.join(Dir.home, 'Applications', 'Aspera CLI'),
|
74
|
-
log_root: File.join(Dir.home, 'Library', 'Logs', 'Aspera')
|
75
|
-
}, {
|
76
|
-
expected: HSTS,
|
77
|
-
app_root: File.join('', 'Library', 'Aspera'),
|
78
|
-
log_root: File.join(Dir.home, 'Library', 'Logs', 'Aspera')
|
79
|
-
}, {
|
80
|
-
expected: DRIVE,
|
81
|
-
app_root: File.join('', 'Applications', 'Aspera Drive.app'),
|
82
|
-
log_root: File.join(Dir.home, 'Library', 'Logs', 'Aspera_Drive'),
|
83
|
-
sub_bin: File.join('Contents', 'Resources')
|
84
|
-
}, {
|
85
|
-
expected: ASPERA,
|
86
|
-
app_root: File.join('', 'Applications', 'IBM Aspera.app'),
|
87
|
-
log_root: File.join(Dir.home, 'Library', 'Logs', 'IBM Aspera'),
|
88
|
-
sub_bin: File.join('Contents', 'Resources', 'sdk', 'aspera', 'bin')
|
89
|
-
}]
|
90
|
-
else [{ # other: Linux and Unix family
|
91
|
-
expected: CONNECT,
|
92
|
-
app_root: File.join(Dir.home, '.aspera', 'connect'),
|
93
|
-
run_root: File.join(Dir.home, '.aspera', 'connect')
|
94
|
-
}, {
|
95
|
-
expected: CLI_V1,
|
96
|
-
app_root: File.join(Dir.home, '.aspera', 'cli')
|
97
|
-
}, {
|
98
|
-
expected: HSTS,
|
99
|
-
app_root: File.join('', 'opt', 'aspera')
|
100
|
-
}]
|
101
|
-
end
|
102
|
-
result # .each {|item| item.deep_do {|h, _k, _v, _m|h.freeze}}.freeze
|
103
|
-
end
|
104
|
-
|
105
|
-
# @return the list of installed products in format of product_locations_on_current_os
|
106
|
-
def installed_products
|
107
|
-
if @@found_products.nil?
|
108
|
-
scan_locations = product_locations_on_current_os.clone
|
109
|
-
# add SDK as first search path
|
110
|
-
scan_locations.unshift({
|
111
|
-
expected: 'SDK',
|
112
|
-
app_root: Installation.instance.sdk_folder,
|
113
|
-
sub_bin: ''
|
114
|
-
})
|
115
|
-
# search installed products: with ascp
|
116
|
-
@@found_products = scan_locations.select! do |item| # rubocop:disable Style/ClassVars
|
117
|
-
# skip if not main folder
|
118
|
-
next false unless Dir.exist?(item[:app_root])
|
119
|
-
Log.log.debug{"Found #{item[:app_root]}"}
|
120
|
-
sub_bin = item[:sub_bin] || BIN_SUBFOLDER
|
121
|
-
item[:ascp_path] = File.join(item[:app_root], sub_bin, ascp_filename)
|
122
|
-
# skip if no ascp
|
123
|
-
next false unless File.exist?(item[:ascp_path])
|
124
|
-
# read info from product info file if present
|
125
|
-
product_info_file = "#{item[:app_root]}/#{INFO_META_FILE}"
|
126
|
-
if File.exist?(product_info_file)
|
127
|
-
res_s = XmlSimple.xml_in(File.read(product_info_file), {'ForceArray' => false})
|
128
|
-
item[:name] = res_s['name']
|
129
|
-
item[:version] = res_s['version']
|
130
|
-
else
|
131
|
-
item[:name] = item[:expected]
|
132
|
-
end
|
133
|
-
true # select this version
|
134
|
-
end
|
135
|
-
end
|
136
|
-
return @@found_products
|
137
|
-
end
|
138
|
-
|
139
|
-
# filename for ascp with optional extension (Windows)
|
140
|
-
def ascp_filename
|
141
|
-
return "ascp#{Environment.exe_extension}"
|
142
|
-
end
|
143
|
-
|
144
|
-
# @return folder paths for specified applications
|
145
|
-
# @param name Connect or CLI
|
146
|
-
def folders(name)
|
147
|
-
found = Products.installed_products.select{|i|i[:expected].eql?(name) || i[:name].eql?(name)}
|
148
|
-
raise "Product: #{name} not found, please install." if found.empty?
|
149
|
-
return found.first
|
150
|
-
end
|
151
|
-
|
152
|
-
# @return the file path of local connect where API's URI can be read
|
153
|
-
def connect_uri
|
154
|
-
connect = folders(CONNECT)
|
155
|
-
folder = File.join(connect[:run_root], VAR_RUN_SUBFOLDER)
|
156
|
-
['', 's'].each do |ext|
|
157
|
-
uri_file = File.join(folder, "http#{ext}.uri")
|
158
|
-
Log.log.debug{"checking connect port file: #{uri_file}"}
|
159
|
-
if File.exist?(uri_file)
|
160
|
-
return File.open(uri_file, &:gets).strip
|
161
|
-
end
|
162
|
-
end
|
163
|
-
raise "no connect uri file found in #{folder}"
|
164
|
-
end
|
165
|
-
end
|
166
|
-
end
|
167
|
-
end
|
168
|
-
end
|