17db96d56Sopenharmony_ci"""Module/script to byte-compile all .py files to .pyc files. 27db96d56Sopenharmony_ci 37db96d56Sopenharmony_ciWhen called as a script with arguments, this compiles the directories 47db96d56Sopenharmony_cigiven as arguments recursively; the -l option prevents it from 57db96d56Sopenharmony_cirecursing into directories. 67db96d56Sopenharmony_ci 77db96d56Sopenharmony_ciWithout arguments, it compiles all modules on sys.path, without 87db96d56Sopenharmony_cirecursing into subdirectories. (Even though it should do so for 97db96d56Sopenharmony_cipackages -- for now, you'll have to deal with packages separately.) 107db96d56Sopenharmony_ci 117db96d56Sopenharmony_ciSee module py_compile for details of the actual byte-compilation. 127db96d56Sopenharmony_ci""" 137db96d56Sopenharmony_ciimport os 147db96d56Sopenharmony_ciimport sys 157db96d56Sopenharmony_ciimport importlib.util 167db96d56Sopenharmony_ciimport py_compile 177db96d56Sopenharmony_ciimport struct 187db96d56Sopenharmony_ciimport filecmp 197db96d56Sopenharmony_ci 207db96d56Sopenharmony_cifrom functools import partial 217db96d56Sopenharmony_cifrom pathlib import Path 227db96d56Sopenharmony_ci 237db96d56Sopenharmony_ci__all__ = ["compile_dir","compile_file","compile_path"] 247db96d56Sopenharmony_ci 257db96d56Sopenharmony_cidef _walk_dir(dir, maxlevels, quiet=0): 267db96d56Sopenharmony_ci if quiet < 2 and isinstance(dir, os.PathLike): 277db96d56Sopenharmony_ci dir = os.fspath(dir) 287db96d56Sopenharmony_ci if not quiet: 297db96d56Sopenharmony_ci print('Listing {!r}...'.format(dir)) 307db96d56Sopenharmony_ci try: 317db96d56Sopenharmony_ci names = os.listdir(dir) 327db96d56Sopenharmony_ci except OSError: 337db96d56Sopenharmony_ci if quiet < 2: 347db96d56Sopenharmony_ci print("Can't list {!r}".format(dir)) 357db96d56Sopenharmony_ci names = [] 367db96d56Sopenharmony_ci names.sort() 377db96d56Sopenharmony_ci for name in names: 387db96d56Sopenharmony_ci if name == '__pycache__': 397db96d56Sopenharmony_ci continue 407db96d56Sopenharmony_ci fullname = os.path.join(dir, name) 417db96d56Sopenharmony_ci if not os.path.isdir(fullname): 427db96d56Sopenharmony_ci yield fullname 437db96d56Sopenharmony_ci elif (maxlevels > 0 and name != os.curdir and name != os.pardir and 447db96d56Sopenharmony_ci os.path.isdir(fullname) and not os.path.islink(fullname)): 457db96d56Sopenharmony_ci yield from _walk_dir(fullname, maxlevels=maxlevels - 1, 467db96d56Sopenharmony_ci quiet=quiet) 477db96d56Sopenharmony_ci 487db96d56Sopenharmony_cidef compile_dir(dir, maxlevels=None, ddir=None, force=False, 497db96d56Sopenharmony_ci rx=None, quiet=0, legacy=False, optimize=-1, workers=1, 507db96d56Sopenharmony_ci invalidation_mode=None, *, stripdir=None, 517db96d56Sopenharmony_ci prependdir=None, limit_sl_dest=None, hardlink_dupes=False): 527db96d56Sopenharmony_ci """Byte-compile all modules in the given directory tree. 537db96d56Sopenharmony_ci 547db96d56Sopenharmony_ci Arguments (only dir is required): 557db96d56Sopenharmony_ci 567db96d56Sopenharmony_ci dir: the directory to byte-compile 577db96d56Sopenharmony_ci maxlevels: maximum recursion level (default `sys.getrecursionlimit()`) 587db96d56Sopenharmony_ci ddir: the directory that will be prepended to the path to the 597db96d56Sopenharmony_ci file as it is compiled into each byte-code file. 607db96d56Sopenharmony_ci force: if True, force compilation, even if timestamps are up-to-date 617db96d56Sopenharmony_ci quiet: full output with False or 0, errors only with 1, 627db96d56Sopenharmony_ci no output with 2 637db96d56Sopenharmony_ci legacy: if True, produce legacy pyc paths instead of PEP 3147 paths 647db96d56Sopenharmony_ci optimize: int or list of optimization levels or -1 for level of 657db96d56Sopenharmony_ci the interpreter. Multiple levels leads to multiple compiled 667db96d56Sopenharmony_ci files each with one optimization level. 677db96d56Sopenharmony_ci workers: maximum number of parallel workers 687db96d56Sopenharmony_ci invalidation_mode: how the up-to-dateness of the pyc will be checked 697db96d56Sopenharmony_ci stripdir: part of path to left-strip from source file path 707db96d56Sopenharmony_ci prependdir: path to prepend to beginning of original file path, applied 717db96d56Sopenharmony_ci after stripdir 727db96d56Sopenharmony_ci limit_sl_dest: ignore symlinks if they are pointing outside of 737db96d56Sopenharmony_ci the defined path 747db96d56Sopenharmony_ci hardlink_dupes: hardlink duplicated pyc files 757db96d56Sopenharmony_ci """ 767db96d56Sopenharmony_ci ProcessPoolExecutor = None 777db96d56Sopenharmony_ci if ddir is not None and (stripdir is not None or prependdir is not None): 787db96d56Sopenharmony_ci raise ValueError(("Destination dir (ddir) cannot be used " 797db96d56Sopenharmony_ci "in combination with stripdir or prependdir")) 807db96d56Sopenharmony_ci if ddir is not None: 817db96d56Sopenharmony_ci stripdir = dir 827db96d56Sopenharmony_ci prependdir = ddir 837db96d56Sopenharmony_ci ddir = None 847db96d56Sopenharmony_ci if workers < 0: 857db96d56Sopenharmony_ci raise ValueError('workers must be greater or equal to 0') 867db96d56Sopenharmony_ci if workers != 1: 877db96d56Sopenharmony_ci # Check if this is a system where ProcessPoolExecutor can function. 887db96d56Sopenharmony_ci from concurrent.futures.process import _check_system_limits 897db96d56Sopenharmony_ci try: 907db96d56Sopenharmony_ci _check_system_limits() 917db96d56Sopenharmony_ci except NotImplementedError: 927db96d56Sopenharmony_ci workers = 1 937db96d56Sopenharmony_ci else: 947db96d56Sopenharmony_ci from concurrent.futures import ProcessPoolExecutor 957db96d56Sopenharmony_ci if maxlevels is None: 967db96d56Sopenharmony_ci maxlevels = sys.getrecursionlimit() 977db96d56Sopenharmony_ci files = _walk_dir(dir, quiet=quiet, maxlevels=maxlevels) 987db96d56Sopenharmony_ci success = True 997db96d56Sopenharmony_ci if workers != 1 and ProcessPoolExecutor is not None: 1007db96d56Sopenharmony_ci # If workers == 0, let ProcessPoolExecutor choose 1017db96d56Sopenharmony_ci workers = workers or None 1027db96d56Sopenharmony_ci with ProcessPoolExecutor(max_workers=workers) as executor: 1037db96d56Sopenharmony_ci results = executor.map(partial(compile_file, 1047db96d56Sopenharmony_ci ddir=ddir, force=force, 1057db96d56Sopenharmony_ci rx=rx, quiet=quiet, 1067db96d56Sopenharmony_ci legacy=legacy, 1077db96d56Sopenharmony_ci optimize=optimize, 1087db96d56Sopenharmony_ci invalidation_mode=invalidation_mode, 1097db96d56Sopenharmony_ci stripdir=stripdir, 1107db96d56Sopenharmony_ci prependdir=prependdir, 1117db96d56Sopenharmony_ci limit_sl_dest=limit_sl_dest, 1127db96d56Sopenharmony_ci hardlink_dupes=hardlink_dupes), 1137db96d56Sopenharmony_ci files) 1147db96d56Sopenharmony_ci success = min(results, default=True) 1157db96d56Sopenharmony_ci else: 1167db96d56Sopenharmony_ci for file in files: 1177db96d56Sopenharmony_ci if not compile_file(file, ddir, force, rx, quiet, 1187db96d56Sopenharmony_ci legacy, optimize, invalidation_mode, 1197db96d56Sopenharmony_ci stripdir=stripdir, prependdir=prependdir, 1207db96d56Sopenharmony_ci limit_sl_dest=limit_sl_dest, 1217db96d56Sopenharmony_ci hardlink_dupes=hardlink_dupes): 1227db96d56Sopenharmony_ci success = False 1237db96d56Sopenharmony_ci return success 1247db96d56Sopenharmony_ci 1257db96d56Sopenharmony_cidef compile_file(fullname, ddir=None, force=False, rx=None, quiet=0, 1267db96d56Sopenharmony_ci legacy=False, optimize=-1, 1277db96d56Sopenharmony_ci invalidation_mode=None, *, stripdir=None, prependdir=None, 1287db96d56Sopenharmony_ci limit_sl_dest=None, hardlink_dupes=False): 1297db96d56Sopenharmony_ci """Byte-compile one file. 1307db96d56Sopenharmony_ci 1317db96d56Sopenharmony_ci Arguments (only fullname is required): 1327db96d56Sopenharmony_ci 1337db96d56Sopenharmony_ci fullname: the file to byte-compile 1347db96d56Sopenharmony_ci ddir: if given, the directory name compiled in to the 1357db96d56Sopenharmony_ci byte-code file. 1367db96d56Sopenharmony_ci force: if True, force compilation, even if timestamps are up-to-date 1377db96d56Sopenharmony_ci quiet: full output with False or 0, errors only with 1, 1387db96d56Sopenharmony_ci no output with 2 1397db96d56Sopenharmony_ci legacy: if True, produce legacy pyc paths instead of PEP 3147 paths 1407db96d56Sopenharmony_ci optimize: int or list of optimization levels or -1 for level of 1417db96d56Sopenharmony_ci the interpreter. Multiple levels leads to multiple compiled 1427db96d56Sopenharmony_ci files each with one optimization level. 1437db96d56Sopenharmony_ci invalidation_mode: how the up-to-dateness of the pyc will be checked 1447db96d56Sopenharmony_ci stripdir: part of path to left-strip from source file path 1457db96d56Sopenharmony_ci prependdir: path to prepend to beginning of original file path, applied 1467db96d56Sopenharmony_ci after stripdir 1477db96d56Sopenharmony_ci limit_sl_dest: ignore symlinks if they are pointing outside of 1487db96d56Sopenharmony_ci the defined path. 1497db96d56Sopenharmony_ci hardlink_dupes: hardlink duplicated pyc files 1507db96d56Sopenharmony_ci """ 1517db96d56Sopenharmony_ci 1527db96d56Sopenharmony_ci if ddir is not None and (stripdir is not None or prependdir is not None): 1537db96d56Sopenharmony_ci raise ValueError(("Destination dir (ddir) cannot be used " 1547db96d56Sopenharmony_ci "in combination with stripdir or prependdir")) 1557db96d56Sopenharmony_ci 1567db96d56Sopenharmony_ci success = True 1577db96d56Sopenharmony_ci fullname = os.fspath(fullname) 1587db96d56Sopenharmony_ci stripdir = os.fspath(stripdir) if stripdir is not None else None 1597db96d56Sopenharmony_ci name = os.path.basename(fullname) 1607db96d56Sopenharmony_ci 1617db96d56Sopenharmony_ci dfile = None 1627db96d56Sopenharmony_ci 1637db96d56Sopenharmony_ci if ddir is not None: 1647db96d56Sopenharmony_ci dfile = os.path.join(ddir, name) 1657db96d56Sopenharmony_ci 1667db96d56Sopenharmony_ci if stripdir is not None: 1677db96d56Sopenharmony_ci fullname_parts = fullname.split(os.path.sep) 1687db96d56Sopenharmony_ci stripdir_parts = stripdir.split(os.path.sep) 1697db96d56Sopenharmony_ci ddir_parts = list(fullname_parts) 1707db96d56Sopenharmony_ci 1717db96d56Sopenharmony_ci for spart, opart in zip(stripdir_parts, fullname_parts): 1727db96d56Sopenharmony_ci if spart == opart: 1737db96d56Sopenharmony_ci ddir_parts.remove(spart) 1747db96d56Sopenharmony_ci 1757db96d56Sopenharmony_ci dfile = os.path.join(*ddir_parts) 1767db96d56Sopenharmony_ci 1777db96d56Sopenharmony_ci if prependdir is not None: 1787db96d56Sopenharmony_ci if dfile is None: 1797db96d56Sopenharmony_ci dfile = os.path.join(prependdir, fullname) 1807db96d56Sopenharmony_ci else: 1817db96d56Sopenharmony_ci dfile = os.path.join(prependdir, dfile) 1827db96d56Sopenharmony_ci 1837db96d56Sopenharmony_ci if isinstance(optimize, int): 1847db96d56Sopenharmony_ci optimize = [optimize] 1857db96d56Sopenharmony_ci 1867db96d56Sopenharmony_ci # Use set() to remove duplicates. 1877db96d56Sopenharmony_ci # Use sorted() to create pyc files in a deterministic order. 1887db96d56Sopenharmony_ci optimize = sorted(set(optimize)) 1897db96d56Sopenharmony_ci 1907db96d56Sopenharmony_ci if hardlink_dupes and len(optimize) < 2: 1917db96d56Sopenharmony_ci raise ValueError("Hardlinking of duplicated bytecode makes sense " 1927db96d56Sopenharmony_ci "only for more than one optimization level") 1937db96d56Sopenharmony_ci 1947db96d56Sopenharmony_ci if rx is not None: 1957db96d56Sopenharmony_ci mo = rx.search(fullname) 1967db96d56Sopenharmony_ci if mo: 1977db96d56Sopenharmony_ci return success 1987db96d56Sopenharmony_ci 1997db96d56Sopenharmony_ci if limit_sl_dest is not None and os.path.islink(fullname): 2007db96d56Sopenharmony_ci if Path(limit_sl_dest).resolve() not in Path(fullname).resolve().parents: 2017db96d56Sopenharmony_ci return success 2027db96d56Sopenharmony_ci 2037db96d56Sopenharmony_ci opt_cfiles = {} 2047db96d56Sopenharmony_ci 2057db96d56Sopenharmony_ci if os.path.isfile(fullname): 2067db96d56Sopenharmony_ci for opt_level in optimize: 2077db96d56Sopenharmony_ci if legacy: 2087db96d56Sopenharmony_ci opt_cfiles[opt_level] = fullname + 'c' 2097db96d56Sopenharmony_ci else: 2107db96d56Sopenharmony_ci if opt_level >= 0: 2117db96d56Sopenharmony_ci opt = opt_level if opt_level >= 1 else '' 2127db96d56Sopenharmony_ci cfile = (importlib.util.cache_from_source( 2137db96d56Sopenharmony_ci fullname, optimization=opt)) 2147db96d56Sopenharmony_ci opt_cfiles[opt_level] = cfile 2157db96d56Sopenharmony_ci else: 2167db96d56Sopenharmony_ci cfile = importlib.util.cache_from_source(fullname) 2177db96d56Sopenharmony_ci opt_cfiles[opt_level] = cfile 2187db96d56Sopenharmony_ci 2197db96d56Sopenharmony_ci head, tail = name[:-3], name[-3:] 2207db96d56Sopenharmony_ci if tail == '.py': 2217db96d56Sopenharmony_ci if not force: 2227db96d56Sopenharmony_ci try: 2237db96d56Sopenharmony_ci mtime = int(os.stat(fullname).st_mtime) 2247db96d56Sopenharmony_ci expect = struct.pack('<4sLL', importlib.util.MAGIC_NUMBER, 2257db96d56Sopenharmony_ci 0, mtime & 0xFFFF_FFFF) 2267db96d56Sopenharmony_ci for cfile in opt_cfiles.values(): 2277db96d56Sopenharmony_ci with open(cfile, 'rb') as chandle: 2287db96d56Sopenharmony_ci actual = chandle.read(12) 2297db96d56Sopenharmony_ci if expect != actual: 2307db96d56Sopenharmony_ci break 2317db96d56Sopenharmony_ci else: 2327db96d56Sopenharmony_ci return success 2337db96d56Sopenharmony_ci except OSError: 2347db96d56Sopenharmony_ci pass 2357db96d56Sopenharmony_ci if not quiet: 2367db96d56Sopenharmony_ci print('Compiling {!r}...'.format(fullname)) 2377db96d56Sopenharmony_ci try: 2387db96d56Sopenharmony_ci for index, opt_level in enumerate(optimize): 2397db96d56Sopenharmony_ci cfile = opt_cfiles[opt_level] 2407db96d56Sopenharmony_ci ok = py_compile.compile(fullname, cfile, dfile, True, 2417db96d56Sopenharmony_ci optimize=opt_level, 2427db96d56Sopenharmony_ci invalidation_mode=invalidation_mode) 2437db96d56Sopenharmony_ci if index > 0 and hardlink_dupes: 2447db96d56Sopenharmony_ci previous_cfile = opt_cfiles[optimize[index - 1]] 2457db96d56Sopenharmony_ci if filecmp.cmp(cfile, previous_cfile, shallow=False): 2467db96d56Sopenharmony_ci os.unlink(cfile) 2477db96d56Sopenharmony_ci os.link(previous_cfile, cfile) 2487db96d56Sopenharmony_ci except py_compile.PyCompileError as err: 2497db96d56Sopenharmony_ci success = False 2507db96d56Sopenharmony_ci if quiet >= 2: 2517db96d56Sopenharmony_ci return success 2527db96d56Sopenharmony_ci elif quiet: 2537db96d56Sopenharmony_ci print('*** Error compiling {!r}...'.format(fullname)) 2547db96d56Sopenharmony_ci else: 2557db96d56Sopenharmony_ci print('*** ', end='') 2567db96d56Sopenharmony_ci # escape non-printable characters in msg 2577db96d56Sopenharmony_ci encoding = sys.stdout.encoding or sys.getdefaultencoding() 2587db96d56Sopenharmony_ci msg = err.msg.encode(encoding, errors='backslashreplace').decode(encoding) 2597db96d56Sopenharmony_ci print(msg) 2607db96d56Sopenharmony_ci except (SyntaxError, UnicodeError, OSError) as e: 2617db96d56Sopenharmony_ci success = False 2627db96d56Sopenharmony_ci if quiet >= 2: 2637db96d56Sopenharmony_ci return success 2647db96d56Sopenharmony_ci elif quiet: 2657db96d56Sopenharmony_ci print('*** Error compiling {!r}...'.format(fullname)) 2667db96d56Sopenharmony_ci else: 2677db96d56Sopenharmony_ci print('*** ', end='') 2687db96d56Sopenharmony_ci print(e.__class__.__name__ + ':', e) 2697db96d56Sopenharmony_ci else: 2707db96d56Sopenharmony_ci if ok == 0: 2717db96d56Sopenharmony_ci success = False 2727db96d56Sopenharmony_ci return success 2737db96d56Sopenharmony_ci 2747db96d56Sopenharmony_cidef compile_path(skip_curdir=1, maxlevels=0, force=False, quiet=0, 2757db96d56Sopenharmony_ci legacy=False, optimize=-1, 2767db96d56Sopenharmony_ci invalidation_mode=None): 2777db96d56Sopenharmony_ci """Byte-compile all module on sys.path. 2787db96d56Sopenharmony_ci 2797db96d56Sopenharmony_ci Arguments (all optional): 2807db96d56Sopenharmony_ci 2817db96d56Sopenharmony_ci skip_curdir: if true, skip current directory (default True) 2827db96d56Sopenharmony_ci maxlevels: max recursion level (default 0) 2837db96d56Sopenharmony_ci force: as for compile_dir() (default False) 2847db96d56Sopenharmony_ci quiet: as for compile_dir() (default 0) 2857db96d56Sopenharmony_ci legacy: as for compile_dir() (default False) 2867db96d56Sopenharmony_ci optimize: as for compile_dir() (default -1) 2877db96d56Sopenharmony_ci invalidation_mode: as for compiler_dir() 2887db96d56Sopenharmony_ci """ 2897db96d56Sopenharmony_ci success = True 2907db96d56Sopenharmony_ci for dir in sys.path: 2917db96d56Sopenharmony_ci if (not dir or dir == os.curdir) and skip_curdir: 2927db96d56Sopenharmony_ci if quiet < 2: 2937db96d56Sopenharmony_ci print('Skipping current directory') 2947db96d56Sopenharmony_ci else: 2957db96d56Sopenharmony_ci success = success and compile_dir( 2967db96d56Sopenharmony_ci dir, 2977db96d56Sopenharmony_ci maxlevels, 2987db96d56Sopenharmony_ci None, 2997db96d56Sopenharmony_ci force, 3007db96d56Sopenharmony_ci quiet=quiet, 3017db96d56Sopenharmony_ci legacy=legacy, 3027db96d56Sopenharmony_ci optimize=optimize, 3037db96d56Sopenharmony_ci invalidation_mode=invalidation_mode, 3047db96d56Sopenharmony_ci ) 3057db96d56Sopenharmony_ci return success 3067db96d56Sopenharmony_ci 3077db96d56Sopenharmony_ci 3087db96d56Sopenharmony_cidef main(): 3097db96d56Sopenharmony_ci """Script main program.""" 3107db96d56Sopenharmony_ci import argparse 3117db96d56Sopenharmony_ci 3127db96d56Sopenharmony_ci parser = argparse.ArgumentParser( 3137db96d56Sopenharmony_ci description='Utilities to support installing Python libraries.') 3147db96d56Sopenharmony_ci parser.add_argument('-l', action='store_const', const=0, 3157db96d56Sopenharmony_ci default=None, dest='maxlevels', 3167db96d56Sopenharmony_ci help="don't recurse into subdirectories") 3177db96d56Sopenharmony_ci parser.add_argument('-r', type=int, dest='recursion', 3187db96d56Sopenharmony_ci help=('control the maximum recursion level. ' 3197db96d56Sopenharmony_ci 'if `-l` and `-r` options are specified, ' 3207db96d56Sopenharmony_ci 'then `-r` takes precedence.')) 3217db96d56Sopenharmony_ci parser.add_argument('-f', action='store_true', dest='force', 3227db96d56Sopenharmony_ci help='force rebuild even if timestamps are up to date') 3237db96d56Sopenharmony_ci parser.add_argument('-q', action='count', dest='quiet', default=0, 3247db96d56Sopenharmony_ci help='output only error messages; -qq will suppress ' 3257db96d56Sopenharmony_ci 'the error messages as well.') 3267db96d56Sopenharmony_ci parser.add_argument('-b', action='store_true', dest='legacy', 3277db96d56Sopenharmony_ci help='use legacy (pre-PEP3147) compiled file locations') 3287db96d56Sopenharmony_ci parser.add_argument('-d', metavar='DESTDIR', dest='ddir', default=None, 3297db96d56Sopenharmony_ci help=('directory to prepend to file paths for use in ' 3307db96d56Sopenharmony_ci 'compile-time tracebacks and in runtime ' 3317db96d56Sopenharmony_ci 'tracebacks in cases where the source file is ' 3327db96d56Sopenharmony_ci 'unavailable')) 3337db96d56Sopenharmony_ci parser.add_argument('-s', metavar='STRIPDIR', dest='stripdir', 3347db96d56Sopenharmony_ci default=None, 3357db96d56Sopenharmony_ci help=('part of path to left-strip from path ' 3367db96d56Sopenharmony_ci 'to source file - for example buildroot. ' 3377db96d56Sopenharmony_ci '`-d` and `-s` options cannot be ' 3387db96d56Sopenharmony_ci 'specified together.')) 3397db96d56Sopenharmony_ci parser.add_argument('-p', metavar='PREPENDDIR', dest='prependdir', 3407db96d56Sopenharmony_ci default=None, 3417db96d56Sopenharmony_ci help=('path to add as prefix to path ' 3427db96d56Sopenharmony_ci 'to source file - for example / to make ' 3437db96d56Sopenharmony_ci 'it absolute when some part is removed ' 3447db96d56Sopenharmony_ci 'by `-s` option. ' 3457db96d56Sopenharmony_ci '`-d` and `-p` options cannot be ' 3467db96d56Sopenharmony_ci 'specified together.')) 3477db96d56Sopenharmony_ci parser.add_argument('-x', metavar='REGEXP', dest='rx', default=None, 3487db96d56Sopenharmony_ci help=('skip files matching the regular expression; ' 3497db96d56Sopenharmony_ci 'the regexp is searched for in the full path ' 3507db96d56Sopenharmony_ci 'of each file considered for compilation')) 3517db96d56Sopenharmony_ci parser.add_argument('-i', metavar='FILE', dest='flist', 3527db96d56Sopenharmony_ci help=('add all the files and directories listed in ' 3537db96d56Sopenharmony_ci 'FILE to the list considered for compilation; ' 3547db96d56Sopenharmony_ci 'if "-", names are read from stdin')) 3557db96d56Sopenharmony_ci parser.add_argument('compile_dest', metavar='FILE|DIR', nargs='*', 3567db96d56Sopenharmony_ci help=('zero or more file and directory names ' 3577db96d56Sopenharmony_ci 'to compile; if no arguments given, defaults ' 3587db96d56Sopenharmony_ci 'to the equivalent of -l sys.path')) 3597db96d56Sopenharmony_ci parser.add_argument('-j', '--workers', default=1, 3607db96d56Sopenharmony_ci type=int, help='Run compileall concurrently') 3617db96d56Sopenharmony_ci invalidation_modes = [mode.name.lower().replace('_', '-') 3627db96d56Sopenharmony_ci for mode in py_compile.PycInvalidationMode] 3637db96d56Sopenharmony_ci parser.add_argument('--invalidation-mode', 3647db96d56Sopenharmony_ci choices=sorted(invalidation_modes), 3657db96d56Sopenharmony_ci help=('set .pyc invalidation mode; defaults to ' 3667db96d56Sopenharmony_ci '"checked-hash" if the SOURCE_DATE_EPOCH ' 3677db96d56Sopenharmony_ci 'environment variable is set, and ' 3687db96d56Sopenharmony_ci '"timestamp" otherwise.')) 3697db96d56Sopenharmony_ci parser.add_argument('-o', action='append', type=int, dest='opt_levels', 3707db96d56Sopenharmony_ci help=('Optimization levels to run compilation with. ' 3717db96d56Sopenharmony_ci 'Default is -1 which uses the optimization level ' 3727db96d56Sopenharmony_ci 'of the Python interpreter itself (see -O).')) 3737db96d56Sopenharmony_ci parser.add_argument('-e', metavar='DIR', dest='limit_sl_dest', 3747db96d56Sopenharmony_ci help='Ignore symlinks pointing outsite of the DIR') 3757db96d56Sopenharmony_ci parser.add_argument('--hardlink-dupes', action='store_true', 3767db96d56Sopenharmony_ci dest='hardlink_dupes', 3777db96d56Sopenharmony_ci help='Hardlink duplicated pyc files') 3787db96d56Sopenharmony_ci 3797db96d56Sopenharmony_ci args = parser.parse_args() 3807db96d56Sopenharmony_ci compile_dests = args.compile_dest 3817db96d56Sopenharmony_ci 3827db96d56Sopenharmony_ci if args.rx: 3837db96d56Sopenharmony_ci import re 3847db96d56Sopenharmony_ci args.rx = re.compile(args.rx) 3857db96d56Sopenharmony_ci 3867db96d56Sopenharmony_ci if args.limit_sl_dest == "": 3877db96d56Sopenharmony_ci args.limit_sl_dest = None 3887db96d56Sopenharmony_ci 3897db96d56Sopenharmony_ci if args.recursion is not None: 3907db96d56Sopenharmony_ci maxlevels = args.recursion 3917db96d56Sopenharmony_ci else: 3927db96d56Sopenharmony_ci maxlevels = args.maxlevels 3937db96d56Sopenharmony_ci 3947db96d56Sopenharmony_ci if args.opt_levels is None: 3957db96d56Sopenharmony_ci args.opt_levels = [-1] 3967db96d56Sopenharmony_ci 3977db96d56Sopenharmony_ci if len(args.opt_levels) == 1 and args.hardlink_dupes: 3987db96d56Sopenharmony_ci parser.error(("Hardlinking of duplicated bytecode makes sense " 3997db96d56Sopenharmony_ci "only for more than one optimization level.")) 4007db96d56Sopenharmony_ci 4017db96d56Sopenharmony_ci if args.ddir is not None and ( 4027db96d56Sopenharmony_ci args.stripdir is not None or args.prependdir is not None 4037db96d56Sopenharmony_ci ): 4047db96d56Sopenharmony_ci parser.error("-d cannot be used in combination with -s or -p") 4057db96d56Sopenharmony_ci 4067db96d56Sopenharmony_ci # if flist is provided then load it 4077db96d56Sopenharmony_ci if args.flist: 4087db96d56Sopenharmony_ci try: 4097db96d56Sopenharmony_ci with (sys.stdin if args.flist=='-' else 4107db96d56Sopenharmony_ci open(args.flist, encoding="utf-8")) as f: 4117db96d56Sopenharmony_ci for line in f: 4127db96d56Sopenharmony_ci compile_dests.append(line.strip()) 4137db96d56Sopenharmony_ci except OSError: 4147db96d56Sopenharmony_ci if args.quiet < 2: 4157db96d56Sopenharmony_ci print("Error reading file list {}".format(args.flist)) 4167db96d56Sopenharmony_ci return False 4177db96d56Sopenharmony_ci 4187db96d56Sopenharmony_ci if args.invalidation_mode: 4197db96d56Sopenharmony_ci ivl_mode = args.invalidation_mode.replace('-', '_').upper() 4207db96d56Sopenharmony_ci invalidation_mode = py_compile.PycInvalidationMode[ivl_mode] 4217db96d56Sopenharmony_ci else: 4227db96d56Sopenharmony_ci invalidation_mode = None 4237db96d56Sopenharmony_ci 4247db96d56Sopenharmony_ci success = True 4257db96d56Sopenharmony_ci try: 4267db96d56Sopenharmony_ci if compile_dests: 4277db96d56Sopenharmony_ci for dest in compile_dests: 4287db96d56Sopenharmony_ci if os.path.isfile(dest): 4297db96d56Sopenharmony_ci if not compile_file(dest, args.ddir, args.force, args.rx, 4307db96d56Sopenharmony_ci args.quiet, args.legacy, 4317db96d56Sopenharmony_ci invalidation_mode=invalidation_mode, 4327db96d56Sopenharmony_ci stripdir=args.stripdir, 4337db96d56Sopenharmony_ci prependdir=args.prependdir, 4347db96d56Sopenharmony_ci optimize=args.opt_levels, 4357db96d56Sopenharmony_ci limit_sl_dest=args.limit_sl_dest, 4367db96d56Sopenharmony_ci hardlink_dupes=args.hardlink_dupes): 4377db96d56Sopenharmony_ci success = False 4387db96d56Sopenharmony_ci else: 4397db96d56Sopenharmony_ci if not compile_dir(dest, maxlevels, args.ddir, 4407db96d56Sopenharmony_ci args.force, args.rx, args.quiet, 4417db96d56Sopenharmony_ci args.legacy, workers=args.workers, 4427db96d56Sopenharmony_ci invalidation_mode=invalidation_mode, 4437db96d56Sopenharmony_ci stripdir=args.stripdir, 4447db96d56Sopenharmony_ci prependdir=args.prependdir, 4457db96d56Sopenharmony_ci optimize=args.opt_levels, 4467db96d56Sopenharmony_ci limit_sl_dest=args.limit_sl_dest, 4477db96d56Sopenharmony_ci hardlink_dupes=args.hardlink_dupes): 4487db96d56Sopenharmony_ci success = False 4497db96d56Sopenharmony_ci return success 4507db96d56Sopenharmony_ci else: 4517db96d56Sopenharmony_ci return compile_path(legacy=args.legacy, force=args.force, 4527db96d56Sopenharmony_ci quiet=args.quiet, 4537db96d56Sopenharmony_ci invalidation_mode=invalidation_mode) 4547db96d56Sopenharmony_ci except KeyboardInterrupt: 4557db96d56Sopenharmony_ci if args.quiet < 2: 4567db96d56Sopenharmony_ci print("\n[interrupted]") 4577db96d56Sopenharmony_ci return False 4587db96d56Sopenharmony_ci return True 4597db96d56Sopenharmony_ci 4607db96d56Sopenharmony_ci 4617db96d56Sopenharmony_ciif __name__ == '__main__': 4627db96d56Sopenharmony_ci exit_status = int(not main()) 4637db96d56Sopenharmony_ci sys.exit(exit_status) 464