xref: /third_party/python/Lib/compileall.py (revision 7db96d56)
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