def execute( self, files, # noqa: E501 pylint: disable=too-many-branches,too-many-statements,too-many-locals number=0, label=None, flags="", mimetype=None): """Executes the given list of files. By default, this executes the first command where all conditions apply, but by specifying number=N you can run the 1+Nth command. If a label is specified, only rules with this label will be considered. If you specify the mimetype, rifle will not try to determine it itself. By specifying a flag, you extend the flag that is defined in the rule. Uppercase flags negate the respective lowercase flags. For example: if the flag in the rule is "pw" and you specify "Pf", then the "p" flag is negated and the "f" flag is added, resulting in "wf". """ command = None found_at_least_one = None # Determine command for count, cmd, lbl, flgs in self.list_commands(files, mimetype): if label and label == lbl or not label and count == number: cmd = self.hook_command_preprocessing(cmd) if cmd == ASK_COMMAND: return ASK_COMMAND command = self._build_command(files, cmd, flags + flgs) flags = self._app_flags break else: found_at_least_one = True else: if label and label in get_executables(): cmd = '%s "$@"' % label command = self._build_command(files, cmd, flags) # Execute command if command is None: # pylint: disable=too-many-nested-blocks if found_at_least_one: if label: self.hook_logger("Label '%s' is undefined" % label) else: self.hook_logger("Method number %d is undefined." % number) else: self.hook_logger("No action found.") else: if 'PAGER' not in os.environ: os.environ['PAGER'] = DEFAULT_PAGER if 'EDITOR' not in os.environ: os.environ['EDITOR'] = DEFAULT_EDITOR command = self.hook_command_postprocessing(command) self.hook_before_executing(command, self._mimetype, self._app_flags) try: if 'r' in flags: prefix = ['sudo', '-E', 'su', '-mc'] else: prefix = ['/bin/sh', '-c'] cmd = prefix + [command] if 't' in flags: if 'TERMCMD' not in os.environ: term = os.environ['TERM'] if term.startswith('rxvt-unicode'): term = 'urxvt' elif term.startswith('rxvt-'): # Sometimes urxvt calls itself "rxvt-256color" if 'rxvt' in get_executables(): term = 'rxvt' else: term = 'urxvt' if term not in get_executables(): self.hook_logger( "Can not determine terminal command. " "Please set $TERMCMD manually.") # A fallback terminal that is likely installed: term = 'xterm' os.environ['TERMCMD'] = term cmd = [os.environ['TERMCMD'], '-e'] + cmd if 'f' in flags or 't' in flags: Popen_forked(cmd, env=self.hook_environment(os.environ)) else: process = Popen(cmd, env=self.hook_environment(os.environ)) process.wait() finally: self.hook_after_executing(command, self._mimetype, self._app_flags) return None
def __call__( # pylint: disable=too-many-branches,too-many-statements # pylint: disable=too-many-arguments,too-many-locals self, action=None, try_app_first=False, app='default', files=None, mode=0, flags='', wait=True, **popen_kws): """Run the application in the way specified by the options. Returns False if nothing can be done, None if there was an error, otherwise the process object returned by Popen(). This function tries to find an action if none is defined. """ # Find an action if none was supplied by # creating a Context object and passing it to # an Application object. context = Context(app=app, files=files, mode=mode, fm=self.fm, flags=flags, wait=wait, popen_kws=popen_kws, file=files and files[0] or None) if action is None: return self._log("No way of determining the action!") # Preconditions context.squash_flags() popen_kws = context.popen_kws # shortcut toggle_ui = True pipe_output = False wait_for_enter = False devnull = None if 'shell' not in popen_kws: popen_kws['shell'] = isinstance(action, str) # Set default shell for Popen if popen_kws['shell']: # This doesn't work with fish, see #300 if 'fish' not in os.environ['SHELL']: popen_kws['executable'] = os.environ['SHELL'] if 'stdout' not in popen_kws: popen_kws['stdout'] = sys.stdout if 'stderr' not in popen_kws: popen_kws['stderr'] = sys.stderr # Evaluate the flags to determine keywords # for Popen() and other variables if 'p' in context.flags: popen_kws['stdout'] = PIPE popen_kws['stderr'] = PIPE toggle_ui = False pipe_output = True context.wait = False if 's' in context.flags: devnull_writable = open(os.devnull, 'w') devnull_readable = open(os.devnull, 'r') for key in ('stdout', 'stderr'): popen_kws[key] = devnull_writable toggle_ui = False popen_kws['stdin'] = devnull_readable if 'f' in context.flags: toggle_ui = False context.wait = False if 'w' in context.flags: if not pipe_output and context.wait: # <-- sanity check wait_for_enter = True if 'r' in context.flags: # TODO: make 'r' flag work with pipes if 'sudo' not in get_executables(): return self._log("Can not run with 'r' flag, sudo is not installed!") f_flag = ('f' in context.flags) if isinstance(action, str): action = 'sudo ' + (f_flag and '-b ' or '') + action else: action = ['sudo'] + (f_flag and ['-b'] or []) + action toggle_ui = True context.wait = True if 't' in context.flags: if 'DISPLAY' not in os.environ: return self._log("Can not run with 't' flag, no display found!") term = get_term() if isinstance(action, str): action = term + ' -e ' + action else: action = [term, '-e'] + action toggle_ui = False context.wait = False popen_kws['args'] = action # Finally, run it if toggle_ui: self._activate_ui(False) try: error = None process = None self.fm.signal_emit('runner.execute.before', popen_kws=popen_kws, context=context) try: if 'f' in context.flags: # This can fail and return False if os.fork() is not # supported, but we assume it is, since curses is used. Popen_forked(**popen_kws) else: process = Popen(**popen_kws) except OSError as ex: error = ex self._log("Failed to run: %s\n%s" % (str(action), str(ex))) else: if context.wait: process.wait() elif process: self.zombies.add(process) if wait_for_enter: press_enter() finally: self.fm.signal_emit('runner.execute.after', popen_kws=popen_kws, context=context, error=error) if devnull: devnull.close() if toggle_ui: self._activate_ui(True) if pipe_output and process: return self(action='less', app='pager', # pylint: disable=lost-exception try_app_first=True, stdin=process.stdout) return process # pylint: disable=lost-exception
def execute(self, files, # noqa: E501 pylint: disable=too-many-branches,too-many-statements,too-many-locals number=0, label=None, flags="", mimetype=None): """Executes the given list of files. By default, this executes the first command where all conditions apply, but by specifying number=N you can run the 1+Nth command. If a label is specified, only rules with this label will be considered. If you specify the mimetype, rifle will not try to determine it itself. By specifying a flag, you extend the flag that is defined in the rule. Uppercase flags negate the respective lowercase flags. For example: if the flag in the rule is "pw" and you specify "Pf", then the "p" flag is negated and the "f" flag is added, resulting in "wf". """ command = None found_at_least_one = None # Determine command for count, cmd, lbl, flgs in self.list_commands(files, mimetype): if label and label == lbl or not label and count == number: cmd = self.hook_command_preprocessing(cmd) if cmd == ASK_COMMAND: return ASK_COMMAND command = self._build_command(files, cmd, flags + flgs) flags = self._app_flags break else: found_at_least_one = True else: if label and label in get_executables(): cmd = '%s "$@"' % label command = self._build_command(files, cmd, flags) # Execute command if command is None: # pylint: disable=too-many-nested-blocks if found_at_least_one: if label: self.hook_logger("Label '%s' is undefined" % label) else: self.hook_logger("Method number %d is undefined." % number) else: self.hook_logger("No action found.") else: if 'PAGER' not in os.environ: os.environ['PAGER'] = DEFAULT_PAGER if 'EDITOR' not in os.environ: os.environ['EDITOR'] = os.environ.get('VISUAL', DEFAULT_EDITOR) command = self.hook_command_postprocessing(command) self.hook_before_executing(command, self._mimetype, self._app_flags) try: if 'r' in flags: prefix = ['sudo', '-E', 'su', 'root', '-mc'] else: prefix = ['/bin/sh', '-c'] cmd = prefix + [command] if 't' in flags: term = os.environ.get('TERMCMD', os.environ['TERM']) # Handle aliases of xterm and urxvt, rxvt and st and # termite # Match 'xterm', 'xterm-256color' if term in ['xterm', 'xterm-256color']: term = 'xterm' if term in ['xterm-kitty']: term = 'kitty' if term in ['xterm-termite']: term = 'termite' if term in ['st', 'st-256color']: term = 'st' if term in ['urxvt', 'rxvt-unicode', 'rxvt-unicode-256color']: term = 'urxvt' if term in ['rxvt', 'rxvt-256color']: if 'rxvt' in get_executables(): term = 'rxvt' else: term = 'urxvt' if term not in get_executables(): self.hook_logger("Can not determine terminal command, " "using rifle to determine fallback. " "Please set $TERMCMD manually or " "change fallbacks in rifle.conf.") self._mimetype = 'ranger/x-terminal-emulator' self.execute( files=[command.split(';')[1].split('--')[0].strip()] + files, flags='f', mimetype='ranger/x-terminal-emulator') return None # Choose correct cmdflag accordingly if term in ['xfce4-terminal', 'mate-terminal', 'terminator']: cmdflag = '-x' elif term in ['xterm', 'urxvt', 'rxvt', 'lxterminal', 'konsole', 'lilyterm', 'cool-retro-term', 'terminology', 'pantheon-terminal', 'termite', 'st', 'stterm']: cmdflag = '-e' elif term in ['gnome-terminal', 'kitty']: cmdflag = '--' elif term in ['tilda', ]: cmdflag = '-c' else: cmdflag = '-e' os.environ['TERMCMD'] = term # These terms don't work with the '/bin/sh set --' scheme. # A temporary fix. if term in ['tilda', 'pantheon-terminal', 'terminology', 'termite']: target = command.split(';')[0].split('--')[1].strip() app = command.split(';')[1].split('--')[0].strip() cmd = [os.environ['TERMCMD'], cmdflag, '%s %s' % (app, target)] elif term in ['guake']: cmd = [os.environ['TERMCMD'], '-n', '${PWD}', cmdflag] + cmd else: cmd = [os.environ['TERMCMD'], cmdflag] + cmd # self.hook_logger('cmd: %s' %cmd) if 'f' in flags or 't' in flags: Popen_forked(cmd, env=self.hook_environment(os.environ)) else: with Popen( cmd, env=self.hook_environment(os.environ) ) as process: process.wait() finally: self.hook_after_executing(command, self._mimetype, self._app_flags) return None