diff options
-rw-r--r-- | ranger/core/fm.py | 6 | ||||
-rw-r--r-- | ranger/core/linemode.py | 5 | ||||
-rw-r--r-- | ranger/core/main.py | 11 | ||||
-rw-r--r-- | ranger/ext/spawn.py | 49 | ||||
-rw-r--r-- | ranger/ext/vcs/vcs.py | 35 |
5 files changed, 75 insertions, 31 deletions
diff --git a/ranger/core/fm.py b/ranger/core/fm.py index 8168b7d6..fb6dd6b9 100644 --- a/ranger/core/fm.py +++ b/ranger/core/fm.py @@ -49,7 +49,7 @@ class FM(Actions, SignalDispatcher): self.ui = ui self.start_paths = paths self.directories = dict() - self.log = deque(maxlen=20) + self.log = deque(maxlen=1000) self.bookmarks = bookmarks self.current_tab = 1 self.tabs = {} @@ -70,9 +70,9 @@ class FM(Actions, SignalDispatcher): self.hostname = socket.gethostname() self.home_path = os.path.expanduser('~') - self.log.append('ranger {0} started! Process ID is {1}.' + self.log.appendleft('ranger {0} started! Process ID is {1}.' .format(__version__, os.getpid())) - self.log.append('Running on Python ' + sys.version.replace('\n', '')) + self.log.appendleft('Running on Python ' + sys.version.replace('\n', '')) mimetypes.knownfiles.append(os.path.expanduser('~/.mime.types')) mimetypes.knownfiles.append(self.relpath('data/mime.types')) diff --git a/ranger/core/linemode.py b/ranger/core/linemode.py index 96557515..a8ce4e6d 100644 --- a/ranger/core/linemode.py +++ b/ranger/core/linemode.py @@ -7,6 +7,7 @@ import sys from abc import * from datetime import datetime from ranger.ext.human_readable import human_readable +from ranger.ext.spawn import spawn DEFAULT_LINEMODE = "filename" @@ -97,9 +98,9 @@ class FileInfoLinemode(LinemodeBase): def infostring(self, file, metadata): if not file.is_directory: - from subprocess import check_output, CalledProcessError + from subprocess import Popen, PIPE, CalledProcessError try: - fileinfo = check_output(["file", "-bL", file.path]).strip() + fileinfo = spawn(["file", "-bL", file.path]).strip() except CalledProcessError: return "unknown" if sys.version_info[0] >= 3: diff --git a/ranger/core/main.py b/ranger/core/main.py index 118a7480..93c71e81 100644 --- a/ranger/core/main.py +++ b/ranger/core/main.py @@ -112,7 +112,7 @@ def main(): if fm.username == 'root': fm.settings.preview_files = False fm.settings.use_preview_script = False - fm.log.append("Running as root, disabling the file previews.") + fm.log.appendleft("Running as root, disabling the file previews.") if not arg.debug: from ranger.ext import curses_interrupt_handler curses_interrupt_handler.install_interrupt_handler() @@ -313,12 +313,11 @@ def load_settings(fm, clean): else: module = importlib.import_module('plugins.' + plugin) fm.commands.load_commands_from_module(module) - fm.log.append("Loaded plugin '%s'." % plugin) - except Exception as e: - fm.log.append("Error in plugin '%s'" % plugin) + fm.log.appendleft("Loaded plugin '%s'." % plugin) + except Exception: import traceback - for line in traceback.format_exception_only(type(e), e): - fm.log.append(line) + fm.log.extendleft(reversed(traceback.format_exc().splitlines())) + fm.notify("Error in plugin '%s'" % plugin, bad=True) ranger.fm = None # COMPAT: Load the outdated options.py diff --git a/ranger/ext/spawn.py b/ranger/ext/spawn.py index 7c5c921c..393d48d9 100644 --- a/ranger/ext/spawn.py +++ b/ranger/ext/spawn.py @@ -1,18 +1,57 @@ # This file is part of ranger, the console file manager. # License: GNU GPL version 3, see the file "AUTHORS" for details. -from subprocess import Popen, PIPE +from subprocess import Popen, PIPE, CalledProcessError ENCODING = 'utf-8' -def spawn(*args): - """Runs a program, waits for its termination and returns its stdout""" +def spawn(*args, **kwargs): + """Runs a program, waits for its termination and returns its stdout + + This function is similar to python 2.7's subprocess.check_output, + but is favored due to python 2.6 compatibility. + + The arguments may be: + + spawn(string) + spawn(command, arg1, arg2...) + spawn([command, arg1, arg2]) + + The string will be run through a shell, otherwise the command is executed + directly. + + The keyword argument "decode" determines if the output shall be decoded + with the encoding '%s'. + + Further keyword arguments are passed to Popen. + """ % (ENCODING, ) + if len(args) == 1: popen_arguments = args[0] shell = isinstance(popen_arguments, str) else: popen_arguments = args shell = False - process = Popen(popen_arguments, stdout=PIPE, shell=shell) + + if 'decode' in kwargs: + do_decode = kwargs['decode'] + del kwargs['decode'] + else: + do_decode = True + if 'stdout' not in kwargs: + kwargs['stdout'] = PIPE + if 'shell' not in kwargs: + kwargs['shell'] = shell + + process = Popen(popen_arguments, **kwargs) stdout, stderr = process.communicate() - return stdout.decode(ENCODING) + return_value = process.poll() + if return_value: + error = CalledProcessError(return_value, popen_arguments[0]) + error.output = stdout + raise error + + if do_decode: + return stdout.decode(ENCODING) + else: + return stdout diff --git a/ranger/ext/vcs/vcs.py b/ranger/ext/vcs/vcs.py index 9c7be653..cfdc1e3b 100644 --- a/ranger/ext/vcs/vcs.py +++ b/ranger/ext/vcs/vcs.py @@ -7,6 +7,7 @@ import os import subprocess import threading import time +from ranger.ext.spawn import spawn # Python2 compatibility try: @@ -119,14 +120,13 @@ class Vcs(object): # pylint: disable=too-many-instance-attributes with open(os.devnull, 'w') as devnull: try: if catchout: - output = subprocess.check_output(cmd, cwd=path, stderr=devnull) - if retbytes: - return output - else: - output = output.decode('UTF-8') + output = spawn(cmd, cwd=path, stderr=devnull, + decode=not retbytes) + if (not retbytes and rstrip_newline and + output.endswith('\n')): if rstrip_newline and output.endswith('\n'): return output[:-1] - return output + return output else: subprocess.check_call(cmd, cwd=path, stdout=devnull, stderr=devnull) except (subprocess.CalledProcessError, FileNotFoundError): @@ -460,15 +460,20 @@ class VcsThread(threading.Thread): # pylint: disable=too-many-instance-attribut self.paused.clear() self.awoken.clear() - self._queue_process() - - if self.redraw: - self.redraw = False - for column in self.ui.browser.columns: - if column.target and column.target.is_directory: - column.need_redraw = True - self.ui.status.need_redraw = True - self.ui.redraw() + try: + self._queue_process() + + if self.redraw: + self.redraw = False + for column in self.ui.browser.columns: + if column.target and column.target.is_directory: + column.need_redraw = True + self.ui.status.need_redraw = True + self.ui.redraw() + except Exception: # pylint: disable=broad-except + import traceback + self.ui.fm.log.extendleft(reversed(traceback.format_exc().splitlines())) + self.ui.fm.notify('VCS Exception', bad=True) def pause(self): """Pause thread""" |