1*cda5da8dSAndroid Build Coastguard Worker"""distutils.util 2*cda5da8dSAndroid Build Coastguard Worker 3*cda5da8dSAndroid Build Coastguard WorkerMiscellaneous utility functions -- anything that doesn't fit into 4*cda5da8dSAndroid Build Coastguard Workerone of the other *util.py modules. 5*cda5da8dSAndroid Build Coastguard Worker""" 6*cda5da8dSAndroid Build Coastguard Worker 7*cda5da8dSAndroid Build Coastguard Workerimport os 8*cda5da8dSAndroid Build Coastguard Workerimport re 9*cda5da8dSAndroid Build Coastguard Workerimport importlib.util 10*cda5da8dSAndroid Build Coastguard Workerimport string 11*cda5da8dSAndroid Build Coastguard Workerimport sys 12*cda5da8dSAndroid Build Coastguard Workerimport distutils 13*cda5da8dSAndroid Build Coastguard Workerfrom distutils.errors import DistutilsPlatformError 14*cda5da8dSAndroid Build Coastguard Workerfrom distutils.dep_util import newer 15*cda5da8dSAndroid Build Coastguard Workerfrom distutils.spawn import spawn 16*cda5da8dSAndroid Build Coastguard Workerfrom distutils import log 17*cda5da8dSAndroid Build Coastguard Workerfrom distutils.errors import DistutilsByteCompileError 18*cda5da8dSAndroid Build Coastguard Worker 19*cda5da8dSAndroid Build Coastguard Workerdef get_host_platform(): 20*cda5da8dSAndroid Build Coastguard Worker """Return a string that identifies the current platform. This is used mainly to 21*cda5da8dSAndroid Build Coastguard Worker distinguish platform-specific build directories and platform-specific built 22*cda5da8dSAndroid Build Coastguard Worker distributions. Typically includes the OS name and version and the 23*cda5da8dSAndroid Build Coastguard Worker architecture (as supplied by 'os.uname()'), although the exact information 24*cda5da8dSAndroid Build Coastguard Worker included depends on the OS; eg. on Linux, the kernel version isn't 25*cda5da8dSAndroid Build Coastguard Worker particularly important. 26*cda5da8dSAndroid Build Coastguard Worker 27*cda5da8dSAndroid Build Coastguard Worker Examples of returned values: 28*cda5da8dSAndroid Build Coastguard Worker linux-i586 29*cda5da8dSAndroid Build Coastguard Worker linux-alpha (?) 30*cda5da8dSAndroid Build Coastguard Worker solaris-2.6-sun4u 31*cda5da8dSAndroid Build Coastguard Worker 32*cda5da8dSAndroid Build Coastguard Worker Windows will return one of: 33*cda5da8dSAndroid Build Coastguard Worker win-amd64 (64bit Windows on AMD64 (aka x86_64, Intel64, EM64T, etc) 34*cda5da8dSAndroid Build Coastguard Worker win32 (all others - specifically, sys.platform is returned) 35*cda5da8dSAndroid Build Coastguard Worker 36*cda5da8dSAndroid Build Coastguard Worker For other non-POSIX platforms, currently just returns 'sys.platform'. 37*cda5da8dSAndroid Build Coastguard Worker 38*cda5da8dSAndroid Build Coastguard Worker """ 39*cda5da8dSAndroid Build Coastguard Worker if os.name == 'nt': 40*cda5da8dSAndroid Build Coastguard Worker if 'amd64' in sys.version.lower(): 41*cda5da8dSAndroid Build Coastguard Worker return 'win-amd64' 42*cda5da8dSAndroid Build Coastguard Worker if '(arm)' in sys.version.lower(): 43*cda5da8dSAndroid Build Coastguard Worker return 'win-arm32' 44*cda5da8dSAndroid Build Coastguard Worker if '(arm64)' in sys.version.lower(): 45*cda5da8dSAndroid Build Coastguard Worker return 'win-arm64' 46*cda5da8dSAndroid Build Coastguard Worker return sys.platform 47*cda5da8dSAndroid Build Coastguard Worker 48*cda5da8dSAndroid Build Coastguard Worker # Set for cross builds explicitly 49*cda5da8dSAndroid Build Coastguard Worker if "_PYTHON_HOST_PLATFORM" in os.environ: 50*cda5da8dSAndroid Build Coastguard Worker return os.environ["_PYTHON_HOST_PLATFORM"] 51*cda5da8dSAndroid Build Coastguard Worker 52*cda5da8dSAndroid Build Coastguard Worker if os.name != "posix" or not hasattr(os, 'uname'): 53*cda5da8dSAndroid Build Coastguard Worker # XXX what about the architecture? NT is Intel or Alpha, 54*cda5da8dSAndroid Build Coastguard Worker # Mac OS is M68k or PPC, etc. 55*cda5da8dSAndroid Build Coastguard Worker return sys.platform 56*cda5da8dSAndroid Build Coastguard Worker 57*cda5da8dSAndroid Build Coastguard Worker # Try to distinguish various flavours of Unix 58*cda5da8dSAndroid Build Coastguard Worker 59*cda5da8dSAndroid Build Coastguard Worker (osname, host, release, version, machine) = os.uname() 60*cda5da8dSAndroid Build Coastguard Worker 61*cda5da8dSAndroid Build Coastguard Worker # Convert the OS name to lowercase, remove '/' characters, and translate 62*cda5da8dSAndroid Build Coastguard Worker # spaces (for "Power Macintosh") 63*cda5da8dSAndroid Build Coastguard Worker osname = osname.lower().replace('/', '') 64*cda5da8dSAndroid Build Coastguard Worker machine = machine.replace(' ', '_') 65*cda5da8dSAndroid Build Coastguard Worker machine = machine.replace('/', '-') 66*cda5da8dSAndroid Build Coastguard Worker 67*cda5da8dSAndroid Build Coastguard Worker if osname[:5] == "linux": 68*cda5da8dSAndroid Build Coastguard Worker # At least on Linux/Intel, 'machine' is the processor -- 69*cda5da8dSAndroid Build Coastguard Worker # i386, etc. 70*cda5da8dSAndroid Build Coastguard Worker # XXX what about Alpha, SPARC, etc? 71*cda5da8dSAndroid Build Coastguard Worker return "%s-%s" % (osname, machine) 72*cda5da8dSAndroid Build Coastguard Worker elif osname[:5] == "sunos": 73*cda5da8dSAndroid Build Coastguard Worker if release[0] >= "5": # SunOS 5 == Solaris 2 74*cda5da8dSAndroid Build Coastguard Worker osname = "solaris" 75*cda5da8dSAndroid Build Coastguard Worker release = "%d.%s" % (int(release[0]) - 3, release[2:]) 76*cda5da8dSAndroid Build Coastguard Worker # We can't use "platform.architecture()[0]" because a 77*cda5da8dSAndroid Build Coastguard Worker # bootstrap problem. We use a dict to get an error 78*cda5da8dSAndroid Build Coastguard Worker # if some suspicious happens. 79*cda5da8dSAndroid Build Coastguard Worker bitness = {2147483647:"32bit", 9223372036854775807:"64bit"} 80*cda5da8dSAndroid Build Coastguard Worker machine += ".%s" % bitness[sys.maxsize] 81*cda5da8dSAndroid Build Coastguard Worker # fall through to standard osname-release-machine representation 82*cda5da8dSAndroid Build Coastguard Worker elif osname[:3] == "aix": 83*cda5da8dSAndroid Build Coastguard Worker from _aix_support import aix_platform 84*cda5da8dSAndroid Build Coastguard Worker return aix_platform() 85*cda5da8dSAndroid Build Coastguard Worker elif osname[:6] == "cygwin": 86*cda5da8dSAndroid Build Coastguard Worker osname = "cygwin" 87*cda5da8dSAndroid Build Coastguard Worker rel_re = re.compile (r'[\d.]+', re.ASCII) 88*cda5da8dSAndroid Build Coastguard Worker m = rel_re.match(release) 89*cda5da8dSAndroid Build Coastguard Worker if m: 90*cda5da8dSAndroid Build Coastguard Worker release = m.group() 91*cda5da8dSAndroid Build Coastguard Worker elif osname[:6] == "darwin": 92*cda5da8dSAndroid Build Coastguard Worker import _osx_support, distutils.sysconfig 93*cda5da8dSAndroid Build Coastguard Worker osname, release, machine = _osx_support.get_platform_osx( 94*cda5da8dSAndroid Build Coastguard Worker distutils.sysconfig.get_config_vars(), 95*cda5da8dSAndroid Build Coastguard Worker osname, release, machine) 96*cda5da8dSAndroid Build Coastguard Worker 97*cda5da8dSAndroid Build Coastguard Worker return "%s-%s-%s" % (osname, release, machine) 98*cda5da8dSAndroid Build Coastguard Worker 99*cda5da8dSAndroid Build Coastguard Workerdef get_platform(): 100*cda5da8dSAndroid Build Coastguard Worker if os.name == 'nt': 101*cda5da8dSAndroid Build Coastguard Worker TARGET_TO_PLAT = { 102*cda5da8dSAndroid Build Coastguard Worker 'x86' : 'win32', 103*cda5da8dSAndroid Build Coastguard Worker 'x64' : 'win-amd64', 104*cda5da8dSAndroid Build Coastguard Worker 'arm' : 'win-arm32', 105*cda5da8dSAndroid Build Coastguard Worker } 106*cda5da8dSAndroid Build Coastguard Worker return TARGET_TO_PLAT.get(os.environ.get('VSCMD_ARG_TGT_ARCH')) or get_host_platform() 107*cda5da8dSAndroid Build Coastguard Worker else: 108*cda5da8dSAndroid Build Coastguard Worker return get_host_platform() 109*cda5da8dSAndroid Build Coastguard Worker 110*cda5da8dSAndroid Build Coastguard Workerdef convert_path (pathname): 111*cda5da8dSAndroid Build Coastguard Worker """Return 'pathname' as a name that will work on the native filesystem, 112*cda5da8dSAndroid Build Coastguard Worker i.e. split it on '/' and put it back together again using the current 113*cda5da8dSAndroid Build Coastguard Worker directory separator. Needed because filenames in the setup script are 114*cda5da8dSAndroid Build Coastguard Worker always supplied in Unix style, and have to be converted to the local 115*cda5da8dSAndroid Build Coastguard Worker convention before we can actually use them in the filesystem. Raises 116*cda5da8dSAndroid Build Coastguard Worker ValueError on non-Unix-ish systems if 'pathname' either starts or 117*cda5da8dSAndroid Build Coastguard Worker ends with a slash. 118*cda5da8dSAndroid Build Coastguard Worker """ 119*cda5da8dSAndroid Build Coastguard Worker if os.sep == '/': 120*cda5da8dSAndroid Build Coastguard Worker return pathname 121*cda5da8dSAndroid Build Coastguard Worker if not pathname: 122*cda5da8dSAndroid Build Coastguard Worker return pathname 123*cda5da8dSAndroid Build Coastguard Worker if pathname[0] == '/': 124*cda5da8dSAndroid Build Coastguard Worker raise ValueError("path '%s' cannot be absolute" % pathname) 125*cda5da8dSAndroid Build Coastguard Worker if pathname[-1] == '/': 126*cda5da8dSAndroid Build Coastguard Worker raise ValueError("path '%s' cannot end with '/'" % pathname) 127*cda5da8dSAndroid Build Coastguard Worker 128*cda5da8dSAndroid Build Coastguard Worker paths = pathname.split('/') 129*cda5da8dSAndroid Build Coastguard Worker while '.' in paths: 130*cda5da8dSAndroid Build Coastguard Worker paths.remove('.') 131*cda5da8dSAndroid Build Coastguard Worker if not paths: 132*cda5da8dSAndroid Build Coastguard Worker return os.curdir 133*cda5da8dSAndroid Build Coastguard Worker return os.path.join(*paths) 134*cda5da8dSAndroid Build Coastguard Worker 135*cda5da8dSAndroid Build Coastguard Worker# convert_path () 136*cda5da8dSAndroid Build Coastguard Worker 137*cda5da8dSAndroid Build Coastguard Worker 138*cda5da8dSAndroid Build Coastguard Workerdef change_root (new_root, pathname): 139*cda5da8dSAndroid Build Coastguard Worker """Return 'pathname' with 'new_root' prepended. If 'pathname' is 140*cda5da8dSAndroid Build Coastguard Worker relative, this is equivalent to "os.path.join(new_root,pathname)". 141*cda5da8dSAndroid Build Coastguard Worker Otherwise, it requires making 'pathname' relative and then joining the 142*cda5da8dSAndroid Build Coastguard Worker two, which is tricky on DOS/Windows and Mac OS. 143*cda5da8dSAndroid Build Coastguard Worker """ 144*cda5da8dSAndroid Build Coastguard Worker if os.name == 'posix': 145*cda5da8dSAndroid Build Coastguard Worker if not os.path.isabs(pathname): 146*cda5da8dSAndroid Build Coastguard Worker return os.path.join(new_root, pathname) 147*cda5da8dSAndroid Build Coastguard Worker else: 148*cda5da8dSAndroid Build Coastguard Worker return os.path.join(new_root, pathname[1:]) 149*cda5da8dSAndroid Build Coastguard Worker 150*cda5da8dSAndroid Build Coastguard Worker elif os.name == 'nt': 151*cda5da8dSAndroid Build Coastguard Worker (drive, path) = os.path.splitdrive(pathname) 152*cda5da8dSAndroid Build Coastguard Worker if path[0] == '\\': 153*cda5da8dSAndroid Build Coastguard Worker path = path[1:] 154*cda5da8dSAndroid Build Coastguard Worker return os.path.join(new_root, path) 155*cda5da8dSAndroid Build Coastguard Worker 156*cda5da8dSAndroid Build Coastguard Worker else: 157*cda5da8dSAndroid Build Coastguard Worker raise DistutilsPlatformError("nothing known about platform '%s'" % os.name) 158*cda5da8dSAndroid Build Coastguard Worker 159*cda5da8dSAndroid Build Coastguard Worker 160*cda5da8dSAndroid Build Coastguard Worker_environ_checked = 0 161*cda5da8dSAndroid Build Coastguard Workerdef check_environ (): 162*cda5da8dSAndroid Build Coastguard Worker """Ensure that 'os.environ' has all the environment variables we 163*cda5da8dSAndroid Build Coastguard Worker guarantee that users can use in config files, command-line options, 164*cda5da8dSAndroid Build Coastguard Worker etc. Currently this includes: 165*cda5da8dSAndroid Build Coastguard Worker HOME - user's home directory (Unix only) 166*cda5da8dSAndroid Build Coastguard Worker PLAT - description of the current platform, including hardware 167*cda5da8dSAndroid Build Coastguard Worker and OS (see 'get_platform()') 168*cda5da8dSAndroid Build Coastguard Worker """ 169*cda5da8dSAndroid Build Coastguard Worker global _environ_checked 170*cda5da8dSAndroid Build Coastguard Worker if _environ_checked: 171*cda5da8dSAndroid Build Coastguard Worker return 172*cda5da8dSAndroid Build Coastguard Worker 173*cda5da8dSAndroid Build Coastguard Worker if os.name == 'posix' and 'HOME' not in os.environ: 174*cda5da8dSAndroid Build Coastguard Worker try: 175*cda5da8dSAndroid Build Coastguard Worker import pwd 176*cda5da8dSAndroid Build Coastguard Worker os.environ['HOME'] = pwd.getpwuid(os.getuid())[5] 177*cda5da8dSAndroid Build Coastguard Worker except (ImportError, KeyError): 178*cda5da8dSAndroid Build Coastguard Worker # bpo-10496: if the current user identifier doesn't exist in the 179*cda5da8dSAndroid Build Coastguard Worker # password database, do nothing 180*cda5da8dSAndroid Build Coastguard Worker pass 181*cda5da8dSAndroid Build Coastguard Worker 182*cda5da8dSAndroid Build Coastguard Worker if 'PLAT' not in os.environ: 183*cda5da8dSAndroid Build Coastguard Worker os.environ['PLAT'] = get_platform() 184*cda5da8dSAndroid Build Coastguard Worker 185*cda5da8dSAndroid Build Coastguard Worker _environ_checked = 1 186*cda5da8dSAndroid Build Coastguard Worker 187*cda5da8dSAndroid Build Coastguard Worker 188*cda5da8dSAndroid Build Coastguard Workerdef subst_vars (s, local_vars): 189*cda5da8dSAndroid Build Coastguard Worker """Perform shell/Perl-style variable substitution on 'string'. Every 190*cda5da8dSAndroid Build Coastguard Worker occurrence of '$' followed by a name is considered a variable, and 191*cda5da8dSAndroid Build Coastguard Worker variable is substituted by the value found in the 'local_vars' 192*cda5da8dSAndroid Build Coastguard Worker dictionary, or in 'os.environ' if it's not in 'local_vars'. 193*cda5da8dSAndroid Build Coastguard Worker 'os.environ' is first checked/augmented to guarantee that it contains 194*cda5da8dSAndroid Build Coastguard Worker certain values: see 'check_environ()'. Raise ValueError for any 195*cda5da8dSAndroid Build Coastguard Worker variables not found in either 'local_vars' or 'os.environ'. 196*cda5da8dSAndroid Build Coastguard Worker """ 197*cda5da8dSAndroid Build Coastguard Worker check_environ() 198*cda5da8dSAndroid Build Coastguard Worker def _subst (match, local_vars=local_vars): 199*cda5da8dSAndroid Build Coastguard Worker var_name = match.group(1) 200*cda5da8dSAndroid Build Coastguard Worker if var_name in local_vars: 201*cda5da8dSAndroid Build Coastguard Worker return str(local_vars[var_name]) 202*cda5da8dSAndroid Build Coastguard Worker else: 203*cda5da8dSAndroid Build Coastguard Worker return os.environ[var_name] 204*cda5da8dSAndroid Build Coastguard Worker 205*cda5da8dSAndroid Build Coastguard Worker try: 206*cda5da8dSAndroid Build Coastguard Worker return re.sub(r'\$([a-zA-Z_][a-zA-Z_0-9]*)', _subst, s) 207*cda5da8dSAndroid Build Coastguard Worker except KeyError as var: 208*cda5da8dSAndroid Build Coastguard Worker raise ValueError("invalid variable '$%s'" % var) 209*cda5da8dSAndroid Build Coastguard Worker 210*cda5da8dSAndroid Build Coastguard Worker# subst_vars () 211*cda5da8dSAndroid Build Coastguard Worker 212*cda5da8dSAndroid Build Coastguard Worker 213*cda5da8dSAndroid Build Coastguard Workerdef grok_environment_error (exc, prefix="error: "): 214*cda5da8dSAndroid Build Coastguard Worker # Function kept for backward compatibility. 215*cda5da8dSAndroid Build Coastguard Worker # Used to try clever things with EnvironmentErrors, 216*cda5da8dSAndroid Build Coastguard Worker # but nowadays str(exception) produces good messages. 217*cda5da8dSAndroid Build Coastguard Worker return prefix + str(exc) 218*cda5da8dSAndroid Build Coastguard Worker 219*cda5da8dSAndroid Build Coastguard Worker 220*cda5da8dSAndroid Build Coastguard Worker# Needed by 'split_quoted()' 221*cda5da8dSAndroid Build Coastguard Worker_wordchars_re = _squote_re = _dquote_re = None 222*cda5da8dSAndroid Build Coastguard Workerdef _init_regex(): 223*cda5da8dSAndroid Build Coastguard Worker global _wordchars_re, _squote_re, _dquote_re 224*cda5da8dSAndroid Build Coastguard Worker _wordchars_re = re.compile(r'[^\\\'\"%s ]*' % string.whitespace) 225*cda5da8dSAndroid Build Coastguard Worker _squote_re = re.compile(r"'(?:[^'\\]|\\.)*'") 226*cda5da8dSAndroid Build Coastguard Worker _dquote_re = re.compile(r'"(?:[^"\\]|\\.)*"') 227*cda5da8dSAndroid Build Coastguard Worker 228*cda5da8dSAndroid Build Coastguard Workerdef split_quoted (s): 229*cda5da8dSAndroid Build Coastguard Worker """Split a string up according to Unix shell-like rules for quotes and 230*cda5da8dSAndroid Build Coastguard Worker backslashes. In short: words are delimited by spaces, as long as those 231*cda5da8dSAndroid Build Coastguard Worker spaces are not escaped by a backslash, or inside a quoted string. 232*cda5da8dSAndroid Build Coastguard Worker Single and double quotes are equivalent, and the quote characters can 233*cda5da8dSAndroid Build Coastguard Worker be backslash-escaped. The backslash is stripped from any two-character 234*cda5da8dSAndroid Build Coastguard Worker escape sequence, leaving only the escaped character. The quote 235*cda5da8dSAndroid Build Coastguard Worker characters are stripped from any quoted string. Returns a list of 236*cda5da8dSAndroid Build Coastguard Worker words. 237*cda5da8dSAndroid Build Coastguard Worker """ 238*cda5da8dSAndroid Build Coastguard Worker 239*cda5da8dSAndroid Build Coastguard Worker # This is a nice algorithm for splitting up a single string, since it 240*cda5da8dSAndroid Build Coastguard Worker # doesn't require character-by-character examination. It was a little 241*cda5da8dSAndroid Build Coastguard Worker # bit of a brain-bender to get it working right, though... 242*cda5da8dSAndroid Build Coastguard Worker if _wordchars_re is None: _init_regex() 243*cda5da8dSAndroid Build Coastguard Worker 244*cda5da8dSAndroid Build Coastguard Worker s = s.strip() 245*cda5da8dSAndroid Build Coastguard Worker words = [] 246*cda5da8dSAndroid Build Coastguard Worker pos = 0 247*cda5da8dSAndroid Build Coastguard Worker 248*cda5da8dSAndroid Build Coastguard Worker while s: 249*cda5da8dSAndroid Build Coastguard Worker m = _wordchars_re.match(s, pos) 250*cda5da8dSAndroid Build Coastguard Worker end = m.end() 251*cda5da8dSAndroid Build Coastguard Worker if end == len(s): 252*cda5da8dSAndroid Build Coastguard Worker words.append(s[:end]) 253*cda5da8dSAndroid Build Coastguard Worker break 254*cda5da8dSAndroid Build Coastguard Worker 255*cda5da8dSAndroid Build Coastguard Worker if s[end] in string.whitespace: # unescaped, unquoted whitespace: now 256*cda5da8dSAndroid Build Coastguard Worker words.append(s[:end]) # we definitely have a word delimiter 257*cda5da8dSAndroid Build Coastguard Worker s = s[end:].lstrip() 258*cda5da8dSAndroid Build Coastguard Worker pos = 0 259*cda5da8dSAndroid Build Coastguard Worker 260*cda5da8dSAndroid Build Coastguard Worker elif s[end] == '\\': # preserve whatever is being escaped; 261*cda5da8dSAndroid Build Coastguard Worker # will become part of the current word 262*cda5da8dSAndroid Build Coastguard Worker s = s[:end] + s[end+1:] 263*cda5da8dSAndroid Build Coastguard Worker pos = end+1 264*cda5da8dSAndroid Build Coastguard Worker 265*cda5da8dSAndroid Build Coastguard Worker else: 266*cda5da8dSAndroid Build Coastguard Worker if s[end] == "'": # slurp singly-quoted string 267*cda5da8dSAndroid Build Coastguard Worker m = _squote_re.match(s, end) 268*cda5da8dSAndroid Build Coastguard Worker elif s[end] == '"': # slurp doubly-quoted string 269*cda5da8dSAndroid Build Coastguard Worker m = _dquote_re.match(s, end) 270*cda5da8dSAndroid Build Coastguard Worker else: 271*cda5da8dSAndroid Build Coastguard Worker raise RuntimeError("this can't happen (bad char '%c')" % s[end]) 272*cda5da8dSAndroid Build Coastguard Worker 273*cda5da8dSAndroid Build Coastguard Worker if m is None: 274*cda5da8dSAndroid Build Coastguard Worker raise ValueError("bad string (mismatched %s quotes?)" % s[end]) 275*cda5da8dSAndroid Build Coastguard Worker 276*cda5da8dSAndroid Build Coastguard Worker (beg, end) = m.span() 277*cda5da8dSAndroid Build Coastguard Worker s = s[:beg] + s[beg+1:end-1] + s[end:] 278*cda5da8dSAndroid Build Coastguard Worker pos = m.end() - 2 279*cda5da8dSAndroid Build Coastguard Worker 280*cda5da8dSAndroid Build Coastguard Worker if pos >= len(s): 281*cda5da8dSAndroid Build Coastguard Worker words.append(s) 282*cda5da8dSAndroid Build Coastguard Worker break 283*cda5da8dSAndroid Build Coastguard Worker 284*cda5da8dSAndroid Build Coastguard Worker return words 285*cda5da8dSAndroid Build Coastguard Worker 286*cda5da8dSAndroid Build Coastguard Worker# split_quoted () 287*cda5da8dSAndroid Build Coastguard Worker 288*cda5da8dSAndroid Build Coastguard Worker 289*cda5da8dSAndroid Build Coastguard Workerdef execute (func, args, msg=None, verbose=0, dry_run=0): 290*cda5da8dSAndroid Build Coastguard Worker """Perform some action that affects the outside world (eg. by 291*cda5da8dSAndroid Build Coastguard Worker writing to the filesystem). Such actions are special because they 292*cda5da8dSAndroid Build Coastguard Worker are disabled by the 'dry_run' flag. This method takes care of all 293*cda5da8dSAndroid Build Coastguard Worker that bureaucracy for you; all you have to do is supply the 294*cda5da8dSAndroid Build Coastguard Worker function to call and an argument tuple for it (to embody the 295*cda5da8dSAndroid Build Coastguard Worker "external action" being performed), and an optional message to 296*cda5da8dSAndroid Build Coastguard Worker print. 297*cda5da8dSAndroid Build Coastguard Worker """ 298*cda5da8dSAndroid Build Coastguard Worker if msg is None: 299*cda5da8dSAndroid Build Coastguard Worker msg = "%s%r" % (func.__name__, args) 300*cda5da8dSAndroid Build Coastguard Worker if msg[-2:] == ',)': # correct for singleton tuple 301*cda5da8dSAndroid Build Coastguard Worker msg = msg[0:-2] + ')' 302*cda5da8dSAndroid Build Coastguard Worker 303*cda5da8dSAndroid Build Coastguard Worker log.info(msg) 304*cda5da8dSAndroid Build Coastguard Worker if not dry_run: 305*cda5da8dSAndroid Build Coastguard Worker func(*args) 306*cda5da8dSAndroid Build Coastguard Worker 307*cda5da8dSAndroid Build Coastguard Worker 308*cda5da8dSAndroid Build Coastguard Workerdef strtobool (val): 309*cda5da8dSAndroid Build Coastguard Worker """Convert a string representation of truth to true (1) or false (0). 310*cda5da8dSAndroid Build Coastguard Worker 311*cda5da8dSAndroid Build Coastguard Worker True values are 'y', 'yes', 't', 'true', 'on', and '1'; false values 312*cda5da8dSAndroid Build Coastguard Worker are 'n', 'no', 'f', 'false', 'off', and '0'. Raises ValueError if 313*cda5da8dSAndroid Build Coastguard Worker 'val' is anything else. 314*cda5da8dSAndroid Build Coastguard Worker """ 315*cda5da8dSAndroid Build Coastguard Worker val = val.lower() 316*cda5da8dSAndroid Build Coastguard Worker if val in ('y', 'yes', 't', 'true', 'on', '1'): 317*cda5da8dSAndroid Build Coastguard Worker return 1 318*cda5da8dSAndroid Build Coastguard Worker elif val in ('n', 'no', 'f', 'false', 'off', '0'): 319*cda5da8dSAndroid Build Coastguard Worker return 0 320*cda5da8dSAndroid Build Coastguard Worker else: 321*cda5da8dSAndroid Build Coastguard Worker raise ValueError("invalid truth value %r" % (val,)) 322*cda5da8dSAndroid Build Coastguard Worker 323*cda5da8dSAndroid Build Coastguard Worker 324*cda5da8dSAndroid Build Coastguard Workerdef byte_compile (py_files, 325*cda5da8dSAndroid Build Coastguard Worker optimize=0, force=0, 326*cda5da8dSAndroid Build Coastguard Worker prefix=None, base_dir=None, 327*cda5da8dSAndroid Build Coastguard Worker verbose=1, dry_run=0, 328*cda5da8dSAndroid Build Coastguard Worker direct=None): 329*cda5da8dSAndroid Build Coastguard Worker """Byte-compile a collection of Python source files to .pyc 330*cda5da8dSAndroid Build Coastguard Worker files in a __pycache__ subdirectory. 'py_files' is a list 331*cda5da8dSAndroid Build Coastguard Worker of files to compile; any files that don't end in ".py" are silently 332*cda5da8dSAndroid Build Coastguard Worker skipped. 'optimize' must be one of the following: 333*cda5da8dSAndroid Build Coastguard Worker 0 - don't optimize 334*cda5da8dSAndroid Build Coastguard Worker 1 - normal optimization (like "python -O") 335*cda5da8dSAndroid Build Coastguard Worker 2 - extra optimization (like "python -OO") 336*cda5da8dSAndroid Build Coastguard Worker If 'force' is true, all files are recompiled regardless of 337*cda5da8dSAndroid Build Coastguard Worker timestamps. 338*cda5da8dSAndroid Build Coastguard Worker 339*cda5da8dSAndroid Build Coastguard Worker The source filename encoded in each bytecode file defaults to the 340*cda5da8dSAndroid Build Coastguard Worker filenames listed in 'py_files'; you can modify these with 'prefix' and 341*cda5da8dSAndroid Build Coastguard Worker 'basedir'. 'prefix' is a string that will be stripped off of each 342*cda5da8dSAndroid Build Coastguard Worker source filename, and 'base_dir' is a directory name that will be 343*cda5da8dSAndroid Build Coastguard Worker prepended (after 'prefix' is stripped). You can supply either or both 344*cda5da8dSAndroid Build Coastguard Worker (or neither) of 'prefix' and 'base_dir', as you wish. 345*cda5da8dSAndroid Build Coastguard Worker 346*cda5da8dSAndroid Build Coastguard Worker If 'dry_run' is true, doesn't actually do anything that would 347*cda5da8dSAndroid Build Coastguard Worker affect the filesystem. 348*cda5da8dSAndroid Build Coastguard Worker 349*cda5da8dSAndroid Build Coastguard Worker Byte-compilation is either done directly in this interpreter process 350*cda5da8dSAndroid Build Coastguard Worker with the standard py_compile module, or indirectly by writing a 351*cda5da8dSAndroid Build Coastguard Worker temporary script and executing it. Normally, you should let 352*cda5da8dSAndroid Build Coastguard Worker 'byte_compile()' figure out to use direct compilation or not (see 353*cda5da8dSAndroid Build Coastguard Worker the source for details). The 'direct' flag is used by the script 354*cda5da8dSAndroid Build Coastguard Worker generated in indirect mode; unless you know what you're doing, leave 355*cda5da8dSAndroid Build Coastguard Worker it set to None. 356*cda5da8dSAndroid Build Coastguard Worker """ 357*cda5da8dSAndroid Build Coastguard Worker 358*cda5da8dSAndroid Build Coastguard Worker # Late import to fix a bootstrap issue: _posixsubprocess is built by 359*cda5da8dSAndroid Build Coastguard Worker # setup.py, but setup.py uses distutils. 360*cda5da8dSAndroid Build Coastguard Worker import subprocess 361*cda5da8dSAndroid Build Coastguard Worker 362*cda5da8dSAndroid Build Coastguard Worker # nothing is done if sys.dont_write_bytecode is True 363*cda5da8dSAndroid Build Coastguard Worker if sys.dont_write_bytecode: 364*cda5da8dSAndroid Build Coastguard Worker raise DistutilsByteCompileError('byte-compiling is disabled.') 365*cda5da8dSAndroid Build Coastguard Worker 366*cda5da8dSAndroid Build Coastguard Worker # First, if the caller didn't force us into direct or indirect mode, 367*cda5da8dSAndroid Build Coastguard Worker # figure out which mode we should be in. We take a conservative 368*cda5da8dSAndroid Build Coastguard Worker # approach: choose direct mode *only* if the current interpreter is 369*cda5da8dSAndroid Build Coastguard Worker # in debug mode and optimize is 0. If we're not in debug mode (-O 370*cda5da8dSAndroid Build Coastguard Worker # or -OO), we don't know which level of optimization this 371*cda5da8dSAndroid Build Coastguard Worker # interpreter is running with, so we can't do direct 372*cda5da8dSAndroid Build Coastguard Worker # byte-compilation and be certain that it's the right thing. Thus, 373*cda5da8dSAndroid Build Coastguard Worker # always compile indirectly if the current interpreter is in either 374*cda5da8dSAndroid Build Coastguard Worker # optimize mode, or if either optimization level was requested by 375*cda5da8dSAndroid Build Coastguard Worker # the caller. 376*cda5da8dSAndroid Build Coastguard Worker if direct is None: 377*cda5da8dSAndroid Build Coastguard Worker direct = (__debug__ and optimize == 0) 378*cda5da8dSAndroid Build Coastguard Worker 379*cda5da8dSAndroid Build Coastguard Worker # "Indirect" byte-compilation: write a temporary script and then 380*cda5da8dSAndroid Build Coastguard Worker # run it with the appropriate flags. 381*cda5da8dSAndroid Build Coastguard Worker if not direct: 382*cda5da8dSAndroid Build Coastguard Worker try: 383*cda5da8dSAndroid Build Coastguard Worker from tempfile import mkstemp 384*cda5da8dSAndroid Build Coastguard Worker (script_fd, script_name) = mkstemp(".py") 385*cda5da8dSAndroid Build Coastguard Worker except ImportError: 386*cda5da8dSAndroid Build Coastguard Worker from tempfile import mktemp 387*cda5da8dSAndroid Build Coastguard Worker (script_fd, script_name) = None, mktemp(".py") 388*cda5da8dSAndroid Build Coastguard Worker log.info("writing byte-compilation script '%s'", script_name) 389*cda5da8dSAndroid Build Coastguard Worker if not dry_run: 390*cda5da8dSAndroid Build Coastguard Worker if script_fd is not None: 391*cda5da8dSAndroid Build Coastguard Worker script = os.fdopen(script_fd, "w") 392*cda5da8dSAndroid Build Coastguard Worker else: 393*cda5da8dSAndroid Build Coastguard Worker script = open(script_name, "w") 394*cda5da8dSAndroid Build Coastguard Worker 395*cda5da8dSAndroid Build Coastguard Worker with script: 396*cda5da8dSAndroid Build Coastguard Worker script.write("""\ 397*cda5da8dSAndroid Build Coastguard Workerfrom distutils.util import byte_compile 398*cda5da8dSAndroid Build Coastguard Workerfiles = [ 399*cda5da8dSAndroid Build Coastguard Worker""") 400*cda5da8dSAndroid Build Coastguard Worker 401*cda5da8dSAndroid Build Coastguard Worker # XXX would be nice to write absolute filenames, just for 402*cda5da8dSAndroid Build Coastguard Worker # safety's sake (script should be more robust in the face of 403*cda5da8dSAndroid Build Coastguard Worker # chdir'ing before running it). But this requires abspath'ing 404*cda5da8dSAndroid Build Coastguard Worker # 'prefix' as well, and that breaks the hack in build_lib's 405*cda5da8dSAndroid Build Coastguard Worker # 'byte_compile()' method that carefully tacks on a trailing 406*cda5da8dSAndroid Build Coastguard Worker # slash (os.sep really) to make sure the prefix here is "just 407*cda5da8dSAndroid Build Coastguard Worker # right". This whole prefix business is rather delicate -- the 408*cda5da8dSAndroid Build Coastguard Worker # problem is that it's really a directory, but I'm treating it 409*cda5da8dSAndroid Build Coastguard Worker # as a dumb string, so trailing slashes and so forth matter. 410*cda5da8dSAndroid Build Coastguard Worker 411*cda5da8dSAndroid Build Coastguard Worker #py_files = map(os.path.abspath, py_files) 412*cda5da8dSAndroid Build Coastguard Worker #if prefix: 413*cda5da8dSAndroid Build Coastguard Worker # prefix = os.path.abspath(prefix) 414*cda5da8dSAndroid Build Coastguard Worker 415*cda5da8dSAndroid Build Coastguard Worker script.write(",\n".join(map(repr, py_files)) + "]\n") 416*cda5da8dSAndroid Build Coastguard Worker script.write(""" 417*cda5da8dSAndroid Build Coastguard Workerbyte_compile(files, optimize=%r, force=%r, 418*cda5da8dSAndroid Build Coastguard Worker prefix=%r, base_dir=%r, 419*cda5da8dSAndroid Build Coastguard Worker verbose=%r, dry_run=0, 420*cda5da8dSAndroid Build Coastguard Worker direct=1) 421*cda5da8dSAndroid Build Coastguard Worker""" % (optimize, force, prefix, base_dir, verbose)) 422*cda5da8dSAndroid Build Coastguard Worker 423*cda5da8dSAndroid Build Coastguard Worker msg = distutils._DEPRECATION_MESSAGE 424*cda5da8dSAndroid Build Coastguard Worker cmd = [sys.executable] 425*cda5da8dSAndroid Build Coastguard Worker cmd.extend(subprocess._optim_args_from_interpreter_flags()) 426*cda5da8dSAndroid Build Coastguard Worker cmd.append(f'-Wignore:{msg}:DeprecationWarning') 427*cda5da8dSAndroid Build Coastguard Worker cmd.append(script_name) 428*cda5da8dSAndroid Build Coastguard Worker spawn(cmd, dry_run=dry_run) 429*cda5da8dSAndroid Build Coastguard Worker execute(os.remove, (script_name,), "removing %s" % script_name, 430*cda5da8dSAndroid Build Coastguard Worker dry_run=dry_run) 431*cda5da8dSAndroid Build Coastguard Worker 432*cda5da8dSAndroid Build Coastguard Worker # "Direct" byte-compilation: use the py_compile module to compile 433*cda5da8dSAndroid Build Coastguard Worker # right here, right now. Note that the script generated in indirect 434*cda5da8dSAndroid Build Coastguard Worker # mode simply calls 'byte_compile()' in direct mode, a weird sort of 435*cda5da8dSAndroid Build Coastguard Worker # cross-process recursion. Hey, it works! 436*cda5da8dSAndroid Build Coastguard Worker else: 437*cda5da8dSAndroid Build Coastguard Worker from py_compile import compile 438*cda5da8dSAndroid Build Coastguard Worker 439*cda5da8dSAndroid Build Coastguard Worker for file in py_files: 440*cda5da8dSAndroid Build Coastguard Worker if file[-3:] != ".py": 441*cda5da8dSAndroid Build Coastguard Worker # This lets us be lazy and not filter filenames in 442*cda5da8dSAndroid Build Coastguard Worker # the "install_lib" command. 443*cda5da8dSAndroid Build Coastguard Worker continue 444*cda5da8dSAndroid Build Coastguard Worker 445*cda5da8dSAndroid Build Coastguard Worker # Terminology from the py_compile module: 446*cda5da8dSAndroid Build Coastguard Worker # cfile - byte-compiled file 447*cda5da8dSAndroid Build Coastguard Worker # dfile - purported source filename (same as 'file' by default) 448*cda5da8dSAndroid Build Coastguard Worker if optimize >= 0: 449*cda5da8dSAndroid Build Coastguard Worker opt = '' if optimize == 0 else optimize 450*cda5da8dSAndroid Build Coastguard Worker cfile = importlib.util.cache_from_source( 451*cda5da8dSAndroid Build Coastguard Worker file, optimization=opt) 452*cda5da8dSAndroid Build Coastguard Worker else: 453*cda5da8dSAndroid Build Coastguard Worker cfile = importlib.util.cache_from_source(file) 454*cda5da8dSAndroid Build Coastguard Worker dfile = file 455*cda5da8dSAndroid Build Coastguard Worker if prefix: 456*cda5da8dSAndroid Build Coastguard Worker if file[:len(prefix)] != prefix: 457*cda5da8dSAndroid Build Coastguard Worker raise ValueError("invalid prefix: filename %r doesn't start with %r" 458*cda5da8dSAndroid Build Coastguard Worker % (file, prefix)) 459*cda5da8dSAndroid Build Coastguard Worker dfile = dfile[len(prefix):] 460*cda5da8dSAndroid Build Coastguard Worker if base_dir: 461*cda5da8dSAndroid Build Coastguard Worker dfile = os.path.join(base_dir, dfile) 462*cda5da8dSAndroid Build Coastguard Worker 463*cda5da8dSAndroid Build Coastguard Worker cfile_base = os.path.basename(cfile) 464*cda5da8dSAndroid Build Coastguard Worker if direct: 465*cda5da8dSAndroid Build Coastguard Worker if force or newer(file, cfile): 466*cda5da8dSAndroid Build Coastguard Worker log.info("byte-compiling %s to %s", file, cfile_base) 467*cda5da8dSAndroid Build Coastguard Worker if not dry_run: 468*cda5da8dSAndroid Build Coastguard Worker compile(file, cfile, dfile) 469*cda5da8dSAndroid Build Coastguard Worker else: 470*cda5da8dSAndroid Build Coastguard Worker log.debug("skipping byte-compilation of %s to %s", 471*cda5da8dSAndroid Build Coastguard Worker file, cfile_base) 472*cda5da8dSAndroid Build Coastguard Worker 473*cda5da8dSAndroid Build Coastguard Worker# byte_compile () 474*cda5da8dSAndroid Build Coastguard Worker 475*cda5da8dSAndroid Build Coastguard Workerdef rfc822_escape (header): 476*cda5da8dSAndroid Build Coastguard Worker """Return a version of the string escaped for inclusion in an 477*cda5da8dSAndroid Build Coastguard Worker RFC-822 header, by ensuring there are 8 spaces space after each newline. 478*cda5da8dSAndroid Build Coastguard Worker """ 479*cda5da8dSAndroid Build Coastguard Worker lines = header.split('\n') 480*cda5da8dSAndroid Build Coastguard Worker sep = '\n' + 8 * ' ' 481*cda5da8dSAndroid Build Coastguard Worker return sep.join(lines) 482*cda5da8dSAndroid Build Coastguard Worker 483*cda5da8dSAndroid Build Coastguard Worker# 2to3 support 484*cda5da8dSAndroid Build Coastguard Worker 485*cda5da8dSAndroid Build Coastguard Workerdef run_2to3(files, fixer_names=None, options=None, explicit=None): 486*cda5da8dSAndroid Build Coastguard Worker """Invoke 2to3 on a list of Python files. 487*cda5da8dSAndroid Build Coastguard Worker The files should all come from the build area, as the 488*cda5da8dSAndroid Build Coastguard Worker modification is done in-place. To reduce the build time, 489*cda5da8dSAndroid Build Coastguard Worker only files modified since the last invocation of this 490*cda5da8dSAndroid Build Coastguard Worker function should be passed in the files argument.""" 491*cda5da8dSAndroid Build Coastguard Worker 492*cda5da8dSAndroid Build Coastguard Worker if not files: 493*cda5da8dSAndroid Build Coastguard Worker return 494*cda5da8dSAndroid Build Coastguard Worker 495*cda5da8dSAndroid Build Coastguard Worker # Make this class local, to delay import of 2to3 496*cda5da8dSAndroid Build Coastguard Worker from lib2to3.refactor import RefactoringTool, get_fixers_from_package 497*cda5da8dSAndroid Build Coastguard Worker class DistutilsRefactoringTool(RefactoringTool): 498*cda5da8dSAndroid Build Coastguard Worker def log_error(self, msg, *args, **kw): 499*cda5da8dSAndroid Build Coastguard Worker log.error(msg, *args) 500*cda5da8dSAndroid Build Coastguard Worker 501*cda5da8dSAndroid Build Coastguard Worker def log_message(self, msg, *args): 502*cda5da8dSAndroid Build Coastguard Worker log.info(msg, *args) 503*cda5da8dSAndroid Build Coastguard Worker 504*cda5da8dSAndroid Build Coastguard Worker def log_debug(self, msg, *args): 505*cda5da8dSAndroid Build Coastguard Worker log.debug(msg, *args) 506*cda5da8dSAndroid Build Coastguard Worker 507*cda5da8dSAndroid Build Coastguard Worker if fixer_names is None: 508*cda5da8dSAndroid Build Coastguard Worker fixer_names = get_fixers_from_package('lib2to3.fixes') 509*cda5da8dSAndroid Build Coastguard Worker r = DistutilsRefactoringTool(fixer_names, options=options) 510*cda5da8dSAndroid Build Coastguard Worker r.refactor(files, write=True) 511*cda5da8dSAndroid Build Coastguard Worker 512*cda5da8dSAndroid Build Coastguard Workerdef copydir_run_2to3(src, dest, template=None, fixer_names=None, 513*cda5da8dSAndroid Build Coastguard Worker options=None, explicit=None): 514*cda5da8dSAndroid Build Coastguard Worker """Recursively copy a directory, only copying new and changed files, 515*cda5da8dSAndroid Build Coastguard Worker running run_2to3 over all newly copied Python modules afterward. 516*cda5da8dSAndroid Build Coastguard Worker 517*cda5da8dSAndroid Build Coastguard Worker If you give a template string, it's parsed like a MANIFEST.in. 518*cda5da8dSAndroid Build Coastguard Worker """ 519*cda5da8dSAndroid Build Coastguard Worker from distutils.dir_util import mkpath 520*cda5da8dSAndroid Build Coastguard Worker from distutils.file_util import copy_file 521*cda5da8dSAndroid Build Coastguard Worker from distutils.filelist import FileList 522*cda5da8dSAndroid Build Coastguard Worker filelist = FileList() 523*cda5da8dSAndroid Build Coastguard Worker curdir = os.getcwd() 524*cda5da8dSAndroid Build Coastguard Worker os.chdir(src) 525*cda5da8dSAndroid Build Coastguard Worker try: 526*cda5da8dSAndroid Build Coastguard Worker filelist.findall() 527*cda5da8dSAndroid Build Coastguard Worker finally: 528*cda5da8dSAndroid Build Coastguard Worker os.chdir(curdir) 529*cda5da8dSAndroid Build Coastguard Worker filelist.files[:] = filelist.allfiles 530*cda5da8dSAndroid Build Coastguard Worker if template: 531*cda5da8dSAndroid Build Coastguard Worker for line in template.splitlines(): 532*cda5da8dSAndroid Build Coastguard Worker line = line.strip() 533*cda5da8dSAndroid Build Coastguard Worker if not line: continue 534*cda5da8dSAndroid Build Coastguard Worker filelist.process_template_line(line) 535*cda5da8dSAndroid Build Coastguard Worker copied = [] 536*cda5da8dSAndroid Build Coastguard Worker for filename in filelist.files: 537*cda5da8dSAndroid Build Coastguard Worker outname = os.path.join(dest, filename) 538*cda5da8dSAndroid Build Coastguard Worker mkpath(os.path.dirname(outname)) 539*cda5da8dSAndroid Build Coastguard Worker res = copy_file(os.path.join(src, filename), outname, update=1) 540*cda5da8dSAndroid Build Coastguard Worker if res[1]: copied.append(outname) 541*cda5da8dSAndroid Build Coastguard Worker run_2to3([fn for fn in copied if fn.lower().endswith('.py')], 542*cda5da8dSAndroid Build Coastguard Worker fixer_names=fixer_names, options=options, explicit=explicit) 543*cda5da8dSAndroid Build Coastguard Worker return copied 544*cda5da8dSAndroid Build Coastguard Worker 545*cda5da8dSAndroid Build Coastguard Workerclass Mixin2to3: 546*cda5da8dSAndroid Build Coastguard Worker '''Mixin class for commands that run 2to3. 547*cda5da8dSAndroid Build Coastguard Worker To configure 2to3, setup scripts may either change 548*cda5da8dSAndroid Build Coastguard Worker the class variables, or inherit from individual commands 549*cda5da8dSAndroid Build Coastguard Worker to override how 2to3 is invoked.''' 550*cda5da8dSAndroid Build Coastguard Worker 551*cda5da8dSAndroid Build Coastguard Worker # provide list of fixers to run; 552*cda5da8dSAndroid Build Coastguard Worker # defaults to all from lib2to3.fixers 553*cda5da8dSAndroid Build Coastguard Worker fixer_names = None 554*cda5da8dSAndroid Build Coastguard Worker 555*cda5da8dSAndroid Build Coastguard Worker # options dictionary 556*cda5da8dSAndroid Build Coastguard Worker options = None 557*cda5da8dSAndroid Build Coastguard Worker 558*cda5da8dSAndroid Build Coastguard Worker # list of fixers to invoke even though they are marked as explicit 559*cda5da8dSAndroid Build Coastguard Worker explicit = None 560*cda5da8dSAndroid Build Coastguard Worker 561*cda5da8dSAndroid Build Coastguard Worker def run_2to3(self, files): 562*cda5da8dSAndroid Build Coastguard Worker return run_2to3(files, self.fixer_names, self.options, self.explicit) 563