feat(packaging): include Inno Setup installers, Linux scripts, and bundles in release distribution
CI Test Suite / Run Component Tests & Pipeline Verification (push) Successful in 1m29s
CI Test Suite / Run Component Tests & Pipeline Verification (push) Successful in 1m29s
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
[Setup]
|
[Setup]
|
||||||
AppName=LOGAR Client
|
AppName=LOGAR Client
|
||||||
AppVersion=3.0.0
|
AppVersion=3.0.1
|
||||||
DefaultDirName={autopf}\LOGAR
|
DefaultDirName={autopf}\LOGAR
|
||||||
OutputDir=..\dist
|
OutputDir=..\dist
|
||||||
OutputBaseFilename=LOGAR-Client-Setup
|
OutputBaseFilename=LOGAR-Client-Setup
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[Setup]
|
[Setup]
|
||||||
AppName=LOGAR Server
|
AppName=LOGAR Server
|
||||||
AppVersion=3.0.0
|
AppVersion=3.0.1
|
||||||
DefaultDirName={autopf}\LOGAR-Server
|
DefaultDirName={autopf}\LOGAR-Server
|
||||||
OutputDir=..\dist
|
OutputDir=..\dist
|
||||||
OutputBaseFilename=LOGAR-Server-Setup
|
OutputBaseFilename=LOGAR-Server-Setup
|
||||||
|
|||||||
@@ -139,10 +139,13 @@ def create_windows_exe_zipapp(script_name, exe_name):
|
|||||||
def compile_inno_setup_installers():
|
def compile_inno_setup_installers():
|
||||||
"""Compiles Inno Setup installers if iscc or innosetup wrapper is available."""
|
"""Compiles Inno Setup installers if iscc or innosetup wrapper is available."""
|
||||||
iscc_cmd = None
|
iscc_cmd = None
|
||||||
|
user_iscc = os.path.expanduser(r"~\AppData\Local\Programs\Inno Setup 6\ISCC.exe")
|
||||||
if shutil.which("iscc"):
|
if shutil.which("iscc"):
|
||||||
iscc_cmd = ["iscc"]
|
iscc_cmd = ["iscc"]
|
||||||
elif shutil.which("innosetup"):
|
elif shutil.which("innosetup"):
|
||||||
iscc_cmd = ["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"):
|
elif os.path.exists("C:\\Program Files (x86)\\Inno Setup 6\\ISCC.exe"):
|
||||||
iscc_cmd = ["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"):
|
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")
|
client_bin = os.path.join(DIST_DIR, "Win_Client.exe")
|
||||||
server_bin = os.path.join(DIST_DIR, "Server.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 = []
|
sums = []
|
||||||
if os.path.exists(client_bin):
|
if os.path.exists(client_bin):
|
||||||
client_hash = calculate_sha256(client_bin)
|
client_hash = calculate_sha256(client_bin)
|
||||||
@@ -209,7 +232,7 @@ def build_windows():
|
|||||||
print(f"[!] Warning: Expected {server_bin} was not found.")
|
print(f"[!] Warning: Expected {server_bin} was not found.")
|
||||||
|
|
||||||
# Inno Setup output checksums if present
|
# 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)
|
inst_path = os.path.join(DIST_DIR, inst)
|
||||||
if os.path.exists(inst_path):
|
if os.path.exists(inst_path):
|
||||||
inst_hash = calculate_sha256(inst_path)
|
inst_hash = calculate_sha256(inst_path)
|
||||||
@@ -221,7 +244,7 @@ def build_windows():
|
|||||||
|
|
||||||
|
|
||||||
def build_linux():
|
def build_linux():
|
||||||
print("[*] Compiling Linux standalone binaries...")
|
print("[*] Compiling Linux standalone binaries and packaging installers...")
|
||||||
is_linux_host = platform.system() == "Linux"
|
is_linux_host = platform.system() == "Linux"
|
||||||
|
|
||||||
if is_linux_host:
|
if is_linux_host:
|
||||||
@@ -254,9 +277,37 @@ def build_linux():
|
|||||||
print("[!] Note: Host platform is not Linux. Generating executable zipapps for Linux target.")
|
print("[!] Note: Host platform is not Linux. Generating executable zipapps for Linux target.")
|
||||||
build_linux_zipapp_fallback()
|
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")
|
client_bin = os.path.join(DIST_DIR, "Linux_Client.bin")
|
||||||
server_bin = os.path.join(DIST_DIR, "Server.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 = []
|
sums = []
|
||||||
if os.path.exists(client_bin):
|
if os.path.exists(client_bin):
|
||||||
client_hash = calculate_sha256(client_bin)
|
client_hash = calculate_sha256(client_bin)
|
||||||
@@ -273,6 +324,12 @@ def build_linux():
|
|||||||
else:
|
else:
|
||||||
print(f"[!] Warning: Expected {server_bin} was not found.")
|
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")
|
sums_path = os.path.join(DIST_DIR, "SHA256SUMS_linux.txt")
|
||||||
with open(sums_path, "w", encoding="utf-8") as f:
|
with open(sums_path, "w", encoding="utf-8") as f:
|
||||||
f.write("\n".join(sums) + "\n")
|
f.write("\n".join(sums) + "\n")
|
||||||
|
|||||||
@@ -13,9 +13,21 @@ import time
|
|||||||
DEFAULT_GITEA_URL = os.environ.get("GITEA_SERVER_URL", "https://gitea.eibl.tech")
|
DEFAULT_GITEA_URL = os.environ.get("GITEA_SERVER_URL", "https://gitea.eibl.tech")
|
||||||
DEFAULT_REPO = os.environ.get("GITEA_REPOSITORY", "me0nline/LOGAR")
|
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):
|
def get_existing_assets(base_url, repo, release_id, token):
|
||||||
url = f"{base_url}/api/v1/repos/{repo}/releases/{release_id}/assets"
|
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:
|
try:
|
||||||
with urllib.request.urlopen(req) as resp:
|
with urllib.request.urlopen(req) as resp:
|
||||||
return json.loads(resp.read().decode("utf-8"))
|
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):
|
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}"
|
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:
|
try:
|
||||||
with urllib.request.urlopen(req) as resp:
|
with urllib.request.urlopen(req) as resp:
|
||||||
pass
|
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):
|
for attempt in range(1, max_retries + 1):
|
||||||
req = urllib.request.Request(url, data=file_bytes, method="POST")
|
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("Content-Type", "application/octet-stream")
|
||||||
req.add_header("Accept", "application/json")
|
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):
|
def create_or_get_release(base_url, repo, tag, token, title=None, notes=None):
|
||||||
url = f"{base_url}/api/v1/repos/{repo}/releases"
|
url = f"{base_url}/api/v1/repos/{repo}/releases"
|
||||||
headers = {
|
headers = {
|
||||||
"Authorization": f"token {token}",
|
"Authorization": get_auth_header(token),
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
"Accept": "application/json"
|
"Accept": "application/json"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Check if release exists
|
# Check if release exists
|
||||||
check_url = f"{base_url}/api/v1/repos/{repo}/releases/tags/{urllib.parse.quote(tag)}"
|
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:
|
try:
|
||||||
with urllib.request.urlopen(check_req) as resp:
|
with urllib.request.urlopen(check_req) as resp:
|
||||||
existing = json.loads(resp.read().decode("utf-8"))
|
existing = json.loads(resp.read().decode("utf-8"))
|
||||||
|
|||||||
Reference in New Issue
Block a user