aspera-cli 4.24.2 → 4.25.0.pre

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.

Potentially problematic release.


This version of aspera-cli might be problematic. Click here for more details.

Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +1064 -758
  4. data/CONTRIBUTING.md +43 -100
  5. data/README.md +671 -419
  6. data/lib/aspera/api/aoc.rb +71 -43
  7. data/lib/aspera/api/cos_node.rb +3 -2
  8. data/lib/aspera/api/faspex.rb +6 -5
  9. data/lib/aspera/api/node.rb +10 -12
  10. data/lib/aspera/ascmd.rb +1 -2
  11. data/lib/aspera/ascp/installation.rb +53 -39
  12. data/lib/aspera/assert.rb +25 -3
  13. data/lib/aspera/cli/error.rb +4 -2
  14. data/lib/aspera/cli/extended_value.rb +84 -60
  15. data/lib/aspera/cli/formatter.rb +55 -22
  16. data/lib/aspera/cli/main.rb +21 -14
  17. data/lib/aspera/cli/manager.rb +348 -247
  18. data/lib/aspera/cli/plugins/alee.rb +3 -3
  19. data/lib/aspera/cli/plugins/aoc.rb +70 -14
  20. data/lib/aspera/cli/plugins/base.rb +57 -49
  21. data/lib/aspera/cli/plugins/config.rb +69 -84
  22. data/lib/aspera/cli/plugins/console.rb +13 -8
  23. data/lib/aspera/cli/plugins/cos.rb +1 -1
  24. data/lib/aspera/cli/plugins/faspex.rb +32 -26
  25. data/lib/aspera/cli/plugins/faspex5.rb +45 -43
  26. data/lib/aspera/cli/plugins/faspio.rb +5 -5
  27. data/lib/aspera/cli/plugins/httpgw.rb +1 -1
  28. data/lib/aspera/cli/plugins/node.rb +131 -120
  29. data/lib/aspera/cli/plugins/oauth.rb +1 -1
  30. data/lib/aspera/cli/plugins/orchestrator.rb +114 -32
  31. data/lib/aspera/cli/plugins/preview.rb +26 -46
  32. data/lib/aspera/cli/plugins/server.rb +6 -8
  33. data/lib/aspera/cli/plugins/shares.rb +27 -32
  34. data/lib/aspera/cli/sync_actions.rb +49 -38
  35. data/lib/aspera/cli/transfer_agent.rb +16 -34
  36. data/lib/aspera/cli/version.rb +1 -1
  37. data/lib/aspera/cli/wizard.rb +8 -5
  38. data/lib/aspera/command_line_builder.rb +20 -17
  39. data/lib/aspera/coverage.rb +1 -1
  40. data/lib/aspera/environment.rb +41 -34
  41. data/lib/aspera/faspex_gw.rb +1 -1
  42. data/lib/aspera/keychain/factory.rb +1 -2
  43. data/lib/aspera/markdown.rb +31 -0
  44. data/lib/aspera/nagios.rb +6 -5
  45. data/lib/aspera/oauth/base.rb +17 -27
  46. data/lib/aspera/oauth/factory.rb +1 -1
  47. data/lib/aspera/oauth/url_json.rb +2 -1
  48. data/lib/aspera/preview/file_types.rb +23 -37
  49. data/lib/aspera/products/connect.rb +3 -3
  50. data/lib/aspera/rest.rb +51 -39
  51. data/lib/aspera/rest_error_analyzer.rb +4 -4
  52. data/lib/aspera/ssh.rb +5 -2
  53. data/lib/aspera/ssl.rb +41 -0
  54. data/lib/aspera/sync/conf.schema.yaml +182 -34
  55. data/lib/aspera/sync/database.rb +2 -1
  56. data/lib/aspera/sync/operations.rb +125 -69
  57. data/lib/aspera/transfer/parameters.rb +3 -4
  58. data/lib/aspera/transfer/spec.rb +2 -3
  59. data/lib/aspera/transfer/spec.schema.yaml +48 -18
  60. data/lib/aspera/transfer/spec_doc.rb +14 -14
  61. data/lib/aspera/uri_reader.rb +1 -1
  62. data/lib/transferd_pb.rb +2 -2
  63. data.tar.gz.sig +0 -0
  64. metadata +19 -6
  65. metadata.gz.sig +3 -2
@@ -17,16 +17,8 @@ module Aspera
17
17
  class ExtendedValue
18
18
  include Singleton
19
19
 
20
- MARKER_START = '@'
21
- MARKER_END = ':'
22
- MARKER_IN_END = '@'
23
-
24
- # Special handlers stop processing of handlers on right
25
- # :extend includes processing of other handlers in itself
26
- # :val keeps the value intact
27
- SPECIAL_HANDLERS = %i[extend val].freeze
28
-
29
- private_constant :MARKER_START, :MARKER_END, :MARKER_IN_END, :SPECIAL_HANDLERS
20
+ # First is default
21
+ DEFAULT_DECODERS = %i[none json ruby yaml]
30
22
 
31
23
  class << self
32
24
  # Decode comma separated table text
@@ -45,8 +37,32 @@ module Aspera
45
37
  return hash_array
46
38
  end
47
39
 
48
- def assert_no_value(value, what)
49
- raise "no value allowed for extended value type: #{what}" unless value.empty?
40
+ # JSON Parser, with more information on error location
41
+ # extract a context: 10 chars before and after the error on the given line and display a pointer "^"
42
+ # :reek:UncommunicativeMethodName
43
+ def JSON_parse(value) # rubocop:disable Naming/MethodName
44
+ JSON.parse(value)
45
+ rescue JSON::ParserError => e
46
+ m = /at line (\d+) column (\d+)/.match(e.message)
47
+ raise if m.nil?
48
+ line = m[1].to_i - 1
49
+ column = m[2].to_i - 1
50
+ lines = value.lines
51
+ raise if line >= lines.size
52
+ error_line = lines[line].chomp
53
+ context_col_beg = [column - 10, 0].max
54
+ context_col_end = [column + 10, error_line.length].min
55
+ context = error_line[context_col_beg...context_col_end]
56
+ cursor_pos = column - context_col_beg
57
+ pointer = ' ' * cursor_pos + '^'.blink
58
+ raise BadArgument, "#{e.message}\n#{context}\n#{pointer}"
59
+ end
60
+
61
+ # The value must be empty
62
+ # @param value [String] The value as parameter
63
+ # @param ext_type [Symbol] The method of extended value
64
+ def assert_no_value(value, ext_type)
65
+ Aspera.assert(value.empty?, type: BadArgument){"no value allowed for extended value type: #{ext_type}"}
50
66
  end
51
67
  end
52
68
 
@@ -54,7 +70,8 @@ module Aspera
54
70
 
55
71
  def initialize
56
72
  # Base handlers
57
- # Other handlers can be set using set_handler, e.g. `preset` is reader in config plugin
73
+ # Other handlers can be set using `on`
74
+ # e.g. `preset` is reader in config plugin
58
75
  @handlers = {
59
76
  val: lambda{ |i| i},
60
77
  base64: lambda{ |i| Base64.decode64(i)},
@@ -62,7 +79,7 @@ module Aspera
62
79
  env: lambda{ |i| ENV.fetch(i, nil)},
63
80
  file: lambda{ |i| File.read(File.expand_path(i))},
64
81
  uri: lambda{ |i| UriReader.read(i)},
65
- json: lambda{ |i| JSON_parse(i)},
82
+ json: lambda{ |i| ExtendedValue.JSON_parse(i)},
66
83
  lines: lambda{ |i| i.split("\n")},
67
84
  list: lambda{ |i| i[1..-1].split(i[0])},
68
85
  none: lambda{ |i| ExtendedValue.assert_no_value(i, :none); nil}, # rubocop:disable Style/Semicolon
@@ -74,63 +91,60 @@ module Aspera
74
91
  stdbin: lambda{ |i| ExtendedValue.assert_no_value(i, :stdbin); $stdin.binmode.read}, # rubocop:disable Style/Semicolon
75
92
  yaml: lambda{ |i| YAML.load(i)},
76
93
  zlib: lambda{ |i| Zlib::Inflate.inflate(i)},
77
- extend: lambda{ |i| ExtendedValue.instance.evaluate_all(i)}
94
+ extend: lambda{ |i| ExtendedValue.instance.evaluate_extend(i)}
78
95
  }
96
+ @regex_single = nil
97
+ @regex_extend = nil
79
98
  @default_decoder = nil
99
+ update_regex
80
100
  end
81
101
 
82
- # Regex to match an extended value
83
- def handler_regex_string
84
- "#{MARKER_START}(#{modifiers.join('|')})#{MARKER_END}"
85
- end
86
-
87
- # JSON Parser, with more information on error location
88
- # :reek:UncommunicativeMethodName
89
- def JSON_parse(value) # rubocop:disable Naming/MethodName
90
- JSON.parse(value)
91
- rescue JSON::ParserError => e
92
- m = /at line (\d+) column (\d+)/.match(e.message)
93
- raise if m.nil?
94
- line = m[1].to_i - 1
95
- column = m[2].to_i - 1
96
- lines = value.lines
97
- raise if line >= lines.size
98
- error_line = lines[line].chomp
99
- context_col_beg = [column - 10, 0].max
100
- context_col_end = [column + 10, error_line.length].min
101
- context = error_line[context_col_beg...context_col_end]
102
- cursor_pos = column - context_col_beg
103
- pointer = ' ' * cursor_pos + '^'.blink
104
- raise BadArgument, "#{e.message}\n#{context}\n#{pointer}"
102
+ # Update the Regex to match an extended value based on @handlers
103
+ def update_regex
104
+ handler_regex = "#{MARKER_START}(#{modifiers.join('|')})#{MARKER_END}"
105
+ @regex_single = Regexp.new("^#{handler_regex}(.*)$", Regexp::MULTILINE)
106
+ @regex_extend = Regexp.new("^(.*)#{handler_regex}([^#{MARKER_IN_END}]*)#{MARKER_IN_END}(.*)$", Regexp::MULTILINE)
105
107
  end
106
108
 
107
109
  public
108
110
 
111
+ attr_reader :default_decoder
112
+
109
113
  def default_decoder=(value)
110
114
  Log.log.debug{"Setting default decoder to (#{value.class}) #{value}"}
111
- Aspera.assert(value.nil? || @handlers.key?(value))
115
+ Aspera.assert_values(value, DEFAULT_DECODERS)
116
+ value = nil if value.eql?(:none)
112
117
  @default_decoder = value
113
118
  end
114
119
 
120
+ # List of Extended Value methods
115
121
  def modifiers; @handlers.keys; end
116
122
 
117
123
  # Add a new handler
118
- def set_handler(name, method)
119
- Log.log.debug{"setting handler for #{name}"}
124
+ def on(name, &block)
120
125
  Aspera.assert_type(name, Symbol){'name'}
121
- @handlers[name] = method
126
+ Aspera.assert(block)
127
+ Log.log.debug{"Setting handler for #{name}"}
128
+ @handlers[name] = block
129
+ update_regex
122
130
  end
123
131
 
124
- # Parse an string value to extended value, if it is a String using supported extended value modifiers
125
- # Other value types are returned as is
126
- # @param value [String] the value to parse
127
- # @param expect [Class,Array] one or a list of expected types
128
- def evaluate(value)
132
+ # Parses a `String` value to extended value.
133
+ # If it is a String using supported extended value modifiers, then evaluate them.
134
+ # Other value types are returned as is.
135
+ # @param value [String] the value to parse
136
+ # @param context [String] Context in which evaluation is done
137
+ # @param allowed [Array<Class>,NilClass] Expected types
138
+ # @return [Object] Evaluated value
139
+ def evaluate(value, context:, allowed: nil)
129
140
  return value unless value.is_a?(String)
130
- regex = Regexp.new("^#{handler_regex_string}(.*)$", Regexp::MULTILINE)
141
+ Aspera.assert_array_all(allowed, Class) unless allowed.nil?
142
+ # use default decoder if not an extended value and expect complex types
143
+ using_default_decoder = allowed&.all?{ |t| DEFAULT_PARSER_TYPES.include?(t)} && !@regex_single.match?(value) && !@default_decoder.nil?
144
+ value = [MARKER_START, @default_decoder, MARKER_END, value].join if using_default_decoder
131
145
  # First determine decoders, in reversed order
132
146
  handlers_reversed = []
133
- while (m = value.match(regex))
147
+ while (m = value.match(@regex_single))
134
148
  handler = m[1].to_sym
135
149
  handlers_reversed.unshift(handler)
136
150
  value = m[2]
@@ -139,27 +153,37 @@ module Aspera
139
153
  Log.log.trace1{"evaluating: #{handlers_reversed}, value: #{value}"}
140
154
  handlers_reversed.each do |handler|
141
155
  value = @handlers[handler].call(value)
156
+ rescue => e
157
+ raise BadArgument, "Evaluation of #{handler} for #{context}: #{e.message}"
142
158
  end
143
159
  return value
144
160
  end
145
161
 
146
- # Parse string value as extended value
147
- # Use default decoder if none is specified
148
- def evaluate_with_default(value)
149
- value = [MARKER_START, @default_decoder, MARKER_END, value].join if value.is_a?(String) && value.match(/^#{handler_regex_string}.*$/).nil? && !@default_decoder.nil?
150
- return evaluate(value)
151
- end
152
-
153
162
  # Find inner extended values
154
- def evaluate_all(value)
155
- regex = Regexp.new("^(.*)#{handler_regex_string}([^#{MARKER_IN_END}]*)#{MARKER_IN_END}(.*)$", Regexp::MULTILINE)
156
- while (m = value.match(regex))
163
+ # Only used in above lambda
164
+ def evaluate_extend(value)
165
+ while (m = value.match(@regex_extend))
157
166
  sub_value = "@#{m[2]}:#{m[3]}"
158
167
  Log.log.debug{"evaluating #{sub_value}"}
159
- value = "#{m[1]}#{evaluate(sub_value)}#{m[4]}"
168
+ value = "#{m[1]}#{evaluate(sub_value, context: 'composite extended value')}#{m[4]}"
160
169
  end
161
170
  return value
162
171
  end
172
+ # marker "@"
173
+ MARKER_START = '@'
174
+ # marker ":"
175
+ MARKER_END = ':'
176
+ # marker "@"
177
+ MARKER_IN_END = '@'
178
+
179
+ # Special handlers stop processing of handlers on right
180
+ # :extend includes processing of other handlers in itself
181
+ # :val keeps the value intact
182
+ SPECIAL_HANDLERS = %i[extend val].freeze
183
+
184
+ # Array and Hash types:
185
+ DEFAULT_PARSER_TYPES = [Array, Hash].freeze
186
+ private_constant :MARKER_START, :MARKER_END, :MARKER_IN_END, :SPECIAL_HANDLERS, :DEFAULT_PARSER_TYPES
163
187
  end
164
188
  end
165
189
  end
@@ -7,6 +7,7 @@ require 'aspera/secret_hider'
7
7
  require 'aspera/environment'
8
8
  require 'aspera/log'
9
9
  require 'aspera/assert'
10
+ require 'aspera/markdown'
10
11
  require 'terminal-table'
11
12
  require 'tty-spinner'
12
13
  require 'yaml'
@@ -64,8 +65,23 @@ module Aspera
64
65
  end
65
66
 
66
67
  # used by spec_doc
67
- def keyword_highlight(value)
68
- value.bold
68
+ # @param match [MatchData,String]
69
+ def markdown(match)
70
+ if match.is_a?(String)
71
+ match = Markdown::FORMATS.match(match)
72
+ Aspera.assert(match)
73
+ end
74
+ Aspera.assert_type(match, MatchData)
75
+ if match[:entity]
76
+ Aspera.assert_values(match[:entity], 'bsol')
77
+ '\\'
78
+ elsif match[:bold]
79
+ match[:bold].to_s.blue
80
+ elsif match[:code]
81
+ match[:code].to_s.bold
82
+ else
83
+ Aspera.error_unexpected_value(match.to_s)
84
+ end
69
85
  end
70
86
 
71
87
  # replace empty values with a readable version on terminal
@@ -100,30 +116,49 @@ module Aspera
100
116
  end
101
117
  end
102
118
 
119
+ # Given a list of string, display that list in a single cell
120
+ def list_to_string(list)
121
+ list.join(',')
122
+ end
123
+
124
+ # Build new prefix
125
+ def add_prefix(prefix, key)
126
+ [prefix, key].compact.join('.')
127
+ end
128
+
129
+ # Add elements of enumerator to the stack, in reverse order
130
+ def add_elements(stack, prefix, enum)
131
+ enum.reverse_each do |key, value|
132
+ stack.push([add_prefix(prefix, key), value])
133
+ end
134
+ end
135
+
103
136
  # Flatten a Hash into single level hash
104
137
  def flatten_hash(input)
105
138
  Aspera.assert_type(input, Hash)
106
139
  return input if input.empty?
107
140
  flat = {}
141
+ # tail (pop,push) contains the next element to display
108
142
  stack = [[nil, input]]
109
143
  until stack.empty?
110
144
  prefix, current = stack.pop
145
+ # empty things will be displayed as such
111
146
  if current.respond_to?(:empty?) && current.empty?
112
147
  flat[prefix] = current
113
148
  next
114
149
  end
115
150
  case current
116
151
  when Hash
117
- current.reverse_each{ |k, v| stack.push([[prefix, k].compact.join('.'), v])}
152
+ add_elements(stack, prefix, current)
118
153
  when Array
119
- if current.all?(String)
120
- flat[prefix] = current.join("\n")
154
+ if current.none?{ |i| i.is_a?(Array) || i.is_a?(Hash)}
155
+ flat[prefix] = list_to_string(current.map(&:to_s))
121
156
  elsif current.all?{ |i| i.is_a?(Hash) && i.keys == ['name']}
122
- flat[prefix] = current.map{ |i| i['name']}.join(', ')
157
+ flat[prefix] = list_to_string(current.map{ |i| i['name']})
123
158
  elsif current.all?{ |i| i.is_a?(Hash) && i.keys.sort == %w[name value]}
124
- stack.push([prefix, current.each_with_object({}){ |i, h| h[i['name']] = i['value']}])
159
+ add_elements(stack, prefix, current.each_with_object({}){ |i, h| h[i['name']] = i['value']})
125
160
  else
126
- current.each_with_index.reverse_each{ |v, k| stack.push([[prefix, k].compact.join('.'), v])}
161
+ add_elements(stack, prefix, current.each_with_index.map{ |v, i| [i, v]})
127
162
  end
128
163
  else
129
164
  flat[prefix] = current
@@ -166,23 +201,23 @@ module Aspera
166
201
  else
167
202
  {}
168
203
  end
169
- options.declare(:format, 'Output format', values: DISPLAY_FORMATS, handler: {o: self, m: :option_handler}, default: :table)
170
- options.declare(:output, 'Destination for results', types: String, handler: {o: self, m: :option_handler})
171
- options.declare(:display, 'Output only some information', values: DISPLAY_LEVELS, handler: {o: self, m: :option_handler}, default: :info)
204
+ options.declare(:format, 'Output format', allowed: DISPLAY_FORMATS, handler: {o: self, m: :option_handler}, default: :table)
205
+ options.declare(:output, 'Destination for results', handler: {o: self, m: :option_handler})
206
+ options.declare(:display, 'Output only some information', allowed: DISPLAY_LEVELS, handler: {o: self, m: :option_handler}, default: :info)
172
207
  options.declare(
173
208
  :fields, "Comma separated list of: fields, or #{SpecialValues::ALL}, or #{SpecialValues::DEF}", handler: {o: self, m: :option_handler},
174
- types: [String, Array, Regexp, Proc],
209
+ allowed: [String, Array, Regexp, Proc],
175
210
  default: SpecialValues::DEF
176
211
  )
177
- options.declare(:select, 'Select only some items in lists: column, value', types: [Hash, Proc], handler: {o: self, m: :option_handler})
178
- options.declare(:table_style, '(Table) Display style', types: [Hash], handler: {o: self, m: :option_handler}, default: default_table_style)
179
- options.declare(:flat_hash, '(Table) Display deep values as additional keys', values: :bool, handler: {o: self, m: :option_handler}, default: true)
212
+ options.declare(:select, 'Select only some items in lists: column, value', allowed: [Hash, Proc], handler: {o: self, m: :option_handler})
213
+ options.declare(:table_style, '(Table) Display style', allowed: [Hash], handler: {o: self, m: :option_handler}, default: default_table_style)
214
+ options.declare(:flat_hash, '(Table) Display deep values as additional keys', allowed: Allowed::TYPES_BOOLEAN, handler: {o: self, m: :option_handler}, default: true)
180
215
  options.declare(
181
- :multi_single, '(Table) Control how object list is displayed as single table, or multiple objects', values: %i[no yes single],
216
+ :multi_single, '(Table) Control how object list is displayed as single table, or multiple objects', allowed: %i[no yes single],
182
217
  handler: {o: self, m: :option_handler}, default: :no
183
218
  )
184
- options.declare(:show_secrets, 'Show secrets on command output', values: :bool, handler: {o: self, m: :option_handler}, default: false)
185
- options.declare(:image, 'Options for image display', types: Hash, handler: {o: self, m: :option_handler}, default: {})
219
+ options.declare(:show_secrets, 'Show secrets on command output', allowed: Allowed::TYPES_BOOLEAN, handler: {o: self, m: :option_handler}, default: false)
220
+ options.declare(:image, 'Options for image display', allowed: Hash, handler: {o: self, m: :option_handler}, default: {})
186
221
  end
187
222
 
188
223
  # method accessed by option manager
@@ -326,8 +361,7 @@ module Aspera
326
361
  end
327
362
  when :object_list
328
363
  # :object_list is an Array of Hash, where key=column name
329
- Aspera.assert_type(data, Array)
330
- Aspera.assert(data.all?(Hash)){"expecting Array of Hash: #{data.inspect}"}
364
+ Aspera.assert_array_all(data, Hash){'result'}
331
365
  data = data.map{ |obj| self.class.flatten_hash(obj)} if @options[:flat_hash]
332
366
  display_table(data, compute_fields(data, fields), single: type.eql?(:single_object))
333
367
  when :value_list
@@ -406,8 +440,7 @@ module Aspera
406
440
  def filter_list_on_fields(data)
407
441
  # by default, keep all data intact
408
442
  return data if @options[:fields].eql?(SpecialValues::DEF) && @options[:select].nil?
409
- Aspera.assert_type(data, Array){'Filtering fields or select requires result is an Array of Hash'}
410
- Aspera.assert(data.all?(Hash)){'Filtering fields or select requires result is an Array of Hash'}
443
+ Aspera.assert_array_all(data, Hash){'filter or select'}
411
444
  filter_columns_on_select(data)
412
445
  return data if @options[:fields].eql?(SpecialValues::DEF)
413
446
  selected_fields = compute_fields(data, @options[:fields])
@@ -214,6 +214,7 @@ module Aspera
214
214
  rescue Net::SSH::AuthenticationFailed => e; exception_info = {e: e, t: 'SSH', security: true}
215
215
  rescue OpenSSL::SSL::SSLError => e; exception_info = {e: e, t: 'SSL'}
216
216
  rescue Cli::BadArgument => e; exception_info = {e: e, t: 'Argument', usage: true}
217
+ rescue Cli::MissingArgument => e; exception_info = {e: e, t: 'Missing', usage: true}
217
218
  rescue Cli::BadIdentifier => e; exception_info = {e: e, t: 'Identifier'}
218
219
  rescue Cli::Error => e; exception_info = {e: e, t: 'Tool', usage: true}
219
220
  rescue Transfer::Error => e; exception_info = {e: e, t: 'Transfer'}
@@ -228,6 +229,7 @@ module Aspera
228
229
  unless exception_info.nil?
229
230
  Log.log.warn(exception_info[:e].message) if Log.instance.logger_type.eql?(:syslog) && exception_info[:security]
230
231
  @context.formatter.display_message(:error, "#{Formatter::ERROR_FLASH} #{exception_info[:t]}: #{exception_info[:e].message}")
232
+ Log.log.debug{(['Backtrace:'] + exception_info[:e].backtrace).join("\n")} if exception_info[:debug]
231
233
  @context.formatter.display_message(:error, 'Use option -h to get help.') if exception_info[:usage]
232
234
  # Is that a known error condition with proposal for remediation ?
233
235
  Hints.hint_for(exception_info[:e], @context.formatter)
@@ -287,7 +289,6 @@ module Aspera
287
289
  @context.options = Manager.new(Info::CMD_NAME, @argv)
288
290
  # Formatter adds options
289
291
  @context.formatter.declare_options(@context.options)
290
- ExtendedValue.instance.default_decoder = @context.options.get_option(:struct_parser)
291
292
  # Compare $0 with expected name
292
293
  current_prog_name = File.basename($PROGRAM_NAME)
293
294
  @context.formatter.display_message(
@@ -349,28 +350,34 @@ module Aspera
349
350
  # Define header for manual
350
351
  def declare_global_options
351
352
  Log.log.debug('declare_global_options')
352
- @context.options.declare(:help, 'Show this message', values: :none, short: 'h'){@option_help = true}
353
- @context.options.declare(:bash_comp, 'Generate bash completion for command', values: :none){@bash_completion = true}
354
- @context.options.declare(:show_config, 'Display parameters used for the provided action', values: :none){@option_show_config = true}
355
- @context.options.declare(:version, 'Display version', values: :none, short: 'v'){@context.formatter.display_message(:data, Cli::VERSION); Process.exit(0)} # rubocop:disable Style/Semicolon
353
+ @context.options.declare(:help, 'Show this message', allowed: Allowed::TYPES_NONE, short: 'h'){@option_help = true}
354
+ @context.options.declare(:bash_comp, 'Generate bash completion for command', allowed: Allowed::TYPES_NONE){@bash_completion = true}
355
+ @context.options.declare(:show_config, 'Display parameters used for the provided action', allowed: Allowed::TYPES_NONE){@option_show_config = true}
356
+ @context.options.declare(:version, 'Display version', allowed: Allowed::TYPES_NONE, short: 'v'){@context.formatter.display_message(:data, Cli::VERSION); Process.exit(0)} # rubocop:disable Style/Semicolon
356
357
  @context.options.declare(
357
358
  :ui, 'Method to start browser',
358
- values: USER_INTERFACES,
359
+ allowed: USER_INTERFACES,
359
360
  handler: {o: Environment.instance, m: :url_method}
360
361
  )
361
362
  @context.options.declare(
362
363
  :invalid_characters, 'Replacement character and invalid filename characters',
363
364
  handler: {o: Environment.instance, m: :file_illegal_characters}
364
365
  )
365
- @context.options.declare(:log_level, 'Log level', values: Log::LEVELS, handler: {o: Log.instance, m: :level})
366
- @context.options.declare(:log_format, 'Log formatter', types: [Proc, Logger::Formatter, String], handler: {o: Log.instance, m: :formatter})
367
- @context.options.declare(:logger, 'Logging method', values: Log::LOG_TYPES, handler: {o: Log.instance, m: :logger_type})
368
- @context.options.declare(:lock_port, 'Prevent dual execution of a command, e.g. in cron', coerce: Integer, types: Integer)
369
- @context.options.declare(:once_only, 'Process only new items (some commands)', values: :bool, default: false)
370
- @context.options.declare(:log_secrets, 'Show passwords in logs', values: :bool, handler: {o: SecretHider.instance, m: :log_secrets})
371
- @context.options.declare(:clean_temp, 'Cleanup temporary files on exit', values: :bool, handler: {o: TempFileManager.instance, m: :cleanup_on_exit})
366
+ @context.options.declare(:log_level, 'Log level', allowed: Log::LEVELS, handler: {o: Log.instance, m: :level})
367
+ @context.options.declare(:log_format, 'Log formatter', allowed: [Proc, Logger::Formatter, String], handler: {o: Log.instance, m: :formatter})
368
+ @context.options.declare(:logger, 'Logging method', allowed: Log::LOG_TYPES, handler: {o: Log.instance, m: :logger_type})
369
+ @context.options.declare(:lock_port, 'Prevent dual execution of a command, e.g. in cron', allowed: Allowed::TYPES_INTEGER)
370
+ @context.options.declare(:once_only, 'Process only new items (some commands)', allowed: Allowed::TYPES_BOOLEAN, default: false)
371
+ @context.options.declare(:log_secrets, 'Show passwords in logs', allowed: Allowed::TYPES_BOOLEAN, handler: {o: SecretHider.instance, m: :log_secrets})
372
+ @context.options.declare(:clean_temp, 'Cleanup temporary files on exit', allowed: Allowed::TYPES_BOOLEAN, handler: {o: TempFileManager.instance, m: :cleanup_on_exit})
372
373
  @context.options.declare(:temp_folder, 'Temporary folder', handler: {o: TempFileManager.instance, m: :global_temp})
373
- @context.options.declare(:pid_file, 'Write process identifier to file, delete on exit', types: String)
374
+ @context.options.declare(:pid_file, 'Write process identifier to file, delete on exit')
375
+ @context.options.declare(
376
+ :parser, 'Default parser for structured parameters and options',
377
+ handler: {o: ExtendedValue.instance, m: :default_decoder},
378
+ allowed: ExtendedValue::DEFAULT_DECODERS,
379
+ default: ExtendedValue::DEFAULT_DECODERS.first
380
+ )
374
381
  # Parse declared options
375
382
  @context.options.parse_options!
376
383
  end