aspera-cli 4.24.2 → 4.25.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 +1070 -758
- data/CONTRIBUTING.md +130 -115
- data/README.md +961 -623
- data/lib/aspera/agent/direct.rb +14 -12
- data/lib/aspera/agent/factory.rb +9 -6
- data/lib/aspera/agent/transferd.rb +8 -8
- data/lib/aspera/api/aoc.rb +104 -67
- data/lib/aspera/api/ats.rb +1 -0
- data/lib/aspera/api/cos_node.rb +3 -2
- data/lib/aspera/api/faspex.rb +17 -10
- data/lib/aspera/api/node.rb +10 -12
- data/lib/aspera/ascmd.rb +2 -3
- data/lib/aspera/ascp/installation.rb +60 -46
- data/lib/aspera/ascp/management.rb +9 -5
- data/lib/aspera/assert.rb +28 -6
- data/lib/aspera/cli/error.rb +4 -2
- data/lib/aspera/cli/extended_value.rb +94 -62
- data/lib/aspera/cli/formatter.rb +44 -58
- data/lib/aspera/cli/main.rb +21 -14
- data/lib/aspera/cli/manager.rb +317 -250
- data/lib/aspera/cli/plugins/alee.rb +3 -3
- data/lib/aspera/cli/plugins/aoc.rb +139 -78
- data/lib/aspera/cli/plugins/ats.rb +30 -36
- data/lib/aspera/cli/plugins/base.rb +68 -55
- data/lib/aspera/cli/plugins/config.rb +90 -100
- data/lib/aspera/cli/plugins/console.rb +15 -9
- data/lib/aspera/cli/plugins/cos.rb +1 -1
- data/lib/aspera/cli/plugins/faspex.rb +39 -30
- data/lib/aspera/cli/plugins/faspex5.rb +57 -52
- data/lib/aspera/cli/plugins/faspio.rb +10 -7
- data/lib/aspera/cli/plugins/httpgw.rb +3 -2
- data/lib/aspera/cli/plugins/node.rb +140 -125
- data/lib/aspera/cli/plugins/oauth.rb +13 -12
- data/lib/aspera/cli/plugins/orchestrator.rb +116 -33
- data/lib/aspera/cli/plugins/preview.rb +28 -48
- data/lib/aspera/cli/plugins/server.rb +9 -10
- data/lib/aspera/cli/plugins/shares.rb +77 -43
- data/lib/aspera/cli/sync_actions.rb +49 -38
- data/lib/aspera/cli/transfer_agent.rb +16 -35
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/cli/wizard.rb +8 -5
- data/lib/aspera/command_line_builder.rb +24 -21
- data/lib/aspera/coverage.rb +6 -2
- data/lib/aspera/dot_container.rb +108 -0
- data/lib/aspera/environment.rb +71 -84
- data/lib/aspera/faspex_gw.rb +1 -1
- data/lib/aspera/faspex_postproc.rb +1 -1
- data/lib/aspera/id_generator.rb +7 -10
- data/lib/aspera/keychain/factory.rb +1 -2
- data/lib/aspera/keychain/macos_security.rb +2 -2
- data/lib/aspera/log.rb +2 -1
- data/lib/aspera/markdown.rb +31 -0
- data/lib/aspera/nagios.rb +6 -5
- data/lib/aspera/oauth/base.rb +41 -64
- data/lib/aspera/oauth/factory.rb +6 -7
- data/lib/aspera/oauth/generic.rb +1 -1
- data/lib/aspera/oauth/jwt.rb +1 -1
- data/lib/aspera/oauth/url_json.rb +6 -4
- data/lib/aspera/oauth/web.rb +2 -2
- data/lib/aspera/preview/file_types.rb +24 -38
- data/lib/aspera/preview/terminal.rb +95 -29
- data/lib/aspera/preview/utils.rb +6 -5
- data/lib/aspera/products/connect.rb +3 -3
- data/lib/aspera/rest.rb +54 -39
- data/lib/aspera/rest_error_analyzer.rb +4 -4
- data/lib/aspera/ssh.rb +10 -6
- data/lib/aspera/ssl.rb +41 -0
- data/lib/aspera/sync/conf.schema.yaml +184 -36
- data/lib/aspera/sync/database.rb +2 -1
- data/lib/aspera/sync/operations.rb +128 -72
- data/lib/aspera/transfer/parameters.rb +9 -10
- data/lib/aspera/transfer/spec.rb +2 -3
- data/lib/aspera/transfer/spec.schema.yaml +52 -22
- data/lib/aspera/transfer/spec_doc.rb +20 -30
- data/lib/aspera/uri_reader.rb +18 -4
- data/lib/transferd_pb.rb +2 -2
- data.tar.gz.sig +0 -0
- metadata +34 -6
- metadata.gz.sig +0 -0
data/lib/aspera/cli/formatter.rb
CHANGED
|
@@ -7,6 +7,8 @@ require 'aspera/secret_hider'
|
|
|
7
7
|
require 'aspera/environment'
|
|
8
8
|
require 'aspera/log'
|
|
9
9
|
require 'aspera/assert'
|
|
10
|
+
require 'aspera/markdown'
|
|
11
|
+
require 'aspera/dot_container'
|
|
10
12
|
require 'terminal-table'
|
|
11
13
|
require 'tty-spinner'
|
|
12
14
|
require 'yaml'
|
|
@@ -63,16 +65,32 @@ module Aspera
|
|
|
63
65
|
end
|
|
64
66
|
end
|
|
65
67
|
|
|
68
|
+
# Give Markdown String, or matched data, return formatted string for terminal
|
|
66
69
|
# used by spec_doc
|
|
67
|
-
|
|
68
|
-
|
|
70
|
+
# @param match [MatchData,String]
|
|
71
|
+
def markdown_text(match)
|
|
72
|
+
if match.is_a?(String)
|
|
73
|
+
match = Markdown::FORMATS.match(match)
|
|
74
|
+
Aspera.assert(match)
|
|
75
|
+
end
|
|
76
|
+
Aspera.assert_type(match, MatchData)
|
|
77
|
+
if match[:entity]
|
|
78
|
+
Aspera.assert_values(match[:entity], 'bsol')
|
|
79
|
+
'\\'
|
|
80
|
+
elsif match[:bold]
|
|
81
|
+
match[:bold].to_s.blue
|
|
82
|
+
elsif match[:code]
|
|
83
|
+
match[:code].to_s.bold
|
|
84
|
+
else
|
|
85
|
+
Aspera.error_unexpected_value(match.to_s)
|
|
86
|
+
end
|
|
69
87
|
end
|
|
70
88
|
|
|
71
|
-
#
|
|
72
|
-
def
|
|
73
|
-
|
|
74
|
-
until
|
|
75
|
-
current =
|
|
89
|
+
# Replace special values with a readable version on terminal
|
|
90
|
+
def replace_specific_for_terminal(input_hash)
|
|
91
|
+
hash_to_process = [input_hash]
|
|
92
|
+
until hash_to_process.empty?
|
|
93
|
+
current = hash_to_process.pop
|
|
76
94
|
current.each do |key, value|
|
|
77
95
|
case value
|
|
78
96
|
when NilClass
|
|
@@ -84,54 +102,24 @@ module Aspera
|
|
|
84
102
|
when Array
|
|
85
103
|
if value.empty?
|
|
86
104
|
current[key] = special_format('empty list')
|
|
105
|
+
elsif value.all?(String)
|
|
106
|
+
current[key] = value.join(',')
|
|
87
107
|
else
|
|
88
108
|
value.each do |item|
|
|
89
|
-
|
|
109
|
+
hash_to_process.push(item) if item.is_a?(Hash)
|
|
90
110
|
end
|
|
91
111
|
end
|
|
92
112
|
when Hash
|
|
93
113
|
if value.empty?
|
|
94
114
|
current[key] = special_format('empty dict')
|
|
95
115
|
else
|
|
96
|
-
|
|
116
|
+
hash_to_process.push(value)
|
|
97
117
|
end
|
|
98
118
|
end
|
|
99
119
|
end
|
|
100
120
|
end
|
|
101
121
|
end
|
|
102
122
|
|
|
103
|
-
# Flatten a Hash into single level hash
|
|
104
|
-
def flatten_hash(input)
|
|
105
|
-
Aspera.assert_type(input, Hash)
|
|
106
|
-
return input if input.empty?
|
|
107
|
-
flat = {}
|
|
108
|
-
stack = [[nil, input]]
|
|
109
|
-
until stack.empty?
|
|
110
|
-
prefix, current = stack.pop
|
|
111
|
-
if current.respond_to?(:empty?) && current.empty?
|
|
112
|
-
flat[prefix] = current
|
|
113
|
-
next
|
|
114
|
-
end
|
|
115
|
-
case current
|
|
116
|
-
when Hash
|
|
117
|
-
current.reverse_each{ |k, v| stack.push([[prefix, k].compact.join('.'), v])}
|
|
118
|
-
when Array
|
|
119
|
-
if current.all?(String)
|
|
120
|
-
flat[prefix] = current.join("\n")
|
|
121
|
-
elsif current.all?{ |i| i.is_a?(Hash) && i.keys == ['name']}
|
|
122
|
-
flat[prefix] = current.map{ |i| i['name']}.join(', ')
|
|
123
|
-
elsif current.all?{ |i| i.is_a?(Hash) && i.keys.sort == %w[name value]}
|
|
124
|
-
stack.push([prefix, current.each_with_object({}){ |i, h| h[i['name']] = i['value']}])
|
|
125
|
-
else
|
|
126
|
-
current.each_with_index.reverse_each{ |v, k| stack.push([[prefix, k].compact.join('.'), v])}
|
|
127
|
-
end
|
|
128
|
-
else
|
|
129
|
-
flat[prefix] = current
|
|
130
|
-
end
|
|
131
|
-
end
|
|
132
|
-
flat
|
|
133
|
-
end
|
|
134
|
-
|
|
135
123
|
def all_but(list)
|
|
136
124
|
list = [list] unless list.is_a?(Array)
|
|
137
125
|
return list.map{ |i| "#{FIELDS_LESS}#{i}"}.unshift(SpecialValues::ALL)
|
|
@@ -166,23 +154,23 @@ module Aspera
|
|
|
166
154
|
else
|
|
167
155
|
{}
|
|
168
156
|
end
|
|
169
|
-
options.declare(:format, 'Output format',
|
|
170
|
-
options.declare(:output, 'Destination for results',
|
|
171
|
-
options.declare(:display, 'Output only some information',
|
|
157
|
+
options.declare(:format, 'Output format', allowed: DISPLAY_FORMATS, handler: {o: self, m: :option_handler}, default: :table)
|
|
158
|
+
options.declare(:output, 'Destination for results', handler: {o: self, m: :option_handler})
|
|
159
|
+
options.declare(:display, 'Output only some information', allowed: DISPLAY_LEVELS, handler: {o: self, m: :option_handler}, default: :info)
|
|
172
160
|
options.declare(
|
|
173
161
|
:fields, "Comma separated list of: fields, or #{SpecialValues::ALL}, or #{SpecialValues::DEF}", handler: {o: self, m: :option_handler},
|
|
174
|
-
|
|
162
|
+
allowed: [String, Array, Regexp, Proc],
|
|
175
163
|
default: SpecialValues::DEF
|
|
176
164
|
)
|
|
177
|
-
options.declare(:select, 'Select only some items in lists: column, value',
|
|
178
|
-
options.declare(:table_style, '(Table) Display style',
|
|
179
|
-
options.declare(:flat_hash, '(Table) Display deep values as additional keys',
|
|
165
|
+
options.declare(:select, 'Select only some items in lists: column, value', allowed: [Hash, Proc], handler: {o: self, m: :option_handler})
|
|
166
|
+
options.declare(:table_style, '(Table) Display style', allowed: [Hash], handler: {o: self, m: :option_handler}, default: default_table_style)
|
|
167
|
+
options.declare(:flat_hash, '(Table) Display deep values as additional keys', allowed: Allowed::TYPES_BOOLEAN, handler: {o: self, m: :option_handler}, default: true)
|
|
180
168
|
options.declare(
|
|
181
|
-
:multi_single, '(Table) Control how object list is displayed as single table, or multiple objects',
|
|
169
|
+
:multi_single, '(Table) Control how object list is displayed as single table, or multiple objects', allowed: %i[no yes single],
|
|
182
170
|
handler: {o: self, m: :option_handler}, default: :no
|
|
183
171
|
)
|
|
184
|
-
options.declare(:show_secrets, 'Show secrets on command output',
|
|
185
|
-
options.declare(:image, 'Options for image display',
|
|
172
|
+
options.declare(:show_secrets, 'Show secrets on command output', allowed: Allowed::TYPES_BOOLEAN, handler: {o: self, m: :option_handler}, default: false)
|
|
173
|
+
options.declare(:image, 'Options for image display', allowed: Hash, handler: {o: self, m: :option_handler}, default: {})
|
|
186
174
|
end
|
|
187
175
|
|
|
188
176
|
# method accessed by option manager
|
|
@@ -321,14 +309,13 @@ module Aspera
|
|
|
321
309
|
if data.empty?
|
|
322
310
|
display_message(:data, self.class.special_format('empty dict'))
|
|
323
311
|
else
|
|
324
|
-
data =
|
|
312
|
+
data = DotContainer.new(data).to_dotted if @options[:flat_hash]
|
|
325
313
|
display_table([data], compute_fields([data], fields), single: true)
|
|
326
314
|
end
|
|
327
315
|
when :object_list
|
|
328
316
|
# :object_list is an Array of Hash, where key=column name
|
|
329
|
-
Aspera.
|
|
330
|
-
|
|
331
|
-
data = data.map{ |obj| self.class.flatten_hash(obj)} if @options[:flat_hash]
|
|
317
|
+
Aspera.assert_array_all(data, Hash){'result'}
|
|
318
|
+
data = data.map{ |obj| DotContainer.new(obj).to_dotted} if @options[:flat_hash]
|
|
332
319
|
display_table(data, compute_fields(data, fields), single: type.eql?(:single_object))
|
|
333
320
|
when :value_list
|
|
334
321
|
# :value_list is a simple array of values, name of column provided in `name`
|
|
@@ -406,8 +393,7 @@ module Aspera
|
|
|
406
393
|
def filter_list_on_fields(data)
|
|
407
394
|
# by default, keep all data intact
|
|
408
395
|
return data if @options[:fields].eql?(SpecialValues::DEF) && @options[:select].nil?
|
|
409
|
-
Aspera.
|
|
410
|
-
Aspera.assert(data.all?(Hash)){'Filtering fields or select requires result is an Array of Hash'}
|
|
396
|
+
Aspera.assert_array_all(data, Hash){'filter or select'}
|
|
411
397
|
filter_columns_on_select(data)
|
|
412
398
|
return data if @options[:fields].eql?(SpecialValues::DEF)
|
|
413
399
|
selected_fields = compute_fields(data, @options[:fields])
|
|
@@ -441,7 +427,7 @@ module Aspera
|
|
|
441
427
|
return
|
|
442
428
|
end
|
|
443
429
|
filter_columns_on_select(object_array)
|
|
444
|
-
object_array.each{ |i| self.class.
|
|
430
|
+
object_array.each{ |i| self.class.replace_specific_for_terminal(i)}
|
|
445
431
|
# if table has only one element, and only one field, display the value
|
|
446
432
|
if object_array.length == 1 && fields.length == 1
|
|
447
433
|
Log.log.debug("display_table: single element, field: #{fields.first}")
|
data/lib/aspera/cli/main.rb
CHANGED
|
@@ -214,6 +214,7 @@ module Aspera
|
|
|
214
214
|
rescue Net::SSH::AuthenticationFailed => e; exception_info = {e: e, t: 'SSH', security: true}
|
|
215
215
|
rescue OpenSSL::SSL::SSLError => e; exception_info = {e: e, t: 'SSL'}
|
|
216
216
|
rescue Cli::BadArgument => e; exception_info = {e: e, t: 'Argument', usage: true}
|
|
217
|
+
rescue Cli::MissingArgument => e; exception_info = {e: e, t: 'Missing', usage: true}
|
|
217
218
|
rescue Cli::BadIdentifier => e; exception_info = {e: e, t: 'Identifier'}
|
|
218
219
|
rescue Cli::Error => e; exception_info = {e: e, t: 'Tool', usage: true}
|
|
219
220
|
rescue Transfer::Error => e; exception_info = {e: e, t: 'Transfer'}
|
|
@@ -228,6 +229,7 @@ module Aspera
|
|
|
228
229
|
unless exception_info.nil?
|
|
229
230
|
Log.log.warn(exception_info[:e].message) if Log.instance.logger_type.eql?(:syslog) && exception_info[:security]
|
|
230
231
|
@context.formatter.display_message(:error, "#{Formatter::ERROR_FLASH} #{exception_info[:t]}: #{exception_info[:e].message}")
|
|
232
|
+
Log.log.debug{(['Backtrace:'] + exception_info[:e].backtrace).join("\n")} if exception_info[:debug]
|
|
231
233
|
@context.formatter.display_message(:error, 'Use option -h to get help.') if exception_info[:usage]
|
|
232
234
|
# Is that a known error condition with proposal for remediation ?
|
|
233
235
|
Hints.hint_for(exception_info[:e], @context.formatter)
|
|
@@ -287,7 +289,6 @@ module Aspera
|
|
|
287
289
|
@context.options = Manager.new(Info::CMD_NAME, @argv)
|
|
288
290
|
# Formatter adds options
|
|
289
291
|
@context.formatter.declare_options(@context.options)
|
|
290
|
-
ExtendedValue.instance.default_decoder = @context.options.get_option(:struct_parser)
|
|
291
292
|
# Compare $0 with expected name
|
|
292
293
|
current_prog_name = File.basename($PROGRAM_NAME)
|
|
293
294
|
@context.formatter.display_message(
|
|
@@ -349,28 +350,34 @@ module Aspera
|
|
|
349
350
|
# Define header for manual
|
|
350
351
|
def declare_global_options
|
|
351
352
|
Log.log.debug('declare_global_options')
|
|
352
|
-
@context.options.declare(:help, 'Show this message',
|
|
353
|
-
@context.options.declare(:bash_comp, 'Generate bash completion for command',
|
|
354
|
-
@context.options.declare(:show_config, 'Display parameters used for the provided action',
|
|
355
|
-
@context.options.declare(:version, 'Display version',
|
|
353
|
+
@context.options.declare(:help, 'Show this message', allowed: Allowed::TYPES_NONE, short: 'h'){@option_help = true}
|
|
354
|
+
@context.options.declare(:bash_comp, 'Generate bash completion for command', allowed: Allowed::TYPES_NONE){@bash_completion = true}
|
|
355
|
+
@context.options.declare(:show_config, 'Display parameters used for the provided action', allowed: Allowed::TYPES_NONE){@option_show_config = true}
|
|
356
|
+
@context.options.declare(:version, 'Display version', allowed: Allowed::TYPES_NONE, short: 'v'){@context.formatter.display_message(:data, Cli::VERSION); Process.exit(0)} # rubocop:disable Style/Semicolon
|
|
356
357
|
@context.options.declare(
|
|
357
358
|
:ui, 'Method to start browser',
|
|
358
|
-
|
|
359
|
+
allowed: USER_INTERFACES,
|
|
359
360
|
handler: {o: Environment.instance, m: :url_method}
|
|
360
361
|
)
|
|
361
362
|
@context.options.declare(
|
|
362
363
|
:invalid_characters, 'Replacement character and invalid filename characters',
|
|
363
364
|
handler: {o: Environment.instance, m: :file_illegal_characters}
|
|
364
365
|
)
|
|
365
|
-
@context.options.declare(:log_level, 'Log level',
|
|
366
|
-
@context.options.declare(:log_format, 'Log formatter',
|
|
367
|
-
@context.options.declare(:logger, 'Logging method',
|
|
368
|
-
@context.options.declare(:lock_port, 'Prevent dual execution of a command, e.g. in cron',
|
|
369
|
-
@context.options.declare(:once_only, 'Process only new items (some commands)',
|
|
370
|
-
@context.options.declare(:log_secrets, 'Show passwords in logs',
|
|
371
|
-
@context.options.declare(:clean_temp, 'Cleanup temporary files on exit',
|
|
366
|
+
@context.options.declare(:log_level, 'Log level', allowed: Log::LEVELS, handler: {o: Log.instance, m: :level})
|
|
367
|
+
@context.options.declare(:log_format, 'Log formatter', allowed: [Proc, Logger::Formatter, String], handler: {o: Log.instance, m: :formatter})
|
|
368
|
+
@context.options.declare(:logger, 'Logging method', allowed: Log::LOG_TYPES, handler: {o: Log.instance, m: :logger_type})
|
|
369
|
+
@context.options.declare(:lock_port, 'Prevent dual execution of a command, e.g. in cron', allowed: Allowed::TYPES_INTEGER)
|
|
370
|
+
@context.options.declare(:once_only, 'Process only new items (some commands)', allowed: Allowed::TYPES_BOOLEAN, default: false)
|
|
371
|
+
@context.options.declare(:log_secrets, 'Show passwords in logs', allowed: Allowed::TYPES_BOOLEAN, handler: {o: SecretHider.instance, m: :log_secrets})
|
|
372
|
+
@context.options.declare(:clean_temp, 'Cleanup temporary files on exit', allowed: Allowed::TYPES_BOOLEAN, handler: {o: TempFileManager.instance, m: :cleanup_on_exit})
|
|
372
373
|
@context.options.declare(:temp_folder, 'Temporary folder', handler: {o: TempFileManager.instance, m: :global_temp})
|
|
373
|
-
@context.options.declare(:pid_file, 'Write process identifier to file, delete on exit'
|
|
374
|
+
@context.options.declare(:pid_file, 'Write process identifier to file, delete on exit')
|
|
375
|
+
@context.options.declare(
|
|
376
|
+
:parser, 'Default parser for structured parameters and options',
|
|
377
|
+
handler: {o: ExtendedValue.instance, m: :default_decoder},
|
|
378
|
+
allowed: ExtendedValue::DEFAULT_DECODERS,
|
|
379
|
+
default: ExtendedValue::DEFAULT_DECODERS.first
|
|
380
|
+
)
|
|
374
381
|
# Parse declared options
|
|
375
382
|
@context.options.parse_options!
|
|
376
383
|
end
|