aspera-cli 4.24.1 → 4.24.2

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.
Files changed (87) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +15 -2
  4. data/README.md +745 -436
  5. data/bin/ascli +20 -1
  6. data/bin/asession +23 -27
  7. data/lib/aspera/agent/base.rb +10 -21
  8. data/lib/aspera/agent/connect.rb +2 -3
  9. data/lib/aspera/agent/desktop.rb +2 -2
  10. data/lib/aspera/agent/direct.rb +49 -32
  11. data/lib/aspera/agent/factory.rb +31 -0
  12. data/lib/aspera/api/aoc.rb +79 -49
  13. data/lib/aspera/api/faspex.rb +212 -0
  14. data/lib/aspera/api/node.rb +99 -84
  15. data/lib/aspera/ascp/installation.rb +22 -21
  16. data/lib/aspera/ascp/management.rb +119 -23
  17. data/lib/aspera/assert.rb +14 -8
  18. data/lib/aspera/cli/extended_value.rb +15 -15
  19. data/lib/aspera/cli/formatter.rb +7 -5
  20. data/lib/aspera/cli/hints.rb +8 -0
  21. data/lib/aspera/cli/info.rb +4 -4
  22. data/lib/aspera/cli/main.rb +55 -70
  23. data/lib/aspera/cli/manager.rb +7 -4
  24. data/lib/aspera/cli/plugins/alee.rb +2 -1
  25. data/lib/aspera/cli/plugins/aoc.rb +110 -186
  26. data/lib/aspera/cli/plugins/ats.rb +4 -4
  27. data/lib/aspera/cli/plugins/base.rb +335 -0
  28. data/lib/aspera/cli/plugins/basic_auth.rb +45 -0
  29. data/lib/aspera/cli/plugins/config.rb +249 -220
  30. data/lib/aspera/cli/plugins/console.rb +15 -15
  31. data/lib/aspera/cli/plugins/cos.rb +2 -2
  32. data/lib/aspera/cli/plugins/factory.rb +78 -0
  33. data/lib/aspera/cli/plugins/faspex.rb +17 -20
  34. data/lib/aspera/cli/plugins/faspex5.rb +79 -193
  35. data/lib/aspera/cli/plugins/faspio.rb +14 -13
  36. data/lib/aspera/cli/plugins/httpgw.rb +13 -12
  37. data/lib/aspera/cli/plugins/node.rb +34 -32
  38. data/lib/aspera/cli/plugins/oauth.rb +48 -0
  39. data/lib/aspera/cli/plugins/orchestrator.rb +15 -13
  40. data/lib/aspera/cli/plugins/preview.rb +4 -4
  41. data/lib/aspera/cli/plugins/server.rb +15 -13
  42. data/lib/aspera/cli/plugins/shares.rb +18 -15
  43. data/lib/aspera/cli/sync_actions.rb +1 -1
  44. data/lib/aspera/cli/transfer_agent.rb +24 -20
  45. data/lib/aspera/cli/transfer_progress.rb +6 -6
  46. data/lib/aspera/cli/version.rb +3 -3
  47. data/lib/aspera/cli/wizard.rb +65 -53
  48. data/lib/aspera/colors.rb +6 -0
  49. data/lib/aspera/command_line_builder.rb +45 -50
  50. data/lib/aspera/command_line_converter.rb +2 -1
  51. data/lib/aspera/coverage.rb +1 -1
  52. data/lib/aspera/data_repository.rb +1 -1
  53. data/lib/aspera/environment.rb +10 -7
  54. data/lib/aspera/faspex_gw.rb +6 -4
  55. data/lib/aspera/faspex_postproc.rb +1 -1
  56. data/lib/aspera/keychain/macos_security.rb +1 -1
  57. data/lib/aspera/log.rb +37 -9
  58. data/lib/aspera/nagios.rb +1 -1
  59. data/lib/aspera/oauth/base.rb +17 -10
  60. data/lib/aspera/oauth/factory.rb +8 -8
  61. data/lib/aspera/oauth/web.rb +2 -2
  62. data/lib/aspera/products/connect.rb +4 -3
  63. data/lib/aspera/products/desktop.rb +1 -4
  64. data/lib/aspera/products/other.rb +9 -1
  65. data/lib/aspera/products/transferd.rb +0 -1
  66. data/lib/aspera/rest.rb +126 -83
  67. data/lib/aspera/ssh.rb +3 -3
  68. data/lib/aspera/sync/args.schema.yaml +46 -3
  69. data/lib/aspera/sync/conf.schema.yaml +130 -94
  70. data/lib/aspera/sync/operations.rb +16 -16
  71. data/lib/aspera/temp_file_manager.rb +17 -5
  72. data/lib/aspera/transfer/error.rb +16 -7
  73. data/lib/aspera/transfer/parameters.rb +34 -20
  74. data/lib/aspera/transfer/resumer.rb +74 -0
  75. data/lib/aspera/transfer/spec.rb +4 -3
  76. data/lib/aspera/transfer/spec.schema.yaml +132 -51
  77. data/lib/aspera/transfer/spec_doc.rb +41 -35
  78. data/lib/aspera/uri_reader.rb +1 -1
  79. data/lib/aspera/web_auth.rb +6 -6
  80. data.tar.gz.sig +0 -0
  81. metadata +9 -7
  82. metadata.gz.sig +0 -0
  83. data/lib/aspera/cli/basic_auth_plugin.rb +0 -43
  84. data/lib/aspera/cli/plugin.rb +0 -333
  85. data/lib/aspera/cli/plugin_factory.rb +0 -81
  86. data/lib/aspera/resumer.rb +0 -77
  87. data/lib/aspera/transfer/error_info.rb +0 -91
@@ -1,7 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # cspell:ignore initdemo genkey pubkey asperasoft filelists
4
- require 'aspera/cli/basic_auth_plugin'
4
+ require 'aspera/cli/plugins/basic_auth'
5
+ require 'aspera/cli/plugins/factory'
5
6
  require 'aspera/cli/extended_value'
6
7
  require 'aspera/cli/special_values'
7
8
  require 'aspera/cli/version'
@@ -10,8 +11,8 @@ require 'aspera/cli/info'
10
11
  require 'aspera/cli/transfer_progress'
11
12
  require 'aspera/cli/wizard'
12
13
  require 'aspera/ascp/installation'
14
+ require 'aspera/sync/operations'
13
15
  require 'aspera/products/transferd'
14
- require 'aspera/transfer/error_info'
15
16
  require 'aspera/transfer/parameters'
16
17
  require 'aspera/transfer/spec'
17
18
  require 'aspera/transfer/spec_doc'
@@ -36,93 +37,34 @@ require 'erb'
36
37
  module Aspera
37
38
  module Cli
38
39
  module Plugins
39
- # manage the CLI config file
40
- class Config < Cli::Plugin
41
- # folder in $HOME for application files (config, cache)
42
- ASPERA_HOME_FOLDER_NAME = '.aspera'
43
- # default config file
44
- DEFAULT_CONFIG_FILENAME = 'config.yaml'
45
- # reserved preset names
46
- CONF_PRESET_CONFIG = 'config'
47
- CONF_PRESET_VERSION = 'version'
48
- CONF_PRESET_DEFAULTS = 'default'
49
- CONF_PRESET_GLOBAL = 'global_common_defaults'
50
- # special name to identify value of default
51
- GLOBAL_DEFAULT_KEYWORD = 'GLOBAL'
52
- CONF_GLOBAL_SYM = :config
53
- # folder containing custom plugins in user's config folder
54
- ASPERA_PLUGINS_FOLDERNAME = 'plugins'
55
- PERSISTENCY_FOLDER = 'persist_store'
56
- ASPERA = 'aspera'
57
- SERVER_COMMAND = 'server'
58
- DIR_SDK = 'sdk'
59
- DEMO_SERVER = 'demo'
60
- DEMO_PRESET = 'demoserver' # cspell: disable-line
61
- EMAIL_TEST_TEMPLATE = <<~END_OF_TEMPLATE
62
- From: <%=from_name%> <<%=from_email%>>
63
- To: <<%=to%>>
64
- Subject: #{Info::GEM_NAME} email test
65
-
66
- This email was sent to test #{Info::CMD_NAME}.
67
- END_OF_TEMPLATE
68
- # special extended values
69
- EXTEND_PRESET = :preset
70
- EXTEND_VAULT = :vault
71
- PRESET_DIG_SEPARATOR = '.'
72
- DEFAULT_CHECK_NEW_VERSION_DAYS = 7
73
- COFFEE_IMAGE_URL = 'https://enjoyjava.com/wp-content/uploads/2018/01/How-to-make-strong-coffee.jpg'
74
- GEM_CHECK_DATE_FMT = '%Y/%m/%d'
75
- # for testing only
76
- SELF_SIGNED_CERT = OpenSSL::SSL.const_get(:enon_yfirev.to_s.upcase.reverse) # cspell: disable-line
77
- CONF_OVERVIEW_KEYS = %w[preset parameter value].freeze
78
- SMTP_CONF_PARAMS = %i[server tls ssl port domain username password from_name from_email].freeze
79
- private_constant :DEFAULT_CONFIG_FILENAME,
80
- :CONF_PRESET_CONFIG,
81
- :CONF_PRESET_VERSION,
82
- :CONF_PRESET_DEFAULTS,
83
- :CONF_PRESET_GLOBAL,
84
- :ASPERA_PLUGINS_FOLDERNAME,
85
- :ASPERA,
86
- :DEMO_SERVER,
87
- :DEMO_PRESET,
88
- :EMAIL_TEST_TEMPLATE,
89
- :EXTEND_PRESET,
90
- :EXTEND_VAULT,
91
- :DEFAULT_CHECK_NEW_VERSION_DAYS,
92
- :SERVER_COMMAND,
93
- :PRESET_DIG_SEPARATOR,
94
- :COFFEE_IMAGE_URL,
95
- :SELF_SIGNED_CERT,
96
- :PERSISTENCY_FOLDER,
97
- :CONF_OVERVIEW_KEYS,
98
- :SMTP_CONF_PARAMS
99
-
40
+ # Manage the CLI config file
41
+ class Config < Base
100
42
  class << self
101
- # folder containing plugins in the gem's main folder
43
+ # Folder containing plugins in the gem's main folder
102
44
  def gem_plugins_folder
103
45
  File.dirname(File.expand_path(__FILE__))
104
46
  end
105
47
 
106
48
  # @return main folder where code is, i.e. .../lib
107
- # go up as many times as englobing modules (not counting class, as it is a file)
49
+ # Go up as many times as englobing modules (not counting class, as it is a file)
108
50
  def gem_src_root
109
51
  # Module.nesting[2] is Cli::Plugins
110
52
  File.expand_path(Module.nesting[2].to_s.gsub('::', '/').gsub(%r{[^/]+}, '..'), gem_plugins_folder)
111
53
  end
112
54
 
113
- # deep clone hash so that it does not get modified in case of display and secret hide
55
+ # Deep clone hash so that it does not get modified in case of display and secret hide
114
56
  def deep_clone(val)
115
57
  return Marshal.load(Marshal.dump(val))
116
58
  end
117
59
 
118
- # return product family folder (~/.aspera)
60
+ # @return product family folder (~/.aspera)
119
61
  def module_family_folder
120
62
  user_home_folder = Dir.home
121
63
  Aspera.assert(Dir.exist?(user_home_folder), type: Cli::Error){"Home folder does not exist: #{user_home_folder}. Check your user environment."}
122
64
  return File.join(user_home_folder, ASPERA_HOME_FOLDER_NAME)
123
65
  end
124
66
 
125
- # return product config folder (~/.aspera/<name>)
67
+ # @return [String] Product config folder (~/.aspera/<name>)
126
68
  def default_app_main_folder(app_name:)
127
69
  Aspera.assert_type(app_name, String)
128
70
  Aspera.assert(!app_name.empty?)
@@ -131,7 +73,7 @@ module Aspera
131
73
  end
132
74
 
133
75
  def initialize(**_)
134
- # we need to defer parsing of options until we have the config file, so we can use @extend with @preset
76
+ # We need to defer parsing of options until we have the config file, so we can use @extend with @preset
135
77
  super
136
78
  @use_plugin_defaults = true
137
79
  @config_presets = nil
@@ -147,12 +89,12 @@ module Aspera
147
89
  @option_cache_tokens = true
148
90
  @main_folder = nil
149
91
  @option_config_file = nil
150
- # store is used for ruby https
92
+ # Store is used for ruby https
151
93
  @certificate_store = nil
152
- # paths are used for ascp
94
+ # Paths are used for ascp
153
95
  @certificate_paths = nil
154
96
  @progress_bar = nil
155
- # option to set main folder
97
+ # Option to set main folder
156
98
  options.declare(
157
99
  :home, 'Home folder for tool',
158
100
  handler: {o: self, m: :main_folder},
@@ -161,38 +103,38 @@ module Aspera
161
103
  )
162
104
  options.parse_options!
163
105
  Log.log.debug{"#{Info::CMD_NAME} folder: #{@main_folder}"}
164
- # data persistency manager, created by config plugin, set for global object
106
+ # Data persistency manager, created by config plugin, set for global object
165
107
  context.persistency = PersistencyFolder.new(File.join(@main_folder, PERSISTENCY_FOLDER))
166
- # set folders for plugin lookup
167
- PluginFactory.instance.add_lookup_folder(self.class.gem_plugins_folder)
168
- PluginFactory.instance.add_lookup_folder(File.join(@main_folder, ASPERA_PLUGINS_FOLDERNAME))
169
- # option to set config file
108
+ # Set folders for plugin lookup
109
+ Plugins::Factory.instance.add_lookup_folder(self.class.gem_plugins_folder)
110
+ Plugins::Factory.instance.add_lookup_folder(File.join(@main_folder, ASPERA_PLUGINS_FOLDERNAME))
111
+ # Option to set config file
170
112
  options.declare(
171
113
  :config_file, 'Path to YAML file with preset configuration',
172
114
  handler: {o: self, m: :option_config_file},
173
115
  default: File.join(@main_folder, DEFAULT_CONFIG_FILENAME)
174
116
  )
175
117
  options.parse_options!
176
- # read config file (set @config_presets)
118
+ # Read config file (set @config_presets)
177
119
  read_config_file
178
- # add preset handler (needed for smtp)
120
+ # Add preset handler (needed for smtp)
179
121
  ExtendedValue.instance.set_handler(EXTEND_PRESET, lambda{ |v| preset_by_name(v)})
180
122
  ExtendedValue.instance.set_handler(EXTEND_VAULT, lambda{ |v| vault_value(v)})
181
- # load defaults before it can be overridden
123
+ # Load defaults before it can be overridden
182
124
  add_plugin_default_preset(CONF_GLOBAL_SYM)
183
- # vault options
125
+ # Vault options
184
126
  options.declare(:secret, 'Secret for access keys')
185
127
  options.declare(:vault, 'Vault for secrets', types: Hash, default: {})
186
128
  options.declare(:vault_password, 'Vault password')
187
129
  options.parse_options!
188
- # declare generic plugin options only after handlers are declared
189
- Plugin.declare_generic_options(options)
190
- # configuration options
130
+ # Declare generic plugin options only after handlers are declared
131
+ Base.declare_options(options)
132
+ # Configuration options
191
133
  options.declare(:no_default, 'Do not load default configuration for plugin', values: :none, short: 'N'){@use_plugin_defaults = false}
192
134
  options.declare(:preset, 'Load the named option preset from current config file', short: 'P', handler: {o: self, m: :option_preset})
193
135
  options.declare(:version_check_days, 'Period in days to check new version (zero to disable)', coerce: Integer, default: DEFAULT_CHECK_NEW_VERSION_DAYS)
194
136
  options.declare(:plugin_folder, 'Folder where to find additional plugins', handler: {o: self, m: :option_plugin_folder})
195
- # declare wizard options
137
+ # Declare wizard options
196
138
  @wizard = Wizard.new(self, @main_folder)
197
139
  # Transfer SDK options
198
140
  options.declare(:ascp_path, 'Ascp: Path to ascp', handler: {o: Ascp::Installation.instance, m: :ascp_path})
@@ -201,7 +143,7 @@ module Aspera
201
143
  options.declare(:locations_url, 'Ascp: URL to get locations of Aspera Transfer Daemon', handler: {o: Ascp::Installation.instance, m: :transferd_urls})
202
144
  options.declare(:sdk_folder, 'Ascp: SDK folder path', handler: {o: Products::Transferd, m: :sdk_directory})
203
145
  options.declare(:progress_bar, 'Display progress bar', values: :bool, default: Environment.terminal?)
204
- # email options
146
+ # Email options
205
147
  options.declare(:smtp, 'Email: SMTP configuration', types: Hash)
206
148
  options.declare(:notify_to, 'Email: Recipient for notification of transfers')
207
149
  options.declare(:notify_template, 'Email: ERB template for notification of transfers')
@@ -222,21 +164,21 @@ module Aspera
222
164
  if sdk_dir.nil?
223
165
  @sdk_default_location = true
224
166
  Log.log.debug('SDK folder is not set, checking default')
225
- # new location
226
- sdk_dir = self.class.default_app_main_folder(app_name: DIR_SDK)
227
- Log.log.debug{"checking: #{sdk_dir}"}
167
+ # New location
168
+ sdk_dir = self.class.default_app_main_folder(app_name: TRANSFERD_APP_NAME)
169
+ Log.log.debug{"Checking: #{sdk_dir}"}
228
170
  if !Dir.exist?(sdk_dir)
229
- Log.log.debug{"not exists: #{sdk_dir}"}
230
- # former location
231
- former_sdk_folder = File.join(self.class.default_app_main_folder(app_name: Info::CMD_NAME), DIR_SDK)
232
- Log.log.debug{"checking: #{former_sdk_folder}"}
171
+ Log.log.debug{"No such folder: #{sdk_dir}"}
172
+ # Former location
173
+ former_sdk_folder = File.join(self.class.default_app_main_folder(app_name: Info::CMD_NAME), TRANSFERD_APP_NAME)
174
+ Log.log.debug{"Checking: #{former_sdk_folder}"}
233
175
  sdk_dir = former_sdk_folder if Dir.exist?(former_sdk_folder)
234
176
  end
235
- Log.log.debug{"using: #{sdk_dir}"}
177
+ Log.log.debug{"Using: #{sdk_dir}"}
236
178
  Products::Transferd.sdk_directory = sdk_dir
237
179
  end
238
180
  pac_script = options.get_option(:fpac)
239
- # create PAC executor
181
+ # Create PAC executor
240
182
  if !pac_script.nil?
241
183
  @pac_exec = ProxyAutoConfig.new(pac_script).register_uri_generic
242
184
  proxy_user_pass = options.get_option(:proxy_credentials)
@@ -249,23 +191,54 @@ module Aspera
249
191
  RestParameters.instance.user_agent = Info::CMD_NAME
250
192
  RestParameters.instance.progress_bar = @progress_bar
251
193
  RestParameters.instance.session_cb = lambda{ |http_session| update_http_session(http_session)}
252
- @option_http_options.keys.select{ |i| RestParameters.instance.respond_to?(i)}.each do |k|
194
+ # Check http options that are global
195
+ keys_to_delete = []
196
+ @option_http_options.each do |k, v|
253
197
  method = "#{k}=".to_sym
254
- RestParameters.instance.send(method, @option_http_options[k])
255
- @option_http_options.delete(k)
198
+ if RestParameters.instance.respond_to?(method)
199
+ keys_to_delete.push(k)
200
+ RestParameters.instance.send(method, v)
201
+ elsif k.eql?('ssl_options')
202
+ keys_to_delete.push(k)
203
+ # NOTE: here is a hack that allows setting SSLContext options
204
+ Aspera.assert_type(v, Array){'ssl_options'}
205
+ # Start with default options
206
+ ssl_options = OpenSSL::SSL::SSLContext::DEFAULT_PARAMS[:options]
207
+ v.each do |opt|
208
+ case opt
209
+ when Integer
210
+ ssl_options = opt
211
+ when String
212
+ name = "OP_#{opt.start_with?('-') ? opt[1..] : opt}".upcase
213
+ raise Cli::BadArgument, "Unknown ssl_option: #{name}, use one of: #{OpenSSL::SSL.constants.grep(/^OP_/).map{ |c| c.to_s.sub(/^OP_/, '')}.join(', ')}" if !OpenSSL::SSL.const_defined?(name)
214
+ if opt.start_with?('-')
215
+ ssl_options &= ~OpenSSL::SSL.const_get(name)
216
+ else
217
+ ssl_options |= OpenSSL::SSL.const_get(name)
218
+ end
219
+ else
220
+ Aspera.error_unexpected_value(opt.class.name){'Expected String or Integer in ssl_options'}
221
+ end
222
+ end
223
+ OpenSSL::SSL::SSLContext::DEFAULT_PARAMS[:options] = ssl_options
224
+ elsif OAuth::Factory.instance.parameters.key?(k.to_sym)
225
+ keys_to_delete.push(k)
226
+ OAuth::Factory.instance.parameters[k.to_sym] = v
227
+ end
256
228
  end
229
+ keys_to_delete.each{ |k| @option_http_options.delete(k)}
257
230
  OAuth::Factory.instance.persist_mgr = persistency if @option_cache_tokens
258
- OAuth::Web.additionnal_info = "#{Info::CMD_NAME} v#{Cli::VERSION}"
231
+ OAuth::Web.additional_info = "#{Info::CMD_NAME} v#{Cli::VERSION}"
259
232
  Transfer::Parameters.file_list_folder = File.join(@main_folder, 'filelists')
260
233
  RestErrorAnalyzer.instance.log_file = File.join(@main_folder, 'rest_exceptions.log')
261
- # register aspera REST call error handlers
234
+ # Register aspera REST call error handlers
262
235
  RestErrorsAspera.register_handlers
263
236
  end
264
237
 
265
238
  attr_accessor :main_folder, :option_cache_tokens, :option_insecure, :option_warn_insecure_cert, :option_http_options
266
239
  attr_reader :option_ignore_cert_host_port, :progress_bar
267
240
 
268
- # add files, folders or default locations to the certificate store
241
+ # Add files, folders or default locations to the certificate store
269
242
  # @param path_list [Array<String>] list of paths to add
270
243
  # @return the list of paths
271
244
  def trusted_cert_locations=(path_list)
@@ -307,14 +280,14 @@ module Aspera
307
280
  @certificate_paths.uniq!
308
281
  end
309
282
 
310
- # returns only files
283
+ # @return only files
311
284
  def trusted_cert_locations
312
285
  locations = @certificate_paths
313
286
  if locations.nil?
314
- # compute default locations
287
+ # Compute default locations
315
288
  self.trusted_cert_locations = SpecialValues::DEF
316
289
  locations = @certificate_paths
317
- # restore defaults
290
+ # Restore defaults
318
291
  @certificate_paths = @certificate_store = nil
319
292
  end
320
293
  return locations
@@ -357,7 +330,7 @@ module Aspera
357
330
  return ignore_cert
358
331
  end
359
332
 
360
- # called every time a new REST HTTP session is opened to set user-provided options
333
+ # Called every time a new REST HTTP session is opened to set user-provided options
361
334
  # @param http_session [Net::HTTP] the newly created HTTP/S session object
362
335
  def update_http_session(http_session)
363
336
  http_session.set_debug_output(LineLogger.new(:trace2)) if Log.instance.logger.trace2?
@@ -367,38 +340,12 @@ module Aspera
367
340
  Log.log.debug{"Using cert store #{http_session.cert_store} (#{@certificate_store})"} unless http_session.cert_store.nil?
368
341
  @option_http_options.each do |k, v|
369
342
  method = "#{k}=".to_sym
370
- # check if accessor is a method of Net::HTTP
343
+ # Check if accessor is a method of Net::HTTP
371
344
  # continue_timeout= read_timeout= write_timeout=
372
345
  if http_session.respond_to?(method)
373
346
  http_session.send(method, v)
374
- elsif k.eql?('ssl_options')
375
- # NOTE: here is a hack that allows setting SSLContext options
376
- Aspera.assert_type(v, Array){'ssl_options'}
377
- # more dynamic method, but more complex:
378
- # Net::HTTP::SSL_ATTRIBUTES.push(:options) unless Net::HTTP::SSL_ATTRIBUTES.include?(:options)
379
- # Net::HTTP::SSL_IVNAMES.push(:@options) unless Net::HTTP::SSL_IVNAMES.include?(:@options)
380
- # Start with default options
381
- ssl_options = OpenSSL::SSL::SSLContext::DEFAULT_PARAMS[:options]
382
- v.each do |opt|
383
- case opt
384
- when Integer
385
- ssl_options = opt
386
- when String
387
- name = "OP_#{opt.start_with?('-') ? opt[1..] : opt}".upcase
388
- raise Cli::BadArgument, "No such ssl_option: #{name}, use one of: #{OpenSSL::SSL.constants.grep(/^OP_/).map{ |c| c.to_s.sub(/^OP_/, '')}.join(', ')}" if !OpenSSL::SSL.const_defined?(name)
389
- if opt.start_with?('-')
390
- ssl_options &= ~OpenSSL::SSL.const_get(name)
391
- else
392
- ssl_options |= OpenSSL::SSL.const_get(name)
393
- end
394
- else
395
- Aspera.error_unexpected_value(opt.class.name){'Expected String or Integer in ssl_options'}
396
- end
397
- end
398
- # http_session.instance_variable_set(:@options, ssl_options)
399
- OpenSSL::SSL::SSLContext::DEFAULT_PARAMS[:options] = ssl_options
400
347
  else
401
- Log.log.error{"no such HTTP session attribute: #{k}"}
348
+ Log.log.error{"Unknown HTTP session attribute: #{k}"}
402
349
  end
403
350
  end
404
351
  end
@@ -426,35 +373,35 @@ module Aspera
426
373
  end
427
374
 
428
375
  def periodic_check_newer_gem_version
429
- # get verification period
376
+ # Get verification period
430
377
  delay_days = options.get_option(:version_check_days, mandatory: true).to_i
431
- # check only if not zero day
378
+ # Check only if not zero day
432
379
  return if delay_days.eql?(0)
433
- # get last date from persistency
380
+ # Get last date from persistency
434
381
  last_check_array = []
435
382
  check_date_persist = PersistencyActionOnce.new(
436
383
  manager: persistency,
437
384
  data: last_check_array,
438
385
  id: 'version_last_check'
439
386
  )
440
- # get persisted date or nil
387
+ # Get persisted date or nil
441
388
  current_date = Date.today
442
389
  last_check_days = (current_date - Date.strptime(last_check_array.first, GEM_CHECK_DATE_FMT)) rescue nil
443
390
  Log.log.debug{"gem check new version: #{delay_days}, #{last_check_days}, #{current_date}, #{last_check_array}"}
444
391
  return if !last_check_days.nil? && last_check_days < delay_days
445
- # generate timestamp
392
+ # Generate timestamp
446
393
  last_check_array[0] = current_date.strftime(GEM_CHECK_DATE_FMT)
447
394
  check_date_persist.save
448
- # compare this version and the one on internet
395
+ # Compare this version and the one on internet
449
396
  check_data = check_gem_version
450
397
  Log.log.warn do
451
398
  "A new version is available: #{check_data[:latest]}. You have #{check_data[:current]}. Upgrade with: gem update #{check_data[:name]}"
452
399
  end if check_data[:need_update]
453
400
  end
454
401
 
455
- # loads default parameters of plugin if no -P parameter
402
+ # Loads default parameters of plugin if no -P parameter
456
403
  # and if there is a section defined for the plugin in the "default" section
457
- # try to find: conf[conf["default"][plugin_str]]
404
+ # Try to find: conf[conf["default"][plugin_str]]
458
405
  # @param plugin_name_sym : symbol for plugin name
459
406
  def add_plugin_default_preset(plugin_name_sym)
460
407
  default_config_name = get_plugin_default_config_name(plugin_name_sym)
@@ -463,7 +410,7 @@ module Aspera
463
410
  return
464
411
  end
465
412
 
466
- # get the default global preset, or set default one
413
+ # Get the default global preset, or set default one
467
414
  def global_default_preset
468
415
  result = get_plugin_default_config_name(CONF_GLOBAL_SYM)
469
416
  if result.nil?
@@ -491,7 +438,7 @@ module Aspera
491
438
  param_name = param_name.to_s
492
439
  selected_preset = @config_presets[preset]
493
440
  if selected_preset.nil?
494
- Log.log.debug{"No such preset name: #{preset}, initializing"}
441
+ Log.log.debug{"Unknown preset name: #{preset}, initializing"}
495
442
  selected_preset = @config_presets[preset] = {}
496
443
  end
497
444
  Aspera.assert_type(selected_preset, Hash){"#{preset}.#{param_name}"}
@@ -507,8 +454,8 @@ module Aspera
507
454
  nil
508
455
  end
509
456
 
510
- # set parameter and value in global config
511
- # creates one if none already created
457
+ # Set parameter and value in global config
458
+ # Creates one if none already created
512
459
  # @return preset name that contains global default
513
460
  def set_global_default(key, value)
514
461
  set_preset_key(global_default_preset, key, value)
@@ -523,13 +470,13 @@ module Aspera
523
470
  # @return copy of the hash from name (also expands possible includes)
524
471
  def preset_by_name(config_name, include_path = [])
525
472
  raise Cli::Error, 'loop in include' if include_path.include?(config_name)
526
- include_path = include_path.clone # avoid messing up if there are multiple branches
473
+ include_path = include_path.clone # Avoid messing up if there are multiple branches
527
474
  current = @config_presets
528
475
  config_name.split(PRESET_DIG_SEPARATOR).each do |name|
529
476
  Aspera.assert_type(current, Hash, type: Cli::Error){"sub key: #{include_path}"}
530
477
  include_path.push(name)
531
478
  current = current[name]
532
- raise Cli::Error, "No such config preset: #{include_path}" if current.nil?
479
+ raise Cli::Error, "Unknown config preset: #{include_path}" if current.nil?
533
480
  end
534
481
  current = self.class.deep_clone(current) unless current.is_a?(String)
535
482
  return ExtendedValue.instance.evaluate(current)
@@ -547,11 +494,11 @@ module Aspera
547
494
  Aspera.assert_values(value.class, [String, Array]){'plugin folder'}
548
495
  value = [value] if value.is_a?(String)
549
496
  Aspera.assert(value.all?(String)){'plugin folder'}
550
- value.each{ |f| PluginFactory.instance.add_lookup_folder(f)}
497
+ value.each{ |f| Plugins::Factory.instance.add_lookup_folder(f)}
551
498
  end
552
499
 
553
500
  def option_plugin_folder
554
- return PluginFactory.instance.lookup_folders
501
+ return Plugins::Factory.instance.lookup_folders
555
502
  end
556
503
 
557
504
  def option_preset; 'write-only option'; end
@@ -571,14 +518,14 @@ module Aspera
571
518
  JSON.generate(@config_presets).hash
572
519
  end
573
520
 
574
- # read config file and validate format
521
+ # Read config file and validate format
575
522
  def read_config_file
576
523
  Log.log.debug{"config file is: #{@option_config_file}".red}
577
- # files search for configuration, by default the one given by user
524
+ # Files search for configuration, by default the one given by user
578
525
  search_files = [@option_config_file]
579
- # find first existing file (or nil)
526
+ # Find first existing file (or nil)
580
527
  conf_file_to_load = search_files.find{ |f| File.exist?(f)}
581
- # if no file found, create default config
528
+ # If no file found, create default config
582
529
  if conf_file_to_load.nil?
583
530
  Log.log.warn{"No config file found. New configuration file: #{@option_config_file}"}
584
531
  @config_presets = {CONF_PRESET_CONFIG => {CONF_PRESET_VERSION => 'new file'}}
@@ -591,16 +538,16 @@ module Aspera
591
538
  files_to_copy = []
592
539
  Log.dump(:available_presets, @config_presets, level: :trace1)
593
540
  Aspera.assert_type(@config_presets, Hash){'config file YAML'}
594
- # check there is at least the config section
541
+ # Check there is at least the config section
595
542
  Aspera.assert(@config_presets.key?(CONF_PRESET_CONFIG)){"Cannot find key: #{CONF_PRESET_CONFIG}"}
596
543
  version = @config_presets[CONF_PRESET_CONFIG][CONF_PRESET_VERSION]
597
544
  raise Error, 'No version found in config section.' if version.nil?
598
545
  Log.log.debug{"conf version: #{version}"}
599
546
  # VVV if there are any conversion needed, those happen here.
600
- # fix bug in 4.4 (creating key "true" in "default" preset)
547
+ # Fix bug in 4.4 (creating key "true" in "default" preset)
601
548
  @config_presets[CONF_PRESET_DEFAULTS].delete(true) if @config_presets[CONF_PRESET_DEFAULTS].is_a?(Hash)
602
549
  # ^^^ Place new compatibility code before this line
603
- # set version to current
550
+ # Set version to current
604
551
  @config_presets[CONF_PRESET_CONFIG][CONF_PRESET_VERSION] = Cli::VERSION
605
552
  unless files_to_copy.empty?
606
553
  Log.log.warn('Copying referenced files')
@@ -615,7 +562,7 @@ module Aspera
615
562
  rescue StandardError => e
616
563
  Log.log.debug{"-> #{e.class.name} : #{e}"}
617
564
  if File.exist?(@option_config_file)
618
- # then there is a problem with that file.
565
+ # Then there is a problem with that file.
619
566
  new_name = "#{@option_config_file}.pre#{Cli::VERSION}.manual_conversion_needed"
620
567
  File.rename(@option_config_file, new_name)
621
568
  Log.log.warn{"Renamed config file to #{new_name}."}
@@ -674,13 +621,13 @@ module Aspera
674
621
  when :show
675
622
  return Main.result_text(Ascp::Installation.instance.path(:ascp))
676
623
  when :info
677
- # collect info from ascp executable
624
+ # Collect info from ascp executable
678
625
  data = Ascp::Installation.instance.ascp_info
679
- # add command line transfer spec
626
+ # Add command line transfer spec
680
627
  data['ts'] = transfer.option_transfer_spec
681
- # add keys
628
+ # Add keys
682
629
  DataRepository::ELEMENTS.each_with_object(data){ |i, h| h[i.to_s] = DataRepository.instance.item(i)}
683
- # declare those as secrets
630
+ # Declare those as secrets
684
631
  SecretHider::ADDITIONAL_KEYS_TO_HIDE.concat(DataRepository::ELEMENTS.map(&:to_s))
685
632
  return Main.result_single_object(data)
686
633
  when :products
@@ -695,13 +642,13 @@ module Aspera
695
642
  return Main.result_nothing
696
643
  end
697
644
  when :install
698
- # reset to default location, if older default was used
699
- Products::Transferd.sdk_directory = self.class.default_app_main_folder(app_name: DIR_SDK) if @sdk_default_location
645
+ # Reset to default location, if older default was used
646
+ Products::Transferd.sdk_directory = self.class.default_app_main_folder(app_name: TRANSFERD_APP_NAME) if @sdk_default_location
700
647
  version = options.get_next_argument('transferd version', mandatory: false)
701
648
  n, v = Ascp::Installation.instance.install_sdk(url: options.get_option(:sdk_url, mandatory: true), version: version)
702
649
  return Main.result_status("Installed #{n} version #{v}")
703
650
  when :spec
704
- fields, data = Transfer::SpecDoc.man_table(Formatter)
651
+ fields, data = Transfer::SpecDoc.man_table(Formatter, include_option: true)
705
652
  return Main.result_object_list(data, fields: fields.map(&:to_s))
706
653
  when :schema
707
654
  schema = Transfer::Spec::SCHEMA.merge({'$comment'=>'DO NOT EDIT, this file was generated from the YAML.'})
@@ -711,7 +658,7 @@ module Aspera
711
658
  return Main.result_single_object(schema)
712
659
  when :errors
713
660
  error_data = []
714
- Transfer::ERROR_INFO.each_pair do |code, prop|
661
+ Ascp::Management::ERRORS.each_pair do |code, prop|
715
662
  error_data.push(code: code, mnemonic: prop[:c], retry: prop[:r], info: prop[:a])
716
663
  end
717
664
  return Main.result_object_list(error_data)
@@ -724,8 +671,8 @@ module Aspera
724
671
  command = options.get_next_command(%i[list install])
725
672
  case command
726
673
  when :install
727
- # reset to default location, if older default was used
728
- Products::Transferd.sdk_directory = self.class.default_app_main_folder(app_name: DIR_SDK) if @sdk_default_location
674
+ # Reset to default location, if older default was used
675
+ Products::Transferd.sdk_directory = self.class.default_app_main_folder(app_name: TRANSFERD_APP_NAME) if @sdk_default_location
729
676
  version = options.get_next_argument('transferd version', mandatory: false)
730
677
  n, v = Ascp::Installation.instance.install_sdk(url: options.get_option(:sdk_url, mandatory: true), version: version)
731
678
  return Main.result_status("Installed #{n} version #{v}")
@@ -740,9 +687,9 @@ module Aspera
740
687
  Aspera.error_unreachable_line
741
688
  end
742
689
 
743
- # legacy actions available globally
690
+ # Legacy actions available globally
744
691
  PRESET_GBL_ACTIONS = %i[list overview lookup secure].freeze
745
- # operations requiring that preset exists
692
+ # Operations requiring that preset exists
746
693
  PRESET_EXIST_ACTIONS = %i[show delete get unset].freeze
747
694
  # require id
748
695
  PRESET_INSTANCE_ACTIONS = %i[initialize update ask set].concat(PRESET_EXIST_ACTIONS).freeze
@@ -752,13 +699,13 @@ module Aspera
752
699
  action = options.get_next_command(PRESET_ALL_ACTIONS) if action.nil?
753
700
  name = instance_identifier if name.nil? && PRESET_INSTANCE_ACTIONS.include?(action)
754
701
  name = global_default_preset if name.eql?(GLOBAL_DEFAULT_KEYWORD)
755
- # those operations require existing option
702
+ # Those operations require existing option
756
703
  raise "no such preset: #{name}" if PRESET_EXIST_ACTIONS.include?(action) && !@config_presets.key?(name)
757
704
  case action
758
705
  when :list
759
706
  return Main.result_value_list(@config_presets.keys, name: 'name')
760
707
  when :overview
761
- # display process modifies the value (hide secrets): we do not want to save removed secrets
708
+ # Display process modifies the value (hide secrets): we do not want to save removed secrets
762
709
  data = self.class.deep_clone(@config_presets)
763
710
  formatter.hide_secrets(data)
764
711
  result = []
@@ -812,7 +759,7 @@ module Aspera
812
759
  end
813
760
  return Main.result_status("Updated: #{name}")
814
761
  when :lookup
815
- BasicAuthPlugin.declare_options(options)
762
+ BasicAuth.declare_options(options)
816
763
  url = options.get_option(:url, mandatory: true)
817
764
  user = options.get_option(:username, mandatory: true)
818
765
  result = lookup_preset(url: url, username: user)
@@ -863,6 +810,7 @@ module Aspera
863
810
  coffee
864
811
  image
865
812
  ascp
813
+ sync
866
814
  transferd
867
815
  email_test
868
816
  smtp_settings
@@ -880,7 +828,7 @@ module Aspera
880
828
  def execute_action
881
829
  action = options.get_next_command(ACTIONS)
882
830
  case action
883
- when :preset # newer syntax
831
+ when :preset # Newer syntax
884
832
  return execute_preset
885
833
  when :open
886
834
  Environment.instance.open_editor(@option_config_file.to_s)
@@ -890,12 +838,12 @@ module Aspera
890
838
  section = "##{section}" unless section.nil?
891
839
  Environment.instance.open_uri("#{Info::DOC_URL}#{section}")
892
840
  return Main.result_nothing
893
- when :genkey # generate new rsa key
841
+ when :genkey # Generate new rsa key
894
842
  private_key_path = options.get_next_argument('private key file path')
895
843
  private_key_length = options.get_next_argument('size in bits', mandatory: false, validation: Integer, default: OAuth::Jwt::DEFAULT_PRIV_KEY_LENGTH)
896
844
  OAuth::Jwt.generate_rsa_private_key(path: private_key_path, length: private_key_length)
897
845
  return Main.result_status("Generated #{private_key_length} bit RSA key: #{private_key_path}")
898
- when :pubkey # get pub key
846
+ when :pubkey # Get pub key
899
847
  private_key_pem = options.get_next_argument('private key PEM value')
900
848
  return Main.result_text(OpenSSL::PKey::RSA.new(private_key_pem).public_key.to_s)
901
849
  when :remote_certificate
@@ -911,7 +859,7 @@ module Aspera
911
859
  when :name
912
860
  return Main.result_text(remote_chain.first.subject.to_a.find{ |name, _, _| name == 'CN'}[1])
913
861
  end
914
- when :echo # display the content of a value given on command line
862
+ when :echo # Display the content of a value given on command line
915
863
  return Main.result_auto(options.get_next_argument('value', validation: nil))
916
864
  when :download
917
865
  file_url = options.get_next_argument('source URL').chomp
@@ -929,20 +877,20 @@ module Aspera
929
877
  return Main.result_object_list(OAuth::Factory.instance.persisted_tokens)
930
878
  when :show
931
879
  data = OAuth::Factory.instance.get_token_info(instance_identifier)
932
- raise Cli::Error, 'No such identifier' if data.nil?
880
+ raise Cli::Error, 'Unknown identifier' if data.nil?
933
881
  return Main.result_single_object(data)
934
882
  end
935
883
  when :plugins
936
884
  case options.get_next_command(%i[list create])
937
885
  when :list
938
886
  result = []
939
- PluginFactory.instance.plugin_list.each do |name|
940
- plugin_class = PluginFactory.instance.plugin_class(name)
887
+ Plugins::Factory.instance.plugin_list.each do |name|
888
+ plugin_class = Plugins::Factory.instance.plugin_class(name)
941
889
  result.push({
942
890
  plugin: name,
943
891
  detect: Formatter.tick(plugin_class.respond_to?(:detect)),
944
- wizard: Formatter.tick(plugin_class.respond_to?(:wizard)),
945
- path: PluginFactory.instance.plugin_source(name)
892
+ wizard: Formatter.tick(plugin_class.instance_methods.include?(:wizard)),
893
+ path: Plugins::Factory.instance.plugin_source(name)
946
894
  })
947
895
  end
948
896
  return Main.result_object_list(result, fields: %w[plugin detect wizard path])
@@ -951,25 +899,27 @@ module Aspera
951
899
  destination_folder = options.get_next_argument('folder', mandatory: false) || File.join(@main_folder, ASPERA_PLUGINS_FOLDERNAME)
952
900
  plugin_file = File.join(destination_folder, "#{plugin_name}.rb")
953
901
  content = <<~END_OF_PLUGIN_CODE
954
- require 'aspera/cli/plugin'
902
+ require 'aspera/cli/plugins/base'
955
903
  module Aspera
956
904
  module Cli
957
905
  module Plugins
958
- class #{plugin_name.capitalize} < Plugin
906
+ class #{plugin_name.snake_to_capital} < Base
959
907
  ACTIONS=[]
960
- def execute_action; return Main.result_status('You called plugin #{plugin_name}'); end
961
- end # #{plugin_name.capitalize}
962
- end # Plugins
963
- end # Cli
964
- end # Aspera
908
+ def execute_action
909
+ return Main.result_status('You called plugin #{plugin_name}')
910
+ end
911
+ end
912
+ end
913
+ end
914
+ end
965
915
  END_OF_PLUGIN_CODE
966
916
  File.write(plugin_file, content)
967
917
  return Main.result_status("Created #{plugin_file}")
968
918
  end
969
919
  when :detect, :wizard
970
- # interactive mode
920
+ # Interactive mode
971
921
  options.ask_missing_mandatory = true
972
- # detect plugins by url and optional query
922
+ # Detect plugins by url and optional query
973
923
  apps = @wizard.identify_plugins_for_url.freeze
974
924
  return Main.result_object_list(apps) if action.eql?(:detect)
975
925
  return @wizard.find(apps)
@@ -979,6 +929,13 @@ module Aspera
979
929
  return Main.result_image(options.get_next_argument('image URI or blob'))
980
930
  when :ascp
981
931
  execute_action_ascp
932
+ when :sync
933
+ case options.get_next_command(%i[spec])
934
+ when :spec
935
+ fields, data = Transfer::SpecDoc.man_table(Formatter, include_option: true, agent_columns: false, schema: Sync::Operations::CONF_SCHEMA)
936
+ return Main.result_object_list(data, fields: fields.map(&:to_s))
937
+ else Aspera.error_unreachable_line
938
+ end
982
939
  when :transferd
983
940
  execute_action_transferd
984
941
  when :gem
@@ -986,6 +943,7 @@ module Aspera
986
943
  when :path then return Main.result_text(self.class.gem_src_root)
987
944
  when :version then return Main.result_text(Cli::VERSION)
988
945
  when :name then return Main.result_text(Info::GEM_NAME)
946
+ else Aspera.error_unreachable_line
989
947
  end
990
948
  when :folder
991
949
  return Main.result_text(@main_folder)
@@ -997,7 +955,7 @@ module Aspera
997
955
  when :smtp_settings
998
956
  return Main.result_single_object(email_settings)
999
957
  when :proxy_check
1000
- # ensure fpac was provided
958
+ # Ensure fpac was provided
1001
959
  options.get_option(:fpac, mandatory: true)
1002
960
  server_url = options.get_next_argument('server url')
1003
961
  return Main.result_text(@pac_exec.get_proxies(server_url))
@@ -1035,11 +993,11 @@ module Aspera
1035
993
  # @return [Hash] email server setting with defaults if not defined
1036
994
  def email_settings
1037
995
  smtp = options.get_option(:smtp, mandatory: true)
1038
- # change keys from string into symbol
996
+ # Change keys from string into symbol
1039
997
  smtp = smtp.symbolize_keys
1040
998
  unsupported = smtp.keys - SMTP_CONF_PARAMS
1041
999
  raise Cli::Error, "Unsupported SMTP parameter: #{unsupported.join(', ')}, use: #{SMTP_CONF_PARAMS.join(', ')}" unless unsupported.empty?
1042
- # defaults
1000
+ # Defaults
1043
1001
  # smtp[:ssl] = nil (false)
1044
1002
  smtp[:tls] = !smtp[:ssl] unless smtp.key?(:tls)
1045
1003
  smtp[:port] ||= if smtp[:tls]
@@ -1052,7 +1010,7 @@ module Aspera
1052
1010
  smtp[:from_email] ||= smtp[:username] if smtp.key?(:username)
1053
1011
  smtp[:from_name] ||= smtp[:from_email].sub(/@.*$/, '').gsub(/[^a-zA-Z]/, ' ').capitalize if smtp.key?(:username)
1054
1012
  smtp[:domain] ||= smtp[:from_email].sub(/^.*@/, '') if smtp.key?(:from_email)
1055
- # check minimum required
1013
+ # Check minimum required
1056
1014
  %i[server port domain].each do |n|
1057
1015
  Aspera.assert(smtp.key?(n)){"Missing mandatory smtp parameter: #{n}"}
1058
1016
  end
@@ -1060,8 +1018,8 @@ module Aspera
1060
1018
  return smtp
1061
1019
  end
1062
1020
 
1063
- # send email using ERB template
1064
- # @param email_template_default [String] default template, can be overriden by option
1021
+ # Send email using ERB template
1022
+ # @param email_template_default [String] default template, can be overridden by option
1065
1023
  # @param values [Hash] values to be used in template, keys with default: to, from_name, from_email
1066
1024
  def send_email_template(email_template_default: nil, values: {})
1067
1025
  values[:to] ||= options.get_option(:notify_to, mandatory: true)
@@ -1074,14 +1032,14 @@ module Aspera
1074
1032
  end
1075
1033
  start_options = [mail_conf[:domain]]
1076
1034
  start_options.push(mail_conf[:username], mail_conf[:password], :login) if mail_conf.key?(:username) && mail_conf.key?(:password)
1077
- # create a binding with only variables defined in values
1035
+ # Create a binding with only variables defined in values
1078
1036
  template_binding = Environment.empty_binding
1079
- # add variables to binding
1037
+ # Add variables to binding
1080
1038
  values.each do |k, v|
1081
1039
  Aspera.assert_type(k, Symbol)
1082
1040
  template_binding.local_variable_set(k, v)
1083
1041
  end
1084
- # execute template
1042
+ # Execute template
1085
1043
  msg_with_headers = ERB.new(notify_template).result(template_binding)
1086
1044
  Log.dump(:msg_with_headers, msg_with_headers)
1087
1045
  require 'net/smtp'
@@ -1095,7 +1053,7 @@ module Aspera
1095
1053
  end
1096
1054
 
1097
1055
  # Save current configuration to config file
1098
- # return true if file was saved
1056
+ # @return true if file was saved
1099
1057
  def save_config_file_if_needed
1100
1058
  raise Error, 'no configuration loaded' if @config_presets.nil?
1101
1059
  current_checksum = config_checksum
@@ -1109,29 +1067,35 @@ module Aspera
1109
1067
  return true
1110
1068
  end
1111
1069
 
1112
- # returns [String] name if config_presets has default
1113
- # returns nil if there is no config or bypass default params
1070
+ # @return [String] name if config_presets has default
1071
+ # @return nil if there is no config or bypass default params
1114
1072
  def get_plugin_default_config_name(plugin_name_sym)
1115
1073
  Aspera.assert(!@config_presets.nil?){'config_presets shall be defined'}
1116
1074
  if !@use_plugin_defaults
1117
1075
  Log.log.debug('skip default config')
1118
1076
  return
1119
1077
  end
1120
- if @config_presets.key?(CONF_PRESET_DEFAULTS) &&
1121
- @config_presets[CONF_PRESET_DEFAULTS].key?(plugin_name_sym.to_s)
1122
- default_config_name = @config_presets[CONF_PRESET_DEFAULTS][plugin_name_sym.to_s]
1123
- if !@config_presets.key?(default_config_name)
1124
- Log.log.error do
1125
- "Default config name [#{default_config_name}] specified for plugin [#{plugin_name_sym}], but it does not exist in config file.\n" \
1126
- 'Please fix the issue: either create preset with one parameter: ' \
1127
- "(#{Info::CMD_NAME} config id #{default_config_name} init @json:'{}') " \
1128
- "or remove default (#{Info::CMD_NAME} config id default remove #{plugin_name_sym})."
1129
- end
1078
+ if !@config_presets.key?(CONF_PRESET_DEFAULTS)
1079
+ Log.log.debug('No default section')
1080
+ return
1081
+ end
1082
+ Aspera.assert_type(@config_presets[CONF_PRESET_DEFAULTS], Hash){'default section'}
1083
+ if !@config_presets[CONF_PRESET_DEFAULTS].key?(plugin_name_sym.to_s)
1084
+ Log.log.debug("No default for #{plugin_name_sym}")
1085
+ return
1086
+ end
1087
+ default_config_name = @config_presets[CONF_PRESET_DEFAULTS][plugin_name_sym.to_s]
1088
+ if !@config_presets.key?(default_config_name)
1089
+ Log.log.error do
1090
+ "Default config name [#{default_config_name}] specified for plugin [#{plugin_name_sym}], but it does not exist in config file.\n" \
1091
+ "Please fix the issue: either create preset with one parameter:\n" \
1092
+ "#{Info::CMD_NAME} config id #{default_config_name} init @json:'{}'\n" \
1093
+ "or remove default:\n#{Info::CMD_NAME} config id default remove #{plugin_name_sym}"
1130
1094
  end
1131
- raise Cli::Error, "Config name [#{default_config_name}] must be a hash, check config file." if !@config_presets[default_config_name].is_a?(Hash)
1132
- return default_config_name
1095
+ raise Cli::Error, "No such preset: #{default_config_name}"
1133
1096
  end
1134
- return
1097
+ Aspera.assert_type(@config_presets[default_config_name], Hash, type: Cli::Error){'preset type'}
1098
+ return default_config_name
1135
1099
  end
1136
1100
 
1137
1101
  # @return [Hash] result of execution of vault command
@@ -1163,7 +1127,7 @@ module Aspera
1163
1127
  def vault_value(name)
1164
1128
  m = name.split('.')
1165
1129
  raise BadArgument, 'vault name shall match <name>.<param>' unless m.length.eql?(2)
1166
- # this raise exception if label not found:
1130
+ # This raise exception if label not found:
1167
1131
  info = vault.get(label: m[0])
1168
1132
  value = info[m[1].to_sym]
1169
1133
  raise "no such entry value: #{m[1]}" if value.nil?
@@ -1184,12 +1148,12 @@ module Aspera
1184
1148
  )
1185
1149
  end
1186
1150
 
1187
- # Artifically raise an exception for tests
1151
+ # Artificially raise an exception for tests
1188
1152
  def execute_test
1189
1153
  case options.get_next_command(%i[throw web])
1190
1154
  when :throw
1191
1155
  # :type [String]
1192
- # options
1156
+ # Options
1193
1157
  exception_class_name = options.get_next_argument('exception class name', mandatory: true)
1194
1158
  exception_text = options.get_next_argument('exception text', mandatory: true)
1195
1159
  type = Object.const_get(exception_class_name)
@@ -1199,7 +1163,7 @@ module Aspera
1199
1163
  end
1200
1164
  end
1201
1165
 
1202
- # version of URL without trailing "/" and removing default port
1166
+ # Version of URL without trailing "/" and removing default port
1203
1167
  def canonical_url(url)
1204
1168
  url.chomp('/').sub(%r{^(https://[^/]+):443$}, '\1')
1205
1169
  end
@@ -1207,7 +1171,7 @@ module Aspera
1207
1171
  # Look for a preset that has the corresponding URL and username
1208
1172
  # @return the first one matching
1209
1173
  def lookup_preset(url:, username:)
1210
- # remove extra info to maximize match
1174
+ # Remove extra info to maximize match
1211
1175
  url = canonical_url(url)
1212
1176
  Log.log.debug{"Lookup preset for #{username}@#{url}"}
1213
1177
  @config_presets.each_value do |v|
@@ -1232,6 +1196,71 @@ module Aspera
1232
1196
  end
1233
1197
  return secret
1234
1198
  end
1199
+ # Private
1200
+ # Folder in $HOME for application files (config, cache)
1201
+ ASPERA_HOME_FOLDER_NAME = '.aspera'
1202
+ # Default config file
1203
+ DEFAULT_CONFIG_FILENAME = 'config.yaml'
1204
+ # Reserved preset names
1205
+ CONF_PRESET_CONFIG = 'config'
1206
+ CONF_PRESET_VERSION = 'version'
1207
+ CONF_PRESET_DEFAULTS = 'default'
1208
+ CONF_PRESET_GLOBAL = 'global_common_defaults'
1209
+ # Special name to identify value of default
1210
+ GLOBAL_DEFAULT_KEYWORD = 'GLOBAL'
1211
+ CONF_GLOBAL_SYM = :config
1212
+ # Folder containing custom plugins in user's config folder
1213
+ ASPERA_PLUGINS_FOLDERNAME = 'plugins'
1214
+ PERSISTENCY_FOLDER = 'persist_store'
1215
+ ASPERA = 'aspera'
1216
+ SERVER_COMMAND = 'server'
1217
+ TRANSFERD_APP_NAME = 'sdk'
1218
+ DEMO_SERVER = 'demo'
1219
+ DEMO_PRESET = 'demoserver' # cspell: disable-line
1220
+ EMAIL_TEST_TEMPLATE = <<~END_OF_TEMPLATE
1221
+ From: <%=from_name%> <<%=from_email%>>
1222
+ To: <<%=to%>>
1223
+ Subject: #{Info::GEM_NAME} email test
1224
+
1225
+ This email was sent to test #{Info::CMD_NAME}.
1226
+ END_OF_TEMPLATE
1227
+ # Special extended values
1228
+ EXTEND_PRESET = :preset
1229
+ EXTEND_VAULT = :vault
1230
+ PRESET_DIG_SEPARATOR = '.'
1231
+ DEFAULT_CHECK_NEW_VERSION_DAYS = 7
1232
+ COFFEE_IMAGE_URL = 'https://enjoyjava.com/wp-content/uploads/2018/01/How-to-make-strong-coffee.jpg'
1233
+ GEM_CHECK_DATE_FMT = '%Y/%m/%d'
1234
+ # For testing only
1235
+ SELF_SIGNED_CERT = OpenSSL::SSL.const_get(:enon_yfirev.to_s.upcase.reverse) # cspell: disable-line
1236
+ CONF_OVERVIEW_KEYS = %w[preset parameter value].freeze
1237
+ SMTP_CONF_PARAMS = %i[server tls ssl port domain username password from_name from_email].freeze
1238
+
1239
+ private_constant :ASPERA_HOME_FOLDER_NAME,
1240
+ :DEFAULT_CONFIG_FILENAME,
1241
+ :CONF_PRESET_CONFIG,
1242
+ :CONF_PRESET_VERSION,
1243
+ :CONF_PRESET_DEFAULTS,
1244
+ :CONF_PRESET_GLOBAL,
1245
+ :ASPERA_PLUGINS_FOLDERNAME,
1246
+ :ASPERA,
1247
+ :DEMO_SERVER,
1248
+ :DEMO_PRESET,
1249
+ :EMAIL_TEST_TEMPLATE,
1250
+ :EXTEND_PRESET,
1251
+ :EXTEND_VAULT,
1252
+ :DEFAULT_CHECK_NEW_VERSION_DAYS,
1253
+ :SERVER_COMMAND,
1254
+ :PRESET_DIG_SEPARATOR,
1255
+ :COFFEE_IMAGE_URL,
1256
+ :SELF_SIGNED_CERT,
1257
+ :PERSISTENCY_FOLDER,
1258
+ :CONF_OVERVIEW_KEYS,
1259
+ :SMTP_CONF_PARAMS,
1260
+ :TRANSFERD_APP_NAME,
1261
+ :GLOBAL_DEFAULT_KEYWORD,
1262
+ :CONF_GLOBAL_SYM,
1263
+ :GEM_CHECK_DATE_FMT
1235
1264
  end
1236
1265
  end
1237
1266
  end