Files
server-manager/build.py
chrome-storm-c442 a83a97c9d5 v1.5.0: network interface binding, SSH fixes, terminal, release script
- Add network interface selection per server (VPN/multi-NIC support)
- Fix "Install Everything" button hanging on error
- Add interactive SSH terminal with PTY (pyte + xterm-256color)
- Add release.py for automated versioning and changelog generation
- Add CLAUDE.md with project instructions
- Add screenshots and release binaries for v1.1–v1.4

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 14:06:41 -05:00

122 lines
3.5 KiB
Python

#!/usr/bin/env python3
"""
Build script — creates platform-specific executables via PyInstaller.
Run on the target OS to build for that platform.
Usage:
python build.py # build for current platform
python build.py --clean # clean build artifacts first
"""
import os
import sys
import shutil
import platform
# Add project root
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from version import __version__, __app_name__
PROJECT_DIR = os.path.dirname(os.path.abspath(__file__))
DIST_DIR = os.path.join(PROJECT_DIR, "dist")
BUILD_DIR = os.path.join(PROJECT_DIR, "build")
RELEASES_DIR = os.path.join(PROJECT_DIR, "releases")
def get_platform_tag() -> str:
system = platform.system().lower()
machine = platform.machine().lower()
arch_map = {
"x86_64": "x64", "amd64": "x64",
"x86": "x32", "i686": "x32", "i386": "x32",
"aarch64": "arm64", "arm64": "arm64",
"armv7l": "arm",
}
arch = arch_map.get(machine, machine)
os_map = {"windows": "win", "linux": "linux", "darwin": "mac"}
os_tag = os_map.get(system, system)
return f"{os_tag}-{arch}"
def clean():
for d in [DIST_DIR, BUILD_DIR]:
if os.path.exists(d):
shutil.rmtree(d)
for f in os.listdir(PROJECT_DIR):
if f.endswith(".spec"):
os.remove(os.path.join(PROJECT_DIR, f))
print("Cleaned build artifacts")
def build():
tag = get_platform_tag()
print(f"Building {__app_name__} v{__version__} for {tag}...")
system = platform.system().lower()
# PyInstaller command
cmd_parts = [
sys.executable, "-m", "PyInstaller",
"--onefile",
"--windowed",
f"--name={__app_name__}",
"--add-data", f"config/servers.example.json{os.pathsep}config",
"--add-data", f"tools/ssh.py{os.pathsep}tools",
"--add-data", f"tools/skill-ssh.md{os.pathsep}tools",
"--add-data", f"core/encryption.py{os.pathsep}core",
]
# Icon
icon_path = os.path.join(PROJECT_DIR, "assets", "icon.ico")
if os.path.exists(icon_path):
cmd_parts.extend(["--icon", icon_path])
# Hidden imports for customtkinter
cmd_parts.extend([
"--hidden-import", "customtkinter",
"--hidden-import", "PIL",
"--hidden-import", "pyotp",
"--hidden-import", "pyte",
"--hidden-import", "psutil",
"--collect-all", "customtkinter",
])
cmd_parts.append("main.py")
os.chdir(PROJECT_DIR)
ret = os.system(" ".join(f'"{p}"' if " " in p else p for p in cmd_parts))
if ret != 0:
print(f"Build failed with code {ret}")
sys.exit(1)
# Move to releases
os.makedirs(RELEASES_DIR, exist_ok=True)
if system == "windows":
src = os.path.join(DIST_DIR, f"{__app_name__}.exe")
dst = os.path.join(RELEASES_DIR, f"{__app_name__}-v{__version__}-{tag}.exe")
elif system == "darwin":
src = os.path.join(DIST_DIR, __app_name__)
dst = os.path.join(RELEASES_DIR, f"{__app_name__}-v{__version__}-{tag}")
else:
src = os.path.join(DIST_DIR, __app_name__)
dst = os.path.join(RELEASES_DIR, f"{__app_name__}-v{__version__}-{tag}")
if os.path.exists(src):
shutil.copy2(src, dst)
size_mb = os.path.getsize(dst) / (1024 * 1024)
print(f"\nBuild complete: {dst} ({size_mb:.1f} MB)")
else:
print(f"Build output not found: {src}")
sys.exit(1)
if __name__ == "__main__":
if "--clean" in sys.argv:
clean()
build()