def _run_binary(self, kwargs): if not self.cmd[0]: raise xt.XonshError("xonsh: subprocess mode: command is empty") bufsize = 1 try: if xp.ON_WINDOWS and self.binary_loc is not None: # launch process using full paths (https://bugs.python.org/issue8557) cmd = [self.binary_loc] + self.cmd[1:] else: cmd = self.cmd p = self.cls(cmd, bufsize=bufsize, **kwargs) except PermissionError: e = "xonsh: subprocess mode: permission denied: {0}" raise xt.XonshError(e.format(self.cmd[0])) except FileNotFoundError: cmd0 = self.cmd[0] if len(self.cmd) == 1 and cmd0.endswith("?"): with contextlib.suppress(OSError): return self.cls(["man", cmd0.rstrip("?")], bufsize=bufsize, **kwargs) e = "xonsh: subprocess mode: command not found: {0}".format(cmd0) env = XSH.env sug = xt.suggest_commands(cmd0, env) if len(sug.strip()) > 0: e += "\n" + xt.suggest_commands(cmd0, env) raise xt.XonshError(e) return p
def _run_binary(self, kwargs): try: bufsize = 1 p = self.cls(self.cmd, bufsize=bufsize, **kwargs) except PermissionError: e = 'xonsh: subprocess mode: permission denied: {0}' raise XonshError(e.format(self.cmd[0])) except FileNotFoundError: cmd0 = self.cmd[0] e = 'xonsh: subprocess mode: command not found: {0}'.format(cmd0) env = builtins.__xonsh_env__ sug = suggest_commands(cmd0, env, builtins.aliases) if len(sug.strip()) > 0: e += '\n' + suggest_commands(cmd0, env, builtins.aliases) raise XonshError(e) return p
def _run_binary(self, kwargs): try: bufsize = 1 p = self.cls(self.cmd, bufsize=bufsize, **kwargs) except PermissionError: e = "xonsh: subprocess mode: permission denied: {0}" raise XonshError(e.format(self.cmd[0])) except FileNotFoundError: cmd0 = self.cmd[0] if len(self.cmd) == 1 and cmd0.endswith("?"): with contextlib.suppress(OSError): return self.cls(["man", cmd0.rstrip("?")], bufsize=bufsize, **kwargs) e = "xonsh: subprocess mode: command not found: {0}".format(cmd0) env = builtins.__xonsh__.env sug = suggest_commands(cmd0, env, builtins.aliases) if len(sug.strip()) > 0: e += "\n" + suggest_commands(cmd0, env, builtins.aliases) raise XonshError(e) return p
def run_subproc(cmds, captured=False): """Runs a subprocess, in its many forms. This takes a list of 'commands,' which may be a list of command line arguments or a string, representing a special connecting character. For example:: $ ls | grep wakka is represented by the following cmds:: [['ls'], '|', ['grep', 'wakka']] Lastly, the captured argument affects only the last real command. """ env = builtins.__xonsh_env__ background = False procinfo = {} if cmds[-1] == '&': background = True cmds = cmds[:-1] _pipeline_group = None write_target = None last_cmd = len(cmds) - 1 procs = [] prev_proc = None _capture_streams = captured in {'stdout', 'object'} for ix, cmd in enumerate(cmds): starttime = time.time() procinfo['args'] = list(cmd) stdin = None stderr = None if isinstance(cmd, str): continue streams = {} while True: if len(cmd) >= 3 and _is_redirect(cmd[-2]): _redirect_io(streams, cmd[-2], cmd[-1]) cmd = cmd[:-2] elif len(cmd) >= 2 and _is_redirect(cmd[-1]): _redirect_io(streams, cmd[-1]) cmd = cmd[:-1] elif len(cmd) >= 3 and cmd[0] == '<': _redirect_io(streams, cmd[0], cmd[1]) cmd = cmd[2:] else: break # set standard input if 'stdin' in streams: if prev_proc is not None: raise XonshError('Multiple inputs for stdin') stdin = streams['stdin'][-1] procinfo['stdin_redirect'] = streams['stdin'][:-1] elif prev_proc is not None: stdin = prev_proc.stdout # set standard output _stdout_name = None _stderr_name = None if 'stdout' in streams: if ix != last_cmd: raise XonshError('Multiple redirects for stdout') stdout = streams['stdout'][-1] procinfo['stdout_redirect'] = streams['stdout'][:-1] elif ix != last_cmd: stdout = subprocess.PIPE elif _capture_streams: _nstdout = stdout = tempfile.NamedTemporaryFile(delete=False) _stdout_name = stdout.name elif builtins.__xonsh_stdout_uncaptured__ is not None: stdout = builtins.__xonsh_stdout_uncaptured__ else: stdout = None # set standard error if 'stderr' in streams: stderr = streams['stderr'][-1] procinfo['stderr_redirect'] = streams['stderr'][:-1] elif captured == 'object' and ix == last_cmd: _nstderr = stderr = tempfile.NamedTemporaryFile(delete=False) _stderr_name = stderr.name elif builtins.__xonsh_stderr_uncaptured__ is not None: stderr = builtins.__xonsh_stderr_uncaptured__ uninew = (ix == last_cmd) and (not _capture_streams) # find alias if callable(cmd[0]): alias = cmd[0] else: alias = builtins.aliases.get(cmd[0], None) procinfo['alias'] = alias # find binary location, if not callable if alias is None: binary_loc = locate_binary(cmd[0]) elif not callable(alias): binary_loc = locate_binary(alias[0]) # implement AUTO_CD if (alias is None and builtins.__xonsh_env__.get('AUTO_CD') and len(cmd) == 1 and os.path.isdir(cmd[0]) and binary_loc is None): cmd.insert(0, 'cd') alias = builtins.aliases.get('cd', None) if callable(alias): aliased_cmd = alias else: if alias is not None: aliased_cmd = alias + cmd[1:] else: aliased_cmd = cmd if binary_loc is not None: try: aliased_cmd = get_script_subproc_command(binary_loc, aliased_cmd[1:]) except PermissionError: e = 'xonsh: subprocess mode: permission denied: {0}' raise XonshError(e.format(cmd[0])) _stdin_file = None if (stdin is not None and env.get('XONSH_STORE_STDIN') and captured == 'object' and __xonsh_commands_cache__.lazy_locate_binary('cat') and __xonsh_commands_cache__.lazy_locate_binary('tee')): _stdin_file = tempfile.NamedTemporaryFile() cproc = subprocess.Popen(['cat'], stdin=stdin, stdout=subprocess.PIPE) tproc = subprocess.Popen(['tee', _stdin_file.name], stdin=cproc.stdout, stdout=subprocess.PIPE) stdin = tproc.stdout if callable(aliased_cmd): prev_is_proxy = True bgable = getattr(aliased_cmd, '__xonsh_backgroundable__', True) numargs = len(inspect.signature(aliased_cmd).parameters) if numargs == 2: cls = SimpleProcProxy if bgable else SimpleForegroundProcProxy elif numargs == 4: cls = ProcProxy if bgable else ForegroundProcProxy else: e = 'Expected callable with 2 or 4 arguments, not {}' raise XonshError(e.format(numargs)) proc = cls(aliased_cmd, cmd[1:], stdin, stdout, stderr, universal_newlines=uninew) else: prev_is_proxy = False usetee = ((stdout is None) and (not background) and env.get('XONSH_STORE_STDOUT', False)) cls = TeePTYProc if usetee else subprocess.Popen subproc_kwargs = {} if ON_POSIX and cls is subprocess.Popen: def _subproc_pre(): if _pipeline_group is None: os.setpgrp() else: os.setpgid(0, _pipeline_group) signal.signal(signal.SIGTSTP, lambda n, f: signal.pause()) subproc_kwargs['preexec_fn'] = _subproc_pre denv = env.detype() if ON_WINDOWS: # Over write prompt variable as xonsh's $PROMPT does # not make much sense for other subprocs denv['PROMPT'] = '$P$G' try: proc = cls(aliased_cmd, universal_newlines=uninew, env=denv, stdin=stdin, stdout=stdout, stderr=stderr, **subproc_kwargs) except PermissionError: e = 'xonsh: subprocess mode: permission denied: {0}' raise XonshError(e.format(aliased_cmd[0])) except FileNotFoundError: cmd = aliased_cmd[0] e = 'xonsh: subprocess mode: command not found: {0}'.format(cmd) sug = suggest_commands(cmd, env, builtins.aliases) if len(sug.strip()) > 0: e += '\n' + suggest_commands(cmd, env, builtins.aliases) raise XonshError(e) procs.append(proc) prev_proc = proc if ON_POSIX and cls is subprocess.Popen and _pipeline_group is None: _pipeline_group = prev_proc.pid if not prev_is_proxy: add_job({ 'cmds': cmds, 'pids': [i.pid for i in procs], 'obj': prev_proc, 'bg': background }) if (env.get('XONSH_INTERACTIVE') and not env.get('XONSH_STORE_STDOUT') and not _capture_streams): # set title here to get current command running try: builtins.__xonsh_shell__.settitle() except AttributeError: pass if background: return if prev_is_proxy: prev_proc.wait() wait_for_active_job() for proc in procs[:-1]: try: proc.stdout.close() except OSError: pass hist = builtins.__xonsh_history__ hist.last_cmd_rtn = prev_proc.returncode # get output output = b'' if write_target is None: if _stdout_name is not None: with open(_stdout_name, 'rb') as stdoutfile: output = stdoutfile.read() try: _nstdout.close() except Exception: pass os.unlink(_stdout_name) elif prev_proc.stdout not in (None, sys.stdout): output = prev_proc.stdout.read() if _capture_streams: # to get proper encoding from Popen, we have to # use a byte stream and then implement universal_newlines here output = output.decode(encoding=env.get('XONSH_ENCODING'), errors=env.get('XONSH_ENCODING_ERRORS')) output = output.replace('\r\n', '\n') else: hist.last_cmd_out = output if captured == 'object': # get stderr as well named = _stderr_name is not None unnamed = prev_proc.stderr not in {None, sys.stderr} if named: with open(_stderr_name, 'rb') as stderrfile: errout = stderrfile.read() try: _nstderr.close() except Exception: pass os.unlink(_stderr_name) elif unnamed: errout = prev_proc.stderr.read() if named or unnamed: errout = errout.decode(encoding=env.get('XONSH_ENCODING'), errors=env.get('XONSH_ENCODING_ERRORS')) errout = errout.replace('\r\n', '\n') procinfo['stderr'] = errout if getattr(prev_proc, 'signal', None): sig, core = prev_proc.signal sig_str = SIGNAL_MESSAGES.get(sig) if sig_str: if core: sig_str += ' (core dumped)' print(sig_str, file=sys.stderr) if (not prev_is_proxy and hist.last_cmd_rtn is not None and hist.last_cmd_rtn > 0 and env.get('RAISE_SUBPROC_ERROR')): raise subprocess.CalledProcessError(hist.last_cmd_rtn, aliased_cmd, output=output) if captured == 'stdout': return output elif captured is not False: procinfo['executed_cmd'] = aliased_cmd procinfo['pid'] = prev_proc.pid procinfo['returncode'] = prev_proc.returncode procinfo['timestamp'] = (starttime, time.time()) if captured == 'object': procinfo['stdout'] = output if _stdin_file is not None: _stdin_file.seek(0) procinfo['stdin'] = _stdin_file.read().decode() _stdin_file.close() return CompletedCommand(**procinfo) else: return HiddenCompletedCommand(**procinfo)
def run_subproc(cmds, captured=True): """Runs a subprocess, in its many forms. This takes a list of 'commands,' which may be a list of command line arguments or a string, representing a special connecting character. For example:: $ ls | grep wakka is represented by the following cmds:: [['ls'], '|', ['grep', 'wakka']] Lastly, the captured argument affects only the last real command. """ global ENV background = False if cmds[-1] == '&': background = True cmds = cmds[:-1] write_target = None last_cmd = len(cmds) - 1 procs = [] prev_proc = None for ix, cmd in enumerate(cmds): stdin = None stderr = None if isinstance(cmd, string_types): continue streams = {} while True: if len(cmd) >= 3 and _is_redirect(cmd[-2]): _redirect_io(streams, cmd[-2], cmd[-1]) cmd = cmd[:-2] elif len(cmd) >= 2 and _is_redirect(cmd[-1]): _redirect_io(streams, cmd[-1]) cmd = cmd[:-1] elif len(cmd) >= 3 and cmd[0] == '<': _redirect_io(streams, cmd[0], cmd[1]) cmd = cmd[2:] else: break # set standard input if 'stdin' in streams: if prev_proc is not None: raise XonshError('Multiple inputs for stdin') stdin = streams['stdin'] elif prev_proc is not None: stdin = prev_proc.stdout # set standard output if 'stdout' in streams: if ix != last_cmd: raise XonshError('Multiple redirects for stdout') stdout = streams['stdout'] elif captured or ix != last_cmd: stdout = PIPE else: stdout = None # set standard error if 'stderr' in streams: stderr = streams['stderr'] uninew = (ix == last_cmd) and (not captured) alias = builtins.aliases.get(cmd[0], None) if (alias is None and builtins.__xonsh_env__.get('AUTO_CD') and len(cmd) == 1 and os.path.isdir(cmd[0]) and locate_binary(cmd[0], cwd=None) is None): cmd.insert(0, 'cd') alias = builtins.aliases.get('cd', None) if callable(alias): aliased_cmd = alias else: if alias is not None: cmd = alias + cmd[1:] n = _get_runnable_name(cmd[0]) if n is None: aliased_cmd = cmd else: try: aliased_cmd = get_script_subproc_command(n, cmd[1:]) except PermissionError: e = 'xonsh: subprocess mode: permission denied: {0}' raise XonshError(e.format(cmd[0])) if callable(aliased_cmd): prev_is_proxy = True numargs = len(inspect.signature(aliased_cmd).parameters) if numargs == 2: cls = SimpleProcProxy elif numargs == 4: cls = ProcProxy else: e = 'Expected callable with 2 or 4 arguments, not {}' raise XonshError(e.format(numargs)) proc = cls(aliased_cmd, cmd[1:], stdin, stdout, stderr, universal_newlines=uninew) else: prev_is_proxy = False usetee = (stdout is None) and (not background) and \ ENV.get('XONSH_STORE_STDOUT', False) cls = TeePTYProc if usetee else Popen subproc_kwargs = {} if ON_POSIX and cls is Popen: subproc_kwargs['preexec_fn'] = _subproc_pre try: proc = cls(aliased_cmd, universal_newlines=uninew, env=ENV.detype(), stdin=stdin, stdout=stdout, stderr=stderr, **subproc_kwargs) except PermissionError: e = 'xonsh: subprocess mode: permission denied: {0}' raise XonshError(e.format(aliased_cmd[0])) except FileNotFoundError: cmd = aliased_cmd[0] e = 'xonsh: subprocess mode: command not found: {0}'.format(cmd) sug = suggest_commands(cmd, ENV, builtins.aliases) if len(sug.strip()) > 0: e += '\n' + suggest_commands(cmd, ENV, builtins.aliases) raise XonshError(e) procs.append(proc) prev_proc = proc for proc in procs[:-1]: try: proc.stdout.close() except OSError: pass if not prev_is_proxy: add_job({ 'cmds': cmds, 'pids': [i.pid for i in procs], 'obj': prev_proc, 'bg': background }) if ENV.get('XONSH_INTERACTIVE') and not ENV.get('XONSH_STORE_STDOUT'): # set title here to get current command running try: builtins.__xonsh_shell__.settitle() except AttributeError: pass if background: return if prev_is_proxy: prev_proc.wait() wait_for_active_job() hist = builtins.__xonsh_history__ hist.last_cmd_rtn = prev_proc.returncode if write_target is None: # get output output = b'' if prev_proc.stdout not in (None, sys.stdout): output = prev_proc.stdout.read() if captured: # to get proper encoding from Popen, we have to # use a byte stream and then implement universal_newlines here output = output.decode(encoding=ENV.get('XONSH_ENCODING'), errors=ENV.get('XONSH_ENCODING_ERRORS')) output = output.replace('\r\n', '\n') return output else: hist.last_cmd_out = output
def run_subproc(cmds, captured=True): """Runs a subprocess, in its many forms. This takes a list of 'commands,' which may be a list of command line arguments or a string, representing a special connecting character. For example:: $ ls | grep wakka is represented by the following cmds:: [['ls'], '|', ['grep', 'wakka']] Lastly, the captured argument affects only the last real command. """ global ENV background = False if cmds[-1] == '&': background = True cmds = cmds[:-1] write_target = None last_cmd = len(cmds) - 1 prev = None procs = [] prev_proc = None for ix, cmd in enumerate(cmds): stdin = None stdout = None stderr = None if isinstance(cmd, string_types): prev = cmd continue streams = {} while True: if len(cmd) >= 3 and _is_redirect(cmd[-2]): _redirect_io(streams, cmd[-2], cmd[-1]) cmd = cmd[:-2] elif len(cmd) >= 2 and _is_redirect(cmd[-1]): _redirect_io(streams, cmd[-1]) cmd = cmd[:-1] elif len(cmd) >= 3 and cmd[0] == '<': _redirect_io(streams, cmd[0], cmd[1]) cmd = cmd[2:] else: break # set standard input if 'stdin' in streams: if prev_proc is not None: raise XonshError('Multiple inputs for stdin') stdin = streams['stdin'] elif prev_proc is not None: stdin = prev_proc.stdout # set standard output if 'stdout' in streams: if ix != last_cmd: raise XonshError('Multiple redirects for stdout') stdout = streams['stdout'] elif captured or ix != last_cmd: stdout = PIPE else: stdout = None # set standard error if 'stderr' in streams: stderr = streams['stderr'] uninew = ix == last_cmd alias = builtins.aliases.get(cmd[0], None) if callable(alias): aliased_cmd = alias else: if alias is not None: cmd = alias + cmd[1:] n = _get_runnable_name(cmd[0]) if n is None: aliased_cmd = cmd else: try: aliased_cmd = get_script_subproc_command(n, cmd[1:]) except PermissionError: e = 'xonsh: subprocess mode: permission denied: {0}' raise XonshError(e.format(cmd[0])) if callable(aliased_cmd): prev_is_proxy = True numargs = len(inspect.signature(aliased_cmd).parameters) if numargs == 2: cls = SimpleProcProxy elif numargs == 4: cls = ProcProxy else: e = 'Expected callable with 2 or 4 arguments, not {}' raise XonshError(e.format(numargs)) proc = cls(aliased_cmd, cmd[1:], stdin, stdout, stderr, universal_newlines=uninew) else: prev_is_proxy = False subproc_kwargs = {} if ON_POSIX: subproc_kwargs['preexec_fn'] = _subproc_pre try: proc = Popen(aliased_cmd, universal_newlines=uninew, env=ENV.detype(), stdin=stdin, stdout=stdout, stderr=stderr, **subproc_kwargs) except PermissionError: e = 'xonsh: subprocess mode: permission denied: {0}' raise XonshError(e.format(aliased_cmd[0])) except FileNotFoundError: cmd = aliased_cmd[0] e = 'xonsh: subprocess mode: command not found: {0}'.format( cmd) sug = suggest_commands(cmd, ENV, builtins.aliases) if len(sug.strip()) > 0: e += '\n' + suggest_commands(cmd, ENV, builtins.aliases) raise XonshError(e) procs.append(proc) prev = None prev_proc = proc for proc in procs[:-1]: try: proc.stdout.close() except OSError: pass if not prev_is_proxy: add_job({ 'cmds': cmds, 'pids': [i.pid for i in procs], 'obj': prev_proc, 'bg': background }) if background: return if prev_is_proxy: prev_proc.wait() wait_for_active_job() if write_target is None: # get output output = '' if prev_proc.stdout not in (None, sys.stdout): output = prev_proc.stdout.read() if captured: return output elif last_stdout not in (PIPE, None, sys.stdout): last_stdout.close()
def run_subproc(cmds, captured=False): """Runs a subprocess, in its many forms. This takes a list of 'commands,' which may be a list of command line arguments or a string, representing a special connecting character. For example:: $ ls | grep wakka is represented by the following cmds:: [['ls'], '|', ['grep', 'wakka']] Lastly, the captured argument affects only the last real command. """ global ENV background = False procinfo = {} if cmds[-1] == '&': background = True cmds = cmds[:-1] write_target = None last_cmd = len(cmds) - 1 procs = [] prev_proc = None _capture_streams = captured in {'stdout', 'object'} for ix, cmd in enumerate(cmds): starttime = time.time() procinfo['args'] = list(cmd) stdin = None stderr = None if isinstance(cmd, str): continue streams = {} while True: if len(cmd) >= 3 and _is_redirect(cmd[-2]): _redirect_io(streams, cmd[-2], cmd[-1]) cmd = cmd[:-2] elif len(cmd) >= 2 and _is_redirect(cmd[-1]): _redirect_io(streams, cmd[-1]) cmd = cmd[:-1] elif len(cmd) >= 3 and cmd[0] == '<': _redirect_io(streams, cmd[0], cmd[1]) cmd = cmd[2:] else: break # set standard input if 'stdin' in streams: if prev_proc is not None: raise XonshError('Multiple inputs for stdin') stdin = streams['stdin'][-1] procinfo['stdin_redirect'] = streams['stdin'][:-1] elif prev_proc is not None: stdin = prev_proc.stdout # set standard output _stdout_name = None _stderr_name = None if 'stdout' in streams: if ix != last_cmd: raise XonshError('Multiple redirects for stdout') stdout = streams['stdout'][-1] procinfo['stdout_redirect'] = streams['stdout'][:-1] elif ix != last_cmd: stdout = PIPE elif _capture_streams: _nstdout = stdout = tempfile.NamedTemporaryFile(delete=False) _stdout_name = stdout.name elif builtins.__xonsh_stdout_uncaptured__ is not None: stdout = builtins.__xonsh_stdout_uncaptured__ else: stdout = None # set standard error if 'stderr' in streams: stderr = streams['stderr'][-1] procinfo['stderr_redirect'] = streams['stderr'][:-1] elif captured == 'object' and ix == last_cmd: _nstderr = stderr = tempfile.NamedTemporaryFile(delete=False) _stderr_name = stderr.name elif builtins.__xonsh_stderr_uncaptured__ is not None: stderr = builtins.__xonsh_stderr_uncaptured__ uninew = (ix == last_cmd) and (not _capture_streams) alias = builtins.aliases.get(cmd[0], None) procinfo['alias'] = alias if (alias is None and builtins.__xonsh_env__.get('AUTO_CD') and len(cmd) == 1 and os.path.isdir(cmd[0]) and locate_binary(cmd[0]) is None): cmd.insert(0, 'cd') alias = builtins.aliases.get('cd', None) if callable(alias): aliased_cmd = alias else: if alias is not None: cmd = alias + cmd[1:] n = locate_binary(cmd[0]) if n is None: aliased_cmd = cmd else: try: aliased_cmd = get_script_subproc_command(n, cmd[1:]) except PermissionError: e = 'xonsh: subprocess mode: permission denied: {0}' raise XonshError(e.format(cmd[0])) _stdin_file = None if (stdin is not None and ENV.get('XONSH_STORE_STDIN') and captured == 'object' and 'cat' in __xonsh_commands_cache__ and 'tee' in __xonsh_commands_cache__): _stdin_file = tempfile.NamedTemporaryFile() cproc = Popen(['cat'], stdin=stdin, stdout=PIPE) tproc = Popen(['tee', _stdin_file.name], stdin=cproc.stdout, stdout=PIPE) stdin = tproc.stdout if callable(aliased_cmd): prev_is_proxy = True bgable = getattr(aliased_cmd, '__xonsh_backgroundable__', True) numargs = len(inspect.signature(aliased_cmd).parameters) if numargs == 2: cls = SimpleProcProxy if bgable else SimpleForegroundProcProxy elif numargs == 4: cls = ProcProxy if bgable else ForegroundProcProxy else: e = 'Expected callable with 2 or 4 arguments, not {}' raise XonshError(e.format(numargs)) proc = cls(aliased_cmd, cmd[1:], stdin, stdout, stderr, universal_newlines=uninew) else: prev_is_proxy = False usetee = ((stdout is None) and (not background) and ENV.get('XONSH_STORE_STDOUT', False)) cls = TeePTYProc if usetee else Popen subproc_kwargs = {} if ON_POSIX and cls is Popen: subproc_kwargs['preexec_fn'] = _subproc_pre try: proc = cls(aliased_cmd, universal_newlines=uninew, env=ENV.detype(), stdin=stdin, stdout=stdout, stderr=stderr, **subproc_kwargs) except PermissionError: e = 'xonsh: subprocess mode: permission denied: {0}' raise XonshError(e.format(aliased_cmd[0])) except FileNotFoundError: cmd = aliased_cmd[0] e = 'xonsh: subprocess mode: command not found: {0}'.format(cmd) sug = suggest_commands(cmd, ENV, builtins.aliases) if len(sug.strip()) > 0: e += '\n' + suggest_commands(cmd, ENV, builtins.aliases) raise XonshError(e) procs.append(proc) prev_proc = proc for proc in procs[:-1]: try: proc.stdout.close() except OSError: pass if not prev_is_proxy: add_job({ 'cmds': cmds, 'pids': [i.pid for i in procs], 'obj': prev_proc, 'bg': background }) if (ENV.get('XONSH_INTERACTIVE') and not ENV.get('XONSH_STORE_STDOUT') and not _capture_streams): # set title here to get current command running try: builtins.__xonsh_shell__.settitle() except AttributeError: pass if background: return if prev_is_proxy: prev_proc.wait() wait_for_active_job() hist = builtins.__xonsh_history__ hist.last_cmd_rtn = prev_proc.returncode # get output output = b'' if write_target is None: if _stdout_name is not None: with open(_stdout_name, 'rb') as stdoutfile: output = stdoutfile.read() try: _nstdout.close() except: pass os.unlink(_stdout_name) elif prev_proc.stdout not in (None, sys.stdout): output = prev_proc.stdout.read() if _capture_streams: # to get proper encoding from Popen, we have to # use a byte stream and then implement universal_newlines here output = output.decode(encoding=ENV.get('XONSH_ENCODING'), errors=ENV.get('XONSH_ENCODING_ERRORS')) output = output.replace('\r\n', '\n') else: hist.last_cmd_out = output if captured == 'object': # get stderr as well named = _stderr_name is not None unnamed = prev_proc.stderr not in {None, sys.stderr} if named: with open(_stderr_name, 'rb') as stderrfile: errout = stderrfile.read() try: _nstderr.close() except: pass os.unlink(_stderr_name) elif unnamed: errout = prev_proc.stderr.read() if named or unnamed: errout = errout.decode(encoding=ENV.get('XONSH_ENCODING'), errors=ENV.get('XONSH_ENCODING_ERRORS')) errout = errout.replace('\r\n', '\n') procinfo['stderr'] = errout if getattr(prev_proc, 'signal', None): sig, core = prev_proc.signal sig_str = SIGNAL_MESSAGES.get(sig) if sig_str: if core: sig_str += ' (core dumped)' print(sig_str, file=sys.stderr) if (not prev_is_proxy and hist.last_cmd_rtn is not None and hist.last_cmd_rtn > 0 and ENV.get('RAISE_SUBPROC_ERROR')): raise CalledProcessError(hist.last_cmd_rtn, aliased_cmd, output=output) if captured == 'stdout': return output elif captured is not False: procinfo['executed_cmd'] = aliased_cmd procinfo['pid'] = prev_proc.pid procinfo['returncode'] = prev_proc.returncode procinfo['timestamp'] = (starttime, time.time()) if captured == 'object': procinfo['stdout'] = output if _stdin_file is not None: _stdin_file.seek(0) procinfo['stdin'] = _stdin_file.read().decode() _stdin_file.close() return CompletedCommand(**procinfo) else: return HiddenCompletedCommand(**procinfo)
def run_subproc(cmds, captured=True): """Runs a subprocess, in its many forms. This takes a list of 'commands,' which may be a list of command line arguments or a string, representing a special connecting character. For example:: $ ls | grep wakka is represented by the following cmds:: [['ls'], '|', ['grep', 'wakka']] Lastly, the captured argument affects only the last real command. """ global ENV background = False if cmds[-1] == '&': background = True cmds = cmds[:-1] write_target = None last_cmd = len(cmds) - 1 prev = None procs = [] prev_proc = None for ix, cmd in enumerate(cmds): stdin = None stdout = None stderr = None if isinstance(cmd, string_types): prev = cmd continue streams = {} while True: if len(cmd) >= 3 and _is_redirect(cmd[-2]): _redirect_io(streams, cmd[-2], cmd[-1]) cmd = cmd[:-2] elif len(cmd) >= 2 and _is_redirect(cmd[-1]): _redirect_io(streams, cmd[-1]) cmd = cmd[:-1] elif len(cmd) >= 3 and cmd[0] == '<': _redirect_io(streams, cmd[0], cmd[1]) cmd = cmd[2:] else: break # set standard input if 'stdin' in streams: if prev_proc is not None: raise XonshError('Multiple inputs for stdin') stdin = streams['stdin'] elif prev_proc is not None: stdin = prev_proc.stdout # set standard output if 'stdout' in streams: if ix != last_cmd: raise XonshError('Multiple redirects for stdout') stdout = streams['stdout'] elif captured or ix != last_cmd: stdout = PIPE else: stdout = None # set standard error if 'stderr' in streams: stderr = streams['stderr'] uninew = ix == last_cmd alias = builtins.aliases.get(cmd[0], None) if callable(alias): aliased_cmd = alias else: if alias is not None: cmd = alias + cmd[1:] n = _get_runnable_name(cmd[0]) if n is None: aliased_cmd = cmd else: try: aliased_cmd = get_script_subproc_command(n, cmd[1:]) except PermissionError: e = 'xonsh: subprocess mode: permission denied: {0}' raise XonshError(e.format(cmd[0])) if callable(aliased_cmd): prev_is_proxy = True numargs = len(inspect.signature(aliased_cmd).parameters) if numargs == 2: cls = SimpleProcProxy elif numargs == 4: cls = ProcProxy else: e = 'Expected callable with 2 or 4 arguments, not {}' raise XonshError(e.format(numargs)) proc = cls(aliased_cmd, cmd[1:], stdin, stdout, stderr, universal_newlines=uninew) else: prev_is_proxy = False subproc_kwargs = {} if ON_POSIX: subproc_kwargs['preexec_fn'] = _subproc_pre try: proc = Popen(aliased_cmd, universal_newlines=uninew, env=ENV.detype(), stdin=stdin, stdout=stdout, stderr=stderr, **subproc_kwargs) except PermissionError: e = 'xonsh: subprocess mode: permission denied: {0}' raise XonshError(e.format(aliased_cmd[0])) except FileNotFoundError: cmd = aliased_cmd[0] e = 'xonsh: subprocess mode: command not found: {0}'.format(cmd) sug = suggest_commands(cmd, ENV, builtins.aliases) if len(sug.strip()) > 0: e += '\n' + suggest_commands(cmd, ENV, builtins.aliases) raise XonshError(e) procs.append(proc) prev = None prev_proc = proc for proc in procs[:-1]: try: proc.stdout.close() except OSError: pass if not prev_is_proxy: add_job({ 'cmds': cmds, 'pids': [i.pid for i in procs], 'obj': prev_proc, 'bg': background }) if background: return if prev_is_proxy: prev_proc.wait() wait_for_active_job() if write_target is None: # get output output = '' if prev_proc.stdout not in (None, sys.stdout): output = prev_proc.stdout.read() if captured: return output elif last_stdout not in (PIPE, None, sys.stdout): last_stdout.close()
def run_subproc(cmds, captured=True): """Runs a subprocess, in its many forms. This takes a list of 'commands,' which may be a list of command line arguments or a string, representing a special connecting character. For example:: $ ls | grep wakka is represented by the following cmds:: [['ls'], '|', ['grep', 'wakka']] Lastly, the captured argument affects only the last real command. """ global ENV background = False if cmds[-1] == '&': background = True cmds = cmds[:-1] write_target = None last_cmd = len(cmds) - 1 prev = None procs = [] prev_proc = None for ix, cmd in enumerate(cmds): stdin = None stdout = None stderr = None if isinstance(cmd, string_types): prev = cmd continue streams = {} while True: if len(cmd) >= 3 and _is_redirect(cmd[-2]): _redirect_io(streams, cmd[-2], cmd[-1]) cmd = cmd[:-2] elif len(cmd) >= 2 and _is_redirect(cmd[-1]): _redirect_io(streams, cmd[-1]) cmd = cmd[:-1] elif len(cmd) >= 3 and cmd[0] == '<': _redirect_io(streams, cmd[0], cmd[1]) cmd = cmd[2:] else: break # set standard input if 'stdin' in streams: if prev_proc is not None: raise XonshError('Multiple inputs for stdin') stdin = streams['stdin'] elif prev_proc is not None: stdin = prev_proc.stdout # set standard output if 'stdout' in streams: if ix != last_cmd: raise XonshError('Multiple redirects for stdout') stdout = streams['stdout'] elif captured or ix != last_cmd: stdout = PIPE else: stdout = None # set standard error if 'stderr' in streams: stderr = streams['stderr'] uninew = (ix == last_cmd) and (not captured) alias = builtins.aliases.get(cmd[0], None) if (alias is None and builtins.__xonsh_env__.get('AUTO_CD') and len(cmds)==1 and os.path.isdir(cmd[0]) and locate_binary(cmd[0], cwd=None) is None): cmd.insert(0, 'cd') alias = builtins.aliases.get('cd', None) if callable(alias): aliased_cmd = alias else: if alias is not None: cmd = alias + cmd[1:] n = _get_runnable_name(cmd[0]) if n is None: aliased_cmd = cmd else: try: aliased_cmd = get_script_subproc_command(n, cmd[1:]) except PermissionError: e = 'xonsh: subprocess mode: permission denied: {0}' raise XonshError(e.format(cmd[0])) if callable(aliased_cmd): prev_is_proxy = True numargs = len(inspect.signature(aliased_cmd).parameters) if numargs == 2: cls = SimpleProcProxy elif numargs == 4: cls = ProcProxy else: e = 'Expected callable with 2 or 4 arguments, not {}' raise XonshError(e.format(numargs)) proc = cls(aliased_cmd, cmd[1:], stdin, stdout, stderr, universal_newlines=uninew) else: prev_is_proxy = False usetee = (stdout is None) and (not background) and \ ENV.get('XONSH_STORE_STDOUT', False) cls = TeePTYProc if usetee else Popen subproc_kwargs = {} if ON_POSIX and cls is Popen: subproc_kwargs['preexec_fn'] = _subproc_pre try: proc = cls(aliased_cmd, universal_newlines=uninew, env=ENV.detype(), stdin=stdin, stdout=stdout, stderr=stderr, **subproc_kwargs) except PermissionError: e = 'xonsh: subprocess mode: permission denied: {0}' raise XonshError(e.format(aliased_cmd[0])) except FileNotFoundError: cmd = aliased_cmd[0] e = 'xonsh: subprocess mode: command not found: {0}'.format(cmd) sug = suggest_commands(cmd, ENV, builtins.aliases) if len(sug.strip()) > 0: e += '\n' + suggest_commands(cmd, ENV, builtins.aliases) raise XonshError(e) procs.append(proc) prev = None prev_proc = proc for proc in procs[:-1]: try: proc.stdout.close() except OSError: pass if not prev_is_proxy: add_job({ 'cmds': cmds, 'pids': [i.pid for i in procs], 'obj': prev_proc, 'bg': background }) if background: return if prev_is_proxy: prev_proc.wait() wait_for_active_job() hist = builtins.__xonsh_history__ hist.last_cmd_rtn = prev_proc.returncode if write_target is None: # get output output = '' if prev_proc.stdout not in (None, sys.stdout): output = prev_proc.stdout.read() if captured: # to get proper encoding from Popen, we have to # use a byte stream and then implement universal_newlines here output = output.decode(encoding=ENV.get('XONSH_ENCODING'), errors=ENV.get('XONSH_ENCODING_ERRORS')) output = output.replace('\r\n', '\n') return output else: hist.last_cmd_out = output
def run_subproc(cmds, captured=True): """Runs a subprocess, in its many forms. This takes a list of 'commands,' which may be a list of command line arguments or a string, representing a special connecting character. For example:: $ ls | grep wakka is represented by the following cmds:: [['ls'], '|', ['grep', 'wakka']] Lastly, the captured argument affects only the last real command. """ global ENV last_stdout = PIPE if captured else None background = False if cmds[-1] == '&': background = True cmds = cmds[:-1] write_target = None if len(cmds) >= 3 and cmds[-2] in WRITER_MODES: write_target = cmds[-1][0] write_mode = WRITER_MODES[cmds[-2]] cmds = cmds[:-2] if write_target is not None: try: last_stdout = open(write_target, write_mode) except FileNotFoundError: e = 'xonsh: {0}: no such file or directory' raise XonshError(e.format(write_target)) else: last_stdout = PIPE last_cmd = cmds[-1] prev = None procs = [] prev_proc = None for cmd in cmds: if isinstance(cmd, string_types): prev = cmd continue stdout = last_stdout if cmd is last_cmd else PIPE uninew = cmd is last_cmd alias = builtins.aliases.get(cmd[0], None) if _is_runnable_name(cmd[0]): try: aliased_cmd = get_script_subproc_command(cmd[0], cmd[1:]) except PermissionError: e = 'xonsh: subprocess mode: permission denied: {0}' raise XonshError(e.format(cmd[0])) elif alias is None: aliased_cmd = cmd elif callable(alias): aliased_cmd = alias else: aliased_cmd = alias + cmd[1:] # compute stdin for subprocess if prev_proc is None: stdin = None else: stdin = prev_proc.stdout if callable(aliased_cmd): prev_is_proxy = True numargs = len(inspect.signature(aliased_cmd).parameters) if numargs == 2: cls = SimpleProcProxy elif numargs == 4: cls = ProcProxy else: e = 'Expected callable with 2 or 4 arguments, not {}' raise XonshError(e.format(numargs)) proc = cls(aliased_cmd, cmd[1:], stdin, stdout, None, universal_newlines=uninew) else: prev_is_proxy = False subproc_kwargs = {} if ON_POSIX: subproc_kwargs['preexec_fn'] = _subproc_pre try: proc = Popen(aliased_cmd, universal_newlines=uninew, env=ENV.detype(), stdin=stdin, stdout=stdout, **subproc_kwargs) except PermissionError: e = 'xonsh: subprocess mode: permission denied: {0}' raise XonshError(e.format(aliased_cmd[0])) except FileNotFoundError: cmd = aliased_cmd[0] e = 'xonsh: subprocess mode: command not found: {0}'.format(cmd) e += '\n' + suggest_commands(cmd, ENV, builtins.aliases) raise XonshError(e) procs.append(proc) prev = None prev_proc = proc for proc in procs[:-1]: try: proc.stdout.close() except OSError: pass if not prev_is_proxy: add_job({ 'cmds': cmds, 'pids': [i.pid for i in procs], 'obj': prev_proc, 'bg': background }) if background: return if prev_is_proxy: prev_proc.wait() wait_for_active_job() if write_target is None: # get output output = '' if prev_proc.stdout not in (None, sys.stdout): output = prev_proc.stdout.read() if captured: return output elif last_stdout not in (PIPE, None, sys.stdout): last_stdout.close()
def run_subproc(cmds, captured=True): """Runs a subprocess, in its many forms. This takes a list of 'commands,' which may be a list of command line arguments or a string, representing a special connecting character. For example:: $ ls | grep wakka is represented by the following cmds:: [['ls'], '|', ['grep', 'wakka']] Lastly, the captured argument affects only the last real command. """ global ENV last_stdout = PIPE if captured else None background = False if cmds[-1] == '&': background = True cmds = cmds[:-1] write_target = None if len(cmds) >= 3 and cmds[-2] in WRITER_MODES: write_target = cmds[-1][0] write_mode = WRITER_MODES[cmds[-2]] cmds = cmds[:-2] last_stdout = PIPE last_cmd = cmds[-1] prev = None procs = [] prev_proc = None for cmd in cmds: if isinstance(cmd, string_types): prev = cmd continue stdout = last_stdout if cmd is last_cmd else PIPE uninew = cmd is last_cmd alias = builtins.aliases.get(cmd[0], None) if is_script(cmd[0]): try: aliased_cmd = get_script_subproc_command(cmd[0], cmd[1:]) except PermissionError: e = 'xonsh: subprocess mode: permission denied: {0}' print(e.format(cmd[0])) return elif alias is None: aliased_cmd = cmd elif callable(alias): prev_proc = _run_callable_subproc(alias, cmd[1:], captured=captured, prev_proc=prev_proc, stdout=stdout) continue else: aliased_cmd = alias + cmd[1:] # compute stdin for subprocess prev_is_proxy = isinstance(prev_proc, ProcProxy) if prev_proc is None: stdin = None elif prev_is_proxy: stdin = PIPE else: stdin = prev_proc.stdout try: proc = Popen(aliased_cmd, universal_newlines=uninew, env=ENV.detype(), stdin=stdin, stdout=stdout) except PermissionError: cmd = aliased_cmd[0] print('xonsh: subprocess mode: permission denied: {0}'.format(cmd)) return except FileNotFoundError: cmd = aliased_cmd[0] print('xonsh: subprocess mode: command not found: {0}'.format(cmd)) print(suggest_commands(cmd, ENV, builtins.aliases), end='') return if prev_is_proxy: proc.communicate(input=prev_proc.stdout) procs.append(proc) prev = None prev_proc = proc for proc in procs[:-1]: proc.stdout.close() if background: return # get output if isinstance(prev_proc, ProcProxy): output = prev_proc.stdout else: # the following prevents Crtl-c from being interpreted by xonsh # while running a subprocess while True: try: output = prev_proc.communicate()[0] break except KeyboardInterrupt: pass # write the output if we should if write_target is not None: try: with open(write_target, write_mode) as f: f.write(output) except FileNotFoundError: print('xonsh: {0}: no such file or directory'.format(write_target)) if captured: return output