aspera-cli 4.16.0 → 4.17.0
Sign up to get free protection for your applications and to get access to all the features.
- 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]
|