diff options
Diffstat (limited to 'contrib/tools/python3/src/Lib/_bootsubprocess.py')
| -rw-r--r-- | contrib/tools/python3/src/Lib/_bootsubprocess.py | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/contrib/tools/python3/src/Lib/_bootsubprocess.py b/contrib/tools/python3/src/Lib/_bootsubprocess.py new file mode 100644 index 00000000000..014782f616c --- /dev/null +++ b/contrib/tools/python3/src/Lib/_bootsubprocess.py @@ -0,0 +1,97 @@ +""" +Basic subprocess implementation for POSIX which only uses os functions. Only +implement features required by setup.py to build C extension modules when +subprocess is unavailable. setup.py is not used on Windows. +""" +import os + + +# distutils.spawn used by distutils.command.build_ext +# calls subprocess.Popen().wait() +class Popen: + def __init__(self, cmd, env=None): + self._cmd = cmd + self._env = env + self.returncode = None + + def wait(self): + pid = os.fork() + if pid == 0: + # Child process + try: + if self._env is not None: + os.execve(self._cmd[0], self._cmd, self._env) + else: + os.execv(self._cmd[0], self._cmd) + finally: + os._exit(1) + else: + # Parent process + _, status = os.waitpid(pid, 0) + self.returncode = os.waitstatus_to_exitcode(status) + + return self.returncode + + +def _check_cmd(cmd): + # Use regex [a-zA-Z0-9./-]+: reject empty string, space, etc. + safe_chars = [] + for first, last in (("a", "z"), ("A", "Z"), ("0", "9")): + for ch in range(ord(first), ord(last) + 1): + safe_chars.append(chr(ch)) + safe_chars.append("./-") + safe_chars = ''.join(safe_chars) + + if isinstance(cmd, (tuple, list)): + check_strs = cmd + elif isinstance(cmd, str): + check_strs = [cmd] + else: + return False + + for arg in check_strs: + if not isinstance(arg, str): + return False + if not arg: + # reject empty string + return False + for ch in arg: + if ch not in safe_chars: + return False + + return True + + +# _aix_support used by distutil.util calls subprocess.check_output() +def check_output(cmd, **kwargs): + if kwargs: + raise NotImplementedError(repr(kwargs)) + + if not _check_cmd(cmd): + raise ValueError(f"unsupported command: {cmd!r}") + + tmp_filename = "check_output.tmp" + if not isinstance(cmd, str): + cmd = " ".join(cmd) + cmd = f"{cmd} >{tmp_filename}" + + try: + # system() spawns a shell + status = os.system(cmd) + exitcode = os.waitstatus_to_exitcode(status) + if exitcode: + raise ValueError(f"Command {cmd!r} returned non-zero " + f"exit status {exitcode!r}") + + try: + with open(tmp_filename, "rb") as fp: + stdout = fp.read() + except FileNotFoundError: + stdout = b'' + finally: + try: + os.unlink(tmp_filename) + except OSError: + pass + + return stdout |
