17db96d56Sopenharmony_ci""" 27db96d56Sopenharmony_ciGenerates a layout of Python for Windows from a build. 37db96d56Sopenharmony_ci 47db96d56Sopenharmony_ciSee python make_layout.py --help for usage. 57db96d56Sopenharmony_ci""" 67db96d56Sopenharmony_ci 77db96d56Sopenharmony_ci__author__ = "Steve Dower <steve.dower@python.org>" 87db96d56Sopenharmony_ci__version__ = "3.8" 97db96d56Sopenharmony_ci 107db96d56Sopenharmony_ciimport argparse 117db96d56Sopenharmony_ciimport functools 127db96d56Sopenharmony_ciimport os 137db96d56Sopenharmony_ciimport re 147db96d56Sopenharmony_ciimport shutil 157db96d56Sopenharmony_ciimport subprocess 167db96d56Sopenharmony_ciimport sys 177db96d56Sopenharmony_ciimport tempfile 187db96d56Sopenharmony_ciimport zipfile 197db96d56Sopenharmony_ci 207db96d56Sopenharmony_cifrom pathlib import Path 217db96d56Sopenharmony_ci 227db96d56Sopenharmony_ciif __name__ == "__main__": 237db96d56Sopenharmony_ci # Started directly, so enable relative imports 247db96d56Sopenharmony_ci __path__ = [str(Path(__file__).resolve().parent)] 257db96d56Sopenharmony_ci 267db96d56Sopenharmony_cifrom .support.appxmanifest import * 277db96d56Sopenharmony_cifrom .support.catalog import * 287db96d56Sopenharmony_cifrom .support.constants import * 297db96d56Sopenharmony_cifrom .support.filesets import * 307db96d56Sopenharmony_cifrom .support.logging import * 317db96d56Sopenharmony_cifrom .support.options import * 327db96d56Sopenharmony_cifrom .support.pip import * 337db96d56Sopenharmony_cifrom .support.props import * 347db96d56Sopenharmony_cifrom .support.nuspec import * 357db96d56Sopenharmony_ci 367db96d56Sopenharmony_ciTEST_PYDS_ONLY = FileStemSet("xxlimited", "xxlimited_35", "_ctypes_test", "_test*") 377db96d56Sopenharmony_ciTEST_DIRS_ONLY = FileNameSet("test", "tests") 387db96d56Sopenharmony_ci 397db96d56Sopenharmony_ciIDLE_DIRS_ONLY = FileNameSet("idlelib") 407db96d56Sopenharmony_ci 417db96d56Sopenharmony_ciTCLTK_PYDS_ONLY = FileStemSet("tcl*", "tk*", "_tkinter") 427db96d56Sopenharmony_ciTCLTK_DIRS_ONLY = FileNameSet("tkinter", "turtledemo") 437db96d56Sopenharmony_ciTCLTK_FILES_ONLY = FileNameSet("turtle.py") 447db96d56Sopenharmony_ci 457db96d56Sopenharmony_ciVENV_DIRS_ONLY = FileNameSet("venv", "ensurepip") 467db96d56Sopenharmony_ci 477db96d56Sopenharmony_ciEXCLUDE_FROM_PYDS = FileStemSet("python*", "pyshellext", "vcruntime*") 487db96d56Sopenharmony_ciEXCLUDE_FROM_LIB = FileNameSet("*.pyc", "__pycache__", "*.pickle") 497db96d56Sopenharmony_ciEXCLUDE_FROM_PACKAGED_LIB = FileNameSet("readme.txt") 507db96d56Sopenharmony_ciEXCLUDE_FROM_COMPILE = FileNameSet("badsyntax_*", "bad_*") 517db96d56Sopenharmony_ciEXCLUDE_FROM_CATALOG = FileSuffixSet(".exe", ".pyd", ".dll") 527db96d56Sopenharmony_ci 537db96d56Sopenharmony_ciREQUIRED_DLLS = FileStemSet("libcrypto*", "libssl*", "libffi*") 547db96d56Sopenharmony_ci 557db96d56Sopenharmony_ciLIB2TO3_GRAMMAR_FILES = FileNameSet("Grammar.txt", "PatternGrammar.txt") 567db96d56Sopenharmony_ci 577db96d56Sopenharmony_ciPY_FILES = FileSuffixSet(".py") 587db96d56Sopenharmony_ciPYC_FILES = FileSuffixSet(".pyc") 597db96d56Sopenharmony_ciCAT_FILES = FileSuffixSet(".cat") 607db96d56Sopenharmony_ciCDF_FILES = FileSuffixSet(".cdf") 617db96d56Sopenharmony_ci 627db96d56Sopenharmony_ciDATA_DIRS = FileNameSet("data") 637db96d56Sopenharmony_ci 647db96d56Sopenharmony_ciTOOLS_DIRS = FileNameSet("scripts", "i18n", "demo", "parser") 657db96d56Sopenharmony_ciTOOLS_FILES = FileSuffixSet(".py", ".pyw", ".txt") 667db96d56Sopenharmony_ci 677db96d56Sopenharmony_ci 687db96d56Sopenharmony_cidef copy_if_modified(src, dest): 697db96d56Sopenharmony_ci try: 707db96d56Sopenharmony_ci dest_stat = os.stat(dest) 717db96d56Sopenharmony_ci except FileNotFoundError: 727db96d56Sopenharmony_ci do_copy = True 737db96d56Sopenharmony_ci else: 747db96d56Sopenharmony_ci src_stat = os.stat(src) 757db96d56Sopenharmony_ci do_copy = ( 767db96d56Sopenharmony_ci src_stat.st_mtime != dest_stat.st_mtime 777db96d56Sopenharmony_ci or src_stat.st_size != dest_stat.st_size 787db96d56Sopenharmony_ci ) 797db96d56Sopenharmony_ci 807db96d56Sopenharmony_ci if do_copy: 817db96d56Sopenharmony_ci shutil.copy2(src, dest) 827db96d56Sopenharmony_ci 837db96d56Sopenharmony_ci 847db96d56Sopenharmony_cidef get_lib_layout(ns): 857db96d56Sopenharmony_ci def _c(f): 867db96d56Sopenharmony_ci if f in EXCLUDE_FROM_LIB: 877db96d56Sopenharmony_ci return False 887db96d56Sopenharmony_ci if f.is_dir(): 897db96d56Sopenharmony_ci if f in TEST_DIRS_ONLY: 907db96d56Sopenharmony_ci return ns.include_tests 917db96d56Sopenharmony_ci if f in TCLTK_DIRS_ONLY: 927db96d56Sopenharmony_ci return ns.include_tcltk 937db96d56Sopenharmony_ci if f in IDLE_DIRS_ONLY: 947db96d56Sopenharmony_ci return ns.include_idle 957db96d56Sopenharmony_ci if f in VENV_DIRS_ONLY: 967db96d56Sopenharmony_ci return ns.include_venv 977db96d56Sopenharmony_ci else: 987db96d56Sopenharmony_ci if f in TCLTK_FILES_ONLY: 997db96d56Sopenharmony_ci return ns.include_tcltk 1007db96d56Sopenharmony_ci return True 1017db96d56Sopenharmony_ci 1027db96d56Sopenharmony_ci for dest, src in rglob(ns.source / "Lib", "**/*", _c): 1037db96d56Sopenharmony_ci yield dest, src 1047db96d56Sopenharmony_ci 1057db96d56Sopenharmony_ci 1067db96d56Sopenharmony_cidef get_tcltk_lib(ns): 1077db96d56Sopenharmony_ci if not ns.include_tcltk: 1087db96d56Sopenharmony_ci return 1097db96d56Sopenharmony_ci 1107db96d56Sopenharmony_ci tcl_lib = os.getenv("TCL_LIBRARY") 1117db96d56Sopenharmony_ci if not tcl_lib or not os.path.isdir(tcl_lib): 1127db96d56Sopenharmony_ci try: 1137db96d56Sopenharmony_ci with open(ns.build / "TCL_LIBRARY.env", "r", encoding="utf-8-sig") as f: 1147db96d56Sopenharmony_ci tcl_lib = f.read().strip() 1157db96d56Sopenharmony_ci except FileNotFoundError: 1167db96d56Sopenharmony_ci pass 1177db96d56Sopenharmony_ci if not tcl_lib or not os.path.isdir(tcl_lib): 1187db96d56Sopenharmony_ci log_warning("Failed to find TCL_LIBRARY") 1197db96d56Sopenharmony_ci return 1207db96d56Sopenharmony_ci 1217db96d56Sopenharmony_ci for dest, src in rglob(Path(tcl_lib).parent, "**/*"): 1227db96d56Sopenharmony_ci yield "tcl/{}".format(dest), src 1237db96d56Sopenharmony_ci 1247db96d56Sopenharmony_ci 1257db96d56Sopenharmony_cidef get_layout(ns): 1267db96d56Sopenharmony_ci def in_build(f, dest="", new_name=None): 1277db96d56Sopenharmony_ci n, _, x = f.rpartition(".") 1287db96d56Sopenharmony_ci n = new_name or n 1297db96d56Sopenharmony_ci src = ns.build / f 1307db96d56Sopenharmony_ci if ns.debug and src not in REQUIRED_DLLS: 1317db96d56Sopenharmony_ci if not src.stem.endswith("_d"): 1327db96d56Sopenharmony_ci src = src.parent / (src.stem + "_d" + src.suffix) 1337db96d56Sopenharmony_ci if not n.endswith("_d"): 1347db96d56Sopenharmony_ci n += "_d" 1357db96d56Sopenharmony_ci f = n + "." + x 1367db96d56Sopenharmony_ci yield dest + n + "." + x, src 1377db96d56Sopenharmony_ci if ns.include_symbols: 1387db96d56Sopenharmony_ci pdb = src.with_suffix(".pdb") 1397db96d56Sopenharmony_ci if pdb.is_file(): 1407db96d56Sopenharmony_ci yield dest + n + ".pdb", pdb 1417db96d56Sopenharmony_ci if ns.include_dev: 1427db96d56Sopenharmony_ci lib = src.with_suffix(".lib") 1437db96d56Sopenharmony_ci if lib.is_file(): 1447db96d56Sopenharmony_ci yield "libs/" + n + ".lib", lib 1457db96d56Sopenharmony_ci 1467db96d56Sopenharmony_ci if ns.include_appxmanifest: 1477db96d56Sopenharmony_ci yield from in_build("python_uwp.exe", new_name="python{}".format(VER_DOT)) 1487db96d56Sopenharmony_ci yield from in_build("pythonw_uwp.exe", new_name="pythonw{}".format(VER_DOT)) 1497db96d56Sopenharmony_ci # For backwards compatibility, but we don't reference these ourselves. 1507db96d56Sopenharmony_ci yield from in_build("python_uwp.exe", new_name="python") 1517db96d56Sopenharmony_ci yield from in_build("pythonw_uwp.exe", new_name="pythonw") 1527db96d56Sopenharmony_ci else: 1537db96d56Sopenharmony_ci yield from in_build("python.exe", new_name="python") 1547db96d56Sopenharmony_ci yield from in_build("pythonw.exe", new_name="pythonw") 1557db96d56Sopenharmony_ci 1567db96d56Sopenharmony_ci yield from in_build(PYTHON_DLL_NAME) 1577db96d56Sopenharmony_ci 1587db96d56Sopenharmony_ci if ns.include_launchers and ns.include_appxmanifest: 1597db96d56Sopenharmony_ci if ns.include_pip: 1607db96d56Sopenharmony_ci yield from in_build("python_uwp.exe", new_name="pip{}".format(VER_DOT)) 1617db96d56Sopenharmony_ci if ns.include_idle: 1627db96d56Sopenharmony_ci yield from in_build("pythonw_uwp.exe", new_name="idle{}".format(VER_DOT)) 1637db96d56Sopenharmony_ci 1647db96d56Sopenharmony_ci if ns.include_stable: 1657db96d56Sopenharmony_ci yield from in_build(PYTHON_STABLE_DLL_NAME) 1667db96d56Sopenharmony_ci 1677db96d56Sopenharmony_ci found_any = False 1687db96d56Sopenharmony_ci for dest, src in rglob(ns.build, "vcruntime*.dll"): 1697db96d56Sopenharmony_ci found_any = True 1707db96d56Sopenharmony_ci yield dest, src 1717db96d56Sopenharmony_ci if not found_any: 1727db96d56Sopenharmony_ci log_error("Failed to locate vcruntime DLL in the build.") 1737db96d56Sopenharmony_ci 1747db96d56Sopenharmony_ci yield "LICENSE.txt", ns.build / "LICENSE.txt" 1757db96d56Sopenharmony_ci 1767db96d56Sopenharmony_ci for dest, src in rglob(ns.build, ("*.pyd", "*.dll")): 1777db96d56Sopenharmony_ci if src.stem.endswith("_d") != bool(ns.debug) and src not in REQUIRED_DLLS: 1787db96d56Sopenharmony_ci continue 1797db96d56Sopenharmony_ci if src in EXCLUDE_FROM_PYDS: 1807db96d56Sopenharmony_ci continue 1817db96d56Sopenharmony_ci if src in TEST_PYDS_ONLY and not ns.include_tests: 1827db96d56Sopenharmony_ci continue 1837db96d56Sopenharmony_ci if src in TCLTK_PYDS_ONLY and not ns.include_tcltk: 1847db96d56Sopenharmony_ci continue 1857db96d56Sopenharmony_ci 1867db96d56Sopenharmony_ci yield from in_build(src.name, dest="" if ns.flat_dlls else "DLLs/") 1877db96d56Sopenharmony_ci 1887db96d56Sopenharmony_ci if ns.zip_lib: 1897db96d56Sopenharmony_ci zip_name = PYTHON_ZIP_NAME 1907db96d56Sopenharmony_ci yield zip_name, ns.temp / zip_name 1917db96d56Sopenharmony_ci else: 1927db96d56Sopenharmony_ci for dest, src in get_lib_layout(ns): 1937db96d56Sopenharmony_ci yield "Lib/{}".format(dest), src 1947db96d56Sopenharmony_ci 1957db96d56Sopenharmony_ci if ns.include_venv: 1967db96d56Sopenharmony_ci yield from in_build("venvlauncher.exe", "Lib/venv/scripts/nt/", "python") 1977db96d56Sopenharmony_ci yield from in_build("venvwlauncher.exe", "Lib/venv/scripts/nt/", "pythonw") 1987db96d56Sopenharmony_ci 1997db96d56Sopenharmony_ci if ns.include_tools: 2007db96d56Sopenharmony_ci 2017db96d56Sopenharmony_ci def _c(d): 2027db96d56Sopenharmony_ci if d.is_dir(): 2037db96d56Sopenharmony_ci return d in TOOLS_DIRS 2047db96d56Sopenharmony_ci return d in TOOLS_FILES 2057db96d56Sopenharmony_ci 2067db96d56Sopenharmony_ci for dest, src in rglob(ns.source / "Tools", "**/*", _c): 2077db96d56Sopenharmony_ci yield "Tools/{}".format(dest), src 2087db96d56Sopenharmony_ci 2097db96d56Sopenharmony_ci if ns.include_underpth: 2107db96d56Sopenharmony_ci yield PYTHON_PTH_NAME, ns.temp / PYTHON_PTH_NAME 2117db96d56Sopenharmony_ci 2127db96d56Sopenharmony_ci if ns.include_dev: 2137db96d56Sopenharmony_ci 2147db96d56Sopenharmony_ci for dest, src in rglob(ns.source / "Include", "**/*.h"): 2157db96d56Sopenharmony_ci yield "include/{}".format(dest), src 2167db96d56Sopenharmony_ci src = ns.source / "PC" / "pyconfig.h" 2177db96d56Sopenharmony_ci yield "include/pyconfig.h", src 2187db96d56Sopenharmony_ci 2197db96d56Sopenharmony_ci for dest, src in get_tcltk_lib(ns): 2207db96d56Sopenharmony_ci yield dest, src 2217db96d56Sopenharmony_ci 2227db96d56Sopenharmony_ci if ns.include_pip: 2237db96d56Sopenharmony_ci for dest, src in get_pip_layout(ns): 2247db96d56Sopenharmony_ci if not isinstance(src, tuple) and ( 2257db96d56Sopenharmony_ci src in EXCLUDE_FROM_LIB or src in EXCLUDE_FROM_PACKAGED_LIB 2267db96d56Sopenharmony_ci ): 2277db96d56Sopenharmony_ci continue 2287db96d56Sopenharmony_ci yield dest, src 2297db96d56Sopenharmony_ci 2307db96d56Sopenharmony_ci if ns.include_chm: 2317db96d56Sopenharmony_ci for dest, src in rglob(ns.doc_build / "htmlhelp", PYTHON_CHM_NAME): 2327db96d56Sopenharmony_ci yield "Doc/{}".format(dest), src 2337db96d56Sopenharmony_ci 2347db96d56Sopenharmony_ci if ns.include_html_doc: 2357db96d56Sopenharmony_ci for dest, src in rglob(ns.doc_build / "html", "**/*"): 2367db96d56Sopenharmony_ci yield "Doc/html/{}".format(dest), src 2377db96d56Sopenharmony_ci 2387db96d56Sopenharmony_ci if ns.include_props: 2397db96d56Sopenharmony_ci for dest, src in get_props_layout(ns): 2407db96d56Sopenharmony_ci yield dest, src 2417db96d56Sopenharmony_ci 2427db96d56Sopenharmony_ci if ns.include_nuspec: 2437db96d56Sopenharmony_ci for dest, src in get_nuspec_layout(ns): 2447db96d56Sopenharmony_ci yield dest, src 2457db96d56Sopenharmony_ci 2467db96d56Sopenharmony_ci for dest, src in get_appx_layout(ns): 2477db96d56Sopenharmony_ci yield dest, src 2487db96d56Sopenharmony_ci 2497db96d56Sopenharmony_ci if ns.include_cat: 2507db96d56Sopenharmony_ci if ns.flat_dlls: 2517db96d56Sopenharmony_ci yield ns.include_cat.name, ns.include_cat 2527db96d56Sopenharmony_ci else: 2537db96d56Sopenharmony_ci yield "DLLs/{}".format(ns.include_cat.name), ns.include_cat 2547db96d56Sopenharmony_ci 2557db96d56Sopenharmony_ci 2567db96d56Sopenharmony_cidef _compile_one_py(src, dest, name, optimize, checked=True): 2577db96d56Sopenharmony_ci import py_compile 2587db96d56Sopenharmony_ci 2597db96d56Sopenharmony_ci if dest is not None: 2607db96d56Sopenharmony_ci dest = str(dest) 2617db96d56Sopenharmony_ci 2627db96d56Sopenharmony_ci mode = ( 2637db96d56Sopenharmony_ci py_compile.PycInvalidationMode.CHECKED_HASH 2647db96d56Sopenharmony_ci if checked 2657db96d56Sopenharmony_ci else py_compile.PycInvalidationMode.UNCHECKED_HASH 2667db96d56Sopenharmony_ci ) 2677db96d56Sopenharmony_ci 2687db96d56Sopenharmony_ci try: 2697db96d56Sopenharmony_ci return Path( 2707db96d56Sopenharmony_ci py_compile.compile( 2717db96d56Sopenharmony_ci str(src), 2727db96d56Sopenharmony_ci dest, 2737db96d56Sopenharmony_ci str(name), 2747db96d56Sopenharmony_ci doraise=True, 2757db96d56Sopenharmony_ci optimize=optimize, 2767db96d56Sopenharmony_ci invalidation_mode=mode, 2777db96d56Sopenharmony_ci ) 2787db96d56Sopenharmony_ci ) 2797db96d56Sopenharmony_ci except py_compile.PyCompileError: 2807db96d56Sopenharmony_ci log_warning("Failed to compile {}", src) 2817db96d56Sopenharmony_ci return None 2827db96d56Sopenharmony_ci 2837db96d56Sopenharmony_ci 2847db96d56Sopenharmony_ci# name argument added to address bpo-37641 2857db96d56Sopenharmony_cidef _py_temp_compile(src, name, ns, dest_dir=None, checked=True): 2867db96d56Sopenharmony_ci if not ns.precompile or src not in PY_FILES or src.parent in DATA_DIRS: 2877db96d56Sopenharmony_ci return None 2887db96d56Sopenharmony_ci dest = (dest_dir or ns.temp) / (src.stem + ".pyc") 2897db96d56Sopenharmony_ci return _compile_one_py(src, dest, name, optimize=2, checked=checked) 2907db96d56Sopenharmony_ci 2917db96d56Sopenharmony_ci 2927db96d56Sopenharmony_cidef _write_to_zip(zf, dest, src, ns, checked=True): 2937db96d56Sopenharmony_ci pyc = _py_temp_compile(src, dest, ns, checked=checked) 2947db96d56Sopenharmony_ci if pyc: 2957db96d56Sopenharmony_ci try: 2967db96d56Sopenharmony_ci zf.write(str(pyc), dest.with_suffix(".pyc")) 2977db96d56Sopenharmony_ci finally: 2987db96d56Sopenharmony_ci try: 2997db96d56Sopenharmony_ci pyc.unlink() 3007db96d56Sopenharmony_ci except: 3017db96d56Sopenharmony_ci log_exception("Failed to delete {}", pyc) 3027db96d56Sopenharmony_ci return 3037db96d56Sopenharmony_ci 3047db96d56Sopenharmony_ci if src in LIB2TO3_GRAMMAR_FILES: 3057db96d56Sopenharmony_ci from lib2to3.pgen2.driver import load_grammar 3067db96d56Sopenharmony_ci 3077db96d56Sopenharmony_ci tmp = ns.temp / src.name 3087db96d56Sopenharmony_ci try: 3097db96d56Sopenharmony_ci shutil.copy(src, tmp) 3107db96d56Sopenharmony_ci load_grammar(str(tmp)) 3117db96d56Sopenharmony_ci for f in ns.temp.glob(src.stem + "*.pickle"): 3127db96d56Sopenharmony_ci zf.write(str(f), str(dest.parent / f.name)) 3137db96d56Sopenharmony_ci try: 3147db96d56Sopenharmony_ci f.unlink() 3157db96d56Sopenharmony_ci except: 3167db96d56Sopenharmony_ci log_exception("Failed to delete {}", f) 3177db96d56Sopenharmony_ci except: 3187db96d56Sopenharmony_ci log_exception("Failed to compile {}", src) 3197db96d56Sopenharmony_ci finally: 3207db96d56Sopenharmony_ci try: 3217db96d56Sopenharmony_ci tmp.unlink() 3227db96d56Sopenharmony_ci except: 3237db96d56Sopenharmony_ci log_exception("Failed to delete {}", tmp) 3247db96d56Sopenharmony_ci 3257db96d56Sopenharmony_ci zf.write(str(src), str(dest)) 3267db96d56Sopenharmony_ci 3277db96d56Sopenharmony_ci 3287db96d56Sopenharmony_cidef generate_source_files(ns): 3297db96d56Sopenharmony_ci if ns.zip_lib: 3307db96d56Sopenharmony_ci zip_name = PYTHON_ZIP_NAME 3317db96d56Sopenharmony_ci zip_path = ns.temp / zip_name 3327db96d56Sopenharmony_ci if zip_path.is_file(): 3337db96d56Sopenharmony_ci zip_path.unlink() 3347db96d56Sopenharmony_ci elif zip_path.is_dir(): 3357db96d56Sopenharmony_ci log_error( 3367db96d56Sopenharmony_ci "Cannot create zip file because a directory exists by the same name" 3377db96d56Sopenharmony_ci ) 3387db96d56Sopenharmony_ci return 3397db96d56Sopenharmony_ci log_info("Generating {} in {}", zip_name, ns.temp) 3407db96d56Sopenharmony_ci ns.temp.mkdir(parents=True, exist_ok=True) 3417db96d56Sopenharmony_ci with zipfile.ZipFile(zip_path, "w", zipfile.ZIP_DEFLATED) as zf: 3427db96d56Sopenharmony_ci for dest, src in get_lib_layout(ns): 3437db96d56Sopenharmony_ci _write_to_zip(zf, dest, src, ns, checked=False) 3447db96d56Sopenharmony_ci 3457db96d56Sopenharmony_ci if ns.include_underpth: 3467db96d56Sopenharmony_ci log_info("Generating {} in {}", PYTHON_PTH_NAME, ns.temp) 3477db96d56Sopenharmony_ci ns.temp.mkdir(parents=True, exist_ok=True) 3487db96d56Sopenharmony_ci with open(ns.temp / PYTHON_PTH_NAME, "w", encoding="utf-8") as f: 3497db96d56Sopenharmony_ci if ns.zip_lib: 3507db96d56Sopenharmony_ci print(PYTHON_ZIP_NAME, file=f) 3517db96d56Sopenharmony_ci if ns.include_pip: 3527db96d56Sopenharmony_ci print("packages", file=f) 3537db96d56Sopenharmony_ci else: 3547db96d56Sopenharmony_ci print("Lib", file=f) 3557db96d56Sopenharmony_ci print("Lib/site-packages", file=f) 3567db96d56Sopenharmony_ci if not ns.flat_dlls: 3577db96d56Sopenharmony_ci print("DLLs", file=f) 3587db96d56Sopenharmony_ci print(".", file=f) 3597db96d56Sopenharmony_ci print(file=f) 3607db96d56Sopenharmony_ci print("# Uncomment to run site.main() automatically", file=f) 3617db96d56Sopenharmony_ci print("#import site", file=f) 3627db96d56Sopenharmony_ci 3637db96d56Sopenharmony_ci if ns.include_pip: 3647db96d56Sopenharmony_ci log_info("Extracting pip") 3657db96d56Sopenharmony_ci extract_pip_files(ns) 3667db96d56Sopenharmony_ci 3677db96d56Sopenharmony_ci 3687db96d56Sopenharmony_cidef _create_zip_file(ns): 3697db96d56Sopenharmony_ci if not ns.zip: 3707db96d56Sopenharmony_ci return None 3717db96d56Sopenharmony_ci 3727db96d56Sopenharmony_ci if ns.zip.is_file(): 3737db96d56Sopenharmony_ci try: 3747db96d56Sopenharmony_ci ns.zip.unlink() 3757db96d56Sopenharmony_ci except OSError: 3767db96d56Sopenharmony_ci log_exception("Unable to remove {}", ns.zip) 3777db96d56Sopenharmony_ci sys.exit(8) 3787db96d56Sopenharmony_ci elif ns.zip.is_dir(): 3797db96d56Sopenharmony_ci log_error("Cannot create ZIP file because {} is a directory", ns.zip) 3807db96d56Sopenharmony_ci sys.exit(8) 3817db96d56Sopenharmony_ci 3827db96d56Sopenharmony_ci ns.zip.parent.mkdir(parents=True, exist_ok=True) 3837db96d56Sopenharmony_ci return zipfile.ZipFile(ns.zip, "w", zipfile.ZIP_DEFLATED) 3847db96d56Sopenharmony_ci 3857db96d56Sopenharmony_ci 3867db96d56Sopenharmony_cidef copy_files(files, ns): 3877db96d56Sopenharmony_ci if ns.copy: 3887db96d56Sopenharmony_ci ns.copy.mkdir(parents=True, exist_ok=True) 3897db96d56Sopenharmony_ci 3907db96d56Sopenharmony_ci try: 3917db96d56Sopenharmony_ci total = len(files) 3927db96d56Sopenharmony_ci except TypeError: 3937db96d56Sopenharmony_ci total = None 3947db96d56Sopenharmony_ci count = 0 3957db96d56Sopenharmony_ci 3967db96d56Sopenharmony_ci zip_file = _create_zip_file(ns) 3977db96d56Sopenharmony_ci try: 3987db96d56Sopenharmony_ci need_compile = [] 3997db96d56Sopenharmony_ci in_catalog = [] 4007db96d56Sopenharmony_ci 4017db96d56Sopenharmony_ci for dest, src in files: 4027db96d56Sopenharmony_ci count += 1 4037db96d56Sopenharmony_ci if count % 10 == 0: 4047db96d56Sopenharmony_ci if total: 4057db96d56Sopenharmony_ci log_info("Processed {:>4} of {} files", count, total) 4067db96d56Sopenharmony_ci else: 4077db96d56Sopenharmony_ci log_info("Processed {} files", count) 4087db96d56Sopenharmony_ci log_debug("Processing {!s}", src) 4097db96d56Sopenharmony_ci 4107db96d56Sopenharmony_ci if isinstance(src, tuple): 4117db96d56Sopenharmony_ci src, content = src 4127db96d56Sopenharmony_ci if ns.copy: 4137db96d56Sopenharmony_ci log_debug("Copy {} -> {}", src, ns.copy / dest) 4147db96d56Sopenharmony_ci (ns.copy / dest).parent.mkdir(parents=True, exist_ok=True) 4157db96d56Sopenharmony_ci with open(ns.copy / dest, "wb") as f: 4167db96d56Sopenharmony_ci f.write(content) 4177db96d56Sopenharmony_ci if ns.zip: 4187db96d56Sopenharmony_ci log_debug("Zip {} into {}", src, ns.zip) 4197db96d56Sopenharmony_ci zip_file.writestr(str(dest), content) 4207db96d56Sopenharmony_ci continue 4217db96d56Sopenharmony_ci 4227db96d56Sopenharmony_ci if ( 4237db96d56Sopenharmony_ci ns.precompile 4247db96d56Sopenharmony_ci and src in PY_FILES 4257db96d56Sopenharmony_ci and src not in EXCLUDE_FROM_COMPILE 4267db96d56Sopenharmony_ci and src.parent not in DATA_DIRS 4277db96d56Sopenharmony_ci and os.path.normcase(str(dest)).startswith(os.path.normcase("Lib")) 4287db96d56Sopenharmony_ci ): 4297db96d56Sopenharmony_ci if ns.copy: 4307db96d56Sopenharmony_ci need_compile.append((dest, ns.copy / dest)) 4317db96d56Sopenharmony_ci else: 4327db96d56Sopenharmony_ci (ns.temp / "Lib" / dest).parent.mkdir(parents=True, exist_ok=True) 4337db96d56Sopenharmony_ci copy_if_modified(src, ns.temp / "Lib" / dest) 4347db96d56Sopenharmony_ci need_compile.append((dest, ns.temp / "Lib" / dest)) 4357db96d56Sopenharmony_ci 4367db96d56Sopenharmony_ci if src not in EXCLUDE_FROM_CATALOG: 4377db96d56Sopenharmony_ci in_catalog.append((src.name, src)) 4387db96d56Sopenharmony_ci 4397db96d56Sopenharmony_ci if ns.copy: 4407db96d56Sopenharmony_ci log_debug("Copy {} -> {}", src, ns.copy / dest) 4417db96d56Sopenharmony_ci (ns.copy / dest).parent.mkdir(parents=True, exist_ok=True) 4427db96d56Sopenharmony_ci try: 4437db96d56Sopenharmony_ci copy_if_modified(src, ns.copy / dest) 4447db96d56Sopenharmony_ci except shutil.SameFileError: 4457db96d56Sopenharmony_ci pass 4467db96d56Sopenharmony_ci 4477db96d56Sopenharmony_ci if ns.zip: 4487db96d56Sopenharmony_ci log_debug("Zip {} into {}", src, ns.zip) 4497db96d56Sopenharmony_ci zip_file.write(src, str(dest)) 4507db96d56Sopenharmony_ci 4517db96d56Sopenharmony_ci if need_compile: 4527db96d56Sopenharmony_ci for dest, src in need_compile: 4537db96d56Sopenharmony_ci compiled = [ 4547db96d56Sopenharmony_ci _compile_one_py(src, None, dest, optimize=0), 4557db96d56Sopenharmony_ci _compile_one_py(src, None, dest, optimize=1), 4567db96d56Sopenharmony_ci _compile_one_py(src, None, dest, optimize=2), 4577db96d56Sopenharmony_ci ] 4587db96d56Sopenharmony_ci for c in compiled: 4597db96d56Sopenharmony_ci if not c: 4607db96d56Sopenharmony_ci continue 4617db96d56Sopenharmony_ci cdest = Path(dest).parent / Path(c).relative_to(src.parent) 4627db96d56Sopenharmony_ci if ns.zip: 4637db96d56Sopenharmony_ci log_debug("Zip {} into {}", c, ns.zip) 4647db96d56Sopenharmony_ci zip_file.write(c, str(cdest)) 4657db96d56Sopenharmony_ci in_catalog.append((cdest.name, cdest)) 4667db96d56Sopenharmony_ci 4677db96d56Sopenharmony_ci if ns.catalog: 4687db96d56Sopenharmony_ci # Just write out the CDF now. Compilation and signing is 4697db96d56Sopenharmony_ci # an extra step 4707db96d56Sopenharmony_ci log_info("Generating {}", ns.catalog) 4717db96d56Sopenharmony_ci ns.catalog.parent.mkdir(parents=True, exist_ok=True) 4727db96d56Sopenharmony_ci write_catalog(ns.catalog, in_catalog) 4737db96d56Sopenharmony_ci 4747db96d56Sopenharmony_ci finally: 4757db96d56Sopenharmony_ci if zip_file: 4767db96d56Sopenharmony_ci zip_file.close() 4777db96d56Sopenharmony_ci 4787db96d56Sopenharmony_ci 4797db96d56Sopenharmony_cidef main(): 4807db96d56Sopenharmony_ci parser = argparse.ArgumentParser() 4817db96d56Sopenharmony_ci parser.add_argument("-v", help="Increase verbosity", action="count") 4827db96d56Sopenharmony_ci parser.add_argument( 4837db96d56Sopenharmony_ci "-s", 4847db96d56Sopenharmony_ci "--source", 4857db96d56Sopenharmony_ci metavar="dir", 4867db96d56Sopenharmony_ci help="The directory containing the repository root", 4877db96d56Sopenharmony_ci type=Path, 4887db96d56Sopenharmony_ci default=None, 4897db96d56Sopenharmony_ci ) 4907db96d56Sopenharmony_ci parser.add_argument( 4917db96d56Sopenharmony_ci "-b", "--build", metavar="dir", help="Specify the build directory", type=Path 4927db96d56Sopenharmony_ci ) 4937db96d56Sopenharmony_ci parser.add_argument( 4947db96d56Sopenharmony_ci "--arch", 4957db96d56Sopenharmony_ci metavar="architecture", 4967db96d56Sopenharmony_ci help="Specify the target architecture", 4977db96d56Sopenharmony_ci type=str, 4987db96d56Sopenharmony_ci default=None, 4997db96d56Sopenharmony_ci ) 5007db96d56Sopenharmony_ci parser.add_argument( 5017db96d56Sopenharmony_ci "--doc-build", 5027db96d56Sopenharmony_ci metavar="dir", 5037db96d56Sopenharmony_ci help="Specify the docs build directory", 5047db96d56Sopenharmony_ci type=Path, 5057db96d56Sopenharmony_ci default=None, 5067db96d56Sopenharmony_ci ) 5077db96d56Sopenharmony_ci parser.add_argument( 5087db96d56Sopenharmony_ci "--copy", 5097db96d56Sopenharmony_ci metavar="directory", 5107db96d56Sopenharmony_ci help="The name of the directory to copy an extracted layout to", 5117db96d56Sopenharmony_ci type=Path, 5127db96d56Sopenharmony_ci default=None, 5137db96d56Sopenharmony_ci ) 5147db96d56Sopenharmony_ci parser.add_argument( 5157db96d56Sopenharmony_ci "--zip", 5167db96d56Sopenharmony_ci metavar="file", 5177db96d56Sopenharmony_ci help="The ZIP file to write all files to", 5187db96d56Sopenharmony_ci type=Path, 5197db96d56Sopenharmony_ci default=None, 5207db96d56Sopenharmony_ci ) 5217db96d56Sopenharmony_ci parser.add_argument( 5227db96d56Sopenharmony_ci "--catalog", 5237db96d56Sopenharmony_ci metavar="file", 5247db96d56Sopenharmony_ci help="The CDF file to write catalog entries to", 5257db96d56Sopenharmony_ci type=Path, 5267db96d56Sopenharmony_ci default=None, 5277db96d56Sopenharmony_ci ) 5287db96d56Sopenharmony_ci parser.add_argument( 5297db96d56Sopenharmony_ci "--log", 5307db96d56Sopenharmony_ci metavar="file", 5317db96d56Sopenharmony_ci help="Write all operations to the specified file", 5327db96d56Sopenharmony_ci type=Path, 5337db96d56Sopenharmony_ci default=None, 5347db96d56Sopenharmony_ci ) 5357db96d56Sopenharmony_ci parser.add_argument( 5367db96d56Sopenharmony_ci "-t", 5377db96d56Sopenharmony_ci "--temp", 5387db96d56Sopenharmony_ci metavar="file", 5397db96d56Sopenharmony_ci help="A temporary working directory", 5407db96d56Sopenharmony_ci type=Path, 5417db96d56Sopenharmony_ci default=None, 5427db96d56Sopenharmony_ci ) 5437db96d56Sopenharmony_ci parser.add_argument( 5447db96d56Sopenharmony_ci "-d", "--debug", help="Include debug build", action="store_true" 5457db96d56Sopenharmony_ci ) 5467db96d56Sopenharmony_ci parser.add_argument( 5477db96d56Sopenharmony_ci "-p", 5487db96d56Sopenharmony_ci "--precompile", 5497db96d56Sopenharmony_ci help="Include .pyc files instead of .py", 5507db96d56Sopenharmony_ci action="store_true", 5517db96d56Sopenharmony_ci ) 5527db96d56Sopenharmony_ci parser.add_argument( 5537db96d56Sopenharmony_ci "-z", "--zip-lib", help="Include library in a ZIP file", action="store_true" 5547db96d56Sopenharmony_ci ) 5557db96d56Sopenharmony_ci parser.add_argument( 5567db96d56Sopenharmony_ci "--flat-dlls", help="Does not create a DLLs directory", action="store_true" 5577db96d56Sopenharmony_ci ) 5587db96d56Sopenharmony_ci parser.add_argument( 5597db96d56Sopenharmony_ci "-a", 5607db96d56Sopenharmony_ci "--include-all", 5617db96d56Sopenharmony_ci help="Include all optional components", 5627db96d56Sopenharmony_ci action="store_true", 5637db96d56Sopenharmony_ci ) 5647db96d56Sopenharmony_ci parser.add_argument( 5657db96d56Sopenharmony_ci "--include-cat", 5667db96d56Sopenharmony_ci metavar="file", 5677db96d56Sopenharmony_ci help="Specify the catalog file to include", 5687db96d56Sopenharmony_ci type=Path, 5697db96d56Sopenharmony_ci default=None, 5707db96d56Sopenharmony_ci ) 5717db96d56Sopenharmony_ci for opt, help in get_argparse_options(): 5727db96d56Sopenharmony_ci parser.add_argument(opt, help=help, action="store_true") 5737db96d56Sopenharmony_ci 5747db96d56Sopenharmony_ci ns = parser.parse_args() 5757db96d56Sopenharmony_ci update_presets(ns) 5767db96d56Sopenharmony_ci 5777db96d56Sopenharmony_ci ns.source = ns.source or (Path(__file__).resolve().parent.parent.parent) 5787db96d56Sopenharmony_ci ns.build = ns.build or Path(sys.executable).parent 5797db96d56Sopenharmony_ci ns.temp = ns.temp or Path(tempfile.mkdtemp()) 5807db96d56Sopenharmony_ci ns.doc_build = ns.doc_build or (ns.source / "Doc" / "build") 5817db96d56Sopenharmony_ci if not ns.source.is_absolute(): 5827db96d56Sopenharmony_ci ns.source = (Path.cwd() / ns.source).resolve() 5837db96d56Sopenharmony_ci if not ns.build.is_absolute(): 5847db96d56Sopenharmony_ci ns.build = (Path.cwd() / ns.build).resolve() 5857db96d56Sopenharmony_ci if not ns.temp.is_absolute(): 5867db96d56Sopenharmony_ci ns.temp = (Path.cwd() / ns.temp).resolve() 5877db96d56Sopenharmony_ci if not ns.doc_build.is_absolute(): 5887db96d56Sopenharmony_ci ns.doc_build = (Path.cwd() / ns.doc_build).resolve() 5897db96d56Sopenharmony_ci if ns.include_cat and not ns.include_cat.is_absolute(): 5907db96d56Sopenharmony_ci ns.include_cat = (Path.cwd() / ns.include_cat).resolve() 5917db96d56Sopenharmony_ci if not ns.arch: 5927db96d56Sopenharmony_ci ns.arch = "amd64" if sys.maxsize > 2 ** 32 else "win32" 5937db96d56Sopenharmony_ci 5947db96d56Sopenharmony_ci if ns.copy and not ns.copy.is_absolute(): 5957db96d56Sopenharmony_ci ns.copy = (Path.cwd() / ns.copy).resolve() 5967db96d56Sopenharmony_ci if ns.zip and not ns.zip.is_absolute(): 5977db96d56Sopenharmony_ci ns.zip = (Path.cwd() / ns.zip).resolve() 5987db96d56Sopenharmony_ci if ns.catalog and not ns.catalog.is_absolute(): 5997db96d56Sopenharmony_ci ns.catalog = (Path.cwd() / ns.catalog).resolve() 6007db96d56Sopenharmony_ci 6017db96d56Sopenharmony_ci configure_logger(ns) 6027db96d56Sopenharmony_ci 6037db96d56Sopenharmony_ci log_info( 6047db96d56Sopenharmony_ci """OPTIONS 6057db96d56Sopenharmony_ciSource: {ns.source} 6067db96d56Sopenharmony_ciBuild: {ns.build} 6077db96d56Sopenharmony_ciTemp: {ns.temp} 6087db96d56Sopenharmony_ciArch: {ns.arch} 6097db96d56Sopenharmony_ci 6107db96d56Sopenharmony_ciCopy to: {ns.copy} 6117db96d56Sopenharmony_ciZip to: {ns.zip} 6127db96d56Sopenharmony_ciCatalog: {ns.catalog}""", 6137db96d56Sopenharmony_ci ns=ns, 6147db96d56Sopenharmony_ci ) 6157db96d56Sopenharmony_ci 6167db96d56Sopenharmony_ci if ns.arch not in ("win32", "amd64", "arm32", "arm64"): 6177db96d56Sopenharmony_ci log_error("--arch is not a valid value (win32, amd64, arm32, arm64)") 6187db96d56Sopenharmony_ci return 4 6197db96d56Sopenharmony_ci if ns.arch in ("arm32", "arm64"): 6207db96d56Sopenharmony_ci for n in ("include_idle", "include_tcltk"): 6217db96d56Sopenharmony_ci if getattr(ns, n): 6227db96d56Sopenharmony_ci log_warning(f"Disabling --{n.replace('_', '-')} on unsupported platform") 6237db96d56Sopenharmony_ci setattr(ns, n, False) 6247db96d56Sopenharmony_ci 6257db96d56Sopenharmony_ci if ns.include_idle and not ns.include_tcltk: 6267db96d56Sopenharmony_ci log_warning("Assuming --include-tcltk to support --include-idle") 6277db96d56Sopenharmony_ci ns.include_tcltk = True 6287db96d56Sopenharmony_ci 6297db96d56Sopenharmony_ci try: 6307db96d56Sopenharmony_ci generate_source_files(ns) 6317db96d56Sopenharmony_ci files = list(get_layout(ns)) 6327db96d56Sopenharmony_ci copy_files(files, ns) 6337db96d56Sopenharmony_ci except KeyboardInterrupt: 6347db96d56Sopenharmony_ci log_info("Interrupted by Ctrl+C") 6357db96d56Sopenharmony_ci return 3 6367db96d56Sopenharmony_ci except SystemExit: 6377db96d56Sopenharmony_ci raise 6387db96d56Sopenharmony_ci except: 6397db96d56Sopenharmony_ci log_exception("Unhandled error") 6407db96d56Sopenharmony_ci 6417db96d56Sopenharmony_ci if error_was_logged(): 6427db96d56Sopenharmony_ci log_error("Errors occurred.") 6437db96d56Sopenharmony_ci return 1 6447db96d56Sopenharmony_ci 6457db96d56Sopenharmony_ci 6467db96d56Sopenharmony_ciif __name__ == "__main__": 6477db96d56Sopenharmony_ci sys.exit(int(main() or 0)) 648