aspera-cli 4.24.0 → 4.24.1
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 +5 -0
- data/README.md +538 -524
- data/lib/aspera/cli/main.rb +1 -1
- data/lib/aspera/cli/plugins/config.rb +14 -1
- data/lib/aspera/cli/plugins/faspex5.rb +2 -2
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/cli/wizard.rb +10 -13
- data/lib/aspera/environment.rb +4 -3
- data/lib/aspera/log.rb +53 -30
- data/lib/aspera/sync/operations.rb +58 -61
- data.tar.gz.sig +0 -0
- metadata +2 -2
- metadata.gz.sig +0 -0
data/lib/aspera/cli/main.rb
CHANGED
@@ -378,7 +378,7 @@ module Aspera
|
|
378
378
|
:invalid_characters, 'Replacement character and invalid filename characters',
|
379
379
|
handler: {o: Environment.instance, m: :file_illegal_characters}
|
380
380
|
)
|
381
|
-
@context.options.declare(:log_level, 'Log level', values: Log
|
381
|
+
@context.options.declare(:log_level, 'Log level', values: Log::LEVELS, handler: {o: Log.instance, m: :level})
|
382
382
|
@context.options.declare(:log_format, 'Log formatter', types: [Proc, Logger::Formatter, String], handler: {o: Log.instance, m: :formatter})
|
383
383
|
@context.options.declare(:logger, 'Logging method', values: Log::LOG_TYPES, handler: {o: Log.instance, m: :logger_type})
|
384
384
|
@context.options.declare(:lock_port, 'Prevent dual execution of a command, e.g. in cron', coerce: Integer, types: Integer)
|
@@ -473,6 +473,19 @@ module Aspera
|
|
473
473
|
return result
|
474
474
|
end
|
475
475
|
|
476
|
+
def defaults_set(plugin_name, preset_name, preset_values, option_default, option_override)
|
477
|
+
@config_presets[CONF_PRESET_DEFAULTS] ||= {}
|
478
|
+
raise Cli::Error, "A default configuration already exists for plugin '#{plugin_name}' (use --override=yes or --default=no)" \
|
479
|
+
if !option_override && option_default && @config_presets[CONF_PRESET_DEFAULTS].key?(plugin_name)
|
480
|
+
raise Cli::Error, "Preset already exists: #{preset_name} (use --override=yes or provide alternate name on command line)" \
|
481
|
+
if !option_override && @config_presets.key?(preset_name)
|
482
|
+
if option_default
|
483
|
+
formatter.display_status("Setting config preset as default for #{plugin_name}")
|
484
|
+
@config_presets[CONF_PRESET_DEFAULTS][plugin_name.to_s] = preset_name
|
485
|
+
end
|
486
|
+
@config_presets[preset_name] = preset_values
|
487
|
+
end
|
488
|
+
|
476
489
|
def set_preset_key(preset, param_name, param_value)
|
477
490
|
Aspera.assert_values(param_name.class, [String, Symbol]){'parameter'}
|
478
491
|
param_name = param_name.to_s
|
@@ -505,9 +518,9 @@ module Aspera
|
|
505
518
|
attr_reader :gem_url
|
506
519
|
attr_accessor :option_config_file
|
507
520
|
|
508
|
-
# @return the hash from name (also expands possible includes)
|
509
521
|
# @param config_name name of the preset in config file
|
510
522
|
# @param include_path used to detect and avoid include loops
|
523
|
+
# @return copy of the hash from name (also expands possible includes)
|
511
524
|
def preset_by_name(config_name, include_path = [])
|
512
525
|
raise Cli::Error, 'loop in include' if include_path.include?(config_name)
|
513
526
|
include_path = include_path.clone # avoid messing up if there are multiple branches
|
@@ -113,13 +113,13 @@ module Aspera
|
|
113
113
|
raise "Username shall be an email in Faspex: #{wiz_username}" if !(wiz_username =~ /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i)
|
114
114
|
if options.get_option(:client_id).nil? || options.get_option(:client_secret).nil?
|
115
115
|
formatter.display_status('Ask the ascli client id and secret to your Administrator.'.red)
|
116
|
-
formatter.display_status("
|
116
|
+
formatter.display_status("Log in as an admin user at: #{instance_url}")
|
117
117
|
Environment.instance.open_uri(instance_url)
|
118
118
|
formatter.display_status('Navigate to: 𓃑 → Admin → Configurations → API clients')
|
119
119
|
formatter.display_status('Create an API client with:')
|
120
120
|
formatter.display_status('- name: ascli')
|
121
121
|
formatter.display_status('- JWT: enabled')
|
122
|
-
formatter.display_status("
|
122
|
+
formatter.display_status("Log in as user #{wiz_username.red}. Navigate to your profile:")
|
123
123
|
formatter.display_status('👤 → Account Settings → Preferences → Public Key in PEM:')
|
124
124
|
formatter.display_status(pub_key_pem)
|
125
125
|
formatter.display_status('Once set, fill in the parameters:')
|
data/lib/aspera/cli/version.rb
CHANGED
data/lib/aspera/cli/wizard.rb
CHANGED
@@ -28,6 +28,10 @@ module Aspera
|
|
28
28
|
@parent.formatter
|
29
29
|
end
|
30
30
|
|
31
|
+
def config
|
32
|
+
@parent.config
|
33
|
+
end
|
34
|
+
|
31
35
|
# Find a plugin, and issue the "require"
|
32
36
|
# @return [Hash] plugin info: { product:, name:, url:, version: }
|
33
37
|
def identify_plugins_for_url
|
@@ -68,6 +72,8 @@ module Aspera
|
|
68
72
|
return found_apps
|
69
73
|
end
|
70
74
|
|
75
|
+
# Wizard function, creates configuration
|
76
|
+
# @param apps [Array] list of detected apps
|
71
77
|
def find(apps)
|
72
78
|
identification = if apps.length.eql?(1)
|
73
79
|
Log.log.debug{"Detected: #{identification}"}
|
@@ -101,7 +107,7 @@ module Aspera
|
|
101
107
|
private_key_path = options.get_option(:key_path)
|
102
108
|
# give a chance to provide
|
103
109
|
if private_key_path.nil?
|
104
|
-
formatter.display_status('
|
110
|
+
formatter.display_status('Path to private RSA key (leave empty to generate):')
|
105
111
|
private_key_path = options.get_option(:key_path, mandatory: true).to_s
|
106
112
|
end
|
107
113
|
# else generate path
|
@@ -138,20 +144,11 @@ module Aspera
|
|
138
144
|
# Write configuration file
|
139
145
|
formatter.display_status("Preparing preset: #{wiz_preset_name}")
|
140
146
|
# init defaults if necessary
|
141
|
-
@config_presets[CONF_PRESET_DEFAULTS] ||= {}
|
142
147
|
option_override = options.get_option(:override, mandatory: true)
|
143
|
-
|
144
|
-
|
145
|
-
raise Cli::Error, "Preset already exists: #{wiz_preset_name} (use --override=yes or --id=<name>)" \
|
146
|
-
if !option_override && @config_presets.key?(wiz_preset_name)
|
147
|
-
@config_presets[wiz_preset_name] = wizard_result[:preset_value].stringify_keys
|
148
|
+
option_default = options.get_option(:default, mandatory: true)
|
149
|
+
config.defaults_set(identification[:product], wiz_preset_name, wizard_result[:preset_value].stringify_keys, option_default, option_override)
|
148
150
|
test_args = wizard_result[:test_args]
|
149
|
-
|
150
|
-
formatter.display_status("Setting config preset as default for #{identification[:product]}")
|
151
|
-
@config_presets[CONF_PRESET_DEFAULTS][identification[:product].to_s] = wiz_preset_name
|
152
|
-
else
|
153
|
-
test_args = "-P#{wiz_preset_name} #{test_args}"
|
154
|
-
end
|
151
|
+
test_args = "-P#{wiz_preset_name} #{test_args}" unless option_default
|
155
152
|
# TODO: actually test the command
|
156
153
|
return Main.result_status("You can test with:\n#{Info::CMD_NAME} #{identification[:product]} #{test_args}")
|
157
154
|
end
|
data/lib/aspera/environment.rb
CHANGED
@@ -311,11 +311,12 @@ module Aspera
|
|
311
311
|
# @return [String] A file name safe to use on file system
|
312
312
|
def sanitized_filename(filename)
|
313
313
|
safe_char = safe_filename_character
|
314
|
-
# Windows does not allow file name
|
315
|
-
#
|
314
|
+
# Windows does not allow file name:
|
315
|
+
# - with control characters anywhere
|
316
|
+
# - ending with space or dot
|
316
317
|
filename = filename
|
317
|
-
.gsub(/[\. ]+$/, safe_char)
|
318
318
|
.gsub(/[\x00-\x1F\x7F]/, safe_char)
|
319
|
+
.sub(/[. ]+\z/, safe_char)
|
319
320
|
if @file_illegal_characters&.size.to_i >= 2
|
320
321
|
# replace all illegal characters with safe_char
|
321
322
|
filename = filename.tr(@file_illegal_characters[1..-1], safe_char)
|
data/lib/aspera/log.rb
CHANGED
@@ -17,12 +17,17 @@ $VERBOSE = nil
|
|
17
17
|
class Logger
|
18
18
|
# Two additionnal trace levels
|
19
19
|
TRACE_MAX = 2
|
20
|
+
|
20
21
|
# Add custom level to logger severity, below debug level
|
21
22
|
module Severity
|
22
23
|
1.upto(TRACE_MAX).each{ |level| const_set(:"TRACE#{level}", - level)}
|
23
24
|
end
|
24
|
-
|
25
|
+
|
26
|
+
# Hash : key: log level int, value: uppercase log level label
|
25
27
|
SEVERITY_LABEL = Severity.constants.each_with_object({}){ |name, hash| hash[Severity.const_get(name)] = name}
|
28
|
+
|
29
|
+
# @param severity [Integer] Log severity as int
|
30
|
+
# @return [String] Log severity upper case label
|
26
31
|
def format_severity(severity)
|
27
32
|
SEVERITY_LABEL[severity] || 'ANY'
|
28
33
|
end
|
@@ -51,34 +56,23 @@ module Aspera
|
|
51
56
|
|
52
57
|
# Where logs are sent to
|
53
58
|
LOG_TYPES = %i[stderr stdout syslog].freeze
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
}.freeze
|
59
|
+
|
60
|
+
# Levels are :trace2,:trace1,:debug,:info,:warn,:error,fatal,:unknown
|
61
|
+
LEVELS = Logger::Severity.constants.sort{ |a, b| Logger::Severity.const_get(a) <=> Logger::Severity.const_get(b)}.map{ |c| c.downcase.to_sym}.freeze
|
62
|
+
|
59
63
|
# Class methods
|
60
64
|
class << self
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
when :INFO then 'INF'.green
|
67
|
-
when :WARN then 'WRN'.bg_brown.black
|
68
|
-
when :ERROR then 'ERR'.bg_red.blink
|
69
|
-
when :FATAL then 'FTL'.magenta
|
70
|
-
when :UNKNOWN then 'UKN'.blink
|
71
|
-
else Aspera.error_unexpected_value(level){'log level'}
|
72
|
-
end
|
65
|
+
# Applies the provided list of string decoration (colors) to the value.
|
66
|
+
# @param value [String] Value to enhance.
|
67
|
+
# @param colors [Array(Symbol)] List of decorations
|
68
|
+
def apply_colors(value, colors)
|
69
|
+
colors.inject(value){ |s, c| s.send(c)}
|
73
70
|
end
|
74
71
|
|
75
|
-
#
|
76
|
-
def levels; Logger::Severity.constants.sort{ |a, b| Logger::Severity.const_get(a) <=> Logger::Severity.const_get(b)}.map{ |c| c.downcase.to_sym}; end
|
77
|
-
|
78
|
-
# get the logger object of singleton
|
72
|
+
# Get the logger object of singleton
|
79
73
|
def log; instance.logger; end
|
80
74
|
|
81
|
-
# Dump object (`Hash`) using specified level
|
75
|
+
# Dump object (`Hash`) to log using specified level
|
82
76
|
#
|
83
77
|
# @param name [String, Symbol] Name of object dumped
|
84
78
|
# @param object [Hash, nil] Data to dump
|
@@ -90,14 +84,16 @@ module Aspera
|
|
90
84
|
instance.logger.send(level, obj_dump(name, object))
|
91
85
|
end
|
92
86
|
|
87
|
+
# @return [String] Dump of object
|
93
88
|
def obj_dump(name, object)
|
94
|
-
dump_text =
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
89
|
+
dump_text =
|
90
|
+
case instance.dump_format
|
91
|
+
when :json
|
92
|
+
JSON.pretty_generate(object) rescue PP.pp(object, +'')
|
93
|
+
when :ruby
|
94
|
+
PP.pp(object, +'')
|
95
|
+
else error_unexpected_value(instance.dump_format){'dump format'}
|
96
|
+
end
|
101
97
|
"#{name.to_s.green} (#{instance.dump_format})=\n#{dump_text}"
|
102
98
|
end
|
103
99
|
|
@@ -121,6 +117,7 @@ module Aspera
|
|
121
117
|
end
|
122
118
|
|
123
119
|
# Set log level of underlying logger given symbol level
|
120
|
+
# @param new_level [Symbol] One of LEVELS
|
124
121
|
def level=(new_level)
|
125
122
|
@logger.level = Logger::Severity.const_get(new_level.to_sym.upcase)
|
126
123
|
end
|
@@ -141,6 +138,7 @@ module Aspera
|
|
141
138
|
end
|
142
139
|
|
143
140
|
# Get symbol of debug level of underlying logger
|
141
|
+
# @return [Symbol] One of LEVELS
|
144
142
|
def level
|
145
143
|
Logger::Severity.constants.each do |name|
|
146
144
|
return name.downcase.to_sym if @logger.level.eql?(Logger::Severity.const_get(name))
|
@@ -188,5 +186,30 @@ module Aspera
|
|
188
186
|
# This sets @logger and @logger_type (self needed to call method instead of local var)
|
189
187
|
self.logger_type = @logger_type
|
190
188
|
end
|
189
|
+
|
190
|
+
# Define decoration of levels
|
191
|
+
LVL_DECO = {
|
192
|
+
TRACE2: %i{dim},
|
193
|
+
TRACE1: %i{blue},
|
194
|
+
DEBUG: %i{cyan},
|
195
|
+
INFO: %i{green},
|
196
|
+
WARN: %i{bg_brown black},
|
197
|
+
ERROR: %i{bg_red blink},
|
198
|
+
FATAL: %i{magenta},
|
199
|
+
UNKNOWN: %i{blink}
|
200
|
+
}.freeze
|
201
|
+
|
202
|
+
# Short levels with color
|
203
|
+
LVL_COLOR = LVL_DECO.map{ |k, v| [k, apply_colors("#{k[..2]}#{k[-1]}", v)]}.to_h.freeze
|
204
|
+
|
205
|
+
DEFAULT_FORMATTER = ->(s, _d, _p, m){"#{LVL_COLOR[s]} #{m}\n"}
|
206
|
+
|
207
|
+
# pre-defined formatters
|
208
|
+
FORMATTERS = {
|
209
|
+
standard: Logger::Formatter.new,
|
210
|
+
default: DEFAULT_FORMATTER
|
211
|
+
}.freeze
|
212
|
+
|
213
|
+
private_constant :LVL_DECO, :LVL_COLOR, :DEFAULT_FORMATTER, :FORMATTERS
|
191
214
|
end
|
192
215
|
end
|
@@ -25,19 +25,19 @@ module Aspera
|
|
25
25
|
|
26
26
|
class << self
|
27
27
|
# Set `remote_dir` in sync parameters based on transfer spec
|
28
|
-
# @param params [Hash]
|
28
|
+
# @param params [Hash] Sync parameters, old or new format
|
29
29
|
# @param remote_dir_key [String] key to update in above hash
|
30
30
|
# @param transfer_spec [Hash] transfer spec
|
31
|
-
def update_remote_dir(
|
31
|
+
def update_remote_dir(params, remote_dir_key, transfer_spec)
|
32
32
|
if transfer_spec.dig(*%w[tags aspera node file_id])
|
33
33
|
# in AoC, use gen4
|
34
|
-
|
34
|
+
params[remote_dir_key] = '/'
|
35
35
|
elsif transfer_spec['cookie']&.start_with?('aspera.shares2')
|
36
36
|
# TODO : something more generic, independent of Shares
|
37
37
|
# in Shares, the actual folder on remote end is not always the same as the name of the share
|
38
38
|
remote_key = transfer_spec['direction'].eql?('send') ? 'destination' : 'source'
|
39
39
|
actual_remote = transfer_spec['paths']&.first&.[](remote_key)
|
40
|
-
|
40
|
+
params[remote_dir_key] = actual_remote if actual_remote
|
41
41
|
end
|
42
42
|
nil
|
43
43
|
end
|
@@ -70,34 +70,36 @@ module Aspera
|
|
70
70
|
end
|
71
71
|
|
72
72
|
# Get symbol of sync direction, defaulting to :push
|
73
|
-
# @param params [Hash]
|
73
|
+
# @param params [Hash] Sync parameters, old or new format
|
74
74
|
# @return [Symbol] direction symbol, one of :push, :pull, :bidi
|
75
75
|
def direction_sym(params)
|
76
76
|
(params['direction'] || DEFAULT_DIRECTION).to_sym
|
77
77
|
end
|
78
78
|
|
79
79
|
# Start the sync process
|
80
|
-
# @param
|
80
|
+
# @param params [Hash] Sync parameters, old or new format
|
81
|
+
# @param opt_ts [Hash] Optional transfer spec
|
81
82
|
# @param &block [nil, Proc] block to generate transfer spec, takes: direction (one of DIRECTIONS), local_dir, remote_dir
|
82
|
-
def start(
|
83
|
-
Log.dump(:sync_params_initial,
|
84
|
-
Aspera.assert_type(
|
83
|
+
def start(params, opt_ts = nil)
|
84
|
+
Log.dump(:sync_params_initial, params)
|
85
|
+
Aspera.assert_type(params, Hash)
|
86
|
+
Aspera.assert(PARAM_KEYS.any?{ |k| params.key?(k)}, type: Error){'At least one of `local` or `sessions` must be present in async parameters'}
|
85
87
|
env_args = {
|
86
88
|
args: [],
|
87
89
|
env: {}
|
88
90
|
}
|
89
|
-
if
|
91
|
+
if params.key?('local')
|
90
92
|
# "conf" format
|
91
|
-
Aspera.assert_type(
|
92
|
-
remote =
|
93
|
+
Aspera.assert_type(params['local'], Hash){'local'}
|
94
|
+
remote = params['remote']
|
93
95
|
Aspera.assert_type(remote, Hash){'remote'}
|
94
96
|
Aspera.assert_type(remote['path'], String){'remote path'}
|
95
97
|
# get transfer spec if possible, and feed back to new structure
|
96
98
|
if block_given?
|
97
|
-
transfer_spec = yield(direction_sym(
|
99
|
+
transfer_spec = yield(direction_sym(params), params['local']['path'], remote['path'])
|
98
100
|
Log.dump(:auth_ts, transfer_spec)
|
99
101
|
transfer_spec.deep_merge!(opt_ts) unless opt_ts.nil?
|
100
|
-
tspec_to_sync_info(transfer_spec,
|
102
|
+
tspec_to_sync_info(transfer_spec, params, CONF_SCHEMA)
|
101
103
|
update_remote_dir(remote, 'path', transfer_spec)
|
102
104
|
end
|
103
105
|
remote['connect_mode'] ||= transfer_spec['wss_enabled'] ? 'ws' : 'ssh'
|
@@ -107,18 +109,18 @@ module Aspera
|
|
107
109
|
remote['private_key_paths'].concat(add_certificates)
|
108
110
|
end
|
109
111
|
# '--exclusive-mgmt-port=12345', '--arg-err-path=-',
|
110
|
-
env_args[:args] = ["--conf64=#{Base64.strict_encode64(JSON.generate(
|
111
|
-
Log.dump(:sync_conf,
|
112
|
+
env_args[:args] = ["--conf64=#{Base64.strict_encode64(JSON.generate(params))}"]
|
113
|
+
Log.dump(:sync_conf, params)
|
112
114
|
agent = Agent::Direct.new
|
113
115
|
agent.start_and_monitor_process(session: {}, name: :async, **env_args)
|
114
|
-
|
116
|
+
else
|
115
117
|
# "args" format
|
116
118
|
raise StandardError, "Only 'sessions', and optionally 'instance' keys are allowed" unless
|
117
|
-
|
118
|
-
Aspera.assert_type(
|
119
|
-
Aspera.assert_type(
|
119
|
+
params.keys.push('instance').uniq.sort.eql?(CMDLINE_PARAMS_KEYS)
|
120
|
+
Aspera.assert_type(params['sessions'], Array)
|
121
|
+
Aspera.assert_type(params['sessions'].first, Hash)
|
120
122
|
if block_given?
|
121
|
-
|
123
|
+
params['sessions'].each do |session|
|
122
124
|
Aspera.assert_type(session['local_dir'], String){'local_dir'}
|
123
125
|
Aspera.assert_type(session['remote_dir'], String){'remote_dir'}
|
124
126
|
transfer_spec = yield(direction_sym(session), session['local_dir'], session['remote_dir'])
|
@@ -129,13 +131,13 @@ module Aspera
|
|
129
131
|
update_remote_dir(session, 'remote_dir', transfer_spec)
|
130
132
|
end
|
131
133
|
end
|
132
|
-
if
|
133
|
-
Aspera.assert_type(
|
134
|
-
instance_builder = CommandLineBuilder.new(
|
134
|
+
if params.key?('instance')
|
135
|
+
Aspera.assert_type(params['instance'], Hash)
|
136
|
+
instance_builder = CommandLineBuilder.new(params['instance'], INSTANCE_SCHEMA, CommandLineConverter)
|
135
137
|
instance_builder.process_params
|
136
138
|
instance_builder.add_env_args(env_args)
|
137
139
|
end
|
138
|
-
|
140
|
+
params['sessions'].each do |session_params|
|
139
141
|
Aspera.assert_type(session_params, Hash)
|
140
142
|
Aspera.assert(session_params.key?('name')){'session must contain at least: name'}
|
141
143
|
session_builder = CommandLineBuilder.new(session_params, SESSION_SCHEMA, CommandLineConverter)
|
@@ -143,8 +145,6 @@ module Aspera
|
|
143
145
|
session_builder.add_env_args(env_args)
|
144
146
|
end
|
145
147
|
Environment.secure_execute(exec: Ascp::Installation.instance.path(:async), **env_args)
|
146
|
-
else
|
147
|
-
raise Error, 'At least one of `local` or `sessions` must be present in async parameters'
|
148
148
|
end
|
149
149
|
return
|
150
150
|
end
|
@@ -168,23 +168,24 @@ module Aspera
|
|
168
168
|
end
|
169
169
|
|
170
170
|
# Run `asyncadmin` to get status of sync session
|
171
|
-
# @param
|
171
|
+
# @param params [Hash] sync parameters in conf or args format
|
172
172
|
# @return [Hash] parsed output of asyncadmin
|
173
|
-
def admin_status(
|
173
|
+
def admin_status(params)
|
174
|
+
Aspera.assert(PARAM_KEYS.any?{ |k| params.key?(k)}, type: Error){'At least one of `local` or `sessions` must be present in async parameters'}
|
174
175
|
arguments = ['--quiet']
|
175
|
-
if
|
176
|
+
if params.key?('local')
|
176
177
|
# "conf" format
|
177
|
-
arguments.push("--name=#{
|
178
|
-
if
|
179
|
-
arguments.push("--local-db-dir=#{
|
180
|
-
elsif
|
181
|
-
arguments.push("--local-dir=#{
|
178
|
+
arguments.push("--name=#{params['name']}")
|
179
|
+
if params.key?('local_db_dir')
|
180
|
+
arguments.push("--local-db-dir=#{params['local_db_dir']}")
|
181
|
+
elsif params.dig('local', 'path')
|
182
|
+
arguments.push("--local-dir=#{params.dig('local', 'path')}")
|
182
183
|
else
|
183
184
|
raise Error, 'Missing either local_db_dir or local.path'
|
184
185
|
end
|
185
|
-
|
186
|
+
else
|
186
187
|
# "args" format
|
187
|
-
session =
|
188
|
+
session = params['sessions'].first
|
188
189
|
arguments.push("--name=#{session['name']}")
|
189
190
|
if session.key?('local_db_dir')
|
190
191
|
arguments.push("--local-db-dir=#{session['local_db_dir']}")
|
@@ -193,30 +194,28 @@ module Aspera
|
|
193
194
|
else
|
194
195
|
raise Error, 'Missing either local_db_dir or local_dir'
|
195
196
|
end
|
196
|
-
else
|
197
|
-
raise Error, 'At least one of `local` or `sessions` must be present in async parameters'
|
198
197
|
end
|
199
198
|
stdout = Environment.secure_capture(exec: ASYNC_ADMIN_EXECUTABLE, args: arguments)
|
200
199
|
return parse_status(stdout)
|
201
200
|
end
|
202
201
|
|
203
|
-
# Find the local database folder based on
|
204
|
-
# @param
|
205
|
-
# @param exception [Bool] Raise exception in case of problem, else return nil
|
202
|
+
# Find the local database folder based on params
|
203
|
+
# @param params [Hash] sync parameters in conf or args format
|
206
204
|
# @return [String, nil] path to "local DB dir", i.e. folder that contains folders that contain snap.db
|
207
|
-
def local_db_folder(
|
208
|
-
|
205
|
+
def local_db_folder(params)
|
206
|
+
Aspera.assert(PARAM_KEYS.any?{ |k| params.key?(k)}, type: Error){'At least one of `local` or `sessions` must be present in async parameters'}
|
207
|
+
if params.key?('local')
|
209
208
|
# "conf" format
|
210
|
-
if
|
211
|
-
return
|
212
|
-
elsif (local_path =
|
209
|
+
if params.key?('local_db_dir')
|
210
|
+
return params['local_db_dir']
|
211
|
+
elsif (local_path = params.dig('local', 'path'))
|
213
212
|
return local_path
|
214
213
|
elsif exception
|
215
214
|
raise Error, 'Missing either local_db_dir or local.path'
|
216
215
|
end
|
217
|
-
|
216
|
+
else
|
218
217
|
# "args" format
|
219
|
-
session =
|
218
|
+
session = params['sessions'].first
|
220
219
|
if session.key?('local_db_dir')
|
221
220
|
return session['local_db_dir']
|
222
221
|
elsif session.key?('local_dir')
|
@@ -224,26 +223,23 @@ module Aspera
|
|
224
223
|
elsif exception
|
225
224
|
raise Error, 'Missing either local_db_dir or local_dir'
|
226
225
|
end
|
227
|
-
elsif exception
|
228
|
-
raise Error, 'At least one of `local` or `sessions` must be present in async parameters'
|
229
226
|
end
|
230
227
|
nil
|
231
228
|
end
|
232
229
|
|
233
|
-
def session_name(
|
234
|
-
|
230
|
+
def session_name(params)
|
231
|
+
Aspera.assert(PARAM_KEYS.any?{ |k| params.key?(k)}, type: Error){'At least one of `local` or `sessions` must be present in async parameters'}
|
232
|
+
if params.key?('local')
|
235
233
|
# "conf" format
|
236
|
-
return
|
237
|
-
elsif sync_params.key?('sessions')
|
238
|
-
# "args" format
|
239
|
-
return sync_params['sessions'].first['name']
|
234
|
+
return params['name']
|
240
235
|
else
|
241
|
-
|
236
|
+
# "args" format
|
237
|
+
return params['sessions'].first['name']
|
242
238
|
end
|
243
239
|
end
|
244
240
|
|
245
|
-
def session_db_file(
|
246
|
-
db_file = File.join(local_db_folder(
|
241
|
+
def session_db_file(params)
|
242
|
+
db_file = File.join(local_db_folder(params), PRIVATE_FOLDER, session_name(params), ASYNC_DB)
|
247
243
|
Aspera.assert(File.exist?(db_file)){"Database file #{db_file} does not exist"}
|
248
244
|
db_file
|
249
245
|
end
|
@@ -292,8 +288,9 @@ module Aspera
|
|
292
288
|
ASYNC_ADMIN_EXECUTABLE = 'asyncadmin'
|
293
289
|
PRIVATE_FOLDER = '.private-asp'
|
294
290
|
ASYNC_DB = 'snap.db'
|
291
|
+
PARAM_KEYS = %w[local sessions].freeze
|
295
292
|
|
296
|
-
private_constant :INSTANCE_SCHEMA, :SESSION_SCHEMA, :CONF_SCHEMA, :CMDLINE_PARAMS_KEYS, :ASYNC_ADMIN_EXECUTABLE, :PRIVATE_FOLDER, :ASYNC_DB
|
293
|
+
private_constant :INSTANCE_SCHEMA, :SESSION_SCHEMA, :CONF_SCHEMA, :CMDLINE_PARAMS_KEYS, :ASYNC_ADMIN_EXECUTABLE, :PRIVATE_FOLDER, :ASYNC_DB, :PARAM_KEYS
|
297
294
|
end
|
298
295
|
end
|
299
296
|
end
|
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.24.
|
4
|
+
version: 4.24.1
|
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-10-02 00:00:00.000000000 Z
|
41
41
|
dependencies:
|
42
42
|
- !ruby/object:Gem::Dependency
|
43
43
|
name: blankslate
|
metadata.gz.sig
CHANGED
Binary file
|