aspera-cli 4.13.0 → 4.15.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +81 -7
  4. data/CONTRIBUTING.md +22 -6
  5. data/README.md +2038 -1080
  6. data/bin/ascli +18 -9
  7. data/bin/asession +12 -14
  8. data/examples/dascli +1 -1
  9. data/examples/proxy.pac +1 -1
  10. data/examples/rubyc +24 -0
  11. data/lib/aspera/aoc.rb +219 -159
  12. data/lib/aspera/ascmd.rb +25 -14
  13. data/lib/aspera/cli/basic_auth_plugin.rb +12 -9
  14. data/lib/aspera/cli/error.rb +17 -0
  15. data/lib/aspera/cli/extended_value.rb +47 -12
  16. data/lib/aspera/cli/formatter.rb +260 -179
  17. data/lib/aspera/cli/hints.rb +80 -0
  18. data/lib/aspera/cli/main.rb +104 -156
  19. data/lib/aspera/cli/manager.rb +259 -209
  20. data/lib/aspera/cli/plugin.rb +123 -63
  21. data/lib/aspera/cli/plugins/alee.rb +2 -3
  22. data/lib/aspera/cli/plugins/aoc.rb +341 -261
  23. data/lib/aspera/cli/plugins/ats.rb +22 -21
  24. data/lib/aspera/cli/plugins/bss.rb +5 -5
  25. data/lib/aspera/cli/plugins/config.rb +578 -627
  26. data/lib/aspera/cli/plugins/console.rb +44 -6
  27. data/lib/aspera/cli/plugins/cos.rb +15 -17
  28. data/lib/aspera/cli/plugins/faspex.rb +114 -100
  29. data/lib/aspera/cli/plugins/faspex5.rb +411 -264
  30. data/lib/aspera/cli/plugins/node.rb +354 -259
  31. data/lib/aspera/cli/plugins/orchestrator.rb +61 -29
  32. data/lib/aspera/cli/plugins/preview.rb +82 -90
  33. data/lib/aspera/cli/plugins/server.rb +79 -32
  34. data/lib/aspera/cli/plugins/shares.rb +55 -42
  35. data/lib/aspera/cli/sync_actions.rb +68 -0
  36. data/lib/aspera/cli/transfer_agent.rb +66 -73
  37. data/lib/aspera/cli/transfer_progress.rb +74 -0
  38. data/lib/aspera/cli/version.rb +1 -1
  39. data/lib/aspera/colors.rb +12 -8
  40. data/lib/aspera/command_line_builder.rb +14 -11
  41. data/lib/aspera/cos_node.rb +3 -2
  42. data/lib/aspera/data/6 +0 -0
  43. data/lib/aspera/environment.rb +24 -9
  44. data/lib/aspera/fasp/agent_aspera.rb +126 -0
  45. data/lib/aspera/fasp/agent_base.rb +31 -77
  46. data/lib/aspera/fasp/agent_connect.rb +25 -21
  47. data/lib/aspera/fasp/agent_direct.rb +89 -103
  48. data/lib/aspera/fasp/agent_httpgw.rb +231 -149
  49. data/lib/aspera/fasp/agent_node.rb +41 -34
  50. data/lib/aspera/fasp/agent_trsdk.rb +75 -32
  51. data/lib/aspera/fasp/error_info.rb +4 -2
  52. data/lib/aspera/fasp/faux_file.rb +52 -0
  53. data/lib/aspera/fasp/installation.rb +53 -195
  54. data/lib/aspera/fasp/management.rb +244 -0
  55. data/lib/aspera/fasp/parameters.rb +71 -37
  56. data/lib/aspera/fasp/parameters.yaml +76 -8
  57. data/lib/aspera/fasp/products.rb +162 -0
  58. data/lib/aspera/fasp/resume_policy.rb +3 -3
  59. data/lib/aspera/fasp/transfer_spec.rb +7 -6
  60. data/lib/aspera/fasp/uri.rb +26 -24
  61. data/lib/aspera/faspex_gw.rb +2 -2
  62. data/lib/aspera/faspex_postproc.rb +2 -2
  63. data/lib/aspera/hash_ext.rb +14 -4
  64. data/lib/aspera/json_rpc.rb +49 -0
  65. data/lib/aspera/keychain/macos_security.rb +13 -13
  66. data/lib/aspera/line_logger.rb +23 -0
  67. data/lib/aspera/log.rb +58 -16
  68. data/lib/aspera/node.rb +157 -92
  69. data/lib/aspera/oauth.rb +37 -19
  70. data/lib/aspera/open_application.rb +4 -4
  71. data/lib/aspera/persistency_action_once.rb +1 -1
  72. data/lib/aspera/persistency_folder.rb +2 -2
  73. data/lib/aspera/preview/file_types.rb +4 -2
  74. data/lib/aspera/preview/generator.rb +22 -35
  75. data/lib/aspera/preview/options.rb +2 -0
  76. data/lib/aspera/preview/terminal.rb +73 -16
  77. data/lib/aspera/preview/utils.rb +21 -28
  78. data/lib/aspera/proxy_auto_config.js +2 -2
  79. data/lib/aspera/rest.rb +136 -68
  80. data/lib/aspera/rest_call_error.rb +1 -1
  81. data/lib/aspera/rest_error_analyzer.rb +15 -14
  82. data/lib/aspera/rest_errors_aspera.rb +37 -34
  83. data/lib/aspera/secret_hider.rb +18 -15
  84. data/lib/aspera/ssh.rb +5 -2
  85. data/lib/aspera/sync.rb +127 -119
  86. data/lib/aspera/temp_file_manager.rb +10 -3
  87. data/lib/aspera/web_auth.rb +10 -7
  88. data/lib/aspera/web_server_simple.rb +9 -4
  89. data.tar.gz.sig +0 -0
  90. metadata +34 -17
  91. metadata.gz.sig +0 -0
  92. data/docs/test_env.conf +0 -186
  93. data/lib/aspera/cli/listener/line_dump.rb +0 -19
  94. data/lib/aspera/cli/listener/logger.rb +0 -22
  95. data/lib/aspera/cli/listener/progress.rb +0 -50
  96. data/lib/aspera/cli/listener/progress_multi.rb +0 -84
  97. data/lib/aspera/cli/plugins/sync.rb +0 -44
  98. data/lib/aspera/data/7 +0 -0
  99. 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)
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 use unsafe certificates 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,44 +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.add_opt_switch(:help, '-h', 'Show this message.') { @option_help = true }
191
- @opt_mgr.add_opt_switch(:bash_comp, 'generate bash completion for command') { @bash_completion = true }
192
- @opt_mgr.add_opt_switch(:show_config, 'Display parameters used for the provided action.') { @option_show_config = true }
193
- @opt_mgr.add_opt_switch(:rest_debug, '-r', 'more debug for HTTP calls') { @option_rest_debug = true }
194
- @opt_mgr.add_opt_switch(:version, '-v', 'display version') { @formatter.display_message(:data, Aspera::Cli::VERSION); Process.exit(0) } # rubocop:disable Style/Semicolon, Layout/LineLength
195
- @opt_mgr.add_opt_switch(:warnings, '-w', 'check for language warnings') { $VERBOSE = true }
196
- # handler must be set before declaration
197
- @opt_mgr.set_obj_attr(:log_level, Log.instance, :level)
198
- @opt_mgr.set_obj_attr(:logger, Log.instance, :logger_type)
199
- @opt_mgr.set_obj_attr(:insecure, self, :option_insecure, :no)
200
- @opt_mgr.set_obj_attr(:ui, self, :option_ui)
201
- @opt_mgr.set_obj_attr(:http_options, self, :option_http_options)
202
- @opt_mgr.set_obj_attr(:log_secrets, SecretHider, :log_secrets)
203
- @opt_mgr.set_obj_attr(:cache_tokens, self, :option_cache_tokens)
204
- @opt_mgr.add_opt_list(:ui, OpenApplication.user_interfaces, 'method to start browser')
205
- @opt_mgr.add_opt_list(:log_level, Log.levels, 'Log level')
206
- @opt_mgr.add_opt_list(:logger, Log::LOG_TYPES, 'logging method')
207
- @opt_mgr.add_opt_simple(:lock_port, 'prevent dual execution of a command, e.g. in cron')
208
- @opt_mgr.add_opt_simple(:http_options, 'options for http socket (extended value)')
209
- @opt_mgr.add_opt_boolean(:insecure, 'do not validate HTTPS certificate')
210
- @opt_mgr.add_opt_boolean(:once_only, 'process only new items (some commands)')
211
- @opt_mgr.add_opt_boolean(:log_secrets, 'show passwords in logs')
212
- @opt_mgr.add_opt_boolean(:cache_tokens, 'save and reuse Oauth tokens')
213
- @opt_mgr.set_option(:ui, OpenApplication.default_gui_mode)
214
- @opt_mgr.set_option(:once_only, false)
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(
150
+ :ui, 'Method to start browser',
151
+ values: OpenApplication.user_interfaces,
152
+ handler: {o: OpenApplication.instance, m: :url_method},
153
+ default: OpenApplication.default_gui_mode)
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)
215
161
  # parse declared options
216
- @opt_mgr.parse_options!
162
+ options.parse_options!
217
163
  end
218
164
 
219
165
  # @return the plugin instance, based on name
220
166
  # also loads the plugin options, and default values from conf file
221
167
  # @param plugin_name_sym : symbol for plugin name
222
168
  def get_plugin_instance_with_options(plugin_name_sym, env=nil)
223
- env ||= @plugin_env
169
+ env ||= @agents
224
170
  Log.log.debug{"get_plugin_instance_with_options(#{plugin_name_sym})"}
225
- require @plugin_env[:config].plugins[plugin_name_sym][:require_stanza]
171
+ require config.plugins[plugin_name_sym][:require_stanza]
226
172
  # load default params only if no param already loaded before plugin instantiation
227
173
  env[:config].add_plugin_default_preset(plugin_name_sym)
228
174
  command_plugin = Plugins::Config.plugin_class(plugin_name_sym).new(env)
@@ -232,8 +178,8 @@ module Aspera
232
178
  end
233
179
 
234
180
  def generate_bash_completion
235
- if @opt_mgr.get_next_argument('', expected: :multiple, mandatory: false).nil?
236
- @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}
237
183
  else
238
184
  Log.log.warn('only first level completion so far')
239
185
  end
@@ -243,19 +189,19 @@ module Aspera
243
189
  def exit_with_usage(all_plugins)
244
190
  Log.log.debug('exit_with_usage'.bg_red)
245
191
  # display main plugin options
246
- @formatter.display_message(:error, @opt_mgr.parser)
192
+ formatter.display_message(:error, options.parser)
247
193
  if all_plugins
248
194
  # list plugins that have a "require" field, i.e. all but main plugin
249
- @plugin_env[:config].plugins.each_key do |plugin_name_sym|
195
+ config.plugins.each_key do |plugin_name_sym|
250
196
  next if plugin_name_sym.eql?(Plugins::Config::CONF_PLUGIN_SYM)
251
197
  # override main option parser with a brand new, to avoid having global options
252
- plugin_env = @plugin_env.clone
253
- plugin_env[:man_only] = true
198
+ plugin_env = @agents.clone
199
+ plugin_env[:all_manuals] = true # force declaration of all options
254
200
  plugin_env[:options] = Manager.new(PROGRAM_NAME)
255
201
  plugin_env[:options].parser.banner = '' # remove default banner
256
202
  get_plugin_instance_with_options(plugin_name_sym, plugin_env)
257
203
  # display generated help for plugin options
258
- @formatter.display_message(:error, plugin_env[:options].parser.help)
204
+ formatter.display_message(:error, plugin_env[:options].parser.help)
259
205
  end
260
206
  end
261
207
  Process.exit(0)
@@ -265,9 +211,9 @@ module Aspera
265
211
 
266
212
  # early debug for parser
267
213
  # Note: does not accept shortcuts
268
- def early_debug_setup(argv)
214
+ def early_debug_setup
269
215
  Aspera::Log.instance.program_name = PROGRAM_NAME
270
- argv.each do |arg|
216
+ @argv.each do |arg|
271
217
  case arg
272
218
  when '--' then break
273
219
  when /^--log-level=(.*)/ then Aspera::Log.instance.level = Regexp.last_match(1).to_sym
@@ -280,69 +226,78 @@ module Aspera
280
226
 
281
227
  # this is the main function called by initial script just after constructor
282
228
  def process_command_line
283
- Log.log.debug('process_command_line')
284
229
  # catch exception information , if any
285
230
  exception_info = nil
286
- # false if command shall not be executed ("once_only")
231
+ # false if command shall not be executed (e.g. --show-config)
287
232
  execute_command = true
233
+ # catch exceptions
288
234
  begin
235
+ init_agents_and_options
289
236
  # find plugins, shall be after parse! ?
290
- @plugin_env[:config].add_plugins_from_lookup_folders
237
+ config.add_plugins_from_lookup_folders
291
238
  # help requested without command ? (plugins must be known here)
292
- 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?
293
240
  generate_bash_completion if @bash_completion
294
- @plugin_env[:config].periodic_check_newer_gem_version
241
+ config.periodic_check_newer_gem_version
295
242
  command_sym =
296
- if @option_show_config && @opt_mgr.command_or_arg_empty?
243
+ if @option_show_config && options.command_or_arg_empty?
297
244
  Plugins::Config::CONF_PLUGIN_SYM
298
245
  else
299
- @opt_mgr.get_next_command(@plugin_env[:config].plugins.keys.dup.unshift(:help))
246
+ options.get_next_command(config.plugins.keys.dup.unshift(:help))
300
247
  end
301
248
  # command will not be executed, but we need manual
302
- @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
303
250
  # main plugin is not dynamically instantiated
304
251
  case command_sym
305
252
  when :help
306
253
  exit_with_usage(true)
307
254
  when Plugins::Config::CONF_PLUGIN_SYM
308
- command_plugin = @plugin_env[:config]
255
+ command_plugin = config
309
256
  else
310
257
  # get plugin, set options, etc
311
258
  command_plugin = get_plugin_instance_with_options(command_sym)
312
259
  # parse plugin specific options
313
- @opt_mgr.parse_options!
260
+ options.parse_options!
314
261
  end
315
262
  # help requested for current plugin
316
263
  exit_with_usage(false) if @option_help
317
264
  if @option_show_config
318
- @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})
319
266
  execute_command = false
320
267
  end
321
268
  # locking for single execution (only after "per plugin" option, in case lock port is there)
322
- lock_port = @opt_mgr.get_option(:lock_port)
269
+ lock_port = options.get_option(:lock_port)
323
270
  if !lock_port.nil?
324
271
  begin
325
272
  # no need to close later, will be freed on process exit. must save in member else it is garbage collected
326
- Log.log.debug{"Opening lock port #{lock_port.to_i}"}
327
- @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)
328
275
  rescue StandardError => e
329
276
  execute_command = false
330
277
  Log.log.warn{"Another instance is already running (#{e.message})."}
331
278
  end
332
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
333
286
  # execute and display (if not exclusive execution)
334
- @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
335
290
  # finish
336
- @plugin_env[:transfer].shutdown
291
+ transfer.shutdown
337
292
  rescue Net::SSH::AuthenticationFailed => e; exception_info = {e: e, t: 'SSH', security: true}
338
293
  rescue OpenSSL::SSL::SSLError => e; exception_info = {e: e, t: 'SSL'}
339
- rescue CliBadArgument => e; exception_info = {e: e, t: 'Argument', usage: true}
340
- rescue CliNoSuchId => e; exception_info = {e: e, t: 'Identifier'}
341
- rescue CliError => e; exception_info = {e: e, t: 'Tool', usage: true}
342
- 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'}
343
298
  rescue Aspera::RestCallError => e; exception_info = {e: e, t: 'Rest'}
344
299
  rescue SocketError => e; exception_info = {e: e, t: 'Network'}
345
- 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}
346
301
  rescue Interrupt => e; exception_info = {e: e, t: 'Interruption', debug: true}
347
302
  end
348
303
  # cleanup file list files
@@ -350,22 +305,15 @@ module Aspera
350
305
  # 1- processing of error condition
351
306
  unless exception_info.nil?
352
307
  Log.log.warn(exception_info[:e].message) if Aspera::Log.instance.logger_type.eql?(:syslog) && exception_info[:security]
353
- @formatter.display_message(:error, "#{ERROR_FLASH} #{exception_info[:t]}: #{exception_info[:e].message}")
354
- @formatter.display_message(:error, 'Use option -h to get help.') if exception_info[:usage]
355
- # Provide hint on FASP errors
356
- if exception_info[:e].is_a?(Fasp::Error) && exception_info[:e].message.eql?('Remote host is not who we expected')
357
- @formatter.display_message(:error, "For this specific error, refer to:\n"\
358
- "#{SRC_URL}#error-remote-host-is-not-who-we-expected\nAdd this to arguments:\n--ts=@json:'{\"sshfp\":null}'")
359
- end
360
- # Provide hint on SSL errors
361
- if exception_info[:e].is_a?(OpenSSL::SSL::SSLError) && ['does not match the server certificate'].any?{|m|exception_info[:e].message.include?(m)}
362
- @formatter.display_message(:error, "You can ignore SSL errors with option:\n--insecure=yes")
363
- 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)
364
312
  end
365
313
  # 2- processing of command not processed (due to exception or bad command line)
366
314
  if execute_command || @option_show_config
367
- @opt_mgr.final_errors.each do |msg|
368
- @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}")
369
317
  # add code as exception if there is not already an error
370
318
  exception_info = {e: Exception.new(msg), t: 'UnusedArg'} if exception_info.nil?
371
319
  end
@@ -373,9 +321,9 @@ module Aspera
373
321
  # 3- in case of error, fail the process status
374
322
  unless exception_info.nil?
375
323
  # show stack trace in debug mode
376
- raise exception_info[:e] if Log.instance.level.eql?(:debug)
324
+ raise exception_info[:e] if Log.log.debug?
377
325
  # else give hint and exit
378
- @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]
379
327
  Process.exit(1)
380
328
  end
381
329
  return nil