aspera-cli 4.16.0 → 4.17.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 +50 -19
- data/CONTRIBUTING.md +3 -1
- data/README.md +965 -793
- data/bin/asession +29 -21
- data/lib/aspera/{fasp/agent_alpha.rb → agent/alpha.rb} +26 -25
- data/lib/aspera/{fasp/agent_base.rb → agent/base.rb} +15 -12
- data/lib/aspera/{fasp/agent_connect.rb → agent/connect.rb} +13 -11
- data/lib/aspera/{fasp/agent_direct.rb → agent/direct.rb} +49 -53
- data/lib/aspera/{fasp/agent_httpgw.rb → agent/httpgw.rb} +20 -19
- data/lib/aspera/{fasp/agent_node.rb → agent/node.rb} +20 -33
- data/lib/aspera/{fasp/agent_trsdk.rb → agent/trsdk.rb} +11 -11
- data/lib/aspera/api/aoc.rb +586 -0
- data/lib/aspera/api/ats.rb +46 -0
- data/lib/aspera/api/cos_node.rb +95 -0
- data/lib/aspera/api/node.rb +344 -0
- data/lib/aspera/ascmd.rb +46 -10
- data/lib/aspera/{fasp → ascp}/installation.rb +5 -5
- data/lib/aspera/{fasp → ascp}/management.rb +3 -8
- data/lib/aspera/{fasp → ascp}/products.rb +1 -1
- data/lib/aspera/assert.rb +30 -30
- data/lib/aspera/cli/basic_auth_plugin.rb +11 -10
- data/lib/aspera/cli/extended_value.rb +1 -1
- data/lib/aspera/cli/formatter.rb +13 -13
- data/lib/aspera/cli/hints.rb +5 -5
- data/lib/aspera/cli/main.rb +35 -28
- data/lib/aspera/cli/manager.rb +25 -24
- data/lib/aspera/cli/plugin.rb +22 -15
- data/lib/aspera/cli/plugin_factory.rb +61 -0
- data/lib/aspera/cli/plugins/alee.rb +7 -7
- data/lib/aspera/cli/plugins/aoc.rb +83 -77
- data/lib/aspera/cli/plugins/ats.rb +32 -33
- data/lib/aspera/cli/plugins/bss.rb +3 -4
- data/lib/aspera/cli/plugins/config.rb +169 -186
- data/lib/aspera/cli/plugins/console.rb +8 -6
- data/lib/aspera/cli/plugins/cos.rb +19 -18
- data/lib/aspera/cli/plugins/faspex.rb +61 -54
- data/lib/aspera/cli/plugins/faspex5.rb +150 -103
- data/lib/aspera/cli/plugins/node.rb +68 -73
- data/lib/aspera/cli/plugins/orchestrator.rb +34 -44
- data/lib/aspera/cli/plugins/preview.rb +31 -31
- data/lib/aspera/cli/plugins/server.rb +31 -33
- data/lib/aspera/cli/plugins/shares.rb +13 -11
- data/lib/aspera/cli/sync_actions.rb +8 -8
- data/lib/aspera/cli/transfer_agent.rb +32 -19
- data/lib/aspera/cli/transfer_progress.rb +1 -1
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/colors.rb +5 -0
- data/lib/aspera/command_line_builder.rb +14 -14
- data/lib/aspera/coverage.rb +1 -2
- data/lib/aspera/data_repository.rb +1 -1
- data/lib/aspera/environment.rb +2 -3
- data/lib/aspera/faspex_gw.rb +5 -6
- data/lib/aspera/faspex_postproc.rb +1 -1
- data/lib/aspera/id_generator.rb +2 -2
- data/lib/aspera/json_rpc.rb +5 -5
- data/lib/aspera/keychain/encrypted_hash.rb +6 -6
- data/lib/aspera/keychain/macos_security.rb +27 -22
- data/lib/aspera/log.rb +2 -2
- data/lib/aspera/nagios.rb +3 -3
- data/lib/aspera/node_simulator.rb +5 -6
- data/lib/aspera/oauth/base.rb +143 -0
- data/lib/aspera/oauth/factory.rb +124 -0
- data/lib/aspera/oauth/generic.rb +34 -0
- data/lib/aspera/oauth/jwt.rb +51 -0
- data/lib/aspera/oauth/url_json.rb +31 -0
- data/lib/aspera/oauth/web.rb +50 -0
- data/lib/aspera/oauth.rb +5 -331
- data/lib/aspera/open_application.rb +7 -7
- data/lib/aspera/persistency_action_once.rb +4 -4
- data/lib/aspera/persistency_folder.rb +2 -2
- data/lib/aspera/preview/generator.rb +5 -5
- data/lib/aspera/preview/terminal.rb +3 -2
- data/lib/aspera/preview/utils.rb +3 -3
- data/lib/aspera/proxy_auto_config.rb +4 -4
- data/lib/aspera/rest.rb +175 -144
- data/lib/aspera/rest_errors_aspera.rb +3 -3
- data/lib/aspera/resumer.rb +77 -0
- data/lib/aspera/ssh.rb +6 -1
- data/lib/aspera/{fasp → transfer}/error.rb +3 -3
- data/lib/aspera/{fasp → transfer}/error_info.rb +1 -1
- data/lib/aspera/{fasp → transfer}/faux_file.rb +1 -1
- data/lib/aspera/{fasp → transfer}/parameters.rb +58 -89
- data/lib/aspera/{fasp/transfer_spec.rb → transfer/spec.rb} +18 -16
- data/lib/aspera/{fasp/parameters.yaml → transfer/spec.yaml} +4 -99
- data/lib/aspera/{fasp → transfer}/sync.rb +32 -32
- data/lib/aspera/{fasp → transfer}/uri.rb +9 -8
- data/lib/aspera/web_server_simple.rb +11 -3
- data.tar.gz.sig +0 -0
- metadata +36 -63
- metadata.gz.sig +0 -0
- data/lib/aspera/aoc.rb +0 -601
- data/lib/aspera/ats_api.rb +0 -47
- data/lib/aspera/cos_node.rb +0 -94
- data/lib/aspera/fasp/resume_policy.rb +0 -79
- data/lib/aspera/node.rb +0 -339
data/lib/aspera/assert.rb
CHANGED
|
@@ -6,40 +6,40 @@ module Aspera
|
|
|
6
6
|
|
|
7
7
|
class AssertError < StandardError
|
|
8
8
|
end
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
end
|
|
9
|
+
class << self
|
|
10
|
+
# the block is executed in the context of the Aspera module
|
|
11
|
+
def assert(assertion, info = nil, level: 2, exception_class: AssertError)
|
|
12
|
+
raise InternalError, 'bad assert: both info and block given' unless info.nil? || !block_given?
|
|
13
|
+
return if assertion
|
|
14
|
+
message = 'assertion failed'
|
|
15
|
+
info = yield if block_given?
|
|
16
|
+
message = "#{message}: #{info}" if info
|
|
17
|
+
message = "#{message}: #{caller(level..level).first}"
|
|
18
|
+
raise exception_class, message
|
|
19
|
+
end
|
|
21
20
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
21
|
+
# assert that value has the given type
|
|
22
|
+
# @param value [Object] the value to check
|
|
23
|
+
# @param type [Class] the expected type
|
|
24
|
+
def assert_type(value, type, exception_class: AssertError)
|
|
25
|
+
assert(value.is_a?(type), level: 3, exception_class: exception_class){"#{block_given? ? "#{yield}: " : nil}expecting #{type}, but have #{value.inspect}"}
|
|
26
|
+
end
|
|
28
27
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
28
|
+
# assert that value is one of the given values
|
|
29
|
+
def assert_values(value, values, exception_class: AssertError)
|
|
30
|
+
assert(values.include?(value), level: 3, exception_class: exception_class) do
|
|
31
|
+
"#{block_given? ? "#{yield}: " : nil}expecting one of #{values.inspect}, but have #{value.inspect}"
|
|
32
|
+
end
|
|
33
33
|
end
|
|
34
|
-
end
|
|
35
34
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
35
|
+
# the line with this shall never be reached
|
|
36
|
+
def error_unreachable_line
|
|
37
|
+
raise InternalError, "unreachable line reached: #{caller(2..2).first}"
|
|
38
|
+
end
|
|
40
39
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
40
|
+
# the value is not one of the expected values
|
|
41
|
+
def error_unexpected_value(value, exception_class: InternalError)
|
|
42
|
+
raise exception_class, "#{block_given? ? "#{yield}: " : nil}unexpected value: #{value.inspect}"
|
|
43
|
+
end
|
|
44
44
|
end
|
|
45
45
|
end
|
|
@@ -6,22 +6,23 @@ require 'aspera/cli/plugin'
|
|
|
6
6
|
module Aspera
|
|
7
7
|
module Cli
|
|
8
8
|
# base class for applications supporting basic authentication
|
|
9
|
-
class BasicAuthPlugin <
|
|
9
|
+
class BasicAuthPlugin < Cli::Plugin
|
|
10
10
|
class << self
|
|
11
|
-
|
|
12
|
-
def declare_options(options, force: false
|
|
13
|
-
return if @@basic_options_declared && !force
|
|
14
|
-
|
|
11
|
+
#@@basic_options_declared = false # rubocop:disable Style/ClassVars
|
|
12
|
+
def declare_options(options) # , force: false
|
|
13
|
+
#return if @@basic_options_declared && !force
|
|
14
|
+
#@@basic_options_declared = true # rubocop:disable Style/ClassVars
|
|
15
15
|
options.declare(:url, 'URL of application, e.g. https://faspex.example.com/aspera/faspex')
|
|
16
|
-
options.declare(:username, '
|
|
16
|
+
options.declare(:username, "User's name to log in")
|
|
17
17
|
options.declare(:password, "User's password")
|
|
18
18
|
options.parse_options!
|
|
19
19
|
end
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
-
def initialize(env)
|
|
23
|
-
super(env)
|
|
24
|
-
|
|
22
|
+
def initialize(basic_options: true, **env)
|
|
23
|
+
super(**env)
|
|
24
|
+
# , force: env[:all_manuals]
|
|
25
|
+
BasicAuthPlugin.declare_options(options) if basic_options
|
|
25
26
|
end
|
|
26
27
|
|
|
27
28
|
# returns a Rest object with basic auth
|
|
@@ -38,7 +39,7 @@ module Aspera
|
|
|
38
39
|
end
|
|
39
40
|
|
|
40
41
|
def basic_auth_api(subpath=nil)
|
|
41
|
-
return Rest.new(basic_auth_params(subpath))
|
|
42
|
+
return Rest.new(**basic_auth_params(subpath))
|
|
42
43
|
end
|
|
43
44
|
end # BasicAuthPlugin
|
|
44
45
|
end # Cli
|
data/lib/aspera/cli/formatter.rb
CHANGED
|
@@ -20,7 +20,7 @@ module Aspera
|
|
|
20
20
|
|
|
21
21
|
# General method
|
|
22
22
|
def flatten(something)
|
|
23
|
-
assert_type(something, Hash)
|
|
23
|
+
Aspera.assert_type(something, Hash)
|
|
24
24
|
@result = {}
|
|
25
25
|
flatten_any(something, '')
|
|
26
26
|
return @result
|
|
@@ -107,7 +107,7 @@ module Aspera
|
|
|
107
107
|
class << self
|
|
108
108
|
# Highlight special values
|
|
109
109
|
def special(what, use_colors: $stdout.isatty)
|
|
110
|
-
result = "<#{what}>"
|
|
110
|
+
result = $stdout.isatty ? "<#{what}>" : "<#{what}>"
|
|
111
111
|
if use_colors
|
|
112
112
|
result = if %w[null empty].any?{|s|what.include?(s)}
|
|
113
113
|
result.dim
|
|
@@ -158,7 +158,7 @@ module Aspera
|
|
|
158
158
|
end
|
|
159
159
|
|
|
160
160
|
def option_handler(option_symbol, operation, value=nil)
|
|
161
|
-
assert_values(operation, %i[set get])
|
|
161
|
+
Aspera.assert_values(operation, %i[set get])
|
|
162
162
|
case operation
|
|
163
163
|
when :set
|
|
164
164
|
@options[option_symbol] = value
|
|
@@ -170,7 +170,7 @@ module Aspera
|
|
|
170
170
|
end
|
|
171
171
|
end
|
|
172
172
|
when :get then return @options[option_symbol]
|
|
173
|
-
else error_unreachable_line
|
|
173
|
+
else Aspera.error_unreachable_line
|
|
174
174
|
end
|
|
175
175
|
nil
|
|
176
176
|
end
|
|
@@ -199,7 +199,7 @@ module Aspera
|
|
|
199
199
|
when :data then $stdout.puts(message) unless @options[:display].eql?(:error)
|
|
200
200
|
when :info then $stdout.puts(message) if @options[:display].eql?(:info)
|
|
201
201
|
when :error then $stderr.puts(message)
|
|
202
|
-
else error_unexpected_value(message_level)
|
|
202
|
+
else Aspera.error_unexpected_value(message_level)
|
|
203
203
|
end
|
|
204
204
|
end
|
|
205
205
|
|
|
@@ -232,7 +232,7 @@ module Aspera
|
|
|
232
232
|
when Array then @options[:fields]
|
|
233
233
|
when Regexp then return all_fields(data).select{|i|i.match(@options[:fields])}
|
|
234
234
|
when Proc then return all_fields(data).select{|i|@options[:fields].call(i)}
|
|
235
|
-
else error_unexpected_value(@options[:fields])
|
|
235
|
+
else Aspera.error_unexpected_value(@options[:fields])
|
|
236
236
|
end
|
|
237
237
|
result = []
|
|
238
238
|
until request.empty?
|
|
@@ -265,7 +265,7 @@ module Aspera
|
|
|
265
265
|
# object_array: array of hash
|
|
266
266
|
# fields: list of column names
|
|
267
267
|
def display_table(object_array, fields)
|
|
268
|
-
assert(!fields.nil?){'missing fields parameter'}
|
|
268
|
+
Aspera.assert(!fields.nil?){'missing fields parameter'}
|
|
269
269
|
case @options[:select]
|
|
270
270
|
when Proc
|
|
271
271
|
object_array.select!{|i|@options[:select].call(i)}
|
|
@@ -309,10 +309,10 @@ module Aspera
|
|
|
309
309
|
|
|
310
310
|
# this method displays the results, especially the table format
|
|
311
311
|
def display_results(results)
|
|
312
|
-
assert_type(results, Hash)
|
|
313
|
-
assert((results.keys - RESULT_PARAMS).empty?){"result unsupported key: #{results.keys - RESULT_PARAMS}"}
|
|
314
|
-
assert(results.key?(:type)){"result must have type (#{results})"}
|
|
315
|
-
assert(results.key?(:data) || %i[empty nothing].include?(results[:type])){'result must have data'}
|
|
312
|
+
Aspera.assert_type(results, Hash)
|
|
313
|
+
Aspera.assert((results.keys - RESULT_PARAMS).empty?){"result unsupported key: #{results.keys - RESULT_PARAMS}"}
|
|
314
|
+
Aspera.assert(results.key?(:type)){"result must have type (#{results})"}
|
|
315
|
+
Aspera.assert(results.key?(:data) || %i[empty nothing].include?(results[:type])){'result must have data'}
|
|
316
316
|
Log.log.debug{"display_results: #{results[:data].class} #{results[:type]}"}
|
|
317
317
|
display_item_count(results[:data].length, results[:total]) if results.key?(:total)
|
|
318
318
|
SecretHider.deep_remove_secret(results[:data]) unless @options[:show_secrets] || @options[:display].eql?(:data)
|
|
@@ -336,8 +336,8 @@ module Aspera
|
|
|
336
336
|
when :object_list, :single_object
|
|
337
337
|
obj_list = results[:data]
|
|
338
338
|
obj_list = [obj_list] if results[:type].eql?(:single_object)
|
|
339
|
-
assert_type(obj_list, Array)
|
|
340
|
-
assert(obj_list.all?(Hash)){"expecting Array of Hash: #{obj_list.inspect}"}
|
|
339
|
+
Aspera.assert_type(obj_list, Array)
|
|
340
|
+
Aspera.assert(obj_list.all?(Hash)){"expecting Array of Hash: #{obj_list.inspect}"}
|
|
341
341
|
# :object_list is an array of hash tables, where key=colum name
|
|
342
342
|
obj_list = obj_list.map{|obj|Flattener.new.flatten(obj)} if @options[:flat_hash]
|
|
343
343
|
display_table(obj_list, compute_fields(obj_list, results[:fields]))
|
data/lib/aspera/cli/hints.rb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require 'aspera/
|
|
3
|
+
require 'aspera/transfer/error'
|
|
4
4
|
require 'aspera/rest'
|
|
5
5
|
require 'aspera/log'
|
|
6
6
|
require 'aspera/assert'
|
|
@@ -14,7 +14,7 @@ module Aspera
|
|
|
14
14
|
# Well know issues that users may get
|
|
15
15
|
ERROR_HINTS = [
|
|
16
16
|
{
|
|
17
|
-
exception:
|
|
17
|
+
exception: Transfer::Error,
|
|
18
18
|
match: 'Remote host is not who we expected',
|
|
19
19
|
remediation: [
|
|
20
20
|
'For this specific error, refer to:',
|
|
@@ -24,7 +24,7 @@ module Aspera
|
|
|
24
24
|
]
|
|
25
25
|
},
|
|
26
26
|
{
|
|
27
|
-
exception:
|
|
27
|
+
exception: RestCallError,
|
|
28
28
|
match: /Signature has expired/,
|
|
29
29
|
remediation: [
|
|
30
30
|
'There is too much time difference between your computer and the server',
|
|
@@ -60,13 +60,13 @@ module Aspera
|
|
|
60
60
|
matches = hint[:match]
|
|
61
61
|
matches = [matches] unless matches.is_a?(Array)
|
|
62
62
|
matches.each do |m|
|
|
63
|
-
assert_values(m.class, [String, Regexp])
|
|
63
|
+
Aspera.assert_values(m.class, [String, Regexp])
|
|
64
64
|
case m
|
|
65
65
|
when String
|
|
66
66
|
next unless message.eql?(m)
|
|
67
67
|
when Regexp
|
|
68
68
|
next unless message.match?(m)
|
|
69
|
-
else error_unexpected_value(m)
|
|
69
|
+
else Aspera.error_unexpected_value(m)
|
|
70
70
|
end
|
|
71
71
|
remediation = hint[:remediation]
|
|
72
72
|
remediation = [remediation] unless remediation.is_a?(Array)
|
data/lib/aspera/cli/main.rb
CHANGED
|
@@ -4,6 +4,7 @@ require 'aspera/cli/manager'
|
|
|
4
4
|
require 'aspera/cli/formatter'
|
|
5
5
|
require 'aspera/cli/plugins/config'
|
|
6
6
|
require 'aspera/cli/extended_value'
|
|
7
|
+
require 'aspera/cli/plugin_factory'
|
|
7
8
|
require 'aspera/cli/transfer_agent'
|
|
8
9
|
require 'aspera/cli/version'
|
|
9
10
|
require 'aspera/cli/info'
|
|
@@ -19,6 +20,9 @@ module Aspera
|
|
|
19
20
|
class Main
|
|
20
21
|
# Plugins store transfer result using this key and use result_transfer_multiple()
|
|
21
22
|
STATUS_FIELD = 'status'
|
|
23
|
+
CONF_PLUGIN_SYM = :config
|
|
24
|
+
|
|
25
|
+
private_constant :CONF_PLUGIN_SYM
|
|
22
26
|
|
|
23
27
|
class << self
|
|
24
28
|
# expect some list, but nothing to display
|
|
@@ -69,7 +73,7 @@ module Aspera
|
|
|
69
73
|
|
|
70
74
|
# shortcuts helpers like in plugins
|
|
71
75
|
%i[options transfer config formatter persistency].each do |name|
|
|
72
|
-
define_method(name){@
|
|
76
|
+
define_method(name){@plug_init[name]}
|
|
73
77
|
end
|
|
74
78
|
|
|
75
79
|
# =============================================================
|
|
@@ -80,7 +84,7 @@ module Aspera
|
|
|
80
84
|
def initialize(argv)
|
|
81
85
|
@argv = argv
|
|
82
86
|
# environment provided to plugin for various capabilities
|
|
83
|
-
@
|
|
87
|
+
@plug_init = Plugin::INIT_PARAMS.each_with_object({}) { |key, hash| hash[key] = nil }
|
|
84
88
|
@option_help = false
|
|
85
89
|
@option_show_config = false
|
|
86
90
|
@bash_completion = false
|
|
@@ -88,11 +92,12 @@ module Aspera
|
|
|
88
92
|
|
|
89
93
|
# This can throw exception if there is a problem with the environment, needs to be caught by execute method
|
|
90
94
|
def init_agents_and_options
|
|
95
|
+
@plug_init[:only_manual] = false
|
|
91
96
|
# create formatter, in case there is an exception, it is used to display.
|
|
92
|
-
@
|
|
97
|
+
@plug_init[:formatter] = Formatter.new
|
|
93
98
|
# second : manage debug level (allows debugging of option parser)
|
|
94
99
|
early_debug_setup
|
|
95
|
-
@
|
|
100
|
+
@plug_init[:options] = Manager.new(PROGRAM_NAME)
|
|
96
101
|
# give command line arguments to option manager
|
|
97
102
|
options.parse_command_line(@argv)
|
|
98
103
|
# formatter adds options
|
|
@@ -105,11 +110,14 @@ module Aspera
|
|
|
105
110
|
# declare and parse global options
|
|
106
111
|
declare_global_options
|
|
107
112
|
# the Config plugin adds the @preset parser, so declare before TransferAgent which may use it
|
|
108
|
-
@
|
|
113
|
+
@plug_init[:config] = Plugins::Config.new(**@plug_init, gem: GEM_NAME, name: PROGRAM_NAME, help: DOC_URL, version: Cli::VERSION)
|
|
114
|
+
@plug_init[:persistency] = @plug_init[:config].persistency
|
|
109
115
|
# data persistency
|
|
110
|
-
assert(@
|
|
116
|
+
Aspera.assert(@plug_init[:persistency]){'missing persistency object'}
|
|
111
117
|
# the TransferAgent plugin may use the @preset parser
|
|
112
|
-
@
|
|
118
|
+
@plug_init[:config].transfer = @plug_init[:transfer] = TransferAgent.new(options, config)
|
|
119
|
+
nil_keys = @plug_init.select{|_, value|value.nil?}.keys
|
|
120
|
+
Aspera.assert(nil_keys.empty?){"nil : #{nil_keys}"}
|
|
113
121
|
Log.log.debug('plugin env created'.red)
|
|
114
122
|
# set banner when all environment is created so that additional extended value modifiers are known, e.g. @preset
|
|
115
123
|
options.parser.banner = app_banner
|
|
@@ -119,7 +127,7 @@ module Aspera
|
|
|
119
127
|
t = ' ' * 8
|
|
120
128
|
return <<~END_OF_BANNER
|
|
121
129
|
NAME
|
|
122
|
-
#{t}#{PROGRAM_NAME} -- a command line tool for Aspera Applications (v#{
|
|
130
|
+
#{t}#{PROGRAM_NAME} -- a command line tool for Aspera Applications (v#{Cli::VERSION})
|
|
123
131
|
|
|
124
132
|
SYNOPSIS
|
|
125
133
|
#{t}#{PROGRAM_NAME} COMMANDS [OPTIONS] [ARGS]
|
|
@@ -155,7 +163,7 @@ module Aspera
|
|
|
155
163
|
options.declare(:help, 'Show this message', values: :none, short: 'h') { @option_help = true }
|
|
156
164
|
options.declare(:bash_comp, 'Generate bash completion for command', values: :none) { @bash_completion = true }
|
|
157
165
|
options.declare(:show_config, 'Display parameters used for the provided action', values: :none) { @option_show_config = true }
|
|
158
|
-
options.declare(:version, 'Display version', values: :none, short: 'v') { formatter.display_message(:data,
|
|
166
|
+
options.declare(:version, 'Display version', values: :none, short: 'v') { formatter.display_message(:data, Cli::VERSION); Process.exit(0) } # rubocop:disable Style/Semicolon, Layout/LineLength
|
|
159
167
|
options.declare(:warnings, 'Check for language warnings', values: :none, short: 'w') { $VERBOSE = true }
|
|
160
168
|
options.declare(
|
|
161
169
|
:ui, 'Method to start browser',
|
|
@@ -177,20 +185,19 @@ module Aspera
|
|
|
177
185
|
# also loads the plugin options, and default values from conf file
|
|
178
186
|
# @param plugin_name_sym : symbol for plugin name
|
|
179
187
|
def get_plugin_instance_with_options(plugin_name_sym, env=nil)
|
|
180
|
-
env ||= @
|
|
188
|
+
env ||= @plug_init
|
|
181
189
|
Log.log.debug{"get_plugin_instance_with_options(#{plugin_name_sym})"}
|
|
182
|
-
require
|
|
190
|
+
require PluginFactory.instance.plugins[plugin_name_sym][:require_stanza]
|
|
183
191
|
# load default params only if no param already loaded before plugin instantiation
|
|
184
192
|
env[:config].add_plugin_default_preset(plugin_name_sym)
|
|
185
|
-
command_plugin =
|
|
193
|
+
command_plugin = PluginFactory.instance.create(plugin_name_sym, **env)
|
|
186
194
|
Log.log.debug{"got #{command_plugin.class}"}
|
|
187
|
-
# TODO: check that ancestor is Plugin?
|
|
188
195
|
return command_plugin
|
|
189
196
|
end
|
|
190
197
|
|
|
191
198
|
def generate_bash_completion
|
|
192
199
|
if options.get_next_argument('', expected: :multiple, mandatory: false).nil?
|
|
193
|
-
|
|
200
|
+
PluginFactory.instance.plugins.each_key{|p|puts p}
|
|
194
201
|
else
|
|
195
202
|
Log.log.warn('only first level completion so far')
|
|
196
203
|
end
|
|
@@ -203,11 +210,11 @@ module Aspera
|
|
|
203
210
|
formatter.display_message(:error, options.parser)
|
|
204
211
|
if all_plugins
|
|
205
212
|
# list plugins that have a "require" field, i.e. all but main plugin
|
|
206
|
-
|
|
207
|
-
next if plugin_name_sym.eql?(
|
|
213
|
+
PluginFactory.instance.plugins.each_key do |plugin_name_sym|
|
|
214
|
+
next if plugin_name_sym.eql?(CONF_PLUGIN_SYM)
|
|
208
215
|
# override main option parser with a brand new, to avoid having global options
|
|
209
|
-
plugin_env = @
|
|
210
|
-
plugin_env[:
|
|
216
|
+
plugin_env = @plug_init.clone
|
|
217
|
+
plugin_env[:only_manual] = true # force declaration of all options
|
|
211
218
|
plugin_env[:options] = Manager.new(PROGRAM_NAME)
|
|
212
219
|
plugin_env[:options].parser.banner = '' # remove default banner
|
|
213
220
|
get_plugin_instance_with_options(plugin_name_sym, plugin_env)
|
|
@@ -223,12 +230,12 @@ module Aspera
|
|
|
223
230
|
# early debug for parser
|
|
224
231
|
# Note: does not accept shortcuts
|
|
225
232
|
def early_debug_setup
|
|
226
|
-
|
|
233
|
+
Log.instance.program_name = PROGRAM_NAME
|
|
227
234
|
@argv.each do |arg|
|
|
228
235
|
case arg
|
|
229
236
|
when '--' then break
|
|
230
|
-
when /^--log-level=(.*)/ then
|
|
231
|
-
when /^--logger=(.*)/ then
|
|
237
|
+
when /^--log-level=(.*)/ then Log.instance.level = Regexp.last_match(1).to_sym
|
|
238
|
+
when /^--logger=(.*)/ then Log.instance.logger_type = Regexp.last_match(1).to_sym
|
|
232
239
|
end
|
|
233
240
|
rescue => e
|
|
234
241
|
$stderr.puts("Error: #{e}")
|
|
@@ -247,16 +254,16 @@ module Aspera
|
|
|
247
254
|
begin
|
|
248
255
|
init_agents_and_options
|
|
249
256
|
# find plugins, shall be after parse! ?
|
|
250
|
-
|
|
257
|
+
PluginFactory.instance.add_plugins_from_lookup_folders
|
|
251
258
|
# help requested without command ? (plugins must be known here)
|
|
252
259
|
exit_with_usage(true) if @option_help && options.command_or_arg_empty?
|
|
253
260
|
generate_bash_completion if @bash_completion
|
|
254
261
|
config.periodic_check_newer_gem_version
|
|
255
262
|
command_sym =
|
|
256
263
|
if @option_show_config && options.command_or_arg_empty?
|
|
257
|
-
|
|
264
|
+
CONF_PLUGIN_SYM
|
|
258
265
|
else
|
|
259
|
-
options.get_next_command(
|
|
266
|
+
options.get_next_command(PluginFactory.instance.plugins.keys.dup.unshift(:help))
|
|
260
267
|
end
|
|
261
268
|
# command will not be executed, but we need manual
|
|
262
269
|
options.fail_on_missing_mandatory = false if @option_help || @option_show_config
|
|
@@ -264,7 +271,7 @@ module Aspera
|
|
|
264
271
|
case command_sym
|
|
265
272
|
when :help
|
|
266
273
|
exit_with_usage(true)
|
|
267
|
-
when
|
|
274
|
+
when CONF_PLUGIN_SYM
|
|
268
275
|
command_plugin = config
|
|
269
276
|
else
|
|
270
277
|
# get plugin, set options, etc
|
|
@@ -307,8 +314,8 @@ module Aspera
|
|
|
307
314
|
rescue Cli::BadArgument => e; exception_info = {e: e, t: 'Argument', usage: true}
|
|
308
315
|
rescue Cli::NoSuchIdentifier => e; exception_info = {e: e, t: 'Identifier'}
|
|
309
316
|
rescue Cli::Error => e; exception_info = {e: e, t: 'Tool', usage: true}
|
|
310
|
-
rescue
|
|
311
|
-
rescue
|
|
317
|
+
rescue Transfer::Error => e; exception_info = {e: e, t: 'Transfer'}
|
|
318
|
+
rescue RestCallError => e; exception_info = {e: e, t: 'Rest'}
|
|
312
319
|
rescue SocketError => e; exception_info = {e: e, t: 'Network'}
|
|
313
320
|
rescue StandardError => e; exception_info = {e: e, t: "Other(#{e.class.name})", debug: true}
|
|
314
321
|
rescue Interrupt => e; exception_info = {e: e, t: 'Interruption', debug: true}
|
|
@@ -317,7 +324,7 @@ module Aspera
|
|
|
317
324
|
TempFileManager.instance.cleanup
|
|
318
325
|
# 1- processing of error condition
|
|
319
326
|
unless exception_info.nil?
|
|
320
|
-
Log.log.warn(exception_info[:e].message) if
|
|
327
|
+
Log.log.warn(exception_info[:e].message) if Log.instance.logger_type.eql?(:syslog) && exception_info[:security]
|
|
321
328
|
formatter.display_message(:error, "#{Formatter::ERROR_FLASH} #{exception_info[:t]}: #{exception_info[:e].message}")
|
|
322
329
|
formatter.display_message(:error, 'Use option -h to get help.') if exception_info[:usage]
|
|
323
330
|
# Is that a known error condition with proposal for remediation ?
|
data/lib/aspera/cli/manager.rb
CHANGED
|
@@ -21,7 +21,7 @@ module Aspera
|
|
|
21
21
|
@option_name = option_name
|
|
22
22
|
@has_writer = @object.respond_to?(writer_method)
|
|
23
23
|
Log.log.debug{"AttrAccessor: #{@option_name}: #{@object.class}.#{@method}: writer=#{@has_writer}"}
|
|
24
|
-
assert(@object.respond_to?(@method)) {"#{object} does not respond to #{method_name}"}
|
|
24
|
+
Aspera.assert(@object.respond_to?(@method)) {"#{object} does not respond to #{method_name}"}
|
|
25
25
|
end
|
|
26
26
|
|
|
27
27
|
def value
|
|
@@ -61,7 +61,7 @@ module Aspera
|
|
|
61
61
|
|
|
62
62
|
class << self
|
|
63
63
|
def enum_to_bool(enum)
|
|
64
|
-
assert_values(enum, BOOLEAN_VALUES){'boolean'}
|
|
64
|
+
Aspera.assert_values(enum, BOOLEAN_VALUES){'boolean'}
|
|
65
65
|
return TRUE_VALUES.include?(enum)
|
|
66
66
|
end
|
|
67
67
|
|
|
@@ -75,8 +75,8 @@ module Aspera
|
|
|
75
75
|
matching_exact = allowed_values.select{|i| i.to_s.eql?(short_value)}
|
|
76
76
|
return matching_exact.first if matching_exact.length == 1
|
|
77
77
|
matching = allowed_values.select{|i| i.to_s.start_with?(short_value)}
|
|
78
|
-
multi_choice_assert(!matching.empty?,"unknown value for #{descr}: #{short_value}", allowed_values)
|
|
79
|
-
multi_choice_assert(matching.length.eql?(1),"ambiguous shortcut for #{descr}: #{short_value}", matching)
|
|
78
|
+
multi_choice_assert(!matching.empty?, "unknown value for #{descr}: #{short_value}", allowed_values)
|
|
79
|
+
multi_choice_assert(matching.length.eql?(1), "ambiguous shortcut for #{descr}: #{short_value}", matching)
|
|
80
80
|
return enum_to_bool(matching.first) if allowed_values.eql?(BOOLEAN_VALUES)
|
|
81
81
|
return matching.first
|
|
82
82
|
end
|
|
@@ -84,8 +84,8 @@ module Aspera
|
|
|
84
84
|
# Generates error message with list of allowed values
|
|
85
85
|
# @param error_msg [String] error message
|
|
86
86
|
# @param choices [Array] list of allowed values
|
|
87
|
-
def multi_choice_assert(assertion,error_msg, choices)
|
|
88
|
-
raise Cli::BadArgument,
|
|
87
|
+
def multi_choice_assert(assertion, error_msg, choices)
|
|
88
|
+
raise Cli::BadArgument, [error_msg, 'Use:'].concat(choices.map{|c|"- #{c}"}.sort).join("\n") unless assertion
|
|
89
89
|
end
|
|
90
90
|
|
|
91
91
|
# change option name with dash to name with underscore
|
|
@@ -103,7 +103,7 @@ module Aspera
|
|
|
103
103
|
# @param type_list [NilClass, Class, Array[Class]] accepted value type(s)
|
|
104
104
|
def validate_type(what, descr, value, type_list)
|
|
105
105
|
return nil if type_list.nil?
|
|
106
|
-
assert(type_list.is_a?(Array) && type_list.all?(Class)){'types must be a Class Array'}
|
|
106
|
+
Aspera.assert(type_list.is_a?(Array) && type_list.all?(Class)){'types must be a Class Array'}
|
|
107
107
|
raise Cli::BadArgument,
|
|
108
108
|
"#{what.to_s.capitalize} #{descr} is a #{value.class} but must be #{type_list.length > 1 ? 'one of ' : ''}#{type_list.map(&:name).join(',')}" unless \
|
|
109
109
|
type_list.any?{|t|value.is_a?(t)}
|
|
@@ -181,14 +181,15 @@ module Aspera
|
|
|
181
181
|
# @param default [Object] default value
|
|
182
182
|
# @return value, list or nil
|
|
183
183
|
def get_next_argument(descr, expected: :single, mandatory: true, type: nil, aliases: nil, default: nil)
|
|
184
|
-
assert(%i[single multiple].include?(expected) || (expected.is_a?(Array) && expected.all?(Symbol)))
|
|
185
|
-
|
|
186
|
-
|
|
184
|
+
Aspera.assert(%i[single multiple].include?(expected) || (expected.is_a?(Array) && expected.all?(Symbol))) do
|
|
185
|
+
'expected must be single, multiple, or array of symbol'
|
|
186
|
+
end
|
|
187
|
+
Aspera.assert(type.nil? || type.is_a?(Class) || (type.is_a?(Array) && type.all?(Class))){'type must be Class or Array of Class'}
|
|
188
|
+
Aspera.assert(aliases.nil? || (aliases.is_a?(Hash) && aliases.keys.all?(Symbol) && aliases.values.all?(Symbol))){'aliases must be Hash'}
|
|
187
189
|
allowed_types = type
|
|
188
190
|
unless allowed_types.nil?
|
|
189
191
|
allowed_types = [allowed_types] unless allowed_types.is_a?(Array)
|
|
190
192
|
descr = "#{descr} (#{allowed_types.join(', ')})"
|
|
191
|
-
Log.log.debug{">>>> #{descr}=#{allowed_types}"}
|
|
192
193
|
end
|
|
193
194
|
result =
|
|
194
195
|
if !@unprocessed_cmd_line_arguments.empty?
|
|
@@ -207,7 +208,7 @@ module Aspera
|
|
|
207
208
|
allowed_values = [].concat(expected)
|
|
208
209
|
allowed_values.concat(aliases.keys) unless aliases.nil?
|
|
209
210
|
self.class.get_from_list(@unprocessed_cmd_line_arguments.shift, descr, allowed_values)
|
|
210
|
-
else error_unexpected_value(expected)
|
|
211
|
+
else Aspera.error_unexpected_value(expected)
|
|
211
212
|
end
|
|
212
213
|
elsif !default.nil? then default
|
|
213
214
|
# no value provided, either get value interactively, or exception
|
|
@@ -232,7 +233,7 @@ module Aspera
|
|
|
232
233
|
# @param mandatory [Boolean] if true, raise error if option not set
|
|
233
234
|
def get_option(option_symbol, mandatory: false, default: nil)
|
|
234
235
|
attributes = @declared_options[option_symbol]
|
|
235
|
-
assert(attributes){"option not declared: #{option_symbol}"}
|
|
236
|
+
Aspera.assert(attributes){"option not declared: #{option_symbol}"}
|
|
236
237
|
result = nil
|
|
237
238
|
case attributes[:read_write]
|
|
238
239
|
when :accessor
|
|
@@ -295,10 +296,10 @@ module Aspera
|
|
|
295
296
|
# @param types [Class, Array] accepted value type(s)
|
|
296
297
|
# @param block [Proc] block to execute when option is found
|
|
297
298
|
def declare(option_symbol, description, handler: nil, default: nil, values: nil, short: nil, coerce: nil, types: nil, deprecation: nil, &block)
|
|
298
|
-
assert(!@declared_options.key?(option_symbol)){"#{option_symbol} already declared"}
|
|
299
|
-
assert(description[-1] != '.'){"#{option_symbol} ends with dot"}
|
|
300
|
-
assert(description[0] == description[0].upcase){"#{option_symbol} description does not start with capital"}
|
|
301
|
-
assert(!['hash', 'extended value'].any?{|s|description.downcase.include?(s) }){"#{option_symbol} shall use :types"}
|
|
299
|
+
Aspera.assert(!@declared_options.key?(option_symbol)){"#{option_symbol} already declared"}
|
|
300
|
+
Aspera.assert(description[-1] != '.'){"#{option_symbol} ends with dot"}
|
|
301
|
+
Aspera.assert(description[0] == description[0].upcase){"#{option_symbol} description does not start with capital"}
|
|
302
|
+
Aspera.assert(!['hash', 'extended value'].any?{|s|description.downcase.include?(s) }){"#{option_symbol} shall use :types"}
|
|
302
303
|
opt = @declared_options[option_symbol] = {
|
|
303
304
|
read_write: handler.nil? ? :value : :accessor,
|
|
304
305
|
# by default passwords and secrets are sensitive, else specify when declaring the option
|
|
@@ -306,7 +307,7 @@ module Aspera
|
|
|
306
307
|
}
|
|
307
308
|
if !types.nil?
|
|
308
309
|
types = [types] unless types.is_a?(Array)
|
|
309
|
-
assert(types.all?(Class)){"types must be Array of Class: #{types}"}
|
|
310
|
+
Aspera.assert(types.all?(Class)){"types must be Array of Class: #{types}"}
|
|
310
311
|
opt[:types] = types
|
|
311
312
|
description = "#{description} (#{types.map(&:name).join(', ')})"
|
|
312
313
|
end
|
|
@@ -316,8 +317,8 @@ module Aspera
|
|
|
316
317
|
end
|
|
317
318
|
Log.log.debug{"declare: #{option_symbol}: #{opt[:read_write]}".green}
|
|
318
319
|
if opt[:read_write].eql?(:accessor)
|
|
319
|
-
assert_type(handler, Hash)
|
|
320
|
-
assert(handler.keys.sort.eql?(%i[m o]))
|
|
320
|
+
Aspera.assert_type(handler, Hash)
|
|
321
|
+
Aspera.assert(handler.keys.sort.eql?(%i[m o]))
|
|
321
322
|
Log.log.debug{"set attr obj #{option_symbol} (#{handler[:o]},#{handler[:m]})"}
|
|
322
323
|
opt[:accessor] = AttrAccessor.new(handler[:o], handler[:m], option_symbol)
|
|
323
324
|
end
|
|
@@ -356,11 +357,11 @@ module Aspera
|
|
|
356
357
|
set_option(option_symbol, time_string, SOURCE_USER)
|
|
357
358
|
end
|
|
358
359
|
when :none
|
|
359
|
-
assert(!block.nil?){"missing block for #{option_symbol}"}
|
|
360
|
+
Aspera.assert(!block.nil?){"missing block for #{option_symbol}"}
|
|
360
361
|
on_args.push(symbol_to_option(option_symbol, nil))
|
|
361
362
|
on_args.push("-#{short}") if short.is_a?(String)
|
|
362
363
|
@parser.on(*on_args, &block)
|
|
363
|
-
else error_unexpected_value(values)
|
|
364
|
+
else Aspera.error_unexpected_value(values)
|
|
364
365
|
end
|
|
365
366
|
Log.log.debug{"on_args=#{on_args}"}
|
|
366
367
|
end
|
|
@@ -368,7 +369,7 @@ module Aspera
|
|
|
368
369
|
# Adds each of the keys of specified hash as an option
|
|
369
370
|
# @param preset_hash [Hash] hash of options to add
|
|
370
371
|
def add_option_preset(preset_hash, op: :push)
|
|
371
|
-
assert_type(preset_hash, Hash)
|
|
372
|
+
Aspera.assert_type(preset_hash, Hash)
|
|
372
373
|
Log.log.debug{"add_option_preset=#{preset_hash}"}
|
|
373
374
|
# incremental override
|
|
374
375
|
preset_hash.each{|k, v|@unprocessed_defaults.send(op, [k.to_sym, v])}
|
|
@@ -470,7 +471,7 @@ module Aspera
|
|
|
470
471
|
def get_interactive(type, descr, expected: :single)
|
|
471
472
|
if !@ask_missing_mandatory
|
|
472
473
|
raise Cli::BadArgument, "missing argument (#{expected}): #{descr}" unless expected.is_a?(Array)
|
|
473
|
-
self.class.multi_choice_assert(false,"missing: #{descr}", expected)
|
|
474
|
+
self.class.multi_choice_assert(false, "missing: #{descr}", expected)
|
|
474
475
|
end
|
|
475
476
|
result = nil
|
|
476
477
|
sensitive = type.eql?(:option) && @declared_options[descr.to_sym].is_a?(Hash) && @declared_options[descr.to_sym][:sensitive]
|