Repository navigation
Expand file tree
/
Copy pathbuild.py
More file actions
108 lines (89 loc) · 3.15 KB
/
Copy pathbuild.py
File metadata and controls
108 lines (89 loc) · 3.15 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
"""Build script to compile EnvCleaner into a self-contained Windows executable and release package."""
from __future__ import annotations
import os
import shutil
import subprocess
import sys
import zipfile
from pathlib import Path
# Ensure project root is in sys.path
PROJECT_ROOT = Path(__file__).resolve().parent
if str(PROJECT_ROOT) not in sys.path:
sys.path.insert(0, str(PROJECT_ROOT))
from envcleaner import __version__
DIST_DIR = PROJECT_ROOT / "dist"
BUILD_DIR = PROJECT_ROOT / "build"
ENTRY_POINT = PROJECT_ROOT / "envcleaner" / "main.py"
EXE_NAME = "EnvCleaner.exe"
ZIP_NAME = f"EnvCleaner-v{__version__}-windows-x64.zip"
def run_tests() -> bool:
print("--------------------------------------------------")
print("[1/3] Running automated unit and UI test suite...")
print("--------------------------------------------------")
ret = subprocess.call(
[
sys.executable,
"-m",
"unittest",
"discover",
"-s",
"tests",
"-p",
"test_*.py",
],
cwd=str(PROJECT_ROOT),
)
return ret == 0
def build_executable() -> bool:
print("--------------------------------------------------")
print(f"[2/3] Compiling {EXE_NAME} with PyInstaller...")
print("--------------------------------------------------")
cmd = [
sys.executable,
"-m",
"PyInstaller",
"--noconfirm",
"--clean",
"--onefile",
"--windowed",
"--name",
"EnvCleaner",
"--paths",
str(PROJECT_ROOT),
str(ENTRY_POINT),
]
ret = subprocess.call(cmd, cwd=str(PROJECT_ROOT))
return ret == 0
def package_release() -> Path:
print("--------------------------------------------------")
print(f"[3/3] Packaging release zip: {ZIP_NAME}...")
print("--------------------------------------------------")
exe_path = DIST_DIR / EXE_NAME
if not exe_path.exists():
raise FileNotFoundError(f"Built executable not found: {exe_path}")
zip_path = DIST_DIR / ZIP_NAME
with zipfile.ZipFile(zip_path, "w", zipfile.ZIP_DEFLATED) as zf:
zf.write(exe_path, arcname=EXE_NAME)
if (PROJECT_ROOT / "README.md").exists():
zf.write(PROJECT_ROOT / "README.md", arcname="README.md")
if (PROJECT_ROOT / "LICENSE").exists():
zf.write(PROJECT_ROOT / "LICENSE", arcname="LICENSE")
size_mb = exe_path.stat().st_size / (1024 * 1024)
zip_mb = zip_path.stat().st_size / (1024 * 1024)
print("\n==================================================")
print(" [SUCCESS] Self-contained release created:")
print(f" Executable: {exe_path} ({size_mb:.1f} MB)")
print(f" Release Zip: {zip_path} ({zip_mb:.1f} MB)")
print("==================================================")
return zip_path
def main() -> int:
if not run_tests():
print("[ERROR] Tests failed! Aborting build.", file=sys.stderr)
return 1
if not build_executable():
print("[ERROR] PyInstaller compilation failed!", file=sys.stderr)
return 1
package_release()
return 0
if __name__ == "__main__":
sys.exit(main())