-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathprogram.py
More file actions
122 lines (97 loc) · 4.34 KB
/
Copy pathprogram.py
File metadata and controls
122 lines (97 loc) · 4.34 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
"""Application entrypoint and Tk runtime bootstrap.
The entrypoint configures Tcl/Tk, imports the UI lazily for packaging safety,
creates the single root window, and hands ongoing control to Tk's event loop.
"""
# Entrypoint helpers deliberately avoid importing Tk until main() is called.
from __future__ import annotations
import os
import shutil
import sys
import tempfile
from pathlib import Path
# =============================================================================
# Entry Point
# =============================================================================
# - Relation: supports Tk runtime discovery before the UI package is imported.
# - Inputs: receives candidate directories and the required runtime filename.
# - Outputs: returns the first matching directory, or None when unavailable.
def _first_existing_file(candidates: tuple[Path, ...], file_name: str) -> Path | None:
for candidate in candidates:
if (candidate / file_name).is_file():
return candidate
return None
# - Relation: prepares bundled Tcl/Tk scripts for the runtime bootstrap.
# - Inputs: receives a script path and exact/replacement version text.
# - Outputs: rewrites the file when the exact text is present; otherwise returns.
def _relax_exact_version_check(file_path: Path, exact: str, relaxed: str) -> None:
try:
text = file_path.read_text(encoding="utf-8")
except OSError:
return
patched = text.replace(exact, relaxed)
if patched != text:
file_path.write_text(patched, encoding="utf-8")
# - Relation: connects the packaged/source entrypoint to Tcl/Tk environment setup.
# - Inputs: reads the current Python bundle location and accepts no arguments.
# - Outputs: copies compatible runtime files and sets TCL_LIBRARY/TK_LIBRARY.
def configure_tk_runtime() -> None:
"""Point Tk at a usable Tcl/Tk runtime before creating the root window."""
# Source runs already have a native Python Tcl/Tk installation available.
if not getattr(sys, "_MEIPASS", None):
return
base_path = Path(sys._MEIPASS)
source_tcl = _first_existing_file(
(
base_path / "tcl",
base_path / "tcl" / "tcl8.6",
),
"init.tcl",
)
source_tk = _first_existing_file(
(
# Source and bundled Tk directories are both considered.
base_path / "tk",
base_path / "tcl" / "tk8.6",
),
"tk.tcl",
)
if source_tcl is None or source_tk is None:
return
# Use a unique writable directory so stale or locked runtime copies cannot
# prevent a later source or packaged launch from initializing Tk.
runtime_root = Path(tempfile.mkdtemp(prefix="DevTerminalLauncher-tk-"))
patched_tcl = runtime_root / "tcl"
patched_tk = runtime_root / "tk"
# Bundled scripts are copied because installed locations may be read-only.
shutil.copytree(source_tcl, patched_tcl, dirs_exist_ok=True)
shutil.copytree(source_tk, patched_tk, dirs_exist_ok=True)
tcl8_source = source_tcl.parent / "tcl8"
if tcl8_source.is_dir():
shutil.copytree(tcl8_source, runtime_root / "tcl8", dirs_exist_ok=True)
_relax_exact_version_check(
patched_tcl / "init.tcl",
"package require -exact Tcl 8.6.9",
"package require Tcl 8.6",
)
_relax_exact_version_check(
patched_tk / "tk.tcl",
"package require -exact Tk 8.6.9",
"package require Tk 8.6",
)
os.environ["TCL_LIBRARY"] = str(patched_tcl)
os.environ["TK_LIBRARY"] = str(patched_tk)
# Main is kept import-safe for PyInstaller analysis and source-level tooling.
# Keep creation behind main() so packaging tools can import this module safely.
# - Relation: is the process entrypoint that starts the launcher window.
# - Inputs: accepts no arguments and uses the configured runtime environment.
# - Outputs: creates the Tk application and blocks in its event loop.
def main() -> None:
# The entrypoint configures runtime prerequisites before importing Tk UI code.
# It receives no arguments because configuration is read from the environment.
# It returns only when the root window is destroyed and mainloop exits.
configure_tk_runtime()
from dev_terminal_kit.launcher.dev_terminal_launcher import DevTerminalLauncher
app = DevTerminalLauncher()
app.mainloop()
if __name__ == "__main__":
main()