From 62a77e71426ce4e08e410e065ef8789e8dfa6ee8 Mon Sep 17 00:00:00 2001 From: ael-code Date: Fri, 11 Nov 2016 13:12:20 +0100 Subject: core.main: Refactor exit handling Decrease complexity Do not ignore system exit exceptions Properly destroy UI --- ranger/core/main.py | 61 +++++++++++++++++++++++++++++---------------------- ranger/ext/vcs/vcs.py | 18 ++++++++++++--- ranger/gui/ui.py | 2 ++ 3 files changed, 52 insertions(+), 29 deletions(-) diff --git a/ranger/core/main.py b/ranger/core/main.py index cee698c7..281f89f5 100644 --- a/ranger/core/main.py +++ b/ranger/core/main.py @@ -97,7 +97,9 @@ def main( print("Inaccessible paths: %s" % paths) return 1 - crash_traceback = None + profile = None + exit_msg = '' + exit_code = 0 try: # Initialize objects fm = FM(paths=paths) @@ -148,43 +150,50 @@ def main( if ranger.args.profile: import cProfile import pstats - profile = None ranger.__fm = fm # pylint: disable=protected-access - cProfile.run('ranger.__fm.loop()', tempfile.gettempdir() + '/ranger_profile') - profile = pstats.Stats(tempfile.gettempdir() + '/ranger_profile', stream=sys.stderr) + profile_file = tempfile.gettempdir() + '/ranger_profile' + cProfile.run('ranger.__fm.loop()', profile_file) + profile = pstats.Stats(profile_file, stream=sys.stderr) else: fm.loop() except Exception: # pylint: disable=broad-except import traceback - crash_traceback = traceback.format_exc() - except SystemExit as error: - return error.args[0] + exit_msg += '''\ +ranger version: {0} +Python version: {1} +Locale: {2} +'''.format(ranger.__version__, sys.version.split()[0], + '.'.join(str(s) for s in locale.getlocale())) + try: + exit_msg += "Current file: '{0}'\n".format(fm.thisfile.path) + except AttributeError: + pass + exit_msg += ''' +{0} +ranger crashed. Please report this traceback at: +https://github.com/hut/ranger/issues +'''.format(traceback.format_exc()) + exit_code = 1 + + except SystemExit as ex: + if ex.code is not None: + if not isinstance(ex.code, int): + exit_msg = ex.code + exit_code = 1 + else: + exit_code = ex.code finally: - if crash_traceback: - try: - filepath = fm.thisfile.path if fm.thisfile else "None" - except AttributeError: - filepath = "None" try: fm.ui.destroy() except (AttributeError, NameError): pass + # If profiler is enabled print the stats if ranger.args.profile and profile: profile.strip_dirs().sort_stats('cumulative').print_callees() - if crash_traceback: - print("ranger version: %s, executed with python %s" % - (ranger.__version__, sys.version.split()[0])) - print("Locale: %s" % '.'.join(str(s) for s in locale.getlocale())) - try: - print("Current file: %s" % filepath) - except NameError: - pass - print(crash_traceback) - print("ranger crashed. " - "Please report this traceback at:") - print("https://github.com/hut/ranger/issues") - return 1 # pylint: disable=lost-exception - return 0 # pylint: disable=lost-exception + # print the exit message if any + if exit_msg: + sys.stderr.write(exit_msg) + return exit_code # pylint: disable=lost-exception def parse_arguments(): diff --git a/ranger/ext/vcs/vcs.py b/ranger/ext/vcs/vcs.py index 00f51152..fa5c04c0 100644 --- a/ranger/ext/vcs/vcs.py +++ b/ranger/ext/vcs/vcs.py @@ -374,13 +374,14 @@ class VcsThread(threading.Thread): # pylint: disable=too-many-instance-attribut def __init__(self, ui): super(VcsThread, self).__init__() self.daemon = True - self.ui = ui # pylint: disable=invalid-name + self.ui = ui self.queue = queue.Queue() + self._stop = threading.Event() + self.stopped = threading.Event() self.advance = threading.Event() self.advance.set() self.paused = threading.Event() self.awoken = threading.Event() - self.timestamp = time.time() self.redraw = False self.roots = set() @@ -454,10 +455,13 @@ class VcsThread(threading.Thread): # pylint: disable=too-many-instance-attribut self.paused.set() self.advance.wait() self.awoken.wait() + if self._stop.isSet(): + self.stopped.set() + return if not self.advance.isSet(): continue - self.paused.clear() self.awoken.clear() + self.paused.clear() try: self._queue_process() @@ -472,6 +476,14 @@ class VcsThread(threading.Thread): # pylint: disable=too-many-instance-attribut except Exception as ex: # pylint: disable=broad-except self.ui.fm.notify('VCS Exception: View log for more info', bad=True, exception=ex) + def stop(self): + """Stop thread synchronously""" + self._stop.set() + self.paused.wait() + self.advance.set() + self.awoken.set() + self.stopped.wait() + def pause(self): """Pause thread""" self.advance.clear() diff --git a/ranger/gui/ui.py b/ranger/gui/ui.py index 6a2f3c6c..c3bc8539 100644 --- a/ranger/gui/ui.py +++ b/ranger/gui/ui.py @@ -164,6 +164,8 @@ class UI( # pylint: disable=too-many-instance-attributes,too-many-public-method def destroy(self): """Destroy all widgets and turn off curses""" + if 'vcsthread' in self.__dict__: + self.vcsthread.stop() DisplayableContainer.destroy(self) # Restore tmux setting `automatic-rename` -- cgit 1.4.1-2-gfad0