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