mirror of
https://github.com/certbot/certbot.git
synced 2026-08-02 00:22:28 +02:00
Reimplemented exception handling
This commit is contained in:
+32
-31
@@ -2,11 +2,13 @@
|
|||||||
# TODO: Sanity check all input. Be sure to avoid shell code etc...
|
# TODO: Sanity check all input. Be sure to avoid shell code etc...
|
||||||
import argparse
|
import argparse
|
||||||
import atexit
|
import atexit
|
||||||
|
import functools
|
||||||
import logging
|
import logging
|
||||||
import logging.handlers
|
import logging.handlers
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
|
import traceback
|
||||||
|
|
||||||
import configargparse
|
import configargparse
|
||||||
import zope.component
|
import zope.component
|
||||||
@@ -642,15 +644,29 @@ def _setup_logging(args):
|
|||||||
logger.info("Saving debug log to %s", log_file_name)
|
logger.info("Saving debug log to %s", log_file_name)
|
||||||
|
|
||||||
|
|
||||||
def main2(cli_args, args, config, plugins):
|
def _handle_exception(exc_type, exc_value, trace, args):
|
||||||
"""Continued main script execution."""
|
logger.debug(
|
||||||
|
"Exiting abnormally:\n%s",
|
||||||
|
"".join(traceback.format_exception(exc_type, exc_value, trace)))
|
||||||
|
|
||||||
# Displayer
|
if issubclass(exc_type, errors.Error) and (not args or not args.debug):
|
||||||
if args.text_mode:
|
sys.exit(exc_value)
|
||||||
displayer = display_util.FileDisplay(sys.stdout)
|
elif issubclass(exc_type, Exception) and args and not args.debug:
|
||||||
|
sys.exit(
|
||||||
|
"An unexpected error occurred. Please see the logfiles in {0} for "
|
||||||
|
"more details.".format(args.logs_dir))
|
||||||
else:
|
else:
|
||||||
displayer = display_util.NcursesDisplay()
|
traceback.print_exception(exc_type, exc_value, trace, file=sys.stderr)
|
||||||
zope.component.provideUtility(displayer)
|
|
||||||
|
|
||||||
|
def main(cli_args=sys.argv[1:]):
|
||||||
|
"""Command line argument parsing and main script execution."""
|
||||||
|
sys.excepthook = functools.partial(_handle_exception, args=None)
|
||||||
|
|
||||||
|
# note: arg parser internally handles --help (and exits afterwards)
|
||||||
|
plugins = plugins_disco.PluginsRegistry.find_all()
|
||||||
|
args = create_parser(plugins, cli_args).parse_args(cli_args)
|
||||||
|
config = configuration.NamespaceConfig(args)
|
||||||
|
|
||||||
# Setup logging ASAP, otherwise "No handlers could be found for
|
# Setup logging ASAP, otherwise "No handlers could be found for
|
||||||
# logger ..." TODO: this should be done before plugins discovery
|
# logger ..." TODO: this should be done before plugins discovery
|
||||||
@@ -666,6 +682,15 @@ def main2(cli_args, args, config, plugins):
|
|||||||
logger.debug("Arguments: %r", cli_args)
|
logger.debug("Arguments: %r", cli_args)
|
||||||
logger.debug("Discovered plugins: %r", plugins)
|
logger.debug("Discovered plugins: %r", plugins)
|
||||||
|
|
||||||
|
sys.excepthook = functools.partial(_handle_exception, args=args)
|
||||||
|
|
||||||
|
# Displayer
|
||||||
|
if args.text_mode:
|
||||||
|
displayer = display_util.FileDisplay(sys.stdout)
|
||||||
|
else:
|
||||||
|
displayer = display_util.NcursesDisplay()
|
||||||
|
zope.component.provideUtility(displayer)
|
||||||
|
|
||||||
# Reporter
|
# Reporter
|
||||||
report = reporter.Reporter()
|
report = reporter.Reporter()
|
||||||
zope.component.provideUtility(report)
|
zope.component.provideUtility(report)
|
||||||
@@ -685,29 +710,5 @@ def main2(cli_args, args, config, plugins):
|
|||||||
return args.func(args, config, plugins)
|
return args.func(args, config, plugins)
|
||||||
|
|
||||||
|
|
||||||
def main(cli_args=sys.argv[1:]):
|
|
||||||
"""Command line argument parsing and main script execution."""
|
|
||||||
# note: arg parser internally handles --help (and exits afterwards)
|
|
||||||
plugins = plugins_disco.PluginsRegistry.find_all()
|
|
||||||
args = create_parser(plugins, cli_args).parse_args(cli_args)
|
|
||||||
config = configuration.NamespaceConfig(args)
|
|
||||||
|
|
||||||
def handle_exception_common():
|
|
||||||
"""Logs the exception and reraises it if in debug mode."""
|
|
||||||
logger.debug("Exiting abnormally", exc_info=True)
|
|
||||||
if args.debug:
|
|
||||||
raise
|
|
||||||
|
|
||||||
try:
|
|
||||||
return main2(cli_args, args, config, plugins)
|
|
||||||
except errors.Error as error:
|
|
||||||
handle_exception_common()
|
|
||||||
return error
|
|
||||||
except Exception: # pylint: disable=broad-except
|
|
||||||
handle_exception_common()
|
|
||||||
return ("An unexpected error occured. Please see the logfiles in {0} "
|
|
||||||
"for more details.".format(args.logs_dir))
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
sys.exit(main()) # pragma: no cover
|
sys.exit(main()) # pragma: no cover
|
||||||
|
|||||||
@@ -66,12 +66,30 @@ class CLITest(unittest.TestCase):
|
|||||||
attrs = {'view_config_changes.side_effect' : error}
|
attrs = {'view_config_changes.side_effect' : error}
|
||||||
self.assertRaises(
|
self.assertRaises(
|
||||||
errors.Error, self._call, ['--debug'] + cmd_arg, attrs)
|
errors.Error, self._call, ['--debug'] + cmd_arg, attrs)
|
||||||
self._call(cmd_arg, attrs)
|
|
||||||
|
|
||||||
attrs['view_config_changes.side_effect'] = [ValueError]
|
attrs['view_config_changes.side_effect'] = [ValueError]
|
||||||
self.assertRaises(
|
self.assertRaises(
|
||||||
ValueError, self._call, ['--debug'] + cmd_arg, attrs)
|
ValueError, self._call, ['--debug'] + cmd_arg, attrs)
|
||||||
self._call(cmd_arg, attrs)
|
|
||||||
|
@mock.patch("letsencrypt.cli.sys")
|
||||||
|
def test_handle_exception(self, mock_sys):
|
||||||
|
# pylint: disable=protected-access
|
||||||
|
import StringIO
|
||||||
|
from letsencrypt import cli
|
||||||
|
from letsencrypt import errors
|
||||||
|
|
||||||
|
cli._handle_exception(errors.Error, "detail", None, None)
|
||||||
|
mock_sys.exit.assert_called_once_with("detail")
|
||||||
|
|
||||||
|
args = mock.MagicMock(debug=False)
|
||||||
|
cli._handle_exception(ValueError, "detail", None, args)
|
||||||
|
self.assertTrue("logfile" in mock_sys.exit.call_args_list[1][0][0])
|
||||||
|
|
||||||
|
mock_sys.stderr = StringIO.StringIO()
|
||||||
|
exc_value = "A very specific string"
|
||||||
|
cli._handle_exception(KeyboardInterrupt, exc_value, None, None)
|
||||||
|
self.assertTrue(exc_value in mock_sys.stderr.getvalue())
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main() # pragma: no cover
|
unittest.main() # pragma: no cover
|
||||||
|
|||||||
Reference in New Issue
Block a user