aspera-cli 4.17.0 → 4.18.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 +3 -4
- data/CHANGELOG.md +33 -0
- data/CONTRIBUTING.md +15 -1
- data/README.md +711 -432
- data/bin/ascli +5 -0
- data/bin/asession +2 -2
- data/examples/build_package.sh +28 -0
- data/lib/aspera/agent/alpha.rb +10 -8
- data/lib/aspera/agent/base.rb +9 -6
- data/lib/aspera/agent/connect.rb +7 -8
- data/lib/aspera/agent/direct.rb +56 -37
- data/lib/aspera/agent/httpgw.rb +23 -324
- data/lib/aspera/agent/node.rb +19 -20
- data/lib/aspera/agent/trsdk.rb +19 -20
- data/lib/aspera/api/aoc.rb +17 -14
- data/lib/aspera/api/cos_node.rb +4 -4
- data/lib/aspera/api/httpgw.rb +342 -0
- data/lib/aspera/api/node.rb +135 -89
- data/lib/aspera/ascmd.rb +4 -3
- data/lib/aspera/ascp/installation.rb +15 -7
- data/lib/aspera/ascp/management.rb +2 -2
- data/lib/aspera/ascp/products.rb +1 -1
- data/lib/aspera/cli/basic_auth_plugin.rb +5 -9
- data/lib/aspera/cli/extended_value.rb +35 -16
- data/lib/aspera/cli/formatter.rb +161 -70
- data/lib/aspera/cli/hints.rb +18 -0
- data/lib/aspera/cli/main.rb +32 -39
- data/lib/aspera/cli/manager.rb +151 -119
- data/lib/aspera/cli/plugin.rb +27 -21
- data/lib/aspera/cli/plugin_factory.rb +31 -20
- data/lib/aspera/cli/plugins/alee.rb +14 -2
- data/lib/aspera/cli/plugins/aoc.rb +152 -141
- data/lib/aspera/cli/plugins/ats.rb +1 -1
- data/lib/aspera/cli/plugins/config.rb +72 -65
- data/lib/aspera/cli/plugins/console.rb +8 -5
- data/lib/aspera/cli/plugins/faspex.rb +32 -23
- data/lib/aspera/cli/plugins/faspex5.rb +232 -156
- data/lib/aspera/cli/plugins/faspio.rb +85 -0
- data/lib/aspera/cli/plugins/httpgw.rb +55 -0
- data/lib/aspera/cli/plugins/node.rb +129 -64
- data/lib/aspera/cli/plugins/orchestrator.rb +33 -30
- data/lib/aspera/cli/plugins/preview.rb +7 -3
- data/lib/aspera/cli/plugins/server.rb +6 -6
- data/lib/aspera/cli/plugins/shares.rb +16 -14
- data/lib/aspera/cli/special_values.rb +13 -0
- data/lib/aspera/cli/sync_actions.rb +10 -10
- data/lib/aspera/cli/transfer_agent.rb +7 -6
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/environment.rb +70 -9
- data/lib/aspera/faspex_gw.rb +5 -4
- data/lib/aspera/faspex_postproc.rb +2 -2
- data/lib/aspera/log.rb +6 -3
- data/lib/aspera/node_simulator.rb +2 -2
- data/lib/aspera/oauth/base.rb +31 -19
- data/lib/aspera/oauth/factory.rb +12 -13
- data/lib/aspera/oauth/generic.rb +1 -0
- data/lib/aspera/oauth/jwt.rb +18 -15
- data/lib/aspera/oauth/url_json.rb +8 -6
- data/lib/aspera/oauth/web.rb +2 -2
- data/lib/aspera/persistency_folder.rb +2 -2
- data/lib/aspera/preview/generator.rb +3 -3
- data/lib/aspera/preview/options.rb +3 -3
- data/lib/aspera/preview/terminal.rb +4 -4
- data/lib/aspera/preview/utils.rb +3 -3
- data/lib/aspera/proxy_auto_config.rb +5 -1
- data/lib/aspera/rest.rb +105 -88
- data/lib/aspera/rest_call_error.rb +1 -1
- data/lib/aspera/rest_error_analyzer.rb +2 -2
- data/lib/aspera/rest_errors_aspera.rb +1 -1
- data/lib/aspera/resumer.rb +1 -1
- data/lib/aspera/secret_hider.rb +2 -4
- data/lib/aspera/ssh.rb +1 -1
- data/lib/aspera/transfer/parameters.rb +39 -36
- data/lib/aspera/transfer/spec.rb +2 -0
- data/lib/aspera/transfer/sync.rb +2 -1
- data/lib/aspera/transfer/uri.rb +1 -1
- data/lib/aspera/uri_reader.rb +5 -4
- data/lib/aspera/web_auth.rb +1 -1
- data/lib/aspera/web_server_simple.rb +4 -3
- data.tar.gz.sig +0 -0
- metadata +7 -4
- metadata.gz.sig +0 -0
- data/lib/aspera/cli/plugins/bss.rb +0 -71
- data/lib/aspera/open_application.rb +0 -71
data/lib/aspera/cli/formatter.rb
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
# cspell:ignore jsonpp
|
|
4
|
+
require 'aspera/cli/special_values'
|
|
5
|
+
require 'aspera/preview/terminal'
|
|
4
6
|
require 'aspera/secret_hider'
|
|
5
7
|
require 'aspera/environment'
|
|
6
8
|
require 'aspera/log'
|
|
7
9
|
require 'aspera/assert'
|
|
8
10
|
require 'terminal-table'
|
|
11
|
+
require 'tty-spinner'
|
|
9
12
|
require 'yaml'
|
|
10
13
|
require 'pp'
|
|
11
14
|
|
|
@@ -14,8 +17,9 @@ module Aspera
|
|
|
14
17
|
CONF_OVERVIEW_KEYS = %w[preset parameter value].freeze
|
|
15
18
|
# This class is used to transform a complex structure into a simple hash
|
|
16
19
|
class Flattener
|
|
17
|
-
def initialize
|
|
20
|
+
def initialize(formatter)
|
|
18
21
|
@result = nil
|
|
22
|
+
@formatter = formatter
|
|
19
23
|
end
|
|
20
24
|
|
|
21
25
|
# General method
|
|
@@ -48,9 +52,9 @@ module Aspera
|
|
|
48
52
|
elsif something.is_a?(Array)
|
|
49
53
|
flatten_array(something, name)
|
|
50
54
|
elsif something.is_a?(String) && something.empty?
|
|
51
|
-
@result[name] =
|
|
55
|
+
@result[name] = @formatter.special_format('empty string')
|
|
52
56
|
elsif something.nil?
|
|
53
|
-
@result[name] =
|
|
57
|
+
@result[name] = @formatter.special_format('null')
|
|
54
58
|
# elsif something.eql?(true) || something.eql?(false)
|
|
55
59
|
# @result[name] = something
|
|
56
60
|
else
|
|
@@ -63,7 +67,7 @@ module Aspera
|
|
|
63
67
|
# @param name [String] name of englobing key
|
|
64
68
|
def flatten_array(array, name)
|
|
65
69
|
if array.empty?
|
|
66
|
-
@result[name] =
|
|
70
|
+
@result[name] = @formatter.special_format('empty list')
|
|
67
71
|
elsif array.all?(String)
|
|
68
72
|
@result[name] = array.join("\n")
|
|
69
73
|
elsif array.all?{|i| i.is_a?(Hash) && i.keys.eql?(%w[name])}
|
|
@@ -85,18 +89,18 @@ module Aspera
|
|
|
85
89
|
flatten_any(v, "#{prefix}#{k}")
|
|
86
90
|
end
|
|
87
91
|
end
|
|
88
|
-
end
|
|
92
|
+
end
|
|
89
93
|
|
|
90
94
|
# Take care of output
|
|
91
95
|
class Formatter
|
|
96
|
+
# remove a fields from the list
|
|
92
97
|
FIELDS_LESS = '-'
|
|
93
98
|
CSV_RECORD_SEPARATOR = "\n"
|
|
94
99
|
CSV_FIELD_SEPARATOR = ','
|
|
95
100
|
# supported output formats
|
|
96
|
-
DISPLAY_FORMATS = %i[text nagios ruby json jsonpp yaml table csv].freeze
|
|
101
|
+
DISPLAY_FORMATS = %i[text nagios ruby json jsonpp yaml table csv image].freeze
|
|
97
102
|
# user output levels
|
|
98
103
|
DISPLAY_LEVELS = %i[info data error].freeze
|
|
99
|
-
RESULT_PARAMS = %i[type data total fields name].freeze
|
|
100
104
|
|
|
101
105
|
private_constant :DISPLAY_FORMATS, :DISPLAY_LEVELS, :CSV_RECORD_SEPARATOR, :CSV_FIELD_SEPARATOR
|
|
102
106
|
# prefix to display error messages in user messages (terminal)
|
|
@@ -105,27 +109,14 @@ module Aspera
|
|
|
105
109
|
HINT_FLASH = 'HINT:'.bg_green.gray.blink.freeze
|
|
106
110
|
|
|
107
111
|
class << self
|
|
108
|
-
# Highlight special values
|
|
109
|
-
def special(what, use_colors: $stdout.isatty)
|
|
110
|
-
result = $stdout.isatty ? "<#{what}>" : "<#{what}>"
|
|
111
|
-
if use_colors
|
|
112
|
-
result = if %w[null empty].any?{|s|what.include?(s)}
|
|
113
|
-
result.dim
|
|
114
|
-
else
|
|
115
|
-
result.reverse_color
|
|
116
|
-
end
|
|
117
|
-
end
|
|
118
|
-
return result
|
|
119
|
-
end
|
|
120
|
-
|
|
121
112
|
def all_but(list)
|
|
122
113
|
list = [list] unless list.is_a?(Array)
|
|
123
|
-
return list.map{|i|"#{FIELDS_LESS}#{i}"}.unshift(
|
|
114
|
+
return list.map{|i|"#{FIELDS_LESS}#{i}"}.unshift(SpecialValues::ALL)
|
|
124
115
|
end
|
|
125
116
|
|
|
126
117
|
def tick(yes)
|
|
127
118
|
result =
|
|
128
|
-
if Environment.
|
|
119
|
+
if Environment.terminal_supports_unicode?
|
|
129
120
|
if yes
|
|
130
121
|
"\u2713"
|
|
131
122
|
else
|
|
@@ -150,24 +141,55 @@ module Aspera
|
|
|
150
141
|
end
|
|
151
142
|
return result
|
|
152
143
|
end
|
|
153
|
-
end
|
|
144
|
+
end
|
|
154
145
|
|
|
155
146
|
# initialize the formatter
|
|
156
147
|
def initialize
|
|
157
148
|
@options = {}
|
|
149
|
+
@spinner = nil
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
# Highlight special values
|
|
153
|
+
def special_format(what, use_colors: $stdout.isatty)
|
|
154
|
+
result = $stdout.isatty ? "<#{what}>" : "<#{what}>"
|
|
155
|
+
if use_colors
|
|
156
|
+
result = if %w[null empty].any?{|s|what.include?(s)}
|
|
157
|
+
result.dim
|
|
158
|
+
else
|
|
159
|
+
result.reverse_color
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
return result
|
|
158
163
|
end
|
|
159
164
|
|
|
165
|
+
# call this after REST calls if several api calls are expected
|
|
166
|
+
def long_operation_running(title = '')
|
|
167
|
+
return unless Environment.terminal?
|
|
168
|
+
if @spinner.nil?
|
|
169
|
+
@spinner = TTY::Spinner.new('[:spinner] :title', format: :classic)
|
|
170
|
+
@spinner.start
|
|
171
|
+
end
|
|
172
|
+
@spinner.update(title: title)
|
|
173
|
+
@spinner.spin
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
# options are: format, output, display, fields, select, table_style, flat_hash, transpose_single
|
|
160
177
|
def option_handler(option_symbol, operation, value=nil)
|
|
161
178
|
Aspera.assert_values(operation, %i[set get])
|
|
162
179
|
case operation
|
|
163
180
|
when :set
|
|
164
181
|
@options[option_symbol] = value
|
|
165
|
-
|
|
182
|
+
case option_symbol
|
|
183
|
+
when :output
|
|
166
184
|
$stdout = if value.eql?('-')
|
|
167
185
|
STDOUT # rubocop:disable Style/GlobalStdStream
|
|
168
186
|
else
|
|
169
187
|
File.open(value, 'w')
|
|
170
188
|
end
|
|
189
|
+
when :image
|
|
190
|
+
allowed_options = Preview::Terminal.method(:build).parameters.select{|i|i[0].eql?(:key)}.map{|i|i[1]}
|
|
191
|
+
unknown_options = value.keys.map(&:to_sym) - allowed_options
|
|
192
|
+
raise "Invalid parameter(s) for option image: #{unknown_options.join(', ')}, use #{allowed_options.join(', ')}" unless unknown_options.empty?
|
|
171
193
|
end
|
|
172
194
|
when :get then return @options[option_symbol]
|
|
173
195
|
else Aspera.error_unreachable_line
|
|
@@ -176,18 +198,25 @@ module Aspera
|
|
|
176
198
|
end
|
|
177
199
|
|
|
178
200
|
def declare_options(options)
|
|
201
|
+
default_table_style = if Environment.terminal_supports_unicode?
|
|
202
|
+
{border: :unicode_round}
|
|
203
|
+
else
|
|
204
|
+
{}
|
|
205
|
+
end
|
|
206
|
+
|
|
179
207
|
options.declare(:format, 'Output format', values: DISPLAY_FORMATS, handler: {o: self, m: :option_handler}, default: :table)
|
|
180
208
|
options.declare(:output, 'Destination for results', types: String, handler: {o: self, m: :option_handler})
|
|
181
209
|
options.declare(:display, 'Output only some information', values: DISPLAY_LEVELS, handler: {o: self, m: :option_handler}, default: :info)
|
|
182
210
|
options.declare(
|
|
183
|
-
:fields, "Comma separated list of: fields, or #{
|
|
211
|
+
:fields, "Comma separated list of: fields, or #{SpecialValues::ALL}, or #{SpecialValues::DEF}", handler: {o: self, m: :option_handler},
|
|
184
212
|
types: [String, Array, Regexp, Proc],
|
|
185
|
-
default:
|
|
213
|
+
default: SpecialValues::DEF)
|
|
186
214
|
options.declare(:select, 'Select only some items in lists: column, value', types: [Hash, Proc], handler: {o: self, m: :option_handler})
|
|
187
|
-
options.declare(:table_style, 'Table display style', handler: {o: self, m: :option_handler}, default:
|
|
215
|
+
options.declare(:table_style, 'Table display style', types: [Hash], handler: {o: self, m: :option_handler}, default: default_table_style)
|
|
188
216
|
options.declare(:flat_hash, 'Display deep values as additional keys', values: :bool, handler: {o: self, m: :option_handler}, default: true)
|
|
189
217
|
options.declare(:transpose_single, 'Single object fields output vertically', values: :bool, handler: {o: self, m: :option_handler}, default: true)
|
|
190
218
|
options.declare(:show_secrets, 'Show secrets on command output', values: :bool, handler: {o: self, m: :option_handler}, default: false)
|
|
219
|
+
options.declare(:image, 'Options for image display', types: Hash, handler: {o: self, m: :option_handler}, default: {})
|
|
191
220
|
end
|
|
192
221
|
|
|
193
222
|
# main output method
|
|
@@ -220,14 +249,15 @@ module Aspera
|
|
|
220
249
|
data.each_with_object({}){|v, m|v.each_key{|c|m[c] = true}}.keys
|
|
221
250
|
end
|
|
222
251
|
|
|
223
|
-
#
|
|
224
|
-
# data
|
|
225
|
-
# default
|
|
252
|
+
# @return the list of fields to display
|
|
253
|
+
# @param data [Array<Hash>] data to display
|
|
254
|
+
# @param default [Array<String>, Proc] list of fields to display by default (may contain special values)
|
|
226
255
|
def compute_fields(data, default)
|
|
227
256
|
Log.log.debug{"compute_fields: data:#{data.class} default:#{default.class} #{default}"}
|
|
257
|
+
# the requested list of fields, but if can contain special values
|
|
228
258
|
request =
|
|
229
259
|
case @options[:fields]
|
|
230
|
-
when NilClass then [
|
|
260
|
+
# when NilClass then [SpecialValues::DEF]
|
|
231
261
|
when String then @options[:fields].split(',')
|
|
232
262
|
when Array then @options[:fields]
|
|
233
263
|
when Regexp then return all_fields(data).select{|i|i.match(@options[:fields])}
|
|
@@ -243,10 +273,10 @@ module Aspera
|
|
|
243
273
|
item = item[1..-1]
|
|
244
274
|
end
|
|
245
275
|
case item
|
|
246
|
-
when
|
|
276
|
+
when SpecialValues::ALL
|
|
247
277
|
# get the list of all column names used in all lines, not just first one, as all lines may have different columns
|
|
248
278
|
request.unshift(*all_fields(data))
|
|
249
|
-
when
|
|
279
|
+
when SpecialValues::DEF
|
|
250
280
|
default = all_fields(data).select{|i|default.call(i)} if default.is_a?(Proc)
|
|
251
281
|
default = all_fields(data) if default.nil?
|
|
252
282
|
request.unshift(*default)
|
|
@@ -261,20 +291,39 @@ module Aspera
|
|
|
261
291
|
return result
|
|
262
292
|
end
|
|
263
293
|
|
|
294
|
+
# filter the list of items on the fields option
|
|
295
|
+
def filter_list_on_fields(data)
|
|
296
|
+
# by default, keep all data intact
|
|
297
|
+
return data if @options[:fields].eql?(SpecialValues::DEF) && @options[:select].nil?
|
|
298
|
+
Aspera.assert_type(data, Array){'Filtering fields or select requires result is an Array of Hash'}
|
|
299
|
+
Aspera.assert(data.all?(Hash)){'Filtering fields or select requires result is an Array of Hash'}
|
|
300
|
+
filter_columns_on_select(data)
|
|
301
|
+
return data if @options[:fields].eql?(SpecialValues::DEF)
|
|
302
|
+
selected_fields = compute_fields(data, @options[:fields])
|
|
303
|
+
return data.map{|i|i[selected_fields.first]} if selected_fields.length == 1
|
|
304
|
+
return data.map{|i|i.select{|k, _|selected_fields.include?(k)}}
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
# filter the list of items on the select option
|
|
308
|
+
# @param data [Array<Hash>] list of items
|
|
309
|
+
def filter_columns_on_select(data)
|
|
310
|
+
case @options[:select]
|
|
311
|
+
when Proc
|
|
312
|
+
data.select!{|i|@options[:select].call(i)}
|
|
313
|
+
when Hash
|
|
314
|
+
@options[:select].each{|k, v|data.select!{|i|i[k].eql?(v)}}
|
|
315
|
+
end
|
|
316
|
+
end
|
|
317
|
+
|
|
264
318
|
# this method displays a table
|
|
265
319
|
# object_array: array of hash
|
|
266
320
|
# fields: list of column names
|
|
267
321
|
def display_table(object_array, fields)
|
|
268
322
|
Aspera.assert(!fields.nil?){'missing fields parameter'}
|
|
269
|
-
|
|
270
|
-
when Proc
|
|
271
|
-
object_array.select!{|i|@options[:select].call(i)}
|
|
272
|
-
when Hash
|
|
273
|
-
@options[:select].each{|k, v|object_array.select!{|i|i[k].eql?(v)}}
|
|
274
|
-
end
|
|
323
|
+
filter_columns_on_select(object_array)
|
|
275
324
|
if object_array.empty?
|
|
276
325
|
# no display for csv
|
|
277
|
-
display_message(:info,
|
|
326
|
+
display_message(:info, special_format('empty')) if @options[:format].eql?(:table)
|
|
278
327
|
return
|
|
279
328
|
end
|
|
280
329
|
if object_array.length == 1 && fields.length == 1
|
|
@@ -294,72 +343,114 @@ module Aspera
|
|
|
294
343
|
# here : fields : list of column names
|
|
295
344
|
case @options[:format]
|
|
296
345
|
when :table
|
|
297
|
-
style = @options[:table_style].chars
|
|
298
346
|
# display the table !
|
|
299
347
|
display_message(:data, Terminal::Table.new(
|
|
300
348
|
headings: fields,
|
|
301
349
|
rows: final_table_rows,
|
|
302
|
-
|
|
303
|
-
border_y: style[1],
|
|
304
|
-
border_i: style[2]))
|
|
350
|
+
style: @options[:table_style]&.symbolize_keys))
|
|
305
351
|
when :csv
|
|
306
352
|
display_message(:data, final_table_rows.map{|t| t.join(CSV_FIELD_SEPARATOR)}.join(CSV_RECORD_SEPARATOR))
|
|
307
353
|
end
|
|
308
354
|
end
|
|
309
355
|
|
|
356
|
+
# @return text suitable to display an image from url
|
|
357
|
+
def status_image(blob)
|
|
358
|
+
begin
|
|
359
|
+
raise URI::InvalidURIError, 'not uri' if !(blob =~ /\A#{URI::DEFAULT_PARSER.make_regexp}\z/)
|
|
360
|
+
# it's a url
|
|
361
|
+
url = blob
|
|
362
|
+
unless Environment.instance.url_method.eql?(:text)
|
|
363
|
+
Environment.instance.open_uri(url)
|
|
364
|
+
return ''
|
|
365
|
+
end
|
|
366
|
+
# remote_image = Rest.new(base_url: url).read('')
|
|
367
|
+
# mime = remote_image[:http]['content-type']
|
|
368
|
+
# blob = remote_image[:http].body
|
|
369
|
+
# Log.log.warn("Image ? #{remote_image[:http]['content-type']}") unless mime.include?('image/')
|
|
370
|
+
blob = UriReader.read(url)
|
|
371
|
+
rescue URI::InvalidURIError
|
|
372
|
+
nil
|
|
373
|
+
end
|
|
374
|
+
# try base64
|
|
375
|
+
begin
|
|
376
|
+
blob = Base64.strict_decode64(blob)
|
|
377
|
+
rescue
|
|
378
|
+
nil
|
|
379
|
+
end
|
|
380
|
+
return Preview::Terminal.build(blob, **@options[:image].symbolize_keys)
|
|
381
|
+
end
|
|
382
|
+
|
|
310
383
|
# this method displays the results, especially the table format
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
384
|
+
# @param type [Symbol] type of data
|
|
385
|
+
# @param data [Object] data to display
|
|
386
|
+
# @param total [Integer] total number of items
|
|
387
|
+
# @param fields [Array<String>] list of fields to display
|
|
388
|
+
# @param name [String] name of the column to display
|
|
389
|
+
def display_results(type:, data: nil, total: nil, fields: nil, name: nil)
|
|
390
|
+
Log.log.debug{"display_results: #{type} class=#{data.class} data=#{data}"}
|
|
391
|
+
Aspera.assert_type(type, Symbol){'result must have type'}
|
|
392
|
+
Aspera.assert(!data.nil? || %i[empty nothing].include?(type)){'result must have data'}
|
|
393
|
+
display_item_count(data.length, total) unless total.nil?
|
|
394
|
+
SecretHider.deep_remove_secret(data) unless @options[:show_secrets] || @options[:display].eql?(:data)
|
|
319
395
|
case @options[:format]
|
|
320
396
|
when :text
|
|
321
|
-
display_message(:data,
|
|
397
|
+
display_message(:data, data.to_s)
|
|
322
398
|
when :nagios
|
|
323
|
-
Nagios.process(
|
|
399
|
+
Nagios.process(data)
|
|
324
400
|
when :ruby
|
|
325
|
-
display_message(:data, PP.pp(
|
|
401
|
+
display_message(:data, PP.pp(filter_list_on_fields(data), +''))
|
|
326
402
|
when :json
|
|
327
|
-
display_message(:data, JSON.generate(
|
|
403
|
+
display_message(:data, JSON.generate(filter_list_on_fields(data)))
|
|
328
404
|
when :jsonpp
|
|
329
|
-
display_message(:data, JSON.pretty_generate(
|
|
405
|
+
display_message(:data, JSON.pretty_generate(filter_list_on_fields(data)))
|
|
330
406
|
when :yaml
|
|
331
|
-
display_message(:data,
|
|
407
|
+
display_message(:data, YAML.dump(filter_list_on_fields(data)))
|
|
408
|
+
when :image
|
|
409
|
+
# assume it is an url
|
|
410
|
+
url = data
|
|
411
|
+
case type
|
|
412
|
+
when :single_object, :object_list
|
|
413
|
+
url = [url] if type.eql?(:single_object)
|
|
414
|
+
raise 'image display requires a single result' unless url.length == 1
|
|
415
|
+
fields = compute_fields(url, fields)
|
|
416
|
+
raise 'select a field to display' unless fields.length == 1
|
|
417
|
+
url = url.first
|
|
418
|
+
raise 'no such field' unless url.key?(fields.first)
|
|
419
|
+
url = url[fields.first]
|
|
420
|
+
end
|
|
421
|
+
raise "not url: #{url.class} #{url}" unless url.is_a?(String)
|
|
422
|
+
display_message(:data, status_image(url))
|
|
332
423
|
when :table, :csv
|
|
333
|
-
case
|
|
424
|
+
case type
|
|
334
425
|
when :config_over
|
|
335
|
-
display_table(Flattener.new.config_over(
|
|
426
|
+
display_table(Flattener.new(self).config_over(data), CONF_OVERVIEW_KEYS)
|
|
336
427
|
when :object_list, :single_object
|
|
337
|
-
obj_list =
|
|
338
|
-
obj_list = [obj_list] if
|
|
428
|
+
obj_list = data
|
|
429
|
+
obj_list = [obj_list] if type.eql?(:single_object)
|
|
339
430
|
Aspera.assert_type(obj_list, Array)
|
|
340
431
|
Aspera.assert(obj_list.all?(Hash)){"expecting Array of Hash: #{obj_list.inspect}"}
|
|
341
432
|
# :object_list is an array of hash tables, where key=colum name
|
|
342
|
-
obj_list = obj_list.map{|obj|Flattener.new.flatten(obj)} if @options[:flat_hash]
|
|
343
|
-
display_table(obj_list, compute_fields(obj_list,
|
|
433
|
+
obj_list = obj_list.map{|obj|Flattener.new(self).flatten(obj)} if @options[:flat_hash]
|
|
434
|
+
display_table(obj_list, compute_fields(obj_list, fields))
|
|
344
435
|
when :value_list
|
|
345
436
|
# :value_list is a simple array of values, name of column provided in the :name
|
|
346
|
-
display_table(
|
|
437
|
+
display_table(data.map { |i| { name => i } }, [name])
|
|
347
438
|
when :empty # no table
|
|
348
|
-
display_message(:info,
|
|
439
|
+
display_message(:info, special_format('empty'))
|
|
349
440
|
return
|
|
350
441
|
when :nothing # no result expected
|
|
351
442
|
Log.log.debug('no result expected')
|
|
352
443
|
when :status # no table
|
|
353
444
|
# :status displays a simple message
|
|
354
|
-
display_message(:info,
|
|
445
|
+
display_message(:info, data)
|
|
355
446
|
when :text # no table
|
|
356
447
|
# :status displays a simple message
|
|
357
|
-
display_message(:data,
|
|
448
|
+
display_message(:data, data)
|
|
358
449
|
when :other_struct # no table
|
|
359
450
|
# :other_struct is any other type of structure
|
|
360
|
-
display_message(:data, PP.pp(
|
|
451
|
+
display_message(:data, PP.pp(data, +''))
|
|
361
452
|
else
|
|
362
|
-
raise "unknown data type: #{
|
|
453
|
+
raise "unknown data type: #{type}"
|
|
363
454
|
end
|
|
364
455
|
end
|
|
365
456
|
end
|
data/lib/aspera/cli/hints.rb
CHANGED
|
@@ -47,6 +47,24 @@ module Aspera
|
|
|
47
47
|
'if you provide a path: prefix with @file:',
|
|
48
48
|
'e.g. --private-key=@file:/path/to/key.pem'
|
|
49
49
|
]
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
exception: RuntimeError,
|
|
53
|
+
match: /unexpected last event type: INIT/,
|
|
54
|
+
remediation: [
|
|
55
|
+
'ascp exited unexpectedly',
|
|
56
|
+
'it might be due to SSH handshake failure',
|
|
57
|
+
'one can check SSH connection using ssh command'
|
|
58
|
+
]
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
exception: RuntimeError,
|
|
62
|
+
match: /Wrong remote host:/,
|
|
63
|
+
remediation: [
|
|
64
|
+
'If remote node is Cloud Pak For Integration',
|
|
65
|
+
'Make sure that a LoadBalancer is active on cluster',
|
|
66
|
+
'Check the external address of Aspera tcp-proxy pod'
|
|
67
|
+
]
|
|
50
68
|
}
|
|
51
69
|
]
|
|
52
70
|
|
data/lib/aspera/cli/main.rb
CHANGED
|
@@ -9,7 +9,6 @@ require 'aspera/cli/transfer_agent'
|
|
|
9
9
|
require 'aspera/cli/version'
|
|
10
10
|
require 'aspera/cli/info'
|
|
11
11
|
require 'aspera/cli/hints'
|
|
12
|
-
require 'aspera/preview/terminal'
|
|
13
12
|
require 'aspera/secret_hider'
|
|
14
13
|
require 'aspera/log'
|
|
15
14
|
require 'aspera/assert'
|
|
@@ -20,9 +19,10 @@ module Aspera
|
|
|
20
19
|
class Main
|
|
21
20
|
# Plugins store transfer result using this key and use result_transfer_multiple()
|
|
22
21
|
STATUS_FIELD = 'status'
|
|
23
|
-
|
|
22
|
+
COMMAND_CONFIG = :config
|
|
23
|
+
COMMAND_HELP = :help
|
|
24
24
|
|
|
25
|
-
private_constant :
|
|
25
|
+
private_constant :COMMAND_CONFIG, :COMMAND_HELP
|
|
26
26
|
|
|
27
27
|
class << self
|
|
28
28
|
# expect some list, but nothing to display
|
|
@@ -60,14 +60,10 @@ module Aspera
|
|
|
60
60
|
return {type: :object_list, data: status_table}
|
|
61
61
|
end
|
|
62
62
|
|
|
63
|
-
def
|
|
64
|
-
|
|
65
|
-
allowed_options = Preview::Terminal.method(:build).parameters.select{|i|i[0].eql?(:key)}.map{|i|i[1]}
|
|
66
|
-
unknown_options = terminal_options.keys - allowed_options
|
|
67
|
-
raise "invalid options: #{unknown_options.join(', ')}, use #{allowed_options.join(', ')}" unless unknown_options.empty?
|
|
68
|
-
return Main.result_status(Preview::Terminal.build(blob, **terminal_options))
|
|
63
|
+
def result_image(blob, formatter:)
|
|
64
|
+
return Main.result_status(formatter.status_image(blob))
|
|
69
65
|
end
|
|
70
|
-
end
|
|
66
|
+
end
|
|
71
67
|
|
|
72
68
|
private
|
|
73
69
|
|
|
@@ -88,6 +84,8 @@ module Aspera
|
|
|
88
84
|
@option_help = false
|
|
89
85
|
@option_show_config = false
|
|
90
86
|
@bash_completion = false
|
|
87
|
+
early_debug_setup
|
|
88
|
+
Log.log.trace2{Log.dump(:argv, @argv)}
|
|
91
89
|
end
|
|
92
90
|
|
|
93
91
|
# This can throw exception if there is a problem with the environment, needs to be caught by execute method
|
|
@@ -95,13 +93,11 @@ module Aspera
|
|
|
95
93
|
@plug_init[:only_manual] = false
|
|
96
94
|
# create formatter, in case there is an exception, it is used to display.
|
|
97
95
|
@plug_init[:formatter] = Formatter.new
|
|
98
|
-
#
|
|
99
|
-
|
|
100
|
-
@plug_init[:options] = Manager.new(PROGRAM_NAME)
|
|
101
|
-
# give command line arguments to option manager
|
|
102
|
-
options.parse_command_line(@argv)
|
|
96
|
+
# create command line manager with arguments
|
|
97
|
+
@plug_init[:options] = Manager.new(PROGRAM_NAME, @argv)
|
|
103
98
|
# formatter adds options
|
|
104
|
-
formatter.declare_options(options)
|
|
99
|
+
@plug_init[:formatter].declare_options(options)
|
|
100
|
+
ExtendedValue.instance.default_decoder = options.get_option(:struct_parser)
|
|
105
101
|
# compare $0 with expected name
|
|
106
102
|
current_prog_name = File.basename($PROGRAM_NAME)
|
|
107
103
|
formatter.display_message(
|
|
@@ -164,12 +160,11 @@ module Aspera
|
|
|
164
160
|
options.declare(:bash_comp, 'Generate bash completion for command', values: :none) { @bash_completion = true }
|
|
165
161
|
options.declare(:show_config, 'Display parameters used for the provided action', values: :none) { @option_show_config = true }
|
|
166
162
|
options.declare(:version, 'Display version', values: :none, short: 'v') { formatter.display_message(:data, Cli::VERSION); Process.exit(0) } # rubocop:disable Style/Semicolon, Layout/LineLength
|
|
167
|
-
options.declare(:warnings, 'Check for language warnings', values: :none, short: 'w') { $VERBOSE = true }
|
|
168
163
|
options.declare(
|
|
169
164
|
:ui, 'Method to start browser',
|
|
170
|
-
values:
|
|
171
|
-
handler: {o:
|
|
172
|
-
default:
|
|
165
|
+
values: Environment::USER_INTERFACES,
|
|
166
|
+
handler: {o: Environment.instance, m: :url_method},
|
|
167
|
+
default: Environment.default_gui_mode)
|
|
173
168
|
options.declare(:log_level, 'Log level', values: Log.levels, handler: {o: Log.instance, m: :level})
|
|
174
169
|
options.declare(:logger, 'Logging method', values: Log::LOG_TYPES, handler: {o: Log.instance, m: :logger_type})
|
|
175
170
|
options.declare(:lock_port, 'Prevent dual execution of a command, e.g. in cron', coerce: Integer, types: Integer)
|
|
@@ -187,31 +182,29 @@ module Aspera
|
|
|
187
182
|
def get_plugin_instance_with_options(plugin_name_sym, env=nil)
|
|
188
183
|
env ||= @plug_init
|
|
189
184
|
Log.log.debug{"get_plugin_instance_with_options(#{plugin_name_sym})"}
|
|
190
|
-
require PluginFactory.instance.plugins[plugin_name_sym][:require_stanza]
|
|
191
185
|
# load default params only if no param already loaded before plugin instantiation
|
|
192
186
|
env[:config].add_plugin_default_preset(plugin_name_sym)
|
|
193
187
|
command_plugin = PluginFactory.instance.create(plugin_name_sym, **env)
|
|
194
|
-
Log.log.debug{"got #{command_plugin.class}"}
|
|
195
188
|
return command_plugin
|
|
196
189
|
end
|
|
197
190
|
|
|
198
191
|
def generate_bash_completion
|
|
199
|
-
if options.get_next_argument('',
|
|
200
|
-
PluginFactory.instance.
|
|
192
|
+
if options.get_next_argument('', multiple: true, mandatory: false).nil?
|
|
193
|
+
PluginFactory.instance.plugin_list.each{|p|puts p}
|
|
201
194
|
else
|
|
202
195
|
Log.log.warn('only first level completion so far')
|
|
203
196
|
end
|
|
204
197
|
Process.exit(0)
|
|
205
198
|
end
|
|
206
199
|
|
|
207
|
-
def exit_with_usage(
|
|
208
|
-
Log.log.debug(
|
|
200
|
+
def exit_with_usage(include_all_plugins)
|
|
201
|
+
Log.log.debug{"exit_with_usage(#{include_all_plugins})".bg_red}
|
|
209
202
|
# display main plugin options
|
|
210
203
|
formatter.display_message(:error, options.parser)
|
|
211
|
-
if
|
|
204
|
+
if include_all_plugins
|
|
212
205
|
# list plugins that have a "require" field, i.e. all but main plugin
|
|
213
|
-
PluginFactory.instance.
|
|
214
|
-
next if plugin_name_sym.eql?(
|
|
206
|
+
PluginFactory.instance.plugin_list.each do |plugin_name_sym|
|
|
207
|
+
next if plugin_name_sym.eql?(COMMAND_CONFIG)
|
|
215
208
|
# override main option parser with a brand new, to avoid having global options
|
|
216
209
|
plugin_env = @plug_init.clone
|
|
217
210
|
plugin_env[:only_manual] = true # force declaration of all options
|
|
@@ -261,17 +254,17 @@ module Aspera
|
|
|
261
254
|
config.periodic_check_newer_gem_version
|
|
262
255
|
command_sym =
|
|
263
256
|
if @option_show_config && options.command_or_arg_empty?
|
|
264
|
-
|
|
257
|
+
COMMAND_CONFIG
|
|
265
258
|
else
|
|
266
|
-
options.get_next_command(PluginFactory.instance.
|
|
259
|
+
options.get_next_command(PluginFactory.instance.plugin_list.unshift(COMMAND_HELP))
|
|
267
260
|
end
|
|
268
261
|
# command will not be executed, but we need manual
|
|
269
262
|
options.fail_on_missing_mandatory = false if @option_help || @option_show_config
|
|
270
263
|
# main plugin is not dynamically instantiated
|
|
271
264
|
case command_sym
|
|
272
|
-
when
|
|
265
|
+
when COMMAND_HELP
|
|
273
266
|
exit_with_usage(true)
|
|
274
|
-
when
|
|
267
|
+
when COMMAND_CONFIG
|
|
275
268
|
command_plugin = config
|
|
276
269
|
else
|
|
277
270
|
# get plugin, set options, etc
|
|
@@ -282,7 +275,7 @@ module Aspera
|
|
|
282
275
|
# help requested for current plugin
|
|
283
276
|
exit_with_usage(false) if @option_help
|
|
284
277
|
if @option_show_config
|
|
285
|
-
formatter.display_results(
|
|
278
|
+
formatter.display_results(type: :single_object, data: options.known_options(only_defined: true).stringify_keys)
|
|
286
279
|
execute_command = false
|
|
287
280
|
end
|
|
288
281
|
# locking for single execution (only after "per plugin" option, in case lock port is there)
|
|
@@ -304,7 +297,7 @@ module Aspera
|
|
|
304
297
|
at_exit{File.delete(pid_file)}
|
|
305
298
|
end
|
|
306
299
|
# execute and display (if not exclusive execution)
|
|
307
|
-
formatter.display_results(command_plugin.execute_action) if execute_command
|
|
300
|
+
formatter.display_results(**command_plugin.execute_action) if execute_command
|
|
308
301
|
# save config file if command modified it
|
|
309
302
|
config.save_config_file_if_needed
|
|
310
303
|
# finish
|
|
@@ -347,7 +340,7 @@ module Aspera
|
|
|
347
340
|
Process.exit(1)
|
|
348
341
|
end
|
|
349
342
|
return nil
|
|
350
|
-
end
|
|
351
|
-
end
|
|
352
|
-
end
|
|
353
|
-
end
|
|
343
|
+
end
|
|
344
|
+
end
|
|
345
|
+
end
|
|
346
|
+
end
|