Configure separate Windows and Linux Gitea release workflows with dedicated SHA-256 checksums
CI Test Suite / Run Component Tests & Pipeline Verification (push) Successful in 3m48s

This commit is contained in:
2026-09-04 15:46:35 +02:00
parent e7bf277fb9
commit 082b839965
6 changed files with 312 additions and 95 deletions
+135 -53
View File
@@ -5,10 +5,10 @@ import zipapp
import hashlib
import platform
import subprocess
import argparse
ROOT_DIR = os.path.abspath(os.path.dirname(__file__))
DIST_DIR = os.path.abspath("dist")
OUT_DIR = os.path.abspath("out")
BUILD_TEMP = os.path.abspath("build_temp")
def clean_and_prep():
@@ -37,84 +37,166 @@ def build_pyinstaller_binary(script_path, binary_name):
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...")
def calculate_sha256(filepath):
h = hashlib.sha256()
with open(filepath, "rb") as f:
while chunk := f.read(65536):
h.update(chunk)
return h.hexdigest()
def write_checksum_file(filename, digest, binary_filename):
out_path = os.path.join(DIST_DIR, filename)
with open(out_path, "w", encoding="utf-8") as f:
f.write(f"{digest} {binary_filename}\n")
print(f"[+] Generated checksum file: {filename} ({digest[:16]}...)")
def build_linux_zipapp_fallback():
print("[*] Packaging Linux standalone zipapp fallback binaries...")
# Linux Client zipapp
app_dir = os.path.join(BUILD_TEMP, "linux_app")
os.makedirs(app_dir, exist_ok=True)
shutil.copy(os.path.join(ROOT_DIR, "Linux_Client.py"), os.path.join(app_dir, "Linux_Client.py"))
bin_output = os.path.join(DIST_DIR, "Linux_Client.bin")
client_out = os.path.join(DIST_DIR, "Linux_Client.bin")
zipapp.create_archive(
source=app_dir,
target=bin_output,
target=client_out,
interpreter="/usr/bin/env python3",
main="Linux_Client:main"
)
print(f"[+] Successfully generated {bin_output}")
# Server zipapp
srv_dir = os.path.join(BUILD_TEMP, "linux_srv")
os.makedirs(srv_dir, exist_ok=True)
shutil.copy(os.path.join(ROOT_DIR, "Server.py"), os.path.join(srv_dir, "Server.py"))
server_out = os.path.join(DIST_DIR, "Server.bin")
zipapp.create_archive(
source=srv_dir,
target=server_out,
interpreter="/usr/bin/env python3",
main="Server:main"
)
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 build_windows():
print("[*] Compiling Windows standalone executables...")
win_client_script = os.path.join(ROOT_DIR, "Win_Client.py")
build_pyinstaller_binary(win_client_script, "Win_Client")
def main():
print("=" * 60)
print(" LOGAR Binary Packaging (Binaries Only)")
print(f" Platform: {platform.system()} ({platform.machine()})")
print("=" * 60)
server_script = os.path.join(ROOT_DIR, "Server.py")
build_pyinstaller_binary(server_script, "Server")
clean_and_prep()
client_bin = os.path.join(DIST_DIR, "Win_Client.exe")
server_bin = os.path.join(DIST_DIR, "Server.exe")
is_windows = platform.system() == "Windows"
if is_windows:
# Build Windows client executable
win_client_script = os.path.join(ROOT_DIR, "Win_Client.py")
build_pyinstaller_binary(win_client_script, "Win_Client")
# Build Windows server executable
server_script = os.path.join(ROOT_DIR, "Server.py")
build_pyinstaller_binary(server_script, "Server")
# Build Linux client standalone binary
build_linux_zipapp_binary()
sums = []
if os.path.exists(client_bin):
client_hash = calculate_sha256(client_bin)
write_checksum_file("win_client_sha256sum", client_hash, "Win_Client.exe")
write_checksum_file("win_agent_sha256sum", client_hash, "Win_Client.exe")
sums.append(f"{client_hash} Win_Client.exe")
else:
# On Linux runner: Build native Linux binaries
print(f"[!] Warning: Expected {client_bin} was not found.")
if os.path.exists(server_bin):
server_hash = calculate_sha256(server_bin)
write_checksum_file("win_server_sha256sum", server_hash, "Server.exe")
sums.append(f"{server_hash} Server.exe")
else:
print(f"[!] Warning: Expected {server_bin} was not found.")
sums_path = os.path.join(DIST_DIR, "SHA256SUMS_windows.txt")
with open(sums_path, "w", encoding="utf-8") as f:
f.write("\n".join(sums) + "\n")
def build_linux():
print("[*] Compiling Linux standalone binaries...")
is_linux_host = platform.system() == "Linux"
if is_linux_host:
linux_client_script = os.path.join(ROOT_DIR, "Linux_Client.py")
build_pyinstaller_binary(linux_client_script, "Linux_Client.bin")
server_script = os.path.join(ROOT_DIR, "Server.py")
build_pyinstaller_binary(server_script, "Server.bin")
# Also package standalone Windows zipapp executable
win_app_dir = os.path.join(BUILD_TEMP, "win_app")
os.makedirs(win_app_dir, exist_ok=True)
shutil.copy(os.path.join(ROOT_DIR, "Win_Client.py"), os.path.join(win_app_dir, "Win_Client.py"))
win_bin_output = os.path.join(DIST_DIR, "Win_Client.pyz")
zipapp.create_archive(
source=win_app_dir,
target=win_bin_output,
interpreter="/usr/bin/env python3",
main="Win_Client:main"
)
# Normalize extensions in case PyInstaller dropped .bin
for name in ["Linux_Client", "Server"]:
plain_path = os.path.join(DIST_DIR, name)
bin_path = os.path.join(DIST_DIR, f"{name}.bin")
if os.path.exists(plain_path) and not os.path.exists(bin_path):
os.rename(plain_path, bin_path)
generate_checksums()
# Ensure executable permissions on Linux
for b in ["Linux_Client.bin", "Server.bin"]:
p = os.path.join(DIST_DIR, b)
if os.path.exists(p):
try:
os.chmod(p, 0o755)
except Exception:
pass
else:
print("[!] Note: Host platform is not Linux. Generating executable zipapps for Linux target.")
build_linux_zipapp_fallback()
client_bin = os.path.join(DIST_DIR, "Linux_Client.bin")
server_bin = os.path.join(DIST_DIR, "Server.bin")
sums = []
if os.path.exists(client_bin):
client_hash = calculate_sha256(client_bin)
write_checksum_file("linux_client_sha256sum", client_hash, "Linux_Client.bin")
write_checksum_file("linux_agent_sha256sum", client_hash, "Linux_Client.bin")
sums.append(f"{client_hash} Linux_Client.bin")
else:
print(f"[!] Warning: Expected {client_bin} was not found.")
if os.path.exists(server_bin):
server_hash = calculate_sha256(server_bin)
write_checksum_file("linux_server_sha256sum", server_hash, "Server.bin")
sums.append(f"{server_hash} Server.bin")
else:
print(f"[!] Warning: Expected {server_bin} was not found.")
sums_path = os.path.join(DIST_DIR, "SHA256SUMS_linux.txt")
with open(sums_path, "w", encoding="utf-8") as f:
f.write("\n".join(sums) + "\n")
def main(target=None):
if target is None:
parser = argparse.ArgumentParser(description="LOGAR Standalone Binary Compiler & Packager")
parser.add_argument(
"--target", "-t",
choices=["windows", "win", "linux", "auto"],
default="auto",
help="Target platform to compile binaries for (default: auto-detect)"
)
args, _ = parser.parse_known_args()
target = args.target
if target == "auto":
target = "windows" if platform.system() == "Windows" else "linux"
elif target == "win":
target = "windows"
print("=" * 60)
print(" LOGAR Binary Packaging")
print(f" Host Platform: {platform.system()} ({platform.machine()})")
print(f" Target Platform: {target.upper()}")
print("=" * 60)
clean_and_prep()
if target == "windows":
build_windows()
elif target == "linux":
build_linux()
else:
raise ValueError(f"Unsupported target: {target}")
# 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):
for f in sorted(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)