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.
@@ -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'