aspera-cli 4.14.0 → 4.16.0

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 (104) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/BUGS.md +29 -3
  4. data/CHANGELOG.md +300 -185
  5. data/CONTRIBUTING.md +74 -23
  6. data/README.md +2346 -1619
  7. data/bin/ascli +16 -25
  8. data/bin/asession +15 -15
  9. data/examples/dascli +2 -2
  10. data/examples/proxy.pac +1 -1
  11. data/lib/aspera/aoc.rb +216 -150
  12. data/lib/aspera/ascmd.rb +25 -18
  13. data/lib/aspera/assert.rb +45 -0
  14. data/lib/aspera/cli/basic_auth_plugin.rb +9 -6
  15. data/lib/aspera/cli/error.rb +17 -0
  16. data/lib/aspera/cli/extended_value.rb +51 -16
  17. data/lib/aspera/cli/formatter.rb +276 -174
  18. data/lib/aspera/cli/hints.rb +81 -0
  19. data/lib/aspera/cli/main.rb +114 -147
  20. data/lib/aspera/cli/manager.rb +181 -136
  21. data/lib/aspera/cli/plugin.rb +82 -64
  22. data/lib/aspera/cli/plugins/alee.rb +0 -1
  23. data/lib/aspera/cli/plugins/aoc.rb +327 -331
  24. data/lib/aspera/cli/plugins/ats.rb +12 -8
  25. data/lib/aspera/cli/plugins/bss.rb +2 -2
  26. data/lib/aspera/cli/plugins/config.rb +575 -439
  27. data/lib/aspera/cli/plugins/console.rb +40 -0
  28. data/lib/aspera/cli/plugins/cos.rb +4 -5
  29. data/lib/aspera/cli/plugins/faspex.rb +111 -92
  30. data/lib/aspera/cli/plugins/faspex5.rb +245 -182
  31. data/lib/aspera/cli/plugins/node.rb +239 -160
  32. data/lib/aspera/cli/plugins/orchestrator.rb +56 -19
  33. data/lib/aspera/cli/plugins/preview.rb +54 -38
  34. data/lib/aspera/cli/plugins/server.rb +63 -20
  35. data/lib/aspera/cli/plugins/shares.rb +64 -38
  36. data/lib/aspera/cli/sync_actions.rb +68 -0
  37. data/lib/aspera/cli/transfer_agent.rb +64 -67
  38. data/lib/aspera/cli/transfer_progress.rb +73 -0
  39. data/lib/aspera/cli/version.rb +1 -1
  40. data/lib/aspera/colors.rb +3 -1
  41. data/lib/aspera/command_line_builder.rb +27 -22
  42. data/lib/aspera/cos_node.rb +6 -4
  43. data/lib/aspera/coverage.rb +22 -0
  44. data/lib/aspera/data_repository.rb +33 -2
  45. data/lib/aspera/environment.rb +21 -8
  46. data/lib/aspera/fasp/agent_alpha.rb +116 -0
  47. data/lib/aspera/fasp/agent_base.rb +40 -76
  48. data/lib/aspera/fasp/agent_connect.rb +21 -22
  49. data/lib/aspera/fasp/agent_direct.rb +169 -179
  50. data/lib/aspera/fasp/agent_httpgw.rb +200 -195
  51. data/lib/aspera/fasp/agent_node.rb +43 -35
  52. data/lib/aspera/fasp/agent_trsdk.rb +124 -41
  53. data/lib/aspera/fasp/error_info.rb +2 -2
  54. data/lib/aspera/fasp/faux_file.rb +52 -0
  55. data/lib/aspera/fasp/installation.rb +89 -191
  56. data/lib/aspera/fasp/management.rb +249 -0
  57. data/lib/aspera/fasp/parameters.rb +86 -47
  58. data/lib/aspera/fasp/parameters.yaml +75 -8
  59. data/lib/aspera/fasp/products.rb +162 -0
  60. data/lib/aspera/fasp/resume_policy.rb +7 -5
  61. data/lib/aspera/fasp/sync.rb +273 -0
  62. data/lib/aspera/fasp/transfer_spec.rb +10 -8
  63. data/lib/aspera/fasp/uri.rb +6 -6
  64. data/lib/aspera/faspex_gw.rb +11 -8
  65. data/lib/aspera/faspex_postproc.rb +8 -7
  66. data/lib/aspera/hash_ext.rb +2 -2
  67. data/lib/aspera/id_generator.rb +3 -1
  68. data/lib/aspera/json_rpc.rb +51 -0
  69. data/lib/aspera/keychain/encrypted_hash.rb +46 -11
  70. data/lib/aspera/keychain/macos_security.rb +15 -13
  71. data/lib/aspera/line_logger.rb +23 -0
  72. data/lib/aspera/log.rb +61 -19
  73. data/lib/aspera/nagios.rb +7 -2
  74. data/lib/aspera/node.rb +105 -21
  75. data/lib/aspera/node_simulator.rb +214 -0
  76. data/lib/aspera/oauth.rb +57 -36
  77. data/lib/aspera/open_application.rb +4 -4
  78. data/lib/aspera/persistency_action_once.rb +13 -14
  79. data/lib/aspera/persistency_folder.rb +5 -4
  80. data/lib/aspera/preview/file_types.rb +56 -268
  81. data/lib/aspera/preview/generator.rb +28 -39
  82. data/lib/aspera/preview/options.rb +2 -0
  83. data/lib/aspera/preview/terminal.rb +36 -16
  84. data/lib/aspera/preview/utils.rb +23 -29
  85. data/lib/aspera/proxy_auto_config.rb +6 -3
  86. data/lib/aspera/rest.rb +127 -80
  87. data/lib/aspera/rest_call_error.rb +1 -1
  88. data/lib/aspera/rest_error_analyzer.rb +16 -14
  89. data/lib/aspera/rest_errors_aspera.rb +39 -34
  90. data/lib/aspera/secret_hider.rb +18 -17
  91. data/lib/aspera/ssh.rb +10 -5
  92. data/lib/aspera/temp_file_manager.rb +11 -4
  93. data/lib/aspera/web_auth.rb +10 -7
  94. data/lib/aspera/web_server_simple.rb +11 -5
  95. data.tar.gz.sig +0 -0
  96. metadata +108 -39
  97. metadata.gz.sig +0 -0
  98. data/lib/aspera/cli/listener/line_dump.rb +0 -19
  99. data/lib/aspera/cli/listener/logger.rb +0 -22
  100. data/lib/aspera/cli/listener/progress.rb +0 -50
  101. data/lib/aspera/cli/listener/progress_multi.rb +0 -84
  102. data/lib/aspera/cli/plugins/sync.rb +0 -44
  103. data/lib/aspera/fasp/listener.rb +0 -13
  104. data/lib/aspera/sync.rb +0 -213
@@ -7,32 +7,19 @@ require 'aspera/cli/extended_value'
7
7
  require 'aspera/cli/transfer_agent'
8
8
  require 'aspera/cli/version'
9
9
  require 'aspera/cli/info'
10
- require 'aspera/fasp/error'
11
- require 'aspera/open_application'
12
- require 'aspera/temp_file_manager'
13
- require 'aspera/persistency_folder'
14
- require 'aspera/log'
15
- require 'aspera/rest'
16
- require 'aspera/nagios'
17
- require 'aspera/colors'
10
+ require 'aspera/cli/hints'
11
+ require 'aspera/preview/terminal'
18
12
  require 'aspera/secret_hider'
19
- require 'net/ssh'
13
+ require 'aspera/log'
14
+ require 'aspera/assert'
20
15
 
21
16
  module Aspera
22
17
  module Cli
23
18
  # The main CLI class
24
19
  class Main
25
- # prefix to display error messages in user messages (terminal)
26
- ERROR_FLASH = 'ERROR:'.bg_red.gray.blink.freeze
27
- WARNING_FLASH = 'WARNING:'.bg_red.gray.blink.freeze
28
- private_constant :ERROR_FLASH, :WARNING_FLASH
29
-
30
- # store transfer result using this key and use result_transfer_multiple
20
+ # Plugins store transfer result using this key and use result_transfer_multiple()
31
21
  STATUS_FIELD = 'status'
32
22
 
33
- # for testing only
34
- SELF_SIGNED_CERT = OpenSSL::SSL.const_get(:enon_yfirev.to_s.upcase.reverse) # cspell: disable-line
35
-
36
23
  class << self
37
24
  # expect some list, but nothing to display
38
25
  def result_empty; return {type: :empty, data: :nil}; end
@@ -68,85 +55,64 @@ module Aspera
68
55
  raise global_status unless global_status.eql?(:success)
69
56
  return {type: :object_list, data: status_table}
70
57
  end
71
- end
58
+
59
+ def result_picture_in_terminal(options, blob)
60
+ terminal_options = options.get_option(:query, default: {}).symbolize_keys
61
+ allowed_options = Preview::Terminal.method(:build).parameters.select{|i|i[0].eql?(:key)}.map{|i|i[1]}
62
+ unknown_options = terminal_options.keys - allowed_options
63
+ raise "invalid options: #{unknown_options.join(', ')}, use #{allowed_options.join(', ')}" unless unknown_options.empty?
64
+ return Main.result_status(Preview::Terminal.build(blob, **terminal_options))
65
+ end
66
+ end # self
72
67
 
73
68
  private
74
69
 
70
+ # shortcuts helpers like in plugins
71
+ %i[options transfer config formatter persistency].each do |name|
72
+ define_method(name){@agents[name]}
73
+ end
74
+
75
75
  # =============================================================
76
76
  # Parameter handlers
77
77
  #
78
- attr_accessor :option_insecure, :option_http_options, :option_cache_tokens
79
-
80
- def option_ui; OpenApplication.instance.url_method; end
81
-
82
- def option_ui=(value); OpenApplication.instance.url_method = value; end
83
-
84
- # called every time a new REST HTTP session is opened
85
- # @param http [Net::HTTP] the newly created http session object
86
- def http_parameters=(http)
87
- if @option_insecure
88
- url = http.inspect.gsub(/^[^ ]* /, 'https://').gsub(/ [^ ]*$/, '')
89
- if !@ssl_warned_urls.include?(url)
90
- @formatter.display_message(:error, "#{WARNING_FLASH} ignoring certificate for: #{url}. Do not deactivate certificate verification in production.")
91
- @ssl_warned_urls.push(url)
92
- end
93
- http.verify_mode = SELF_SIGNED_CERT
94
- end
95
- http.set_debug_output($stdout) if @option_rest_debug
96
- raise 'http_options expects Hash' unless @option_http_options.is_a?(Hash)
97
-
98
- @option_http_options.each do |k, v|
99
- method = "#{k}=".to_sym
100
- # check if accessor is a method of Net::HTTP
101
- # continue_timeout= read_timeout= write_timeout=
102
- if http.respond_to?(method)
103
- http.send(method, v)
104
- else
105
- Log.log.error{"no such attribute: #{k}"}
106
- end
107
- end
108
- end
109
78
 
110
- # minimum initialization
79
+ # minimum initialization, no exception raised
111
80
  def initialize(argv)
112
- # first thing : manage debug level (allows debugging of option parser)
113
- early_debug_setup(argv)
114
- # compare $0 with expected name
115
- current_prog_name = File.basename($PROGRAM_NAME)
116
- @formatter.display_message(:error, "#{'WARNING'.bg_red.blink.gray} Please use '#{PROGRAM_NAME}' instead of '#{current_prog_name}'") \
117
- unless current_prog_name.eql?(PROGRAM_NAME)
81
+ @argv = argv
82
+ # environment provided to plugin for various capabilities
83
+ @agents = {}
118
84
  @option_help = false
119
- @bash_completion = false
120
85
  @option_show_config = false
121
- @option_insecure = false
122
- @option_rest_debug = false
123
- @option_cache_tokens = true
124
- @option_http_options = {}
125
- @ssl_warned_urls = []
126
- # environment provided to plugin for various capabilities
127
- @plugin_env = {}
86
+ @bash_completion = false
87
+ end
88
+
89
+ # This can throw exception if there is a problem with the environment, needs to be caught by execute method
90
+ def init_agents_and_options
91
+ # create formatter, in case there is an exception, it is used to display.
92
+ @agents[:formatter] = Formatter.new
93
+ # second : manage debug level (allows debugging of option parser)
94
+ early_debug_setup
95
+ @agents[:options] = Manager.new(PROGRAM_NAME)
128
96
  # give command line arguments to option manager
129
- @plugin_env[:options] = @opt_mgr = Manager.new(PROGRAM_NAME, argv: argv)
97
+ options.parse_command_line(@argv)
130
98
  # formatter adds options
131
- @formatter = @plugin_env[:formatter] = Formatter.new(@plugin_env[:options])
132
- Rest.user_agent = PROGRAM_NAME
133
- Rest.session_cb = lambda{|http|self.http_parameters = http}
99
+ formatter.declare_options(options)
100
+ # compare $0 with expected name
101
+ current_prog_name = File.basename($PROGRAM_NAME)
102
+ formatter.display_message(
103
+ :error,
104
+ "#{Formatter::WARNING_FLASH} Please use '#{PROGRAM_NAME}' instead of '#{current_prog_name}'") unless current_prog_name.eql?(PROGRAM_NAME)
134
105
  # declare and parse global options
135
- init_global_options
106
+ declare_global_options
136
107
  # the Config plugin adds the @preset parser, so declare before TransferAgent which may use it
137
- @plugin_env[:config] = Plugins::Config.new(@plugin_env, gem: GEM_NAME, name: PROGRAM_NAME, help: DOC_URL, version: Aspera::Cli::VERSION)
138
- # the TransferAgent plugin may use the @preset parser
139
- @plugin_env[:transfer] = TransferAgent.new(@plugin_env[:options], @plugin_env[:config])
108
+ @agents[:config] = Plugins::Config.new(@agents, gem: GEM_NAME, name: PROGRAM_NAME, help: DOC_URL, version: Aspera::Cli::VERSION)
140
109
  # data persistency
141
- @plugin_env[:persistency] = PersistencyFolder.new(File.join(@plugin_env[:config].main_folder, 'persist_store'))
110
+ assert(@agents[:persistency]){'missing persistency object'}
111
+ # the TransferAgent plugin may use the @preset parser
112
+ @agents[:transfer] = TransferAgent.new(options, config)
142
113
  Log.log.debug('plugin env created'.red)
143
- Oauth.persist_mgr = @plugin_env[:persistency] if @option_cache_tokens
144
- Fasp::Parameters.file_list_folder = File.join(@plugin_env[:config].main_folder, 'filelists')
145
- Aspera::RestErrorAnalyzer.instance.log_file = File.join(@plugin_env[:config].main_folder, 'rest_exceptions.log')
146
- # register aspera REST call error handlers
147
- Aspera::RestErrorsAspera.register_handlers
148
114
  # set banner when all environment is created so that additional extended value modifiers are known, e.g. @preset
149
- @opt_mgr.parser.banner = app_banner
115
+ options.parser.banner = app_banner
150
116
  end
151
117
 
152
118
  def app_banner
@@ -166,7 +132,6 @@ module Aspera
166
132
  #{t}source repo: #{SRC_URL}
167
133
 
168
134
  ENVIRONMENT VARIABLES
169
- #{t}#{@plugin_env[:config].conf_dir_env_var} config folder, default: $HOME/#{Plugins::Config::ASPERA_HOME_FOLDER_NAME}/#{PROGRAM_NAME}
170
135
  #{t}Any option can be set as an environment variable, refer to the manual
171
136
 
172
137
  COMMANDS
@@ -185,38 +150,36 @@ module Aspera
185
150
  end
186
151
 
187
152
  # define header for manual
188
- def init_global_options
189
- Log.log.debug('init_global_options')
190
- @opt_mgr.declare(:help, 'Show this message', values: :none, short: 'h') { @option_help = true }
191
- @opt_mgr.declare(:bash_comp, 'Generate bash completion for command', values: :none) { @bash_completion = true }
192
- @opt_mgr.declare(:show_config, 'Display parameters used for the provided action', values: :none) { @option_show_config = true }
193
- @opt_mgr.declare(:rest_debug, 'More debug for HTTP calls (REST)', values: :none, short: 'r') { @option_rest_debug = true }
194
- @opt_mgr.declare(:version, 'Display version', values: :none, short: 'v') { @formatter.display_message(:data, Aspera::Cli::VERSION); Process.exit(0) } # rubocop:disable Style/Semicolon, Layout/LineLength
195
- @opt_mgr.declare(:warnings, 'Check for language warnings', values: :none, short: 'w') { $VERBOSE = true }
196
- @opt_mgr.declare(
153
+ def declare_global_options
154
+ Log.log.debug('declare_global_options')
155
+ options.declare(:help, 'Show this message', values: :none, short: 'h') { @option_help = true }
156
+ options.declare(:bash_comp, 'Generate bash completion for command', values: :none) { @bash_completion = true }
157
+ options.declare(:show_config, 'Display parameters used for the provided action', values: :none) { @option_show_config = true }
158
+ options.declare(:version, 'Display version', values: :none, short: 'v') { formatter.display_message(:data, Aspera::Cli::VERSION); Process.exit(0) } # rubocop:disable Style/Semicolon, Layout/LineLength
159
+ options.declare(:warnings, 'Check for language warnings', values: :none, short: 'w') { $VERBOSE = true }
160
+ options.declare(
197
161
  :ui, 'Method to start browser',
198
162
  values: OpenApplication.user_interfaces,
199
- handler: {o: self, m: :option_ui},
163
+ handler: {o: OpenApplication.instance, m: :url_method},
200
164
  default: OpenApplication.default_gui_mode)
201
- @opt_mgr.declare(:log_level, 'Log level', values: Log.levels, handler: {o: Log.instance, m: :level})
202
- @opt_mgr.declare(:logger, 'Logging method', values: Log::LOG_TYPES, handler: {o: Log.instance, m: :logger_type})
203
- @opt_mgr.declare(:lock_port, 'Prevent dual execution of a command, e.g. in cron')
204
- @opt_mgr.declare(:http_options, 'Options for http socket', types: Hash, handler: {o: self, m: :option_http_options})
205
- @opt_mgr.declare(:insecure, 'Do not validate HTTPS certificate', values: :bool, handler: {o: self, m: :option_insecure}, default: :no)
206
- @opt_mgr.declare(:once_only, 'Process only new items (some commands)', values: :bool, default: false)
207
- @opt_mgr.declare(:log_secrets, 'Show passwords in logs', values: :bool, handler: {o: SecretHider, m: :log_secrets})
208
- @opt_mgr.declare(:cache_tokens, 'Save and reuse Oauth tokens', values: :bool, handler: {o: self, m: :option_cache_tokens})
165
+ options.declare(:log_level, 'Log level', values: Log.levels, handler: {o: Log.instance, m: :level})
166
+ options.declare(:logger, 'Logging method', values: Log::LOG_TYPES, handler: {o: Log.instance, m: :logger_type})
167
+ options.declare(:lock_port, 'Prevent dual execution of a command, e.g. in cron', coerce: Integer, types: Integer)
168
+ options.declare(:once_only, 'Process only new items (some commands)', values: :bool, default: false)
169
+ options.declare(:log_secrets, 'Show passwords in logs', values: :bool, handler: {o: SecretHider, m: :log_secrets})
170
+ options.declare(:clean_temp, 'Cleanup temporary files on exit', values: :bool, handler: {o: TempFileManager.instance, m: :cleanup_on_exit})
171
+ options.declare(:pid_file, 'Write process identifier to file, delete on exit', types: String)
209
172
  # parse declared options
210
- @opt_mgr.parse_options!
173
+ options.parse_options!
211
174
  end
212
175
 
213
176
  # @return the plugin instance, based on name
214
177
  # also loads the plugin options, and default values from conf file
215
178
  # @param plugin_name_sym : symbol for plugin name
216
179
  def get_plugin_instance_with_options(plugin_name_sym, env=nil)
217
- env ||= @plugin_env
180
+ env ||= @agents
218
181
  Log.log.debug{"get_plugin_instance_with_options(#{plugin_name_sym})"}
219
- require @plugin_env[:config].plugins[plugin_name_sym][:require_stanza]
182
+ require config.plugins[plugin_name_sym][:require_stanza]
220
183
  # load default params only if no param already loaded before plugin instantiation
221
184
  env[:config].add_plugin_default_preset(plugin_name_sym)
222
185
  command_plugin = Plugins::Config.plugin_class(plugin_name_sym).new(env)
@@ -226,8 +189,8 @@ module Aspera
226
189
  end
227
190
 
228
191
  def generate_bash_completion
229
- if @opt_mgr.get_next_argument('', expected: :multiple, mandatory: false).nil?
230
- @plugin_env[:config].plugins.each_key{|p|puts p.to_s}
192
+ if options.get_next_argument('', expected: :multiple, mandatory: false).nil?
193
+ config.plugins.each_key{|p|puts p.to_s}
231
194
  else
232
195
  Log.log.warn('only first level completion so far')
233
196
  end
@@ -237,19 +200,19 @@ module Aspera
237
200
  def exit_with_usage(all_plugins)
238
201
  Log.log.debug('exit_with_usage'.bg_red)
239
202
  # display main plugin options
240
- @formatter.display_message(:error, @opt_mgr.parser)
203
+ formatter.display_message(:error, options.parser)
241
204
  if all_plugins
242
205
  # list plugins that have a "require" field, i.e. all but main plugin
243
- @plugin_env[:config].plugins.each_key do |plugin_name_sym|
206
+ config.plugins.each_key do |plugin_name_sym|
244
207
  next if plugin_name_sym.eql?(Plugins::Config::CONF_PLUGIN_SYM)
245
208
  # override main option parser with a brand new, to avoid having global options
246
- plugin_env = @plugin_env.clone
247
- plugin_env[:man_only] = true
209
+ plugin_env = @agents.clone
210
+ plugin_env[:all_manuals] = true # force declaration of all options
248
211
  plugin_env[:options] = Manager.new(PROGRAM_NAME)
249
212
  plugin_env[:options].parser.banner = '' # remove default banner
250
213
  get_plugin_instance_with_options(plugin_name_sym, plugin_env)
251
214
  # display generated help for plugin options
252
- @formatter.display_message(:error, plugin_env[:options].parser.help)
215
+ formatter.display_message(:error, plugin_env[:options].parser.help)
253
216
  end
254
217
  end
255
218
  Process.exit(0)
@@ -259,14 +222,16 @@ module Aspera
259
222
 
260
223
  # early debug for parser
261
224
  # Note: does not accept shortcuts
262
- def early_debug_setup(argv)
225
+ def early_debug_setup
263
226
  Aspera::Log.instance.program_name = PROGRAM_NAME
264
- argv.each do |arg|
227
+ @argv.each do |arg|
265
228
  case arg
266
229
  when '--' then break
267
230
  when /^--log-level=(.*)/ then Aspera::Log.instance.level = Regexp.last_match(1).to_sym
268
231
  when /^--logger=(.*)/ then Aspera::Log.instance.logger_type = Regexp.last_match(1).to_sym
269
232
  end
233
+ rescue => e
234
+ $stderr.puts("Error: #{e}")
270
235
  end
271
236
  end
272
237
 
@@ -274,69 +239,78 @@ module Aspera
274
239
 
275
240
  # this is the main function called by initial script just after constructor
276
241
  def process_command_line
277
- Log.log.debug('process_command_line')
278
242
  # catch exception information , if any
279
243
  exception_info = nil
280
- # false if command shall not be executed ("once_only")
244
+ # false if command shall not be executed (e.g. --show-config)
281
245
  execute_command = true
246
+ # catch exceptions
282
247
  begin
248
+ init_agents_and_options
283
249
  # find plugins, shall be after parse! ?
284
- @plugin_env[:config].add_plugins_from_lookup_folders
250
+ config.add_plugins_from_lookup_folders
285
251
  # help requested without command ? (plugins must be known here)
286
- exit_with_usage(true) if @option_help && @opt_mgr.command_or_arg_empty?
252
+ exit_with_usage(true) if @option_help && options.command_or_arg_empty?
287
253
  generate_bash_completion if @bash_completion
288
- @plugin_env[:config].periodic_check_newer_gem_version
254
+ config.periodic_check_newer_gem_version
289
255
  command_sym =
290
- if @option_show_config && @opt_mgr.command_or_arg_empty?
256
+ if @option_show_config && options.command_or_arg_empty?
291
257
  Plugins::Config::CONF_PLUGIN_SYM
292
258
  else
293
- @opt_mgr.get_next_command(@plugin_env[:config].plugins.keys.dup.unshift(:help))
259
+ options.get_next_command(config.plugins.keys.dup.unshift(:help))
294
260
  end
295
261
  # command will not be executed, but we need manual
296
- @opt_mgr.fail_on_missing_mandatory = false if @option_help || @option_show_config
262
+ options.fail_on_missing_mandatory = false if @option_help || @option_show_config
297
263
  # main plugin is not dynamically instantiated
298
264
  case command_sym
299
265
  when :help
300
266
  exit_with_usage(true)
301
267
  when Plugins::Config::CONF_PLUGIN_SYM
302
- command_plugin = @plugin_env[:config]
268
+ command_plugin = config
303
269
  else
304
270
  # get plugin, set options, etc
305
271
  command_plugin = get_plugin_instance_with_options(command_sym)
306
272
  # parse plugin specific options
307
- @opt_mgr.parse_options!
273
+ options.parse_options!
308
274
  end
309
275
  # help requested for current plugin
310
276
  exit_with_usage(false) if @option_help
311
277
  if @option_show_config
312
- @formatter.display_results({type: :single_object, data: @opt_mgr.declared_options(only_defined: true)})
278
+ formatter.display_results({type: :single_object, data: options.known_options(only_defined: true).stringify_keys})
313
279
  execute_command = false
314
280
  end
315
281
  # locking for single execution (only after "per plugin" option, in case lock port is there)
316
- lock_port = @opt_mgr.get_option(:lock_port)
282
+ lock_port = options.get_option(:lock_port)
317
283
  if !lock_port.nil?
318
284
  begin
319
285
  # no need to close later, will be freed on process exit. must save in member else it is garbage collected
320
- Log.log.debug{"Opening lock port #{lock_port.to_i}"}
321
- @tcp_server = TCPServer.new('127.0.0.1', lock_port.to_i)
286
+ Log.log.debug{"Opening lock port #{lock_port}"}
287
+ @tcp_server = TCPServer.new('127.0.0.1', lock_port)
322
288
  rescue StandardError => e
323
289
  execute_command = false
324
290
  Log.log.warn{"Another instance is already running (#{e.message})."}
325
291
  end
326
292
  end
293
+ pid_file = options.get_option(:pid_file)
294
+ if !pid_file.nil?
295
+ File.write(pid_file, Process.pid)
296
+ Log.log.debug{"Wrote pid #{Process.pid} to #{pid_file}"}
297
+ at_exit{File.delete(pid_file)}
298
+ end
327
299
  # execute and display (if not exclusive execution)
328
- @formatter.display_results(command_plugin.execute_action) if execute_command
300
+ formatter.display_results(command_plugin.execute_action) if execute_command
301
+ # save config file if command modified it
302
+ config.save_config_file_if_needed
329
303
  # finish
330
- @plugin_env[:transfer].shutdown
304
+ transfer.shutdown
331
305
  rescue Net::SSH::AuthenticationFailed => e; exception_info = {e: e, t: 'SSH', security: true}
332
306
  rescue OpenSSL::SSL::SSLError => e; exception_info = {e: e, t: 'SSL'}
333
- rescue CliBadArgument => e; exception_info = {e: e, t: 'Argument', usage: true}
334
- rescue CliNoSuchId => e; exception_info = {e: e, t: 'Identifier'}
335
- rescue CliError => e; exception_info = {e: e, t: 'Tool', usage: true}
336
- rescue Fasp::Error => e; exception_info = {e: e, t: 'FASP(ascp)'}
307
+ rescue Cli::BadArgument => e; exception_info = {e: e, t: 'Argument', usage: true}
308
+ rescue Cli::NoSuchIdentifier => e; exception_info = {e: e, t: 'Identifier'}
309
+ rescue Cli::Error => e; exception_info = {e: e, t: 'Tool', usage: true}
310
+ rescue Fasp::Error => e; exception_info = {e: e, t: 'Transfer'}
337
311
  rescue Aspera::RestCallError => e; exception_info = {e: e, t: 'Rest'}
338
312
  rescue SocketError => e; exception_info = {e: e, t: 'Network'}
339
- rescue StandardError => e; exception_info = {e: e, t: 'Other', debug: true}
313
+ rescue StandardError => e; exception_info = {e: e, t: "Other(#{e.class.name})", debug: true}
340
314
  rescue Interrupt => e; exception_info = {e: e, t: 'Interruption', debug: true}
341
315
  end
342
316
  # cleanup file list files
@@ -344,22 +318,15 @@ module Aspera
344
318
  # 1- processing of error condition
345
319
  unless exception_info.nil?
346
320
  Log.log.warn(exception_info[:e].message) if Aspera::Log.instance.logger_type.eql?(:syslog) && exception_info[:security]
347
- @formatter.display_message(:error, "#{ERROR_FLASH} #{exception_info[:t]}: #{exception_info[:e].message}")
348
- @formatter.display_message(:error, 'Use option -h to get help.') if exception_info[:usage]
349
- # Provide hint on FASP errors
350
- if exception_info[:e].is_a?(Fasp::Error) && exception_info[:e].message.eql?('Remote host is not who we expected')
351
- @formatter.display_message(:error, "For this specific error, refer to:\n"\
352
- "#{SRC_URL}#error-remote-host-is-not-who-we-expected\nAdd this to arguments:\n--ts=@json:'{\"sshfp\":null}'")
353
- end
354
- # Provide hint on SSL errors
355
- if exception_info[:e].is_a?(OpenSSL::SSL::SSLError) && ['does not match the server certificate'].any?{|m|exception_info[:e].message.include?(m)}
356
- @formatter.display_message(:error, "You can ignore SSL errors with option:\n--insecure=yes")
357
- end
321
+ formatter.display_message(:error, "#{Formatter::ERROR_FLASH} #{exception_info[:t]}: #{exception_info[:e].message}")
322
+ formatter.display_message(:error, 'Use option -h to get help.') if exception_info[:usage]
323
+ # Is that a known error condition with proposal for remediation ?
324
+ Hints.hint_for(exception_info[:e], formatter)
358
325
  end
359
326
  # 2- processing of command not processed (due to exception or bad command line)
360
327
  if execute_command || @option_show_config
361
- @opt_mgr.final_errors.each do |msg|
362
- @formatter.display_message(:error, "#{ERROR_FLASH} Argument: #{msg}")
328
+ options.final_errors.each do |msg|
329
+ formatter.display_message(:error, "#{Formatter::ERROR_FLASH} Argument: #{msg}")
363
330
  # add code as exception if there is not already an error
364
331
  exception_info = {e: Exception.new(msg), t: 'UnusedArg'} if exception_info.nil?
365
332
  end
@@ -367,9 +334,9 @@ module Aspera
367
334
  # 3- in case of error, fail the process status
368
335
  unless exception_info.nil?
369
336
  # show stack trace in debug mode
370
- raise exception_info[:e] if Log.instance.level.eql?(:debug)
337
+ raise exception_info[:e] if Log.log.debug?
371
338
  # else give hint and exit
372
- @formatter.display_message(:error, 'Use --log-level=debug to get more details.') if exception_info[:debug]
339
+ formatter.display_message(:error, 'Use --log-level=debug to get more details.') if exception_info[:debug]
373
340
  Process.exit(1)
374
341
  end
375
342
  return nil