aspera-cli 4.18.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.
@@ -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
- private_constant :FALSE_VALUES, :TRUE_VALUES, :BOOLEAN_VALUES, :OPTION_SEP_LINE, :OPTION_SEP_SYMBOL, :SOURCE_USER, :TYPE_INTEGER
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 choices [Array] list of allowed values
90
- def multi_choice_assert(assertion, error_msg, choices)
91
- raise Cli::BadArgument, [error_msg, 'Use:'].concat(choices.map{|c|"- #{c}"}.sort).join("\n") unless assertion
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 value [Object] value to check
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, value, type_list)
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
- raise Cli::BadArgument,
111
- "#{what.to_s.capitalize} #{descr} is a #{value.class} but must be #{type_list.length > 1 ? 'one of ' : ''}#{type_list.map(&:name).join(',')}" unless \
112
- type_list.any?{|t|value.is_a?(t)}
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
- end
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 type [Class, Array] accepted value type(s)
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, expected: :single, mandatory: true, type: nil, aliases: nil, default: nil)
191
- Aspera.assert(%i[single multiple].include?(expected) || (expected.is_a?(Array) && expected.all?(Symbol))) do
192
- 'expected must be single, multiple, or array of symbol'
193
- end
194
- Aspera.assert(type.nil? || type.is_a?(Class) || (type.is_a?(Array) && type.all?(Class))){'type must be Class or Array of Class'}
195
- Aspera.assert(aliases.nil? || (aliases.is_a?(Hash) && aliases.keys.all?(Symbol) && aliases.values.all?(Symbol))){'aliases must be Hash'}
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
- # there are values
204
- case expected
205
- when :single
206
- ExtendedValue.instance.evaluate(@unprocessed_cmd_line_arguments.shift)
207
- when :multiple
208
- value = @unprocessed_cmd_line_arguments.shift(@unprocessed_cmd_line_arguments.length).map{|v|ExtendedValue.instance.evaluate(v)}
209
- # if expecting list and only one arg of type array : it is the list
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(@unprocessed_cmd_line_arguments.shift, descr, allowed_values)
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(:argument, descr, expected: expected)
215
+ elsif mandatory then get_interactive(descr, multiple: multiple, accept_list: accept_list)
223
216
  end
224
- if result.is_a?(String) && allowed_types.eql?(TYPE_INTEGER)
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
- self.class.validate_type(:argument, descr, result, allowed_types) unless result.nil? && !mandatory
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', expected: command_list, aliases: aliases); end
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
- expected = :single
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
- expected = attributes[:values]
262
+ accept_list = attributes[:values]
268
263
  end
269
- result = get_interactive(:option, option_symbol.to_s, expected: expected)
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
- def set_option(option_symbol, value, where='code override')
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 = ExtendedValue.instance.evaluate(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, false).to_sym
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
- def get_interactive(type, descr, expected: :single)
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
- raise Cli::BadArgument, "missing argument (#{expected}): #{descr}" unless expected.is_a?(Array)
486
- self.class.multi_choice_assert(false, "missing: #{descr}", expected)
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 = type.eql?(:option) && @declared_options[descr.to_sym].is_a?(Hash) && @declared_options[descr.to_sym][:sensitive]
490
- default_prompt = "#{type}: #{descr}"
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
- case expected
493
- when :multiple
494
- result = []
495
- puts(' (one per line, end with empty line)')
496
- loop do
497
- entry = prompt_user_input(default_prompt, sensitive)
498
- break if entry.empty?
499
- result.push(ExtendedValue.instance.evaluate(entry))
500
- end
501
- when :single
502
- result = ExtendedValue.instance.evaluate(prompt_user_input(default_prompt, sensitive))
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
@@ -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
- # use of option `id` is deprecated
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
- type: bulk ? Array : type) if value.nil?
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
- OpenApplication.instance.uri(instance_url)
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
- OpenApplication.instance.uri("#{instance_url}/admin/api-clients")
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', expected: %i[push pull])
323
- source_folder = options.get_next_argument('folder of source files', type: String)
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', type: Hash)
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', type: String)
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', expected: ADMIN_OBJECTS))
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', expected: %i[organizations users nodes])
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', type: Hash))
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', type: Hash))
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 ExtendedValue::ALL, ExtendedValue::INIT
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?(ExtendedValue::INIT)
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', expected: %i[public private])
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', type: String)
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/open_application'
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?(ExtendedValue::DEF)
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 = ExtendedValue::DEF
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
- OpenApplication.instance.uri(one_link['href'])
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', type: Hash)
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 = :yes
808
+ options.ask_missing_mandatory = true
808
809
  @config_presets[name] ||= {}
809
- options.get_next_argument('option names', expected: :multiple).each do |option_name|
810
- option_value = options.get_interactive(:option, option_name)
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
- OpenApplication.editor(@option_config_file.to_s)
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
- OpenApplication.instance.uri("#{@help}#{section}")
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, type: Integer, default: DEFAULT_PRIV_KEY_LENGTH)
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', expected: :single).downcase
931
- destination_folder = options.get_next_argument('folder', expected: :single, mandatory: false) || File.join(@main_folder, ASPERA_PLUGINS_FOLDERNAME)
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 = options.get_option(:id)
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', type: String)
1221
- info = options.get_next_argument('info', type: Hash)
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::OS_X
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'