1*cda5da8dSAndroid Build Coastguard Worker""" 2*cda5da8dSAndroid Build Coastguard WorkerBasic subprocess implementation for POSIX which only uses os functions. Only 3*cda5da8dSAndroid Build Coastguard Workerimplement features required by setup.py to build C extension modules when 4*cda5da8dSAndroid Build Coastguard Workersubprocess is unavailable. setup.py is not used on Windows. 5*cda5da8dSAndroid Build Coastguard Worker""" 6*cda5da8dSAndroid Build Coastguard Workerimport os 7*cda5da8dSAndroid Build Coastguard Worker 8*cda5da8dSAndroid Build Coastguard Worker 9*cda5da8dSAndroid Build Coastguard Worker# distutils.spawn used by distutils.command.build_ext 10*cda5da8dSAndroid Build Coastguard Worker# calls subprocess.Popen().wait() 11*cda5da8dSAndroid Build Coastguard Workerclass Popen: 12*cda5da8dSAndroid Build Coastguard Worker def __init__(self, cmd, env=None): 13*cda5da8dSAndroid Build Coastguard Worker self._cmd = cmd 14*cda5da8dSAndroid Build Coastguard Worker self._env = env 15*cda5da8dSAndroid Build Coastguard Worker self.returncode = None 16*cda5da8dSAndroid Build Coastguard Worker 17*cda5da8dSAndroid Build Coastguard Worker def wait(self): 18*cda5da8dSAndroid Build Coastguard Worker pid = os.fork() 19*cda5da8dSAndroid Build Coastguard Worker if pid == 0: 20*cda5da8dSAndroid Build Coastguard Worker # Child process 21*cda5da8dSAndroid Build Coastguard Worker try: 22*cda5da8dSAndroid Build Coastguard Worker if self._env is not None: 23*cda5da8dSAndroid Build Coastguard Worker os.execve(self._cmd[0], self._cmd, self._env) 24*cda5da8dSAndroid Build Coastguard Worker else: 25*cda5da8dSAndroid Build Coastguard Worker os.execv(self._cmd[0], self._cmd) 26*cda5da8dSAndroid Build Coastguard Worker finally: 27*cda5da8dSAndroid Build Coastguard Worker os._exit(1) 28*cda5da8dSAndroid Build Coastguard Worker else: 29*cda5da8dSAndroid Build Coastguard Worker # Parent process 30*cda5da8dSAndroid Build Coastguard Worker _, status = os.waitpid(pid, 0) 31*cda5da8dSAndroid Build Coastguard Worker self.returncode = os.waitstatus_to_exitcode(status) 32*cda5da8dSAndroid Build Coastguard Worker 33*cda5da8dSAndroid Build Coastguard Worker return self.returncode 34*cda5da8dSAndroid Build Coastguard Worker 35*cda5da8dSAndroid Build Coastguard Worker 36*cda5da8dSAndroid Build Coastguard Workerdef _check_cmd(cmd): 37*cda5da8dSAndroid Build Coastguard Worker # Use regex [a-zA-Z0-9./-]+: reject empty string, space, etc. 38*cda5da8dSAndroid Build Coastguard Worker safe_chars = [] 39*cda5da8dSAndroid Build Coastguard Worker for first, last in (("a", "z"), ("A", "Z"), ("0", "9")): 40*cda5da8dSAndroid Build Coastguard Worker for ch in range(ord(first), ord(last) + 1): 41*cda5da8dSAndroid Build Coastguard Worker safe_chars.append(chr(ch)) 42*cda5da8dSAndroid Build Coastguard Worker safe_chars.append("./-") 43*cda5da8dSAndroid Build Coastguard Worker safe_chars = ''.join(safe_chars) 44*cda5da8dSAndroid Build Coastguard Worker 45*cda5da8dSAndroid Build Coastguard Worker if isinstance(cmd, (tuple, list)): 46*cda5da8dSAndroid Build Coastguard Worker check_strs = cmd 47*cda5da8dSAndroid Build Coastguard Worker elif isinstance(cmd, str): 48*cda5da8dSAndroid Build Coastguard Worker check_strs = [cmd] 49*cda5da8dSAndroid Build Coastguard Worker else: 50*cda5da8dSAndroid Build Coastguard Worker return False 51*cda5da8dSAndroid Build Coastguard Worker 52*cda5da8dSAndroid Build Coastguard Worker for arg in check_strs: 53*cda5da8dSAndroid Build Coastguard Worker if not isinstance(arg, str): 54*cda5da8dSAndroid Build Coastguard Worker return False 55*cda5da8dSAndroid Build Coastguard Worker if not arg: 56*cda5da8dSAndroid Build Coastguard Worker # reject empty string 57*cda5da8dSAndroid Build Coastguard Worker return False 58*cda5da8dSAndroid Build Coastguard Worker for ch in arg: 59*cda5da8dSAndroid Build Coastguard Worker if ch not in safe_chars: 60*cda5da8dSAndroid Build Coastguard Worker return False 61*cda5da8dSAndroid Build Coastguard Worker 62*cda5da8dSAndroid Build Coastguard Worker return True 63*cda5da8dSAndroid Build Coastguard Worker 64*cda5da8dSAndroid Build Coastguard Worker 65*cda5da8dSAndroid Build Coastguard Worker# _aix_support used by distutil.util calls subprocess.check_output() 66*cda5da8dSAndroid Build Coastguard Workerdef check_output(cmd, **kwargs): 67*cda5da8dSAndroid Build Coastguard Worker if kwargs: 68*cda5da8dSAndroid Build Coastguard Worker raise NotImplementedError(repr(kwargs)) 69*cda5da8dSAndroid Build Coastguard Worker 70*cda5da8dSAndroid Build Coastguard Worker if not _check_cmd(cmd): 71*cda5da8dSAndroid Build Coastguard Worker raise ValueError(f"unsupported command: {cmd!r}") 72*cda5da8dSAndroid Build Coastguard Worker 73*cda5da8dSAndroid Build Coastguard Worker tmp_filename = "check_output.tmp" 74*cda5da8dSAndroid Build Coastguard Worker if not isinstance(cmd, str): 75*cda5da8dSAndroid Build Coastguard Worker cmd = " ".join(cmd) 76*cda5da8dSAndroid Build Coastguard Worker cmd = f"{cmd} >{tmp_filename}" 77*cda5da8dSAndroid Build Coastguard Worker 78*cda5da8dSAndroid Build Coastguard Worker try: 79*cda5da8dSAndroid Build Coastguard Worker # system() spawns a shell 80*cda5da8dSAndroid Build Coastguard Worker status = os.system(cmd) 81*cda5da8dSAndroid Build Coastguard Worker exitcode = os.waitstatus_to_exitcode(status) 82*cda5da8dSAndroid Build Coastguard Worker if exitcode: 83*cda5da8dSAndroid Build Coastguard Worker raise ValueError(f"Command {cmd!r} returned non-zero " 84*cda5da8dSAndroid Build Coastguard Worker f"exit status {exitcode!r}") 85*cda5da8dSAndroid Build Coastguard Worker 86*cda5da8dSAndroid Build Coastguard Worker try: 87*cda5da8dSAndroid Build Coastguard Worker with open(tmp_filename, "rb") as fp: 88*cda5da8dSAndroid Build Coastguard Worker stdout = fp.read() 89*cda5da8dSAndroid Build Coastguard Worker except FileNotFoundError: 90*cda5da8dSAndroid Build Coastguard Worker stdout = b'' 91*cda5da8dSAndroid Build Coastguard Worker finally: 92*cda5da8dSAndroid Build Coastguard Worker try: 93*cda5da8dSAndroid Build Coastguard Worker os.unlink(tmp_filename) 94*cda5da8dSAndroid Build Coastguard Worker except OSError: 95*cda5da8dSAndroid Build Coastguard Worker pass 96*cda5da8dSAndroid Build Coastguard Worker 97*cda5da8dSAndroid Build Coastguard Worker return stdout 98