import os import sys import shutil import zipapp import hashlib import platform import subprocess DIST_DIR = os.path.abspath("dist") OUT_DIR = os.path.abspath("out") BUILD_TEMP = os.path.abspath("build_temp") def clean_and_prep(): if os.path.exists(DIST_DIR): shutil.rmtree(DIST_DIR) os.makedirs(DIST_DIR, exist_ok=True) if os.path.exists(BUILD_TEMP): shutil.rmtree(BUILD_TEMP) os.makedirs(BUILD_TEMP, exist_ok=True) def build_pyinstaller_binary(script_path, binary_name): print(f"[*] Compiling {binary_name} with PyInstaller...") cmd = [ sys.executable, "-m", "PyInstaller", "--onefile", "--clean", "--distpath", DIST_DIR, "--workpath", os.path.join(BUILD_TEMP, f"work_{binary_name}"), "--specpath", os.path.join(BUILD_TEMP, f"spec_{binary_name}"), "--name", binary_name, script_path ] res = subprocess.run(cmd, capture_output=True, text=True) if res.returncode != 0: print(f"[!] Compilation error for {binary_name}:\n{res.stderr}") raise RuntimeError(f"Failed to build {binary_name}") print(f"[+] Successfully compiled {binary_name}") def build_linux_zipapp_binary(): print("[*] Packaging Linux_Client.bin executable binary...") app_dir = os.path.join(BUILD_TEMP, "linux_app") os.makedirs(app_dir, exist_ok=True) shutil.copy(os.path.join(OUT_DIR, "linux_client", "Linux_Client.py"), os.path.join(app_dir, "Linux_Client.py")) bin_output = os.path.join(DIST_DIR, "Linux_Client.bin") zipapp.create_archive( source=app_dir, target=bin_output, interpreter="/usr/bin/env python3", main="Linux_Client:main" ) print(f"[+] Successfully generated {bin_output}") def generate_checksums(): checksum_file = os.path.join(DIST_DIR, "SHA256SUMS.txt") lines = [] for fname in sorted(os.listdir(DIST_DIR)): if fname == "SHA256SUMS.txt": continue fpath = os.path.join(DIST_DIR, fname) if os.path.isfile(fpath): with open(fpath, "rb") as f: digest = hashlib.sha256(f.read()).hexdigest() lines.append(f"{digest} {fname}") with open(checksum_file, "w", encoding="utf-8") as f: f.write("\n".join(lines) + "\n") def main(): print("=" * 60) print(" LOGAR Binary Packaging (Binaries Only)") print(f" Platform: {platform.system()} ({platform.machine()})") print("=" * 60) clean_and_prep() is_windows = platform.system() == "Windows" if is_windows: # Build Windows client executable win_client_script = os.path.join(OUT_DIR, "win_client", "Win_Client.py") build_pyinstaller_binary(win_client_script, "Win_Client") # Build Windows server executable server_script = os.path.join(OUT_DIR, "server", "Server.py") build_pyinstaller_binary(server_script, "Server") # Build Linux client standalone binary build_linux_zipapp_binary() else: # On Linux runner: Build native Linux binaries linux_client_script = os.path.join(OUT_DIR, "linux_client", "Linux_Client.py") build_pyinstaller_binary(linux_client_script, "Linux_Client.bin") server_script = os.path.join(OUT_DIR, "server", "Server.py") build_pyinstaller_binary(server_script, "Server.bin") generate_checksums() # Clean temporary build directory if os.path.exists(BUILD_TEMP): shutil.rmtree(BUILD_TEMP, ignore_errors=True) print("\n[+] Binary shipping artifacts assembled in 'dist/':") for f in os.listdir(DIST_DIR): sz = os.path.getsize(os.path.join(DIST_DIR, f)) print(f" - {f} ({sz / (1024*1024):.2f} MB)" if sz > 1024*1024 else f" - {f} ({sz} bytes)") print("=" * 60) if __name__ == "__main__": main()