"""Generates a layout of Python for Windows from a build.See python make_layout.py --help for usage."""__author__ = "Steve Dower <steve.dower@python.org>"__version__ = "3.8"import argparseimport functoolsimport osimport reimport shutilimport subprocessimport sysimport tempfileimport zipfilefrom pathlib import Pathif __name__ == "__main__":# Started directly, so enable relative imports__path__ = [str(Path(__file__).resolve().parent)]from .support.appxmanifest import *from .support.catalog import *from .support.constants import *from .support.filesets import *from .support.logging import *from .support.options import *from .support.pip import *from .support.props import *from .support.nuspec import *BDIST_WININST_FILES_ONLY = FileNameSet("wininst-*", "bdist_wininst.py")BDIST_WININST_STUB = "PC/layout/support/distutils.command.bdist_wininst.py"TEST_PYDS_ONLY = FileStemSet("xxlimited", "_ctypes_test", "_test*")TEST_DIRS_ONLY = FileNameSet("test", "tests")IDLE_DIRS_ONLY = FileNameSet("idlelib")TCLTK_PYDS_ONLY = FileStemSet("tcl*", "tk*", "_tkinter")TCLTK_DIRS_ONLY = FileNameSet("tkinter", "turtledemo")TCLTK_FILES_ONLY = FileNameSet("turtle.py")VENV_DIRS_ONLY = FileNameSet("venv", "ensurepip")EXCLUDE_FROM_PYDS = FileStemSet("python*", "pyshellext", "vcruntime*")EXCLUDE_FROM_LIB = FileNameSet("*.pyc", "__pycache__", "*.pickle")EXCLUDE_FROM_PACKAGED_LIB = FileNameSet("readme.txt")EXCLUDE_FROM_COMPILE = FileNameSet("badsyntax_*", "bad_*")EXCLUDE_FROM_CATALOG = FileSuffixSet(".exe", ".pyd", ".dll")REQUIRED_DLLS = FileStemSet("libcrypto*", "libssl*", "libffi*")LIB2TO3_GRAMMAR_FILES = FileNameSet("Grammar.txt", "PatternGrammar.txt")PY_FILES = FileSuffixSet(".py")PYC_FILES = FileSuffixSet(".pyc")CAT_FILES = FileSuffixSet(".cat")CDF_FILES = FileSuffixSet(".cdf")DATA_DIRS = FileNameSet("data")TOOLS_DIRS = FileNameSet("scripts", "i18n", "pynche", "demo", "parser")TOOLS_FILES = FileSuffixSet(".py", ".pyw", ".txt")def copy_if_modified(src, dest):try:dest_stat = os.stat(dest)except FileNotFoundError:do_copy = Trueelse:src_stat = os.stat(src)do_copy = (src_stat.st_mtime != dest_stat.st_mtimeor src_stat.st_size != dest_stat.st_size)if do_copy:shutil.copy2(src, dest)def get_lib_layout(ns):def _c(f):if f in EXCLUDE_FROM_LIB:return Falseif f.is_dir():if f in TEST_DIRS_ONLY:return ns.include_testsif f in TCLTK_DIRS_ONLY:return ns.include_tcltkif f in IDLE_DIRS_ONLY:return ns.include_idleif f in VENV_DIRS_ONLY:return ns.include_venvelse:if f in TCLTK_FILES_ONLY:return ns.include_tcltkif f in BDIST_WININST_FILES_ONLY:return ns.include_bdist_wininstreturn Truefor dest, src in rglob(ns.source / "Lib", "**/*", _c):yield dest, srcif not ns.include_bdist_wininst:src = ns.source / BDIST_WININST_STUByield Path("distutils/command/bdist_wininst.py"), srcdef get_tcltk_lib(ns):if not ns.include_tcltk:returntcl_lib = os.getenv("TCL_LIBRARY")if not tcl_lib or not os.path.isdir(tcl_lib):try:with open(ns.build / "TCL_LIBRARY.env", "r", encoding="utf-8-sig") as f:tcl_lib = f.read().strip()except FileNotFoundError:passif not tcl_lib or not os.path.isdir(tcl_lib):log_warning("Failed to find TCL_LIBRARY")returnfor dest, src in rglob(Path(tcl_lib).parent, "**/*"):yield "tcl/{}".format(dest), srcdef get_layout(ns):def in_build(f, dest="", new_name=None):n, _, x = f.rpartition(".")n = new_name or nsrc = ns.build / fif ns.debug and src not in REQUIRED_DLLS:if not src.stem.endswith("_d"):src = src.parent / (src.stem + "_d" + src.suffix)if not n.endswith("_d"):n += "_d"f = n + "." + xyield dest + n + "." + x, srcif ns.include_symbols:pdb = src.with_suffix(".pdb")if pdb.is_file():yield dest + n + ".pdb", pdbif ns.include_dev:lib = src.with_suffix(".lib")if lib.is_file():yield "libs/" + n + ".lib", libif ns.include_appxmanifest:yield from in_build("python_uwp.exe", new_name="python{}".format(VER_DOT))yield from in_build("pythonw_uwp.exe", new_name="pythonw{}".format(VER_DOT))# For backwards compatibility, but we don't reference these ourselves.yield from in_build("python_uwp.exe", new_name="python")yield from in_build("pythonw_uwp.exe", new_name="pythonw")else:yield from in_build("python.exe", new_name="python")yield from in_build("pythonw.exe", new_name="pythonw")yield from in_build(PYTHON_DLL_NAME)if ns.include_launchers and ns.include_appxmanifest:if ns.include_pip:yield from in_build("python_uwp.exe", new_name="pip{}".format(VER_DOT))if ns.include_idle:yield from in_build("pythonw_uwp.exe", new_name="idle{}".format(VER_DOT))if ns.include_stable:yield from in_build(PYTHON_STABLE_DLL_NAME)for dest, src in rglob(ns.build, "vcruntime*.dll"):yield dest, srcyield "LICENSE.txt", ns.build / "LICENSE.txt"for dest, src in rglob(ns.build, ("*.pyd", "*.dll")):if src.stem.endswith("_d") != bool(ns.debug) and src not in REQUIRED_DLLS:continueif src in EXCLUDE_FROM_PYDS:continueif src in TEST_PYDS_ONLY and not ns.include_tests:continueif src in TCLTK_PYDS_ONLY and not ns.include_tcltk:continueyield from in_build(src.name, dest="" if ns.flat_dlls else "DLLs/")if ns.zip_lib:zip_name = PYTHON_ZIP_NAMEyield zip_name, ns.temp / zip_nameelse:for dest, src in get_lib_layout(ns):yield "Lib/{}".format(dest), srcif ns.include_venv:yield from in_build("venvlauncher.exe", "Lib/venv/scripts/nt/", "python")yield from in_build("venvwlauncher.exe", "Lib/venv/scripts/nt/", "pythonw")if ns.include_tools:def _c(d):if d.is_dir():return d in TOOLS_DIRSreturn d in TOOLS_FILESfor dest, src in rglob(ns.source / "Tools", "**/*", _c):yield "Tools/{}".format(dest), srcif ns.include_underpth:yield PYTHON_PTH_NAME, ns.temp / PYTHON_PTH_NAMEif ns.include_dev:for dest, src in rglob(ns.source / "Include", "**/*.h"):yield "include/{}".format(dest), srcsrc = ns.source / "PC" / "pyconfig.h"yield "include/pyconfig.h", srcfor dest, src in get_tcltk_lib(ns):yield dest, srcif ns.include_pip:for dest, src in get_pip_layout(ns):if not isinstance(src, tuple) and (src in EXCLUDE_FROM_LIB or src in EXCLUDE_FROM_PACKAGED_LIB):continueyield dest, srcif ns.include_chm:for dest, src in rglob(ns.doc_build / "htmlhelp", PYTHON_CHM_NAME):yield "Doc/{}".format(dest), srcif ns.include_html_doc:for dest, src in rglob(ns.doc_build / "html", "**/*"):yield "Doc/html/{}".format(dest), srcif ns.include_props:for dest, src in get_props_layout(ns):yield dest, srcif ns.include_nuspec:for dest, src in get_nuspec_layout(ns):yield dest, srcfor dest, src in get_appx_layout(ns):yield dest, srcif ns.include_cat:if ns.flat_dlls:yield ns.include_cat.name, ns.include_catelse:yield "DLLs/{}".format(ns.include_cat.name), ns.include_catdef _compile_one_py(src, dest, name, optimize, checked=True):import py_compileif dest is not None:dest = str(dest)mode = (py_compile.PycInvalidationMode.CHECKED_HASHif checkedelse py_compile.PycInvalidationMode.UNCHECKED_HASH)try:return Path(py_compile.compile(str(src),dest,str(name),doraise=True,optimize=optimize,invalidation_mode=mode,))except py_compile.PyCompileError:log_warning("Failed to compile {}", src)return None# name argument added to address bpo-37641def _py_temp_compile(src, name, ns, dest_dir=None, checked=True):if not ns.precompile or src not in PY_FILES or src.parent in DATA_DIRS:return Nonedest = (dest_dir or ns.temp) / (src.stem + ".pyc")return _compile_one_py(src, dest, name, optimize=2, checked=checked)def _write_to_zip(zf, dest, src, ns, checked=True):pyc = _py_temp_compile(src, dest, ns, checked=checked)if pyc:try:zf.write(str(pyc), dest.with_suffix(".pyc"))finally:try:pyc.unlink()except:log_exception("Failed to delete {}", pyc)returnif src in LIB2TO3_GRAMMAR_FILES:from lib2to3.pgen2.driver import load_grammartmp = ns.temp / src.nametry:shutil.copy(src, tmp)load_grammar(str(tmp))for f in ns.temp.glob(src.stem + "*.pickle"):zf.write(str(f), str(dest.parent / f.name))try:f.unlink()except:log_exception("Failed to delete {}", f)except:log_exception("Failed to compile {}", src)finally:try:tmp.unlink()except:log_exception("Failed to delete {}", tmp)zf.write(str(src), str(dest))def generate_source_files(ns):if ns.zip_lib:zip_name = PYTHON_ZIP_NAMEzip_path = ns.temp / zip_nameif zip_path.is_file():zip_path.unlink()elif zip_path.is_dir():log_error("Cannot create zip file because a directory exists by the same name")returnlog_info("Generating {} in {}", zip_name, ns.temp)ns.temp.mkdir(parents=True, exist_ok=True)with zipfile.ZipFile(zip_path, "w", zipfile.ZIP_DEFLATED) as zf:for dest, src in get_lib_layout(ns):_write_to_zip(zf, dest, src, ns, checked=False)if ns.include_underpth:log_info("Generating {} in {}", PYTHON_PTH_NAME, ns.temp)ns.temp.mkdir(parents=True, exist_ok=True)with open(ns.temp / PYTHON_PTH_NAME, "w", encoding="utf-8") as f:if ns.zip_lib:print(PYTHON_ZIP_NAME, file=f)if ns.include_pip:print("packages", file=f)else:print("Lib", file=f)print("Lib/site-packages", file=f)if not ns.flat_dlls:print("DLLs", file=f)print(".", file=f)print(file=f)print("# Uncomment to run site.main() automatically", file=f)print("#import site", file=f)if ns.include_pip:log_info("Extracting pip")extract_pip_files(ns)def _create_zip_file(ns):if not ns.zip:return Noneif ns.zip.is_file():try:ns.zip.unlink()except OSError:log_exception("Unable to remove {}", ns.zip)sys.exit(8)elif ns.zip.is_dir():log_error("Cannot create ZIP file because {} is a directory", ns.zip)sys.exit(8)ns.zip.parent.mkdir(parents=True, exist_ok=True)return zipfile.ZipFile(ns.zip, "w", zipfile.ZIP_DEFLATED)def copy_files(files, ns):if ns.copy:ns.copy.mkdir(parents=True, exist_ok=True)try:total = len(files)except TypeError:total = Nonecount = 0zip_file = _create_zip_file(ns)try:need_compile = []in_catalog = []for dest, src in files:count += 1if count % 10 == 0:if total:log_info("Processed {:>4} of {} files", count, total)else:log_info("Processed {} files", count)log_debug("Processing {!s}", src)if isinstance(src, tuple):src, content = srcif ns.copy:log_debug("Copy {} -> {}", src, ns.copy / dest)(ns.copy / dest).parent.mkdir(parents=True, exist_ok=True)with open(ns.copy / dest, "wb") as f:f.write(content)if ns.zip:log_debug("Zip {} into {}", src, ns.zip)zip_file.writestr(str(dest), content)continueif (ns.precompileand src in PY_FILESand src not in EXCLUDE_FROM_COMPILEand src.parent not in DATA_DIRSand os.path.normcase(str(dest)).startswith(os.path.normcase("Lib"))):if ns.copy:need_compile.append((dest, ns.copy / dest))else:(ns.temp / "Lib" / dest).parent.mkdir(parents=True, exist_ok=True)copy_if_modified(src, ns.temp / "Lib" / dest)need_compile.append((dest, ns.temp / "Lib" / dest))if src not in EXCLUDE_FROM_CATALOG:in_catalog.append((src.name, src))if ns.copy:log_debug("Copy {} -> {}", src, ns.copy / dest)(ns.copy / dest).parent.mkdir(parents=True, exist_ok=True)try:copy_if_modified(src, ns.copy / dest)except shutil.SameFileError:passif ns.zip:log_debug("Zip {} into {}", src, ns.zip)zip_file.write(src, str(dest))if need_compile:for dest, src in need_compile:compiled = [_compile_one_py(src, None, dest, optimize=0),_compile_one_py(src, None, dest, optimize=1),_compile_one_py(src, None, dest, optimize=2),]for c in compiled:if not c:continuecdest = Path(dest).parent / Path(c).relative_to(src.parent)if ns.zip:log_debug("Zip {} into {}", c, ns.zip)zip_file.write(c, str(cdest))in_catalog.append((cdest.name, cdest))if ns.catalog:# Just write out the CDF now. Compilation and signing is# an extra steplog_info("Generating {}", ns.catalog)ns.catalog.parent.mkdir(parents=True, exist_ok=True)write_catalog(ns.catalog, in_catalog)finally:if zip_file:zip_file.close()def main():parser = argparse.ArgumentParser()parser.add_argument("-v", help="Increase verbosity", action="count")parser.add_argument("-s","--source",metavar="dir",help="The directory containing the repository root",type=Path,default=None,)parser.add_argument("-b", "--build", metavar="dir", help="Specify the build directory", type=Path)parser.add_argument("--arch",metavar="architecture",help="Specify the target architecture",type=str,default=None,)parser.add_argument("--doc-build",metavar="dir",help="Specify the docs build directory",type=Path,default=None,)parser.add_argument("--copy",metavar="directory",help="The name of the directory to copy an extracted layout to",type=Path,default=None,)parser.add_argument("--zip",metavar="file",help="The ZIP file to write all files to",type=Path,default=None,)parser.add_argument("--catalog",metavar="file",help="The CDF file to write catalog entries to",type=Path,default=None,)parser.add_argument("--log",metavar="file",help="Write all operations to the specified file",type=Path,default=None,)parser.add_argument("-t","--temp",metavar="file",help="A temporary working directory",type=Path,default=None,)parser.add_argument("-d", "--debug", help="Include debug build", action="store_true")parser.add_argument("-p","--precompile",help="Include .pyc files instead of .py",action="store_true",)parser.add_argument("-z", "--zip-lib", help="Include library in a ZIP file", action="store_true")parser.add_argument("--flat-dlls", help="Does not create a DLLs directory", action="store_true")parser.add_argument("-a","--include-all",help="Include all optional components",action="store_true",)parser.add_argument("--include-cat",metavar="file",help="Specify the catalog file to include",type=Path,default=None,)for opt, help in get_argparse_options():parser.add_argument(opt, help=help, action="store_true")ns = parser.parse_args()update_presets(ns)ns.source = ns.source or (Path(__file__).resolve().parent.parent.parent)ns.build = ns.build or Path(sys.executable).parentns.temp = ns.temp or Path(tempfile.mkdtemp())ns.doc_build = ns.doc_build or (ns.source / "Doc" / "build")if not ns.source.is_absolute():ns.source = (Path.cwd() / ns.source).resolve()if not ns.build.is_absolute():ns.build = (Path.cwd() / ns.build).resolve()if not ns.temp.is_absolute():ns.temp = (Path.cwd() / ns.temp).resolve()if not ns.doc_build.is_absolute():ns.doc_build = (Path.cwd() / ns.doc_build).resolve()if ns.include_cat and not ns.include_cat.is_absolute():ns.include_cat = (Path.cwd() / ns.include_cat).resolve()if not ns.arch:ns.arch = "amd64" if sys.maxsize > 2 ** 32 else "win32"if ns.copy and not ns.copy.is_absolute():ns.copy = (Path.cwd() / ns.copy).resolve()if ns.zip and not ns.zip.is_absolute():ns.zip = (Path.cwd() / ns.zip).resolve()if ns.catalog and not ns.catalog.is_absolute():ns.catalog = (Path.cwd() / ns.catalog).resolve()configure_logger(ns)log_info("""OPTIONSSource: {ns.source}Build: {ns.build}Temp: {ns.temp}Arch: {ns.arch}Copy to: {ns.copy}Zip to: {ns.zip}Catalog: {ns.catalog}""",ns=ns,)if ns.arch not in ("win32", "amd64", "arm32", "arm64"):log_error("--arch is not a valid value (win32, amd64, arm32, arm64)")return 4if ns.arch in ("arm32", "arm64"):for n in ("include_idle", "include_tcltk"):if getattr(ns, n):log_warning(f"Disabling --{n.replace('_', '-')} on unsupported platform")setattr(ns, n, False)if ns.include_idle and not ns.include_tcltk:log_warning("Assuming --include-tcltk to support --include-idle")ns.include_tcltk = Truetry:generate_source_files(ns)files = list(get_layout(ns))copy_files(files, ns)except KeyboardInterrupt:log_info("Interrupted by Ctrl+C")return 3except SystemExit:raiseexcept:log_exception("Unhandled error")if error_was_logged():log_error("Errors occurred.")return 1if __name__ == "__main__":sys.exit(int(main() or 0))
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。