| """Posix-specific implementation of process utilities. |
| |
| This file is only meant to be imported by process.py, not by end-users. |
| """ |
|
|
| |
| |
| |
| |
| |
| |
|
|
| |
| |
| |
|
|
| |
| import errno |
| import os |
| import subprocess as sp |
| import sys |
|
|
| |
| from ._process_common import getoutput, arg_split |
| from IPython.utils.encoding import DEFAULT_ENCODING |
|
|
| |
| |
| |
|
|
| class ProcessHandler(object): |
| """Execute subprocesses under the control of pexpect. |
| """ |
| |
| |
| |
| read_timeout = 0.05 |
|
|
| |
| |
| terminate_timeout = 0.2 |
|
|
| |
| logfile = None |
|
|
| |
| _sh = None |
|
|
| @property |
| def sh(self): |
| if self._sh is None: |
| import pexpect |
| shell_name = os.environ.get("SHELL", "sh") |
| self._sh = pexpect.which(shell_name) |
| if self._sh is None: |
| raise OSError('"{}" shell not found'.format(shell_name)) |
|
|
| return self._sh |
|
|
| def __init__(self, logfile=None, read_timeout=None, terminate_timeout=None): |
| """Arguments are used for pexpect calls.""" |
| self.read_timeout = (ProcessHandler.read_timeout if read_timeout is |
| None else read_timeout) |
| self.terminate_timeout = (ProcessHandler.terminate_timeout if |
| terminate_timeout is None else |
| terminate_timeout) |
| self.logfile = sys.stdout if logfile is None else logfile |
|
|
| def getoutput(self, cmd): |
| """Run a command and return its stdout/stderr as a string. |
| |
| Parameters |
| ---------- |
| cmd : str |
| A command to be executed in the system shell. |
| |
| Returns |
| ------- |
| output : str |
| A string containing the combination of stdout and stderr from the |
| subprocess, in whatever order the subprocess originally wrote to its |
| file descriptors (so the order of the information in this string is the |
| correct order as would be seen if running the command in a terminal). |
| """ |
| import pexpect |
| try: |
| return pexpect.run(self.sh, args=['-c', cmd]).replace('\r\n', '\n') |
| except KeyboardInterrupt: |
| print('^C', file=sys.stderr, end='') |
|
|
| def getoutput_pexpect(self, cmd): |
| """Run a command and return its stdout/stderr as a string. |
| |
| Parameters |
| ---------- |
| cmd : str |
| A command to be executed in the system shell. |
| |
| Returns |
| ------- |
| output : str |
| A string containing the combination of stdout and stderr from the |
| subprocess, in whatever order the subprocess originally wrote to its |
| file descriptors (so the order of the information in this string is the |
| correct order as would be seen if running the command in a terminal). |
| """ |
| import pexpect |
| try: |
| return pexpect.run(self.sh, args=['-c', cmd]).replace('\r\n', '\n') |
| except KeyboardInterrupt: |
| print('^C', file=sys.stderr, end='') |
|
|
| def system(self, cmd): |
| """Execute a command in a subshell. |
| |
| Parameters |
| ---------- |
| cmd : str |
| A command to be executed in the system shell. |
| |
| Returns |
| ------- |
| int : child's exitstatus |
| """ |
| import pexpect |
|
|
| |
| enc = DEFAULT_ENCODING |
| |
| |
| |
| patterns = [pexpect.TIMEOUT, pexpect.EOF] |
| |
| |
| |
| EOF_index = patterns.index(pexpect.EOF) |
| |
| |
| |
| |
| out_size = 0 |
| try: |
| |
| |
| |
| |
| |
| if hasattr(pexpect, 'spawnb'): |
| child = pexpect.spawnb(self.sh, args=['-c', cmd]) |
| else: |
| child = pexpect.spawn(self.sh, args=['-c', cmd]) |
| flush = sys.stdout.flush |
| while True: |
| |
| |
| res_idx = child.expect_list(patterns, self.read_timeout) |
| print(child.before[out_size:].decode(enc, 'replace'), end='') |
| flush() |
| if res_idx==EOF_index: |
| break |
| |
| out_size = len(child.before) |
| except KeyboardInterrupt: |
| |
| |
| |
| child.sendline(chr(3)) |
| |
| |
| try: |
| out_size = len(child.before) |
| child.expect_list(patterns, self.terminate_timeout) |
| print(child.before[out_size:].decode(enc, 'replace'), end='') |
| sys.stdout.flush() |
| except KeyboardInterrupt: |
| |
| pass |
| finally: |
| |
| child.terminate(force=True) |
| |
| child.isalive() |
|
|
| |
| |
| |
| |
| |
| if child.exitstatus is None: |
| |
| if child.signalstatus is None: |
| |
| |
| return 0 |
| return -child.signalstatus |
| if child.exitstatus > 128: |
| return -(child.exitstatus - 128) |
| return child.exitstatus |
|
|
|
|
| |
| |
| |
| |
| |
| system = ProcessHandler().system |
|
|
| def check_pid(pid): |
| try: |
| os.kill(pid, 0) |
| except OSError as err: |
| if err.errno == errno.ESRCH: |
| return False |
| elif err.errno == errno.EPERM: |
| |
| return True |
| raise |
| else: |
| return True |
|
|