aspera-cli 4.18.0 → 4.18.1
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 +3 -2
- data/CHANGELOG.md +10 -0
- data/README.md +96 -59
- data/examples/build_package.sh +28 -0
- data/lib/aspera/agent/alpha.rb +4 -4
- data/lib/aspera/agent/connect.rb +3 -4
- data/lib/aspera/agent/httpgw.rb +1 -1
- data/lib/aspera/api/httpgw.rb +4 -1
- data/lib/aspera/api/node.rb +110 -77
- data/lib/aspera/ascp/products.rb +1 -1
- data/lib/aspera/cli/extended_value.rb +27 -14
- data/lib/aspera/cli/formatter.rb +11 -10
- data/lib/aspera/cli/main.rb +11 -11
- data/lib/aspera/cli/manager.rb +99 -84
- data/lib/aspera/cli/plugin.rb +2 -5
- data/lib/aspera/cli/plugins/aoc.rb +15 -14
- data/lib/aspera/cli/plugins/config.rb +20 -19
- data/lib/aspera/cli/plugins/faspex.rb +5 -4
- data/lib/aspera/cli/plugins/faspex5.rb +16 -13
- data/lib/aspera/cli/plugins/node.rb +46 -38
- data/lib/aspera/cli/plugins/orchestrator.rb +3 -2
- data/lib/aspera/cli/plugins/preview.rb +1 -1
- data/lib/aspera/cli/plugins/server.rb +1 -1
- data/lib/aspera/cli/special_values.rb +13 -0
- data/lib/aspera/cli/sync_actions.rb +4 -4
- data/lib/aspera/cli/transfer_agent.rb +2 -2
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/environment.rb +64 -4
- data/lib/aspera/oauth/web.rb +2 -2
- data/lib/aspera/rest.rb +46 -15
- data.tar.gz.sig +0 -0
- metadata +4 -3
- metadata.gz.sig +0 -0
- data/lib/aspera/open_application.rb +0 -69
data/lib/aspera/cli/manager.rb
CHANGED
@@ -55,12 +55,13 @@ module Aspera
|
|
55
55
|
# option name separator in code (symbol)
|
56
56
|
OPTION_SEP_SYMBOL = '_'
|
57
57
|
SOURCE_USER = 'cmdline' # cspell:disable-line
|
58
|
-
TYPE_INTEGER = [Integer].freeze
|
59
58
|
OPTION_VALUE_SEPARATOR = '='
|
60
59
|
OPTION_PREFIX = '--'
|
61
60
|
OPTIONS_STOP = '--'
|
62
61
|
|
63
|
-
|
62
|
+
DEFAULT_PARSER_TYPES = [Array, Hash].freeze
|
63
|
+
|
64
|
+
private_constant :FALSE_VALUES, :TRUE_VALUES, :BOOLEAN_VALUES, :OPTION_SEP_LINE, :OPTION_SEP_SYMBOL, :SOURCE_USER
|
64
65
|
|
65
66
|
class << self
|
66
67
|
def enum_to_bool(enum)
|
@@ -86,9 +87,9 @@ module Aspera
|
|
86
87
|
|
87
88
|
# Generates error message with list of allowed values
|
88
89
|
# @param error_msg [String] error message
|
89
|
-
# @param
|
90
|
-
def multi_choice_assert(assertion, error_msg,
|
91
|
-
raise Cli::BadArgument, [error_msg, 'Use:'].concat(
|
90
|
+
# @param accept_list [Array] list of allowed values
|
91
|
+
def multi_choice_assert(assertion, error_msg, accept_list)
|
92
|
+
raise Cli::BadArgument, [error_msg, 'Use:'].concat(accept_list.map{|c|"- #{c}"}.sort).join("\n") unless assertion
|
92
93
|
end
|
93
94
|
|
94
95
|
# change option name with dash to name with underscore
|
@@ -102,14 +103,17 @@ module Aspera
|
|
102
103
|
|
103
104
|
# @param what [Symbol] :option or :argument
|
104
105
|
# @param descr [String] description for help
|
105
|
-
# @param
|
106
|
+
# @param to_check [Object] value to check
|
106
107
|
# @param type_list [NilClass, Class, Array[Class]] accepted value type(s)
|
107
|
-
def validate_type(what, descr,
|
108
|
+
def validate_type(what, descr, to_check, type_list, check_array: false)
|
108
109
|
return nil if type_list.nil?
|
109
110
|
Aspera.assert(type_list.is_a?(Array) && type_list.all?(Class)){'types must be a Class Array'}
|
110
|
-
|
111
|
-
|
112
|
-
|
111
|
+
value_list = check_array ? to_check : [to_check]
|
112
|
+
value_list.each do |value|
|
113
|
+
raise Cli::BadArgument,
|
114
|
+
"#{what.to_s.capitalize} #{descr} is a #{value.class} but must be #{type_list.length > 1 ? 'one of ' : ''}#{type_list.map(&:name).join(',')}" unless \
|
115
|
+
type_list.any?{|t|value.is_a?(t)}
|
116
|
+
end
|
113
117
|
end
|
114
118
|
end
|
115
119
|
|
@@ -117,7 +121,7 @@ module Aspera
|
|
117
121
|
attr_accessor :ask_missing_mandatory, :ask_missing_optional
|
118
122
|
attr_writer :fail_on_missing_mandatory
|
119
123
|
|
120
|
-
def initialize(program_name)
|
124
|
+
def initialize(program_name, argv = nil)
|
121
125
|
# command line values *not* starting with '-'
|
122
126
|
@unprocessed_cmd_line_arguments = []
|
123
127
|
# command line values starting with '-'
|
@@ -149,14 +153,7 @@ module Aspera
|
|
149
153
|
Log.log.debug{"env=#{@option_pairs_env}".red}
|
150
154
|
@unprocessed_cmd_line_options = []
|
151
155
|
@unprocessed_cmd_line_arguments = []
|
152
|
-
|
153
|
-
|
154
|
-
def parse_command_line(argv)
|
155
|
-
@parser.separator('')
|
156
|
-
@parser.separator('OPTIONS: global')
|
157
|
-
declare(:interactive, 'Use interactive input of missing params', values: :bool, handler: {o: self, m: :ask_missing_mandatory})
|
158
|
-
declare(:ask_options, 'Ask even optional options', values: :bool, handler: {o: self, m: :ask_missing_optional})
|
159
|
-
parse_options!
|
156
|
+
return if argv.nil?
|
160
157
|
process_options = true
|
161
158
|
until argv.empty?
|
162
159
|
value = argv.shift
|
@@ -174,65 +171,63 @@ module Aspera
|
|
174
171
|
end
|
175
172
|
@initial_cli_options = @unprocessed_cmd_line_options.dup.freeze
|
176
173
|
Log.log.debug{"add_cmd_line_options:commands/arguments=#{@unprocessed_cmd_line_arguments},options=#{@unprocessed_cmd_line_options}".red}
|
174
|
+
@parser.separator('')
|
175
|
+
@parser.separator('OPTIONS: global')
|
176
|
+
declare(:interactive, 'Use interactive input of missing params', values: :bool, handler: {o: self, m: :ask_missing_mandatory})
|
177
|
+
declare(:ask_options, 'Ask even optional options', values: :bool, handler: {o: self, m: :ask_missing_optional})
|
178
|
+
declare(:struct_parser, 'Default parser when expected value is a struct', values: %i[json ruby])
|
179
|
+
# do not parse options yet, let's wait for option `-h` to be overriden
|
177
180
|
end
|
178
181
|
|
179
182
|
# @param descr [String] description for help
|
180
|
-
# @param expected is
|
181
|
-
# - Array of allowed value (single value)
|
182
|
-
# - :multiple for remaining values
|
183
|
-
# - :single for a single unconstrained value
|
184
|
-
# - :integer for a single integer value
|
185
183
|
# @param mandatory [Boolean] if true, raise error if option not set
|
186
|
-
# @param
|
184
|
+
# @param multiple [Boolean] if true, return remaining arguments
|
185
|
+
# @param accept_list [Array] list of allowed values (Symbol)
|
186
|
+
# @param validation [Class, Array] accepted value type(s) or list of Symbols
|
187
187
|
# @param aliases [Hash] map of aliases: key = alias, value = real value
|
188
188
|
# @param default [Object] default value
|
189
|
-
# @return value, list or nil
|
190
|
-
def get_next_argument(descr,
|
191
|
-
Aspera.assert(
|
192
|
-
|
193
|
-
|
194
|
-
Aspera.assert(
|
195
|
-
|
196
|
-
allowed_types = type
|
189
|
+
# @return one value, list or nil (if optional and no default)
|
190
|
+
def get_next_argument(descr, mandatory: true, multiple: false, accept_list: nil, validation: String, aliases: nil, default: nil)
|
191
|
+
Aspera.assert(accept_list.nil? || (accept_list.is_a?(Array) && accept_list.all?(Symbol)))
|
192
|
+
validation = Symbol if accept_list
|
193
|
+
Aspera.assert(validation.nil? || validation.is_a?(Class) || (validation.is_a?(Array) && validation.all?(Class))){'validation must be Class or Array of Class'}
|
194
|
+
Aspera.assert(aliases.nil? || (aliases.is_a?(Hash) && aliases.keys.all?(Symbol) && aliases.values.all?(Symbol))){'aliases must be Hash:Symbol: Symbol'}
|
195
|
+
allowed_types = validation
|
197
196
|
unless allowed_types.nil?
|
198
197
|
allowed_types = [allowed_types] unless allowed_types.is_a?(Array)
|
199
198
|
descr = "#{descr} (#{allowed_types.join(', ')})"
|
200
199
|
end
|
201
200
|
result =
|
202
201
|
if !@unprocessed_cmd_line_arguments.empty?
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
if value.length.eql?(1) && value.first.is_a?(Array)
|
211
|
-
value = value.first
|
212
|
-
end
|
213
|
-
value
|
214
|
-
when Array
|
215
|
-
allowed_values = [].concat(expected)
|
202
|
+
how_many = multiple ? @unprocessed_cmd_line_arguments.length : 1
|
203
|
+
values = @unprocessed_cmd_line_arguments.shift(how_many)
|
204
|
+
values = values.map{|v|evaluate_extended_value(v, allowed_types)}
|
205
|
+
# if expecting list and only one arg of type array : it is the list
|
206
|
+
values = values.first if values.length.eql?(1) && values.first.is_a?(Array)
|
207
|
+
if accept_list
|
208
|
+
allowed_values = [].concat(accept_list)
|
216
209
|
allowed_values.concat(aliases.keys) unless aliases.nil?
|
217
|
-
self.class.get_from_list(
|
218
|
-
else Aspera.error_unexpected_value(expected)
|
210
|
+
values = values.map{|v|self.class.get_from_list(v, descr, allowed_values)}
|
219
211
|
end
|
212
|
+
multiple ? values : values.first
|
220
213
|
elsif !default.nil? then default
|
221
214
|
# no value provided, either get value interactively, or exception
|
222
|
-
elsif mandatory then get_interactive(
|
215
|
+
elsif mandatory then get_interactive(descr, multiple: multiple, accept_list: accept_list)
|
223
216
|
end
|
224
|
-
if result.is_a?(String) &&
|
217
|
+
if result.is_a?(String) && validation.eql?(Integer)
|
225
218
|
int_result = Integer(result, exception: false)
|
226
219
|
raise Cli::BadArgument, "Invalid integer: #{result}" if int_result.nil?
|
227
220
|
result = int_result
|
228
221
|
end
|
229
222
|
Log.log.debug{"#{descr}=#{result}"}
|
230
223
|
result = aliases[result] if aliases&.key?(result)
|
231
|
-
|
224
|
+
# if value comes from JSON/YAML, it may come as Integer
|
225
|
+
result = result.to_s if result.is_a?(Integer) && validation.eql?(String)
|
226
|
+
self.class.validate_type(:argument, descr, result, allowed_types, check_array: multiple) unless result.nil? && !mandatory
|
232
227
|
return result
|
233
228
|
end
|
234
229
|
|
235
|
-
def get_next_command(command_list, aliases: nil); return get_next_argument('command',
|
230
|
+
def get_next_command(command_list, aliases: nil); return get_next_argument('command', accept_list: command_list, aliases: aliases); end
|
236
231
|
|
237
232
|
# Get an option value by name
|
238
233
|
# either return value or calls handler, can return nil
|
@@ -261,13 +256,13 @@ module Aspera
|
|
261
256
|
raise Cli::BadArgument, "Missing mandatory option: #{option_symbol}" if mandatory
|
262
257
|
elsif @ask_missing_optional || mandatory
|
263
258
|
# ask_missing_mandatory
|
264
|
-
|
259
|
+
accept_list = nil
|
265
260
|
# print "please enter: #{option_symbol.to_s}"
|
266
261
|
if @declared_options.key?(option_symbol) && attributes.key?(:values)
|
267
|
-
|
262
|
+
accept_list = attributes[:values]
|
268
263
|
end
|
269
|
-
result = get_interactive(
|
270
|
-
set_option(option_symbol, result, 'interactive')
|
264
|
+
result = get_interactive(option_symbol.to_s, option: true, accept_list: accept_list)
|
265
|
+
set_option(option_symbol, result, where: 'interactive')
|
271
266
|
end
|
272
267
|
end
|
273
268
|
self.class.validate_type(:option, option_symbol, result, attributes[:types]) unless result.nil? && !mandatory
|
@@ -275,12 +270,16 @@ module Aspera
|
|
275
270
|
end
|
276
271
|
|
277
272
|
# set an option value by name, either store value or call handler
|
278
|
-
|
273
|
+
# @param option_symbol [Symbol] option name
|
274
|
+
# @param value [String] value to set
|
275
|
+
# @param where [String] where the value comes from
|
276
|
+
# @param expect [Class, Array] expected value type(s)
|
277
|
+
def set_option(option_symbol, value, where: 'code override')
|
279
278
|
Aspera.assert_type(option_symbol, Symbol)
|
280
279
|
raise Cli::BadArgument, "Unknown option: #{option_symbol}" unless @declared_options.key?(option_symbol)
|
281
280
|
attributes = @declared_options[option_symbol]
|
282
281
|
Log.log.warn("#{option_symbol}: Option is deprecated: #{attributes[:deprecation]}") if attributes[:deprecation]
|
283
|
-
value =
|
282
|
+
value = evaluate_extended_value(value, attributes[:types])
|
284
283
|
value = Manager.enum_to_bool(value) if attributes[:values].eql?(BOOLEAN_VALUES)
|
285
284
|
Log.log.debug{"(#{attributes[:read_write]}/#{where}) set #{option_symbol}=#{value}"}
|
286
285
|
self.class.validate_type(:option, option_symbol, value, attributes[:types])
|
@@ -332,18 +331,18 @@ module Aspera
|
|
332
331
|
Log.log.debug{"set attr obj #{option_symbol} (#{handler[:o]},#{handler[:m]})"}
|
333
332
|
opt[:accessor] = AttrAccessor.new(handler[:o], handler[:m], option_symbol)
|
334
333
|
end
|
335
|
-
set_option(option_symbol, default, 'default') unless default.nil?
|
334
|
+
set_option(option_symbol, default, where: 'default') unless default.nil?
|
336
335
|
on_args = [description]
|
337
336
|
case values
|
338
337
|
when nil
|
339
338
|
on_args.push(symbol_to_option(option_symbol, 'VALUE'))
|
340
339
|
on_args.push("-#{short}VALUE") unless short.nil?
|
341
340
|
on_args.push(coerce) unless coerce.nil?
|
342
|
-
@parser.on(*on_args) { |v| set_option(option_symbol, v, SOURCE_USER) }
|
341
|
+
@parser.on(*on_args) { |v| set_option(option_symbol, v, where: SOURCE_USER) }
|
343
342
|
when Array, :bool
|
344
343
|
if values.eql?(:bool)
|
345
344
|
values = BOOLEAN_VALUES
|
346
|
-
set_option(option_symbol, Manager.enum_to_bool(default), 'default') unless default.nil?
|
345
|
+
set_option(option_symbol, Manager.enum_to_bool(default), where: 'default') unless default.nil?
|
347
346
|
end
|
348
347
|
# this option value must be a symbol
|
349
348
|
opt[:values] = values
|
@@ -355,7 +354,7 @@ module Aspera
|
|
355
354
|
on_args[0] = "#{description}: #{help_values}"
|
356
355
|
on_args.push(symbol_to_option(option_symbol, 'ENUM'))
|
357
356
|
on_args.push(values)
|
358
|
-
@parser.on(*on_args){|v|set_option(option_symbol, self.class.get_from_list(v.to_s, description, values), SOURCE_USER)}
|
357
|
+
@parser.on(*on_args){|v|set_option(option_symbol, self.class.get_from_list(v.to_s, description, values), where: SOURCE_USER)}
|
359
358
|
when :date
|
360
359
|
on_args.push(symbol_to_option(option_symbol, 'DATE'))
|
361
360
|
@parser.on(*on_args) do |v|
|
@@ -364,7 +363,7 @@ module Aspera
|
|
364
363
|
when /^-([0-9]+)h/ then Manager.time_to_string(Time.now - (Regexp.last_match(1).to_i * 3600))
|
365
364
|
else v
|
366
365
|
end
|
367
|
-
set_option(option_symbol, time_string, SOURCE_USER)
|
366
|
+
set_option(option_symbol, time_string, where: SOURCE_USER)
|
368
367
|
end
|
369
368
|
when :none
|
370
369
|
Aspera.assert(!block.nil?){"missing block for #{option_symbol}"}
|
@@ -401,6 +400,7 @@ module Aspera
|
|
401
400
|
end
|
402
401
|
|
403
402
|
# get all original options on command line used to generate a config in config file
|
403
|
+
# @return [Hash] options as taken from config file and command line just before command execution
|
404
404
|
def unprocessed_options_with_value
|
405
405
|
result = {}
|
406
406
|
@initial_cli_options.each do |option_value|
|
@@ -457,7 +457,7 @@ module Aspera
|
|
457
457
|
@unprocessed_cmd_line_options = unknown_options
|
458
458
|
end
|
459
459
|
|
460
|
-
def prompt_user_input(prompt, sensitive)
|
460
|
+
def prompt_user_input(prompt, sensitive: false)
|
461
461
|
return $stdin.getpass("#{prompt}> ") if sensitive
|
462
462
|
print("#{prompt}> ")
|
463
463
|
line = $stdin.gets
|
@@ -471,7 +471,7 @@ module Aspera
|
|
471
471
|
# @return [Symbol] selected symbol
|
472
472
|
def prompt_user_input_in_list(prompt, sym_list)
|
473
473
|
loop do
|
474
|
-
input = prompt_user_input(prompt
|
474
|
+
input = prompt_user_input(prompt).to_sym
|
475
475
|
if sym_list.any?{|a|a.eql?(input)}
|
476
476
|
return input
|
477
477
|
else
|
@@ -480,34 +480,49 @@ module Aspera
|
|
480
480
|
end
|
481
481
|
end
|
482
482
|
|
483
|
-
|
483
|
+
# Prompt user for input in a list of symbols
|
484
|
+
# @param descr [String] description for help
|
485
|
+
# @param option [Boolean] true if command line option
|
486
|
+
# @param multiple [Boolean] true if multiple values expected
|
487
|
+
# @param accept_list [Array] list of expected values
|
488
|
+
def get_interactive(descr, option: false, multiple: false, accept_list: nil)
|
489
|
+
what = option ? 'option' : 'argument'
|
484
490
|
if !@ask_missing_mandatory
|
485
|
-
|
486
|
-
|
491
|
+
message = "missing #{what}: #{descr}"
|
492
|
+
if accept_list.nil?
|
493
|
+
raise Cli::BadArgument, message
|
494
|
+
else
|
495
|
+
self.class.multi_choice_assert(false, message, accept_list)
|
496
|
+
end
|
487
497
|
end
|
488
498
|
result = nil
|
489
|
-
sensitive =
|
490
|
-
default_prompt = "#{
|
499
|
+
sensitive = option && @declared_options[descr.to_sym].is_a?(Hash) && @declared_options[descr.to_sym][:sensitive]
|
500
|
+
default_prompt = "#{what}: #{descr}"
|
491
501
|
# ask interactively
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
result
|
503
|
-
else # one fixed
|
504
|
-
result = self.class.get_from_list(prompt_user_input("#{expected.join(' ')}\n#{default_prompt}", sensitive), descr, expected)
|
502
|
+
result = []
|
503
|
+
puts(' (one per line, end with empty line)') if multiple
|
504
|
+
loop do
|
505
|
+
prompt = default_prompt
|
506
|
+
prompt = "#{accept_list.join(' ')}\n#{default_prompt}" if accept_list
|
507
|
+
entry = prompt_user_input(prompt, sensitive: sensitive)
|
508
|
+
break if entry.empty? && multiple
|
509
|
+
entry = ExtendedValue.instance.evaluate(entry)
|
510
|
+
entry = self.class.get_from_list(entry, descr, accept_list) if accept_list
|
511
|
+
return entry unless multiple
|
512
|
+
result.push(entry)
|
505
513
|
end
|
506
514
|
return result
|
507
515
|
end
|
508
516
|
|
509
517
|
private
|
510
518
|
|
519
|
+
def evaluate_extended_value(value, types)
|
520
|
+
if DEFAULT_PARSER_TYPES.include?(types) || (types.is_a?(Array) && types.all?{|t|DEFAULT_PARSER_TYPES.include?(t)})
|
521
|
+
return ExtendedValue.instance.evaluate_with_default(value)
|
522
|
+
end
|
523
|
+
return ExtendedValue.instance.evaluate(value)
|
524
|
+
end
|
525
|
+
|
511
526
|
# generate command line option from option symbol
|
512
527
|
def symbol_to_option(symbol, opt_val = nil)
|
513
528
|
result = [OPTION_PREFIX, symbol.to_s.gsub(OPTION_SEP_SYMBOL, OPTION_SEP_LINE)].join
|
@@ -537,7 +552,7 @@ module Aspera
|
|
537
552
|
end
|
538
553
|
end
|
539
554
|
options_to_set.each do |k, v|
|
540
|
-
set_option(k, v, where)
|
555
|
+
set_option(k, v, where: where)
|
541
556
|
# keep only unprocessed values for next parse
|
542
557
|
unprocessed_options.delete(k)
|
543
558
|
end
|
data/lib/aspera/cli/plugin.rb
CHANGED
@@ -29,7 +29,6 @@ module Aspera
|
|
29
29
|
:value, 'Value for create, update, list filter', types: Hash,
|
30
30
|
deprecation: '(4.14) Use positional value for create/modify or option: query for list/delete')
|
31
31
|
options.declare(:property, 'Name of property to set (modify operation)')
|
32
|
-
options.declare(:id, 'Resource identifier', deprecation: "(4.14) Use positional identifier after verb (#{INSTANCE_OPS.join(',')})")
|
33
32
|
options.declare(:bulk, 'Bulk operation (only some)', values: :bool, default: :no)
|
34
33
|
options.declare(:bfail, 'Bulk operation error handling', values: :bool, default: :yes)
|
35
34
|
end
|
@@ -66,9 +65,7 @@ module Aspera
|
|
66
65
|
# @return [String, Array] identifier or list of ids
|
67
66
|
def instance_identifier(description: 'identifier', as_option: nil, &block)
|
68
67
|
if as_option.nil?
|
69
|
-
|
70
|
-
res_id = options.get_option(:id)
|
71
|
-
res_id = options.get_next_argument(description) if res_id.nil?
|
68
|
+
res_id = options.get_next_argument(description, multiple: options.get_option(:bulk)) if res_id.nil?
|
72
69
|
else
|
73
70
|
res_id = options.get_option(as_option)
|
74
71
|
end
|
@@ -255,7 +252,7 @@ module Aspera
|
|
255
252
|
Log.log.warn("option `value` is deprecated. Use positional parameter for #{command}") unless value.nil?
|
256
253
|
value = options.get_next_argument(
|
257
254
|
"parameters for #{command}#{description.nil? ? '' : " (#{description})"}", mandatory: default.nil?,
|
258
|
-
|
255
|
+
validation: bulk ? Array : type) if value.nil?
|
259
256
|
value = default if value.nil?
|
260
257
|
unless type.nil?
|
261
258
|
type = [type] unless type.is_a?(Array)
|
@@ -4,6 +4,7 @@ require 'aspera/cli/plugins/node'
|
|
4
4
|
require 'aspera/cli/plugins/ats'
|
5
5
|
require 'aspera/cli/basic_auth_plugin'
|
6
6
|
require 'aspera/cli/transfer_agent'
|
7
|
+
require 'aspera/cli/special_values'
|
7
8
|
require 'aspera/agent/node'
|
8
9
|
require 'aspera/transfer/spec'
|
9
10
|
require 'aspera/api/aoc'
|
@@ -123,7 +124,7 @@ module Aspera
|
|
123
124
|
formatter.display_status(pub_key_pem)
|
124
125
|
if !options.get_option(:test_mode)
|
125
126
|
formatter.display_status('Once updated or validated, press enter.')
|
126
|
-
|
127
|
+
Environment.instance.open_uri(instance_url)
|
127
128
|
$stdin.gets
|
128
129
|
end
|
129
130
|
else
|
@@ -137,7 +138,7 @@ module Aspera
|
|
137
138
|
formatter.display_status('- origin: localhost')
|
138
139
|
formatter.display_status('Use the generated client id and secret in the following prompts.'.red)
|
139
140
|
end
|
140
|
-
|
141
|
+
Environment.instance.open_uri("#{instance_url}/admin/api-clients")
|
141
142
|
options.get_option(:client_id, mandatory: true)
|
142
143
|
options.get_option(:client_secret, mandatory: true)
|
143
144
|
use_browser_authentication = true
|
@@ -319,8 +320,8 @@ module Aspera
|
|
319
320
|
# client side is agent
|
320
321
|
# server side is transfer server
|
321
322
|
# in same workspace
|
322
|
-
push_pull = options.get_next_argument('direction',
|
323
|
-
source_folder = options.get_next_argument('folder of source files',
|
323
|
+
push_pull = options.get_next_argument('direction', accept_list: %i[push pull])
|
324
|
+
source_folder = options.get_next_argument('folder of source files', validation: String)
|
324
325
|
case push_pull
|
325
326
|
when :push
|
326
327
|
client_direction = Transfer::Spec::DIRECTION_SEND
|
@@ -415,7 +416,7 @@ module Aspera
|
|
415
416
|
fields = object.keys.reject{|k|k.eql?('certificate')}
|
416
417
|
return { type: :single_object, data: object, fields: fields }
|
417
418
|
when :modify
|
418
|
-
changes = options.get_next_argument('properties',
|
419
|
+
changes = options.get_next_argument('properties', validation: Hash)
|
419
420
|
return do_bulk_operation(command: command, descr: 'identifier', values: res_id) do |one_id|
|
420
421
|
aoc_api.update("#{resource_class_path}/#{one_id}", changes)
|
421
422
|
{'id' => one_id}
|
@@ -427,7 +428,7 @@ module Aspera
|
|
427
428
|
end
|
428
429
|
when :set_pub_key
|
429
430
|
# special : reads private and generate public
|
430
|
-
the_private_key = options.get_next_argument('private_key PEM value',
|
431
|
+
the_private_key = options.get_next_argument('private_key PEM value', validation: String)
|
431
432
|
the_public_key = OpenSSL::PKey::RSA.new(the_private_key).public_key.to_s
|
432
433
|
aoc_api.update(resource_instance_path, {jwt_grant_enabled: true, public_key: the_public_key})
|
433
434
|
return Main.result_success
|
@@ -449,7 +450,7 @@ module Aspera
|
|
449
450
|
case command_admin
|
450
451
|
when :resource
|
451
452
|
Log.log.warn('resource command is deprecated (4.18), directly use the specific command instead')
|
452
|
-
return execute_resource_action(options.get_next_argument('resource',
|
453
|
+
return execute_resource_action(options.get_next_argument('resource', accept_list: ADMIN_OBJECTS))
|
453
454
|
when *ADMIN_OBJECTS
|
454
455
|
return execute_resource_action(command_admin)
|
455
456
|
when :auth_providers
|
@@ -534,7 +535,7 @@ module Aspera
|
|
534
535
|
return {type: :object_list, data: events}
|
535
536
|
when :transfers
|
536
537
|
event_type = command_analytics.to_s
|
537
|
-
filter_resource = options.get_next_argument('resource',
|
538
|
+
filter_resource = options.get_next_argument('resource', accept_list: %i[organizations users nodes])
|
538
539
|
filter_id = options.get_next_argument('identifier', mandatory: false) ||
|
539
540
|
case filter_resource
|
540
541
|
when :organizations then aoc_api.current_user_info['organization_id']
|
@@ -622,7 +623,7 @@ module Aspera
|
|
622
623
|
when :show
|
623
624
|
return { type: :single_object, data: aoc_api.current_user_info(exception: true) }
|
624
625
|
when :modify
|
625
|
-
aoc_api.update("users/#{aoc_api.current_user_info(exception: true)['id']}", options.get_next_argument('properties',
|
626
|
+
aoc_api.update("users/#{aoc_api.current_user_info(exception: true)['id']}", options.get_next_argument('properties', validation: Hash))
|
626
627
|
return Main.result_status('modified')
|
627
628
|
end
|
628
629
|
when :preferences
|
@@ -631,7 +632,7 @@ module Aspera
|
|
631
632
|
when :show
|
632
633
|
return { type: :single_object, data: aoc_api.read(user_preferences_res)[:data] }
|
633
634
|
when :modify
|
634
|
-
aoc_api.update(user_preferences_res, options.get_next_argument('properties',
|
635
|
+
aoc_api.update(user_preferences_res, options.get_next_argument('properties', validation: Hash))
|
635
636
|
return Main.result_status('modified')
|
636
637
|
end
|
637
638
|
end
|
@@ -690,13 +691,13 @@ module Aspera
|
|
690
691
|
].concat(aoc_api.additional_persistence_ids)))
|
691
692
|
end
|
692
693
|
case ids_to_download
|
693
|
-
when
|
694
|
+
when SpecialValues::ALL, SpecialValues::INIT
|
694
695
|
query = query_read_delete(default: PACKAGE_RECEIVED_BASE_QUERY)
|
695
696
|
Aspera.assert_type(query, Hash){'query'}
|
696
697
|
resolve_dropbox_name_default_ws_id(query)
|
697
698
|
# remove from list the ones already downloaded
|
698
699
|
all_ids = api_read_all('packages', query)[:data].map{|e|e['id']}
|
699
|
-
if ids_to_download.eql?(
|
700
|
+
if ids_to_download.eql?(SpecialValues::INIT)
|
700
701
|
Aspera.assert(skip_ids_persistency){'Only with option once_only'}
|
701
702
|
skip_ids_persistency.data.clear.concat(all_ids)
|
702
703
|
skip_ids_persistency.save
|
@@ -758,9 +759,9 @@ module Aspera
|
|
758
759
|
when *NODE4_EXT_COMMANDS
|
759
760
|
return execute_nodegen4_command(command_repo, aoc_api.context[:home_node_id], file_id: aoc_api.context[:home_file_id], scope: Api::Node::SCOPE_USER)
|
760
761
|
when :short_link
|
761
|
-
link_type = options.get_next_argument('link type',
|
762
|
+
link_type = options.get_next_argument('link type', accept_list: %i[public private])
|
762
763
|
short_link_command = options.get_next_command(%i[create delete list])
|
763
|
-
folder_dest = options.get_next_argument('path',
|
764
|
+
folder_dest = options.get_next_argument('path', validation: String)
|
764
765
|
home_node_api = aoc_api.node_api_from(
|
765
766
|
node_id: aoc_api.context[:home_node_id],
|
766
767
|
workspace_id: aoc_api.context[:workspace_id],
|
@@ -3,6 +3,7 @@
|
|
3
3
|
# cspell:ignore initdemo genkey pubkey asperasoft filelists
|
4
4
|
require 'aspera/cli/basic_auth_plugin'
|
5
5
|
require 'aspera/cli/extended_value'
|
6
|
+
require 'aspera/cli/special_values'
|
6
7
|
require 'aspera/cli/version'
|
7
8
|
require 'aspera/cli/formatter'
|
8
9
|
require 'aspera/cli/info'
|
@@ -15,7 +16,7 @@ require 'aspera/transfer/spec'
|
|
15
16
|
require 'aspera/keychain/encrypted_hash'
|
16
17
|
require 'aspera/keychain/macos_security'
|
17
18
|
require 'aspera/proxy_auto_config'
|
18
|
-
require 'aspera/
|
19
|
+
require 'aspera/environment'
|
19
20
|
require 'aspera/persistency_action_once'
|
20
21
|
require 'aspera/id_generator'
|
21
22
|
require 'aspera/persistency_folder'
|
@@ -293,7 +294,7 @@ module Aspera
|
|
293
294
|
Aspera.assert_type(path, String){'Expecting a String for certificate location'}
|
294
295
|
paths_to_add = [path]
|
295
296
|
Log.log.debug{"Adding cert location: #{path}"}
|
296
|
-
if path.eql?(
|
297
|
+
if path.eql?(SpecialValues::DEF)
|
297
298
|
@certificate_store.set_default_paths
|
298
299
|
paths_to_add = [
|
299
300
|
OpenSSL::X509::DEFAULT_CERT_DIR,
|
@@ -324,7 +325,7 @@ module Aspera
|
|
324
325
|
locations = @certificate_paths
|
325
326
|
if locations.nil?
|
326
327
|
# compute default locations
|
327
|
-
self.trusted_cert_locations =
|
328
|
+
self.trusted_cert_locations = SpecialValues::DEF
|
328
329
|
locations = @certificate_paths
|
329
330
|
# restore defaults
|
330
331
|
@certificate_paths = @certificate_store = nil
|
@@ -685,7 +686,7 @@ module Aspera
|
|
685
686
|
api_connect_cdn.call(operation: 'GET', subpath: file_url, save_to_file: File.join(folder_dest, filename))
|
686
687
|
return Main.result_status("Downloaded: #{filename}")
|
687
688
|
when :open
|
688
|
-
|
689
|
+
Environment.instance.open_uri(one_link['href'])
|
689
690
|
return Main.result_status("Opened: #{one_link['href']}")
|
690
691
|
end
|
691
692
|
end
|
@@ -786,11 +787,11 @@ module Aspera
|
|
786
787
|
when :set
|
787
788
|
param_name = options.get_next_argument('parameter name')
|
788
789
|
param_name = Manager.option_line_to_name(param_name)
|
789
|
-
param_value = options.get_next_argument('parameter value')
|
790
|
+
param_value = options.get_next_argument('parameter value', validation: nil)
|
790
791
|
set_preset_key(name, param_name, param_value)
|
791
792
|
return Main.result_nothing
|
792
793
|
when :initialize
|
793
|
-
config_value = options.get_next_argument('extended value',
|
794
|
+
config_value = options.get_next_argument('extended value', validation: Hash)
|
794
795
|
if @config_presets.key?(name)
|
795
796
|
Log.log.warn{"configuration already exists: #{name}, overwriting"}
|
796
797
|
end
|
@@ -804,10 +805,10 @@ module Aspera
|
|
804
805
|
@config_presets[name].merge!(unprocessed_options)
|
805
806
|
return Main.result_status("Updated: #{name}")
|
806
807
|
when :ask
|
807
|
-
options.ask_missing_mandatory =
|
808
|
+
options.ask_missing_mandatory = true
|
808
809
|
@config_presets[name] ||= {}
|
809
|
-
options.get_next_argument('option names',
|
810
|
-
option_value = options.get_interactive(
|
810
|
+
options.get_next_argument('option names', multiple: true).each do |option_name|
|
811
|
+
option_value = options.get_interactive(option_name, option: true)
|
811
812
|
@config_presets[name][option_name] = option_value
|
812
813
|
end
|
813
814
|
return Main.result_status("Updated: #{name}")
|
@@ -879,16 +880,16 @@ module Aspera
|
|
879
880
|
when :preset # newer syntax
|
880
881
|
return execute_preset
|
881
882
|
when :open
|
882
|
-
|
883
|
+
Environment.open_editor(@option_config_file.to_s)
|
883
884
|
return Main.result_nothing
|
884
885
|
when :documentation
|
885
886
|
section = options.get_next_argument('private key file path', mandatory: false)
|
886
887
|
section = "##{section}" unless section.nil?
|
887
|
-
|
888
|
+
Environment.instance.open_uri("#{@help}#{section}")
|
888
889
|
return Main.result_nothing
|
889
890
|
when :genkey # generate new rsa key
|
890
891
|
private_key_path = options.get_next_argument('private key file path')
|
891
|
-
private_key_length = options.get_next_argument('size in bits', mandatory: false,
|
892
|
+
private_key_length = options.get_next_argument('size in bits', mandatory: false, validation: Integer, default: DEFAULT_PRIV_KEY_LENGTH)
|
892
893
|
self.class.generate_rsa_private_key(path: private_key_path, length: private_key_length)
|
893
894
|
return Main.result_status("Generated #{private_key_length} bit RSA key: #{private_key_path}")
|
894
895
|
when :pubkey # get pub key
|
@@ -908,7 +909,7 @@ module Aspera
|
|
908
909
|
return Main.result_status(remote_chain.first.subject.to_a.find { |name, _, _| name == 'CN' }[1])
|
909
910
|
end
|
910
911
|
when :echo # display the content of a value given on command line
|
911
|
-
return Formatter.auto_type(options.get_next_argument('value'))
|
912
|
+
return Formatter.auto_type(options.get_next_argument('value', validation: nil))
|
912
913
|
when :flush_tokens
|
913
914
|
deleted_files = OAuth::Factory.instance.flush_tokens
|
914
915
|
return {type: :value_list, data: deleted_files, name: 'file'}
|
@@ -927,8 +928,8 @@ module Aspera
|
|
927
928
|
end
|
928
929
|
return {type: :object_list, data: result, fields: %w[plugin detect wizard path]}
|
929
930
|
when :create
|
930
|
-
plugin_name = options.get_next_argument('name'
|
931
|
-
destination_folder = options.get_next_argument('folder',
|
931
|
+
plugin_name = options.get_next_argument('name').downcase
|
932
|
+
destination_folder = options.get_next_argument('folder', mandatory: false) || File.join(@main_folder, ASPERA_PLUGINS_FOLDERNAME)
|
932
933
|
plugin_file = File.join(destination_folder, "#{plugin_name}.rb")
|
933
934
|
content = <<~END_OF_PLUGIN_CODE
|
934
935
|
require 'aspera/cli/plugin'
|
@@ -1077,7 +1078,7 @@ module Aspera
|
|
1077
1078
|
Log.log.debug{"wizard result: #{wizard_result}"}
|
1078
1079
|
Aspera.assert(WIZARD_RESULT_KEYS.eql?(wizard_result.keys.sort)){"missing or extra keys in wizard result: #{wizard_result.keys}"}
|
1079
1080
|
# get preset name from user or default
|
1080
|
-
wiz_preset_name =
|
1081
|
+
wiz_preset_name = nil
|
1081
1082
|
if wiz_preset_name.nil?
|
1082
1083
|
elements = [
|
1083
1084
|
identification[:product],
|
@@ -1217,8 +1218,8 @@ module Aspera
|
|
1217
1218
|
when :show
|
1218
1219
|
return {type: :single_object, data: vault.get(label: options.get_next_argument('label'))}
|
1219
1220
|
when :create
|
1220
|
-
label = options.get_next_argument('label',
|
1221
|
-
info = options.get_next_argument('info',
|
1221
|
+
label = options.get_next_argument('label', validation: String)
|
1222
|
+
info = options.get_next_argument('info', validation: Hash)
|
1222
1223
|
info = info.symbolize_keys
|
1223
1224
|
info[:label] = label
|
1224
1225
|
vault.set(info)
|
@@ -1270,7 +1271,7 @@ module Aspera
|
|
1270
1271
|
info[:password])
|
1271
1272
|
when 'system'
|
1272
1273
|
case Environment.os
|
1273
|
-
when Environment::
|
1274
|
+
when Environment::OS_MACOS
|
1274
1275
|
@vault = Keychain::MacosSystem.new(info[:name], info[:password])
|
1275
1276
|
else
|
1276
1277
|
raise 'not implemented for this OS'
|