#!/usr/bin/python # This file is part of ranger, the console file manager. # License: GNU GPL version 3, see the file "AUTHORS" for details. """rifle, the file executor/opener of ranger This can be used as a standalone program or can be embedded in python code. When used together with ranger, it doesn't have to be installed to $PATH. Example usage: rifle = Rifle("rifle.conf") rifle.reload_config() rifle.execute(["file1", "file2"]) """ import os.path import re from subprocess import Popen, PIPE import sys __version__ = 'rifle 1.7.1' # Options and constants that a user might want to change: DEFAULT_PAGER = 'less' DEFAULT_EDITOR = 'vim' ASK_COMMAND = 'ask' ENCODING = 'utf-8' # Imports from ranger library, plus reimplementations in case ranger is not # installed so rifle can be run as a standalone program. try: from ranger.ext.get_executables import get_executables except ImportError: _cached_executables = None def get_executables(): """Return all executable files in $PATH + Cache them.""" global _cached_executables if _cached_executables is not None: return _cached_executables if 'PATH' in os.environ: paths = os.environ['PATH'].split(':') else: paths = ['/usr/bin', '/bin'] from stat import S_IXOTH, S_IFREG paths_seen = set() _cached_executables = set() for path in paths: if path in paths_seen: continue paths_seen.add(path) try: content = os.listdir(path) except OSError: continue for item in content: abspath = path + '/' + item try: filestat = os.stat(abspath) except OSError: continue if filestat.st_mode & (S_IXOTH | S_IFREG): _cached_executables.add(item) return _cached_executables try: from ranger.ext.popen_forked import Popen_forked except ImportError: def Popen_forked(*args, **kwargs): """Forks process and runs Popen with the given args and kwargs.""" try: pid = os.fork() except OSError: return False if pid == 0: os.setsid() kwargs['stdin'] = open(os.devnull, 'r') kwargs['stdout'] = kwargs['stderr'] = open(os.devnull, 'w') Popen(*args, **kwargs) os._exit(0) return True def _is_terminal(): # Check if stdin (file descriptor 0), stdout (fd 1) and # stderr (fd 2) are connected to a terminal try: os.ttyname(0) os.ttyname(1) os.ttyname(2) except: return False return True def squash_flags(flags): """Remove lowercase flags if the respective uppercase flag exists >>> squash_flags('abc') 'abc' >>> squash_flags('abcC') 'ab' >>> squash_flags('CabcAd') 'bd' """ exclude = ''.join(f.upper() + f.lower() for f in flags if f == f.upper()) return ''.join(f for f in flags if f not in exclude) class Rifle(object): delimiter1 = '=' delimiter2 = ',' # TODO: Test all of the hooks properly def hook_before_executing(self, command, mimetype, flags): pass def hook_after_executing(self, command, mimetype, flags): pass def hook_command_preprocessing(self, command): return command def hook_command_postprocessing(self, command): return command def hook_environment(self, env): return env def hook_logger(self, string): sys.stderr.write(string + "\n") def __init__(self, config_file): self.config_file = config_file self._app_flags = '' self._app_label = None self._initialized_mimetypes = False # get paths for mimetype files self._mimetype_known_files = [ os.path.expanduser("~/.mime.types")] if __file__.endswith("ranger/ext/rifle.py"): # Add ranger's default mimetypes when run from ranger directory self._mimetype_known_files.append( __file__.replace("ext/rifle.py", "data/mime.types")) def reload_config(self, config_file=None): """Replace the current configuration with the one in config_file""" if config_file is None: config_file = self.config_file f = open(config_file, 'r') self.rules = [] lineno = 1 for line in f: if line.startswith('#') or line == '\n': continue line = line.strip() try: if self.delimiter1 not in line: raise Exception("Line without delimiter") tests, command = line.split(self.delimiter1, 1) tests = tests.split(self.delimiter2) tests = tuple(tuple(f.strip().split(None, 1)) for f in tests) command = command.strip() self.rules.append((command, tests)) except Exception as e: self.hook_logger("Syntax error in %s line %d (%s)" % \ (config_file, lineno, str(e))) lineno += 1 f.close() def _eval_condition(self, condition, files, label): # Handle the negation of conditions starting with an exclamation mark, # then pass on the arguments to _eval_condition2(). if not condition: return True if condition[0].startswith('!'): new_condition = tuple([condition[0][1:]]) + tuple(condition[1:]) return not self._eval_condition2(new_condition, files, label) return self._eval_condition2(condition, files, label) def _eval_condition2(self, rule, files, label): # This function evaluates the condition, after _eval_condition() handled # negation of conditions starting with a "!". if not files: return False function = rule[0] argument = rule[1] if len(rule) > 1 else '' if function == 'ext': extension = os.path.basename(files[0]).rsplit('.', 1)[-1].lower() return bool(re.search('^(' + argument + ')$', extension)) elif function == 'name': return bool(re.search(argument, os.path.basename(files[0]))) elif function == 'match': return bool(re.search(argument, files[0])) elif function == 'file': return os.path.isfile(files[0]) elif function == 'directory': return os.path.isdir(files[0]) elif function == 'path': return bool(re.search(argument, os.path.abspath(files[0]))) elif function == 'mime': return bool(re.search(argument, self._get_mimetype(files[0]))) elif function == 'has': if argument.startswith("$"): if argument[1:] in os.environ: return os.environ[argument[1:]] in get_executables() return False else: return argument in get_executables() elif function == 'terminal': return _is_terminal() elif f
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html><head><title>Python: module posixpath</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head><body bgcolor="#f0f0f8">

<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="heading">
<tr bgcolor="#7799ee">
<td valign=bottom>&nbsp;<br>
<font color="#ffffff" face="helvetica, arial">&nbsp;<br><big><big><strong>posixpath</strong></big></big></font></td
><td align=right valign=bottom
><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/lib/python3.1/posixpath.py">/usr/lib/python3.1/posixpath.py</a><br><a href="http://docs.python.org/library/posixpath">Module Docs</a></font></td></tr></table>
    <p><tt>Common&nbsp;operations&nbsp;on&nbsp;Posix&nbsp;pathnames.<br>
&nbsp;<br>
Instead&nbsp