from __future__ import absolute_import from __future__ import print_function from __future__ import unicode_literals import contextlib import os.path import sys import traceback import six import pre_commit.constants as C from pre_commit import five from pre_commit import output from pre_commit.store import Store class FatalError(RuntimeError): pass def _to_bytes(exc): try: return bytes(exc) except Exception: return six.text_type(exc).encode('UTF-8') def _log_and_exit(msg, exc, formatted): error_msg = b''.join(( _to_bytes('### version information\n'), _to_bytes('pre-commit.version={}\n'.format(C.VERSION)), _to_bytes('sys.version={}\n'.format(sys.version.replace('\n', ' '))), _to_bytes('sys.executable={}\n'.format(sys.executable)), _to_bytes('### error information\n'), five.to_bytes(msg), b': ', five.to_bytes(type(exc).__name__), b': ', _to_bytes(exc), b'\n', )) output.write(error_msg) store = Store() log_path = os.path.join(store.directory, 'pre-commit.log') output.write_line('Check the log at {}'.format(log_path)) with open(log_path, 'wb') as log: output.write(error_msg, stream=log) output.write_line(formatted, stream=log) raise SystemExit(1) @contextlib.contextmanager def error_handler(): try: yield except (Exception, KeyboardInterrupt) as e: if isinstance(e, FatalError): msg = 'An error has occurred' elif isinstance(e, KeyboardInterrupt): msg = 'Interrupted (^C)' else: msg = 'An unexpected error has occurred' _log_and_exit(msg, e, traceback.format_exc())