blob: 3eef7556299cf2c113363815c59c20d50dfa7459 [file] [log] [blame]
Steve Dower0cd63912018-12-10 18:52:57 -08001"""
2Generates a layout of Python for Windows from a build.
3
4See python make_layout.py --help for usage.
5"""
6
7__author__ = "Steve Dower <steve.dower@python.org>"
8__version__ = "3.8"
9
10import argparse
11import functools
12import os
13import re
14import shutil
15import subprocess
16import sys
17import tempfile
18import zipfile
19
20from pathlib import Path
21
22if __name__ == "__main__":
23 # Started directly, so enable relative imports
24 __path__ = [str(Path(__file__).resolve().parent)]
25
26from .support.appxmanifest import *
27from .support.catalog import *
28from .support.constants import *
29from .support.filesets import *
30from .support.logging import *
31from .support.options import *
32from .support.pip import *
33from .support.props import *
Steve Dower21a92f82019-06-14 08:29:20 -070034from .support.nuspec import *
Steve Dower0cd63912018-12-10 18:52:57 -080035
36BDIST_WININST_FILES_ONLY = FileNameSet("wininst-*", "bdist_wininst.py")
37BDIST_WININST_STUB = "PC/layout/support/distutils.command.bdist_wininst.py"
38
39TEST_PYDS_ONLY = FileStemSet("xxlimited", "_ctypes_test", "_test*")
40TEST_DIRS_ONLY = FileNameSet("test", "tests")
41
42IDLE_DIRS_ONLY = FileNameSet("idlelib")
43
44TCLTK_PYDS_ONLY = FileStemSet("tcl*", "tk*", "_tkinter")
45TCLTK_DIRS_ONLY = FileNameSet("tkinter", "turtledemo")
46TCLTK_FILES_ONLY = FileNameSet("turtle.py")
47
48VENV_DIRS_ONLY = FileNameSet("venv", "ensurepip")
49
Steve Dower59c2aa22018-12-27 12:44:25 -080050EXCLUDE_FROM_PYDS = FileStemSet("python*", "pyshellext", "vcruntime*")
Steve Dower0cd63912018-12-10 18:52:57 -080051EXCLUDE_FROM_LIB = FileNameSet("*.pyc", "__pycache__", "*.pickle")
52EXCLUDE_FROM_PACKAGED_LIB = FileNameSet("readme.txt")
53EXCLUDE_FROM_COMPILE = FileNameSet("badsyntax_*", "bad_*")
54EXCLUDE_FROM_CATALOG = FileSuffixSet(".exe", ".pyd", ".dll")
55
Paul Monson32119e12019-03-29 16:30:10 -070056REQUIRED_DLLS = FileStemSet("libcrypto*", "libssl*", "libffi*")
Steve Dower0cd63912018-12-10 18:52:57 -080057
58LIB2TO3_GRAMMAR_FILES = FileNameSet("Grammar.txt", "PatternGrammar.txt")
59
60PY_FILES = FileSuffixSet(".py")
61PYC_FILES = FileSuffixSet(".pyc")
62CAT_FILES = FileSuffixSet(".cat")
63CDF_FILES = FileSuffixSet(".cdf")
64
65DATA_DIRS = FileNameSet("data")
66
67TOOLS_DIRS = FileNameSet("scripts", "i18n", "pynche", "demo", "parser")
68TOOLS_FILES = FileSuffixSet(".py", ".pyw", ".txt")
69
Steve Dower21a92f82019-06-14 08:29:20 -070070
Paul Monsonf4e56612019-04-12 09:55:57 -070071def copy_if_modified(src, dest):
72 try:
73 dest_stat = os.stat(dest)
74 except FileNotFoundError:
75 do_copy = True
76 else:
77 src_stat = os.stat(src)
Steve Dower21a92f82019-06-14 08:29:20 -070078 do_copy = (
79 src_stat.st_mtime != dest_stat.st_mtime
80 or src_stat.st_size != dest_stat.st_size
81 )
Paul Monsonf4e56612019-04-12 09:55:57 -070082
83 if do_copy:
84 shutil.copy2(src, dest)
Steve Dower0cd63912018-12-10 18:52:57 -080085
Steve Dower21a92f82019-06-14 08:29:20 -070086
Steve Dower0cd63912018-12-10 18:52:57 -080087def get_lib_layout(ns):
88 def _c(f):
89 if f in EXCLUDE_FROM_LIB:
90 return False
91 if f.is_dir():
92 if f in TEST_DIRS_ONLY:
93 return ns.include_tests
94 if f in TCLTK_DIRS_ONLY:
95 return ns.include_tcltk
96 if f in IDLE_DIRS_ONLY:
97 return ns.include_idle
98 if f in VENV_DIRS_ONLY:
99 return ns.include_venv
100 else:
101 if f in TCLTK_FILES_ONLY:
102 return ns.include_tcltk
103 if f in BDIST_WININST_FILES_ONLY:
104 return ns.include_bdist_wininst
105 return True
106
107 for dest, src in rglob(ns.source / "Lib", "**/*", _c):
108 yield dest, src
109
110 if not ns.include_bdist_wininst:
111 src = ns.source / BDIST_WININST_STUB
112 yield Path("distutils/command/bdist_wininst.py"), src
113
114
115def get_tcltk_lib(ns):
116 if not ns.include_tcltk:
117 return
118
119 tcl_lib = os.getenv("TCL_LIBRARY")
120 if not tcl_lib or not os.path.isdir(tcl_lib):
121 try:
122 with open(ns.build / "TCL_LIBRARY.env", "r", encoding="utf-8-sig") as f:
123 tcl_lib = f.read().strip()
124 except FileNotFoundError:
125 pass
126 if not tcl_lib or not os.path.isdir(tcl_lib):
Steve Dower21a92f82019-06-14 08:29:20 -0700127 log_warning("Failed to find TCL_LIBRARY")
Steve Dower0cd63912018-12-10 18:52:57 -0800128 return
129
130 for dest, src in rglob(Path(tcl_lib).parent, "**/*"):
131 yield "tcl/{}".format(dest), src
132
133
134def get_layout(ns):
135 def in_build(f, dest="", new_name=None):
136 n, _, x = f.rpartition(".")
137 n = new_name or n
138 src = ns.build / f
139 if ns.debug and src not in REQUIRED_DLLS:
140 if not src.stem.endswith("_d"):
141 src = src.parent / (src.stem + "_d" + src.suffix)
142 if not n.endswith("_d"):
143 n += "_d"
144 f = n + "." + x
145 yield dest + n + "." + x, src
146 if ns.include_symbols:
147 pdb = src.with_suffix(".pdb")
148 if pdb.is_file():
149 yield dest + n + ".pdb", pdb
150 if ns.include_dev:
151 lib = src.with_suffix(".lib")
152 if lib.is_file():
153 yield "libs/" + n + ".lib", lib
154
155 if ns.include_appxmanifest:
Steve Dower1fab9cb2019-08-07 10:49:40 -0700156 yield from in_build("python_uwp.exe", new_name="python{}".format(VER_DOT))
157 yield from in_build("pythonw_uwp.exe", new_name="pythonw{}".format(VER_DOT))
158 # For backwards compatibility, but we don't reference these ourselves.
Steve Dower0cd63912018-12-10 18:52:57 -0800159 yield from in_build("python_uwp.exe", new_name="python")
160 yield from in_build("pythonw_uwp.exe", new_name="pythonw")
161 else:
162 yield from in_build("python.exe", new_name="python")
163 yield from in_build("pythonw.exe", new_name="pythonw")
164
165 yield from in_build(PYTHON_DLL_NAME)
166
167 if ns.include_launchers and ns.include_appxmanifest:
168 if ns.include_pip:
Steve Dower1fab9cb2019-08-07 10:49:40 -0700169 yield from in_build("python_uwp.exe", new_name="pip{}".format(VER_DOT))
Steve Dower0cd63912018-12-10 18:52:57 -0800170 if ns.include_idle:
Steve Dower1fab9cb2019-08-07 10:49:40 -0700171 yield from in_build("pythonw_uwp.exe", new_name="idle{}".format(VER_DOT))
Steve Dower0cd63912018-12-10 18:52:57 -0800172
173 if ns.include_stable:
174 yield from in_build(PYTHON_STABLE_DLL_NAME)
175
Steve Dowerfde44ae2020-03-11 14:12:31 +0000176 found_any = False
Steve Dower0cd63912018-12-10 18:52:57 -0800177 for dest, src in rglob(ns.build, "vcruntime*.dll"):
Steve Dowerfde44ae2020-03-11 14:12:31 +0000178 found_any = True
Steve Dower0cd63912018-12-10 18:52:57 -0800179 yield dest, src
Steve Dowerfde44ae2020-03-11 14:12:31 +0000180 if not found_any:
181 log_error("Failed to locate vcruntime DLL in the build.")
Steve Dower0cd63912018-12-10 18:52:57 -0800182
Steve Dower21a92f82019-06-14 08:29:20 -0700183 yield "LICENSE.txt", ns.build / "LICENSE.txt"
Steve Dower28f6cb32019-01-22 10:49:52 -0800184
Steve Dower0cd63912018-12-10 18:52:57 -0800185 for dest, src in rglob(ns.build, ("*.pyd", "*.dll")):
186 if src.stem.endswith("_d") != bool(ns.debug) and src not in REQUIRED_DLLS:
187 continue
188 if src in EXCLUDE_FROM_PYDS:
189 continue
190 if src in TEST_PYDS_ONLY and not ns.include_tests:
191 continue
192 if src in TCLTK_PYDS_ONLY and not ns.include_tcltk:
193 continue
194
195 yield from in_build(src.name, dest="" if ns.flat_dlls else "DLLs/")
196
197 if ns.zip_lib:
198 zip_name = PYTHON_ZIP_NAME
199 yield zip_name, ns.temp / zip_name
200 else:
201 for dest, src in get_lib_layout(ns):
202 yield "Lib/{}".format(dest), src
203
204 if ns.include_venv:
205 yield from in_build("venvlauncher.exe", "Lib/venv/scripts/nt/", "python")
206 yield from in_build("venvwlauncher.exe", "Lib/venv/scripts/nt/", "pythonw")
207
208 if ns.include_tools:
209
210 def _c(d):
211 if d.is_dir():
212 return d in TOOLS_DIRS
213 return d in TOOLS_FILES
214
215 for dest, src in rglob(ns.source / "Tools", "**/*", _c):
216 yield "Tools/{}".format(dest), src
217
218 if ns.include_underpth:
219 yield PYTHON_PTH_NAME, ns.temp / PYTHON_PTH_NAME
220
221 if ns.include_dev:
222
Zackery Spytzedb172a2019-10-28 11:03:27 -0600223 for dest, src in rglob(ns.source / "Include", "**/*.h"):
Steve Dower0cd63912018-12-10 18:52:57 -0800224 yield "include/{}".format(dest), src
225 src = ns.source / "PC" / "pyconfig.h"
226 yield "include/pyconfig.h", src
227
228 for dest, src in get_tcltk_lib(ns):
229 yield dest, src
230
231 if ns.include_pip:
Steve Dower21a92f82019-06-14 08:29:20 -0700232 for dest, src in get_pip_layout(ns):
Steve Dower123536f2019-07-24 15:13:22 -0700233 if not isinstance(src, tuple) and (
Steve Dower21a92f82019-06-14 08:29:20 -0700234 src in EXCLUDE_FROM_LIB or src in EXCLUDE_FROM_PACKAGED_LIB
235 ):
236 continue
237 yield dest, src
Steve Dower0cd63912018-12-10 18:52:57 -0800238
239 if ns.include_chm:
240 for dest, src in rglob(ns.doc_build / "htmlhelp", PYTHON_CHM_NAME):
241 yield "Doc/{}".format(dest), src
242
243 if ns.include_html_doc:
244 for dest, src in rglob(ns.doc_build / "html", "**/*"):
245 yield "Doc/html/{}".format(dest), src
246
247 if ns.include_props:
248 for dest, src in get_props_layout(ns):
249 yield dest, src
250
Steve Dower21a92f82019-06-14 08:29:20 -0700251 if ns.include_nuspec:
252 for dest, src in get_nuspec_layout(ns):
253 yield dest, src
254
Steve Dower0cd63912018-12-10 18:52:57 -0800255 for dest, src in get_appx_layout(ns):
256 yield dest, src
257
258 if ns.include_cat:
259 if ns.flat_dlls:
260 yield ns.include_cat.name, ns.include_cat
261 else:
262 yield "DLLs/{}".format(ns.include_cat.name), ns.include_cat
263
264
Steve Dower872bd2b2019-01-08 02:38:01 -0800265def _compile_one_py(src, dest, name, optimize, checked=True):
Steve Dower0cd63912018-12-10 18:52:57 -0800266 import py_compile
267
268 if dest is not None:
269 dest = str(dest)
270
Steve Dower872bd2b2019-01-08 02:38:01 -0800271 mode = (
272 py_compile.PycInvalidationMode.CHECKED_HASH
273 if checked
274 else py_compile.PycInvalidationMode.UNCHECKED_HASH
275 )
276
Steve Dower0cd63912018-12-10 18:52:57 -0800277 try:
278 return Path(
279 py_compile.compile(
280 str(src),
281 dest,
282 str(name),
283 doraise=True,
284 optimize=optimize,
Steve Dower872bd2b2019-01-08 02:38:01 -0800285 invalidation_mode=mode,
Steve Dower0cd63912018-12-10 18:52:57 -0800286 )
287 )
288 except py_compile.PyCompileError:
289 log_warning("Failed to compile {}", src)
290 return None
291
Steve Dowerde148f22019-11-20 09:30:47 -0800292
Bill Collinsc4cda432019-07-25 22:36:58 +0100293# name argument added to address bpo-37641
294def _py_temp_compile(src, name, ns, dest_dir=None, checked=True):
Steve Dower0cd63912018-12-10 18:52:57 -0800295 if not ns.precompile or src not in PY_FILES or src.parent in DATA_DIRS:
296 return None
Bill Collinsc4cda432019-07-25 22:36:58 +0100297 dest = (dest_dir or ns.temp) / (src.stem + ".pyc")
Steve Dowerde148f22019-11-20 09:30:47 -0800298 return _compile_one_py(src, dest, name, optimize=2, checked=checked)
Steve Dower0cd63912018-12-10 18:52:57 -0800299
300
Steve Dower872bd2b2019-01-08 02:38:01 -0800301def _write_to_zip(zf, dest, src, ns, checked=True):
Bill Collinsc4cda432019-07-25 22:36:58 +0100302 pyc = _py_temp_compile(src, dest, ns, checked=checked)
Steve Dower0cd63912018-12-10 18:52:57 -0800303 if pyc:
304 try:
305 zf.write(str(pyc), dest.with_suffix(".pyc"))
306 finally:
307 try:
308 pyc.unlink()
309 except:
310 log_exception("Failed to delete {}", pyc)
311 return
312
313 if src in LIB2TO3_GRAMMAR_FILES:
314 from lib2to3.pgen2.driver import load_grammar
315
316 tmp = ns.temp / src.name
317 try:
318 shutil.copy(src, tmp)
319 load_grammar(str(tmp))
320 for f in ns.temp.glob(src.stem + "*.pickle"):
321 zf.write(str(f), str(dest.parent / f.name))
322 try:
323 f.unlink()
324 except:
325 log_exception("Failed to delete {}", f)
326 except:
327 log_exception("Failed to compile {}", src)
328 finally:
329 try:
330 tmp.unlink()
331 except:
332 log_exception("Failed to delete {}", tmp)
333
334 zf.write(str(src), str(dest))
335
336
337def generate_source_files(ns):
338 if ns.zip_lib:
339 zip_name = PYTHON_ZIP_NAME
340 zip_path = ns.temp / zip_name
341 if zip_path.is_file():
342 zip_path.unlink()
343 elif zip_path.is_dir():
344 log_error(
345 "Cannot create zip file because a directory exists by the same name"
346 )
347 return
348 log_info("Generating {} in {}", zip_name, ns.temp)
349 ns.temp.mkdir(parents=True, exist_ok=True)
350 with zipfile.ZipFile(zip_path, "w", zipfile.ZIP_DEFLATED) as zf:
351 for dest, src in get_lib_layout(ns):
Steve Dower872bd2b2019-01-08 02:38:01 -0800352 _write_to_zip(zf, dest, src, ns, checked=False)
Steve Dower0cd63912018-12-10 18:52:57 -0800353
354 if ns.include_underpth:
355 log_info("Generating {} in {}", PYTHON_PTH_NAME, ns.temp)
356 ns.temp.mkdir(parents=True, exist_ok=True)
357 with open(ns.temp / PYTHON_PTH_NAME, "w", encoding="utf-8") as f:
358 if ns.zip_lib:
359 print(PYTHON_ZIP_NAME, file=f)
360 if ns.include_pip:
361 print("packages", file=f)
362 else:
363 print("Lib", file=f)
364 print("Lib/site-packages", file=f)
365 if not ns.flat_dlls:
366 print("DLLs", file=f)
367 print(".", file=f)
368 print(file=f)
369 print("# Uncomment to run site.main() automatically", file=f)
370 print("#import site", file=f)
371
Steve Dower0cd63912018-12-10 18:52:57 -0800372 if ns.include_pip:
Steve Dower21a92f82019-06-14 08:29:20 -0700373 log_info("Extracting pip")
374 extract_pip_files(ns)
Steve Dower0cd63912018-12-10 18:52:57 -0800375
376
377def _create_zip_file(ns):
378 if not ns.zip:
379 return None
380
381 if ns.zip.is_file():
382 try:
383 ns.zip.unlink()
384 except OSError:
385 log_exception("Unable to remove {}", ns.zip)
386 sys.exit(8)
387 elif ns.zip.is_dir():
388 log_error("Cannot create ZIP file because {} is a directory", ns.zip)
389 sys.exit(8)
390
391 ns.zip.parent.mkdir(parents=True, exist_ok=True)
392 return zipfile.ZipFile(ns.zip, "w", zipfile.ZIP_DEFLATED)
393
394
395def copy_files(files, ns):
396 if ns.copy:
397 ns.copy.mkdir(parents=True, exist_ok=True)
398
399 try:
400 total = len(files)
401 except TypeError:
402 total = None
403 count = 0
404
405 zip_file = _create_zip_file(ns)
406 try:
407 need_compile = []
408 in_catalog = []
409
410 for dest, src in files:
411 count += 1
412 if count % 10 == 0:
413 if total:
414 log_info("Processed {:>4} of {} files", count, total)
415 else:
416 log_info("Processed {} files", count)
417 log_debug("Processing {!s}", src)
418
Steve Dower21a92f82019-06-14 08:29:20 -0700419 if isinstance(src, tuple):
420 src, content = src
421 if ns.copy:
422 log_debug("Copy {} -> {}", src, ns.copy / dest)
423 (ns.copy / dest).parent.mkdir(parents=True, exist_ok=True)
424 with open(ns.copy / dest, "wb") as f:
425 f.write(content)
426 if ns.zip:
427 log_debug("Zip {} into {}", src, ns.zip)
428 zip_file.writestr(str(dest), content)
429 continue
430
Steve Dower0cd63912018-12-10 18:52:57 -0800431 if (
432 ns.precompile
433 and src in PY_FILES
434 and src not in EXCLUDE_FROM_COMPILE
435 and src.parent not in DATA_DIRS
436 and os.path.normcase(str(dest)).startswith(os.path.normcase("Lib"))
437 ):
438 if ns.copy:
439 need_compile.append((dest, ns.copy / dest))
440 else:
441 (ns.temp / "Lib" / dest).parent.mkdir(parents=True, exist_ok=True)
Paul Monsonf4e56612019-04-12 09:55:57 -0700442 copy_if_modified(src, ns.temp / "Lib" / dest)
Steve Dower0cd63912018-12-10 18:52:57 -0800443 need_compile.append((dest, ns.temp / "Lib" / dest))
444
445 if src not in EXCLUDE_FROM_CATALOG:
446 in_catalog.append((src.name, src))
447
448 if ns.copy:
449 log_debug("Copy {} -> {}", src, ns.copy / dest)
450 (ns.copy / dest).parent.mkdir(parents=True, exist_ok=True)
451 try:
Paul Monsonf4e56612019-04-12 09:55:57 -0700452 copy_if_modified(src, ns.copy / dest)
Steve Dower0cd63912018-12-10 18:52:57 -0800453 except shutil.SameFileError:
454 pass
455
456 if ns.zip:
457 log_debug("Zip {} into {}", src, ns.zip)
458 zip_file.write(src, str(dest))
459
460 if need_compile:
461 for dest, src in need_compile:
462 compiled = [
463 _compile_one_py(src, None, dest, optimize=0),
464 _compile_one_py(src, None, dest, optimize=1),
465 _compile_one_py(src, None, dest, optimize=2),
466 ]
467 for c in compiled:
468 if not c:
469 continue
470 cdest = Path(dest).parent / Path(c).relative_to(src.parent)
471 if ns.zip:
472 log_debug("Zip {} into {}", c, ns.zip)
473 zip_file.write(c, str(cdest))
474 in_catalog.append((cdest.name, cdest))
475
476 if ns.catalog:
477 # Just write out the CDF now. Compilation and signing is
478 # an extra step
479 log_info("Generating {}", ns.catalog)
480 ns.catalog.parent.mkdir(parents=True, exist_ok=True)
481 write_catalog(ns.catalog, in_catalog)
482
483 finally:
484 if zip_file:
485 zip_file.close()
486
487
488def main():
489 parser = argparse.ArgumentParser()
490 parser.add_argument("-v", help="Increase verbosity", action="count")
491 parser.add_argument(
492 "-s",
493 "--source",
494 metavar="dir",
495 help="The directory containing the repository root",
496 type=Path,
497 default=None,
498 )
499 parser.add_argument(
500 "-b", "--build", metavar="dir", help="Specify the build directory", type=Path
501 )
502 parser.add_argument(
Steve Dowerde148f22019-11-20 09:30:47 -0800503 "--arch",
504 metavar="architecture",
505 help="Specify the target architecture",
506 type=str,
507 default=None,
508 )
509 parser.add_argument(
Steve Dower0cd63912018-12-10 18:52:57 -0800510 "--doc-build",
511 metavar="dir",
512 help="Specify the docs build directory",
513 type=Path,
514 default=None,
515 )
516 parser.add_argument(
517 "--copy",
518 metavar="directory",
519 help="The name of the directory to copy an extracted layout to",
520 type=Path,
521 default=None,
522 )
523 parser.add_argument(
524 "--zip",
525 metavar="file",
526 help="The ZIP file to write all files to",
527 type=Path,
528 default=None,
529 )
530 parser.add_argument(
531 "--catalog",
532 metavar="file",
533 help="The CDF file to write catalog entries to",
534 type=Path,
535 default=None,
536 )
537 parser.add_argument(
538 "--log",
539 metavar="file",
540 help="Write all operations to the specified file",
541 type=Path,
542 default=None,
543 )
544 parser.add_argument(
545 "-t",
546 "--temp",
547 metavar="file",
548 help="A temporary working directory",
549 type=Path,
550 default=None,
551 )
552 parser.add_argument(
553 "-d", "--debug", help="Include debug build", action="store_true"
554 )
555 parser.add_argument(
556 "-p",
557 "--precompile",
558 help="Include .pyc files instead of .py",
559 action="store_true",
560 )
561 parser.add_argument(
562 "-z", "--zip-lib", help="Include library in a ZIP file", action="store_true"
563 )
564 parser.add_argument(
565 "--flat-dlls", help="Does not create a DLLs directory", action="store_true"
566 )
567 parser.add_argument(
568 "-a",
569 "--include-all",
570 help="Include all optional components",
571 action="store_true",
572 )
573 parser.add_argument(
574 "--include-cat",
575 metavar="file",
576 help="Specify the catalog file to include",
577 type=Path,
578 default=None,
579 )
580 for opt, help in get_argparse_options():
581 parser.add_argument(opt, help=help, action="store_true")
582
583 ns = parser.parse_args()
584 update_presets(ns)
585
586 ns.source = ns.source or (Path(__file__).resolve().parent.parent.parent)
587 ns.build = ns.build or Path(sys.executable).parent
588 ns.temp = ns.temp or Path(tempfile.mkdtemp())
589 ns.doc_build = ns.doc_build or (ns.source / "Doc" / "build")
590 if not ns.source.is_absolute():
591 ns.source = (Path.cwd() / ns.source).resolve()
592 if not ns.build.is_absolute():
593 ns.build = (Path.cwd() / ns.build).resolve()
594 if not ns.temp.is_absolute():
595 ns.temp = (Path.cwd() / ns.temp).resolve()
596 if not ns.doc_build.is_absolute():
597 ns.doc_build = (Path.cwd() / ns.doc_build).resolve()
598 if ns.include_cat and not ns.include_cat.is_absolute():
599 ns.include_cat = (Path.cwd() / ns.include_cat).resolve()
Steve Dowerde148f22019-11-20 09:30:47 -0800600 if not ns.arch:
601 ns.arch = "amd64" if sys.maxsize > 2 ** 32 else "win32"
Steve Dower0cd63912018-12-10 18:52:57 -0800602
603 if ns.copy and not ns.copy.is_absolute():
604 ns.copy = (Path.cwd() / ns.copy).resolve()
605 if ns.zip and not ns.zip.is_absolute():
606 ns.zip = (Path.cwd() / ns.zip).resolve()
607 if ns.catalog and not ns.catalog.is_absolute():
608 ns.catalog = (Path.cwd() / ns.catalog).resolve()
609
610 configure_logger(ns)
611
612 log_info(
613 """OPTIONS
614Source: {ns.source}
615Build: {ns.build}
616Temp: {ns.temp}
Steve Dowerde148f22019-11-20 09:30:47 -0800617Arch: {ns.arch}
Steve Dower0cd63912018-12-10 18:52:57 -0800618
619Copy to: {ns.copy}
620Zip to: {ns.zip}
621Catalog: {ns.catalog}""",
622 ns=ns,
623 )
624
Steve Dowerde148f22019-11-20 09:30:47 -0800625 if ns.arch not in ("win32", "amd64", "arm32", "arm64"):
626 log_error("--arch is not a valid value (win32, amd64, arm32, arm64)")
627 return 4
628 if ns.arch in ("arm32", "arm64"):
629 for n in ("include_idle", "include_tcltk"):
630 if getattr(ns, n):
631 log_warning(f"Disabling --{n.replace('_', '-')} on unsupported platform")
632 setattr(ns, n, False)
633
Steve Dower0cd63912018-12-10 18:52:57 -0800634 if ns.include_idle and not ns.include_tcltk:
635 log_warning("Assuming --include-tcltk to support --include-idle")
636 ns.include_tcltk = True
637
638 try:
639 generate_source_files(ns)
640 files = list(get_layout(ns))
641 copy_files(files, ns)
642 except KeyboardInterrupt:
643 log_info("Interrupted by Ctrl+C")
644 return 3
645 except SystemExit:
646 raise
647 except:
648 log_exception("Unhandled error")
649
650 if error_was_logged():
651 log_error("Errors occurred.")
652 return 1
653
654
655if __name__ == "__main__":
656 sys.exit(int(main() or 0))