From b0bf322275374dd61feb3801bf1266ef778d61f9 Mon Sep 17 00:00:00 2001 From: max Date: Sat, 26 Sep 2026 13:20:41 +0200 Subject: [PATCH] feat(packaging): include Inno Setup installers, Linux scripts, and bundles in release distribution --- compilation/installer_client.iss | 2 +- compilation/installer_server.iss | 2 +- compilation/package_dist.py | 61 ++++++++++++++++++++++++++++++-- compilation/upload_release.py | 22 +++++++++--- 4 files changed, 78 insertions(+), 9 deletions(-) diff --git a/compilation/installer_client.iss b/compilation/installer_client.iss index 69d8abd..150f96a 100644 --- a/compilation/installer_client.iss +++ b/compilation/installer_client.iss @@ -1,6 +1,6 @@ [Setup] AppName=LOGAR Client -AppVersion=3.0.0 +AppVersion=3.0.1 DefaultDirName={autopf}\LOGAR OutputDir=..\dist OutputBaseFilename=LOGAR-Client-Setup diff --git a/compilation/installer_server.iss b/compilation/installer_server.iss index 5cc0f2f..95cc7e9 100644 --- a/compilation/installer_server.iss +++ b/compilation/installer_server.iss @@ -1,6 +1,6 @@ [Setup] AppName=LOGAR Server -AppVersion=3.0.0 +AppVersion=3.0.1 DefaultDirName={autopf}\LOGAR-Server OutputDir=..\dist OutputBaseFilename=LOGAR-Server-Setup diff --git a/compilation/package_dist.py b/compilation/package_dist.py index bd4285b..7b1e6f0 100644 --- a/compilation/package_dist.py +++ b/compilation/package_dist.py @@ -139,10 +139,13 @@ def create_windows_exe_zipapp(script_name, exe_name): def compile_inno_setup_installers(): """Compiles Inno Setup installers if iscc or innosetup wrapper is available.""" iscc_cmd = None + user_iscc = os.path.expanduser(r"~\AppData\Local\Programs\Inno Setup 6\ISCC.exe") if shutil.which("iscc"): iscc_cmd = ["iscc"] elif shutil.which("innosetup"): iscc_cmd = ["innosetup"] + elif os.path.exists(user_iscc): + iscc_cmd = [user_iscc] elif os.path.exists("C:\\Program Files (x86)\\Inno Setup 6\\ISCC.exe"): iscc_cmd = ["C:\\Program Files (x86)\\Inno Setup 6\\ISCC.exe"] elif os.path.exists("C:\\Program Files\\Inno Setup 6\\ISCC.exe"): @@ -192,6 +195,26 @@ def build_windows(): client_bin = os.path.join(DIST_DIR, "Win_Client.exe") server_bin = os.path.join(DIST_DIR, "Server.exe") + # Windows Zip Bundles + import zipfile + if os.path.exists(client_bin): + client_zip = os.path.join(DIST_DIR, "LOGAR-Windows-Client.zip") + with zipfile.ZipFile(client_zip, "w", zipfile.ZIP_DEFLATED) as zf: + zf.write(client_bin, arcname="Win_Client.exe") + sample_cfg = os.path.join(ROOT_DIR, "out", "win_client", "client_config.sample.json") + if os.path.exists(sample_cfg): + zf.write(sample_cfg, arcname="client_config.sample.json") + print(f"[+] Packaged Windows Client Zip: {os.path.basename(client_zip)}") + + if os.path.exists(server_bin): + server_zip = os.path.join(DIST_DIR, "LOGAR-Windows-Server.zip") + with zipfile.ZipFile(server_zip, "w", zipfile.ZIP_DEFLATED) as zf: + zf.write(server_bin, arcname="Server.exe") + sample_cfg = os.path.join(ROOT_DIR, "server_config.sample.json") + if os.path.exists(sample_cfg): + zf.write(sample_cfg, arcname="server_config.sample.json") + print(f"[+] Packaged Windows Server Zip: {os.path.basename(server_zip)}") + sums = [] if os.path.exists(client_bin): client_hash = calculate_sha256(client_bin) @@ -209,7 +232,7 @@ def build_windows(): print(f"[!] Warning: Expected {server_bin} was not found.") # Inno Setup output checksums if present - for inst in ["LOGAR-Client-Setup.exe", "LOGAR-Server-Setup.exe"]: + for inst in ["LOGAR-Client-Setup.exe", "LOGAR-Server-Setup.exe", "LOGAR-Windows-Client.zip", "LOGAR-Windows-Server.zip"]: inst_path = os.path.join(DIST_DIR, inst) if os.path.exists(inst_path): inst_hash = calculate_sha256(inst_path) @@ -221,7 +244,7 @@ def build_windows(): def build_linux(): - print("[*] Compiling Linux standalone binaries...") + print("[*] Compiling Linux standalone binaries and packaging installers...") is_linux_host = platform.system() == "Linux" if is_linux_host: @@ -254,9 +277,37 @@ def build_linux(): print("[!] Note: Host platform is not Linux. Generating executable zipapps for Linux target.") build_linux_zipapp_fallback() + # Copy Linux installation scripts directly to dist + for sh in ["install_linux_client.sh", "install_linux_server.sh"]: + sh_src = os.path.join(ROOT_DIR, "compilation", sh) + if os.path.exists(sh_src): + sh_dst = os.path.join(DIST_DIR, sh) + shutil.copy(sh_src, sh_dst) + print(f"[+] Copied Linux installer script: {sh}") + + # Package Linux tarballs + import tarfile client_bin = os.path.join(DIST_DIR, "Linux_Client.bin") server_bin = os.path.join(DIST_DIR, "Server.bin") + if os.path.exists(client_bin): + client_tar = os.path.join(DIST_DIR, "LOGAR-Linux-Client.tar.gz") + with tarfile.open(client_tar, "w:gz") as tf: + tf.add(client_bin, arcname="Linux_Client.bin") + client_sh = os.path.join(DIST_DIR, "install_linux_client.sh") + if os.path.exists(client_sh): + tf.add(client_sh, arcname="install_linux_client.sh") + print(f"[+] Packaged Linux Client Tarball: {os.path.basename(client_tar)}") + + if os.path.exists(server_bin): + server_tar = os.path.join(DIST_DIR, "LOGAR-Linux-Server.tar.gz") + with tarfile.open(server_tar, "w:gz") as tf: + tf.add(server_bin, arcname="Server.bin") + server_sh = os.path.join(DIST_DIR, "install_linux_server.sh") + if os.path.exists(server_sh): + tf.add(server_sh, arcname="install_linux_server.sh") + print(f"[+] Packaged Linux Server Tarball: {os.path.basename(server_tar)}") + sums = [] if os.path.exists(client_bin): client_hash = calculate_sha256(client_bin) @@ -273,6 +324,12 @@ def build_linux(): else: print(f"[!] Warning: Expected {server_bin} was not found.") + for item in ["install_linux_client.sh", "install_linux_server.sh", "LOGAR-Linux-Client.tar.gz", "LOGAR-Linux-Server.tar.gz"]: + item_path = os.path.join(DIST_DIR, item) + if os.path.exists(item_path): + item_hash = calculate_sha256(item_path) + sums.append(f"{item_hash} {item}") + 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") diff --git a/compilation/upload_release.py b/compilation/upload_release.py index 7535ad5..6d8fb43 100644 --- a/compilation/upload_release.py +++ b/compilation/upload_release.py @@ -13,9 +13,21 @@ import time DEFAULT_GITEA_URL = os.environ.get("GITEA_SERVER_URL", "https://gitea.eibl.tech") DEFAULT_REPO = os.environ.get("GITEA_REPOSITORY", "me0nline/LOGAR") +import base64 + +def get_auth_header(token): + if not token: + return "" + if token.startswith("Basic ") or token.startswith("token ") or token.startswith("Bearer "): + return token + if ":" in token: + b64 = base64.b64encode(token.encode("utf-8")).decode("ascii") + return f"Basic {b64}" + return f"token {token}" + def get_existing_assets(base_url, repo, release_id, token): url = f"{base_url}/api/v1/repos/{repo}/releases/{release_id}/assets" - req = urllib.request.Request(url, headers={"Authorization": f"token {token}", "Accept": "application/json"}) + req = urllib.request.Request(url, headers={"Authorization": get_auth_header(token), "Accept": "application/json"}) try: with urllib.request.urlopen(req) as resp: return json.loads(resp.read().decode("utf-8")) @@ -24,7 +36,7 @@ def get_existing_assets(base_url, repo, release_id, token): def delete_asset(base_url, repo, release_id, asset_id, token): url = f"{base_url}/api/v1/repos/{repo}/releases/{release_id}/assets/{asset_id}" - req = urllib.request.Request(url, method="DELETE", headers={"Authorization": f"token {token}"}) + req = urllib.request.Request(url, method="DELETE", headers={"Authorization": get_auth_header(token)}) try: with urllib.request.urlopen(req) as resp: pass @@ -47,7 +59,7 @@ def upload_file_to_release(base_url, repo, release_id, token, file_path, max_ret for attempt in range(1, max_retries + 1): req = urllib.request.Request(url, data=file_bytes, method="POST") - req.add_header("Authorization", f"token {token}") + req.add_header("Authorization", get_auth_header(token)) req.add_header("Content-Type", "application/octet-stream") req.add_header("Accept", "application/json") @@ -73,14 +85,14 @@ def upload_file_to_release(base_url, repo, release_id, token, file_path, max_ret def create_or_get_release(base_url, repo, tag, token, title=None, notes=None): url = f"{base_url}/api/v1/repos/{repo}/releases" headers = { - "Authorization": f"token {token}", + "Authorization": get_auth_header(token), "Content-Type": "application/json", "Accept": "application/json" } # Check if release exists check_url = f"{base_url}/api/v1/repos/{repo}/releases/tags/{urllib.parse.quote(tag)}" - check_req = urllib.request.Request(check_url, headers={"Authorization": f"token {token}"}) + check_req = urllib.request.Request(check_url, headers={"Authorization": get_auth_header(token)}) try: with urllib.request.urlopen(check_req) as resp: existing = json.loads(resp.read().decode("utf-8"))