aspera-cli 4.14.0 → 4.16.0

Sign up to get free protection for your applications and to get access to all the features.
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