|
1 | 1 | import os |
2 | 2 | import shutil |
| 3 | +import textwrap |
| 4 | +import uuid |
3 | 5 |
|
4 | 6 | from pathlib import Path |
5 | 7 | from typing import Annotated, Optional |
6 | 8 |
|
7 | 9 | import typer |
8 | 10 |
|
| 11 | +from dbrownell_Common.ContextlibEx import ExitStack |
9 | 12 | from dbrownell_Common import SubprocessEx |
10 | 13 | from dbrownell_Common.Streams.DoneManager import DoneManager, Flags as DoneManagerFlags |
| 14 | +import inflect |
11 | 15 | from typer.core import TyperGroup |
12 | 16 |
|
| 17 | +import FileBackup |
| 18 | + |
13 | 19 |
|
14 | 20 | # ---------------------------------------------------------------------- |
15 | 21 | class NaturalOrderGrouper(TyperGroup): |
@@ -46,12 +52,49 @@ def Build( |
46 | 52 | with DoneManager.CreateCommandLine( |
47 | 53 | flags=DoneManagerFlags.Create(verbose=verbose, debug=debug), |
48 | 54 | ) as dm: |
49 | | - command_line = "cxfreeze --script src/FileBackup/CommandLine/EntryPoint.py --target-name=FileBackup" |
50 | | - |
51 | | - dm.WriteVerbose(f"Command line: {command_line}\n\n") |
52 | | - |
53 | | - with dm.YieldStream() as stream: |
54 | | - dm.result = SubprocessEx.Stream(command_line, stream) |
| 55 | + # inflect uses the typeguard library, which relies on inspect to read the source code of |
| 56 | + # inflect to enforce that arguments are the correct types when invoking functions. This |
| 57 | + # works fine when running the application normally, but does not work by default with |
| 58 | + # cx_Freeze because it does not include the source code of inflect in the built binary. This |
| 59 | + # means that typeguard can't determine the types of the arguments, which causes it to raise |
| 60 | + # an exception. The fix is to include the inflect source code in the built binary so that |
| 61 | + # typeguard can find the function's types and not raise an exception. |
| 62 | + inflect_filename = Path(inflect.__file__).relative_to(Path(__file__).parent) |
| 63 | + |
| 64 | + configuration_filename = Path("setup{}.py".format(str(uuid.uuid4()).replace("-", ""))) |
| 65 | + |
| 66 | + configuration_filename.write_text( |
| 67 | + textwrap.dedent( |
| 68 | + f"""\ |
| 69 | + from cx_Freeze import setup, Executable |
| 70 | +
|
| 71 | + setup( |
| 72 | + name = "FileBackup", |
| 73 | + version = "{FileBackup.__version__}", |
| 74 | + options = {{ |
| 75 | + "build_exe": {{ |
| 76 | + "include_files": [ |
| 77 | + (r"{inflect_filename}", "lib/inflect/{inflect_filename.name}"), |
| 78 | + ], |
| 79 | + "packages": [] |
| 80 | + }}, |
| 81 | + }}, |
| 82 | + executables = [ |
| 83 | + Executable( |
| 84 | + "src/FileBackup/CommandLine/EntryPoint.py", |
| 85 | + target_name="FileBackup", |
| 86 | + base=None, |
| 87 | + ), |
| 88 | + ], |
| 89 | + ) |
| 90 | + """, |
| 91 | + ), |
| 92 | + encoding="utf-8", |
| 93 | + ) |
| 94 | + |
| 95 | + with ExitStack(configuration_filename.unlink): |
| 96 | + with dm.YieldStream() as stream: |
| 97 | + dm.result = SubprocessEx.Stream(f'python "{configuration_filename}" build_exe', stream) |
55 | 98 |
|
56 | 99 |
|
57 | 100 | # ---------------------------------------------------------------------- |
|
0 commit comments