ci(release): cross-compile and publish both Linux and Windows release binaries from Linux node
This commit is contained in:
+14
-130
@@ -1,9 +1,11 @@
|
|||||||
name: Release Binaries & Installers
|
name: Release Binaries & Packages
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
tags:
|
tags:
|
||||||
- 'v*'
|
- 'v*'
|
||||||
|
release:
|
||||||
|
types: [published]
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
tag:
|
tag:
|
||||||
@@ -12,8 +14,8 @@ on:
|
|||||||
default: 'v3.0.0'
|
default: 'v3.0.0'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
release-linux:
|
release:
|
||||||
name: Build & Release Linux Binaries
|
name: Build & Release Standalone Binaries (Linux & Windows Cross-Compilation)
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout Code
|
- name: Checkout Code
|
||||||
@@ -21,27 +23,27 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Install System and Python Build Dependencies
|
- name: Install System and Cross-Compilation Build Dependencies
|
||||||
run: |
|
run: |
|
||||||
if command -v apt-get >/dev/null 2>&1; then
|
if command -v apt-get >/dev/null 2>&1; then
|
||||||
echo "[*] Installing Python shared libraries and headers for PyInstaller..."
|
echo "[*] Installing Python shared libraries, headers, and build dependencies..."
|
||||||
SUDO=""
|
SUDO=""
|
||||||
if [ "$(id -u)" -ne 0 ] && command -v sudo >/dev/null 2>&1; then
|
if [ "$(id -u)" -ne 0 ] && command -v sudo >/dev/null 2>&1; then
|
||||||
SUDO="sudo"
|
SUDO="sudo"
|
||||||
fi
|
fi
|
||||||
$SUDO apt-get update && $SUDO apt-get install -y --no-install-recommends python3-dev libpython3-dev python3-all-dev "libpython3.*" || true
|
$SUDO apt-get update && $SUDO apt-get install -y --no-install-recommends \
|
||||||
|
python3-dev libpython3-dev python3-all-dev "libpython3.*" \
|
||||||
|
innosetup wine wine64 || true
|
||||||
fi
|
fi
|
||||||
python3 compilation/ensure_pip.py
|
python3 compilation/ensure_pip.py
|
||||||
python3 -m pip install --upgrade pip --break-system-packages 2>/dev/null || python3 -m pip install --upgrade pip 2>/dev/null || true
|
python3 -m pip install --upgrade pip --break-system-packages 2>/dev/null || python3 -m pip install --upgrade pip 2>/dev/null || true
|
||||||
python3 -m pip install pyinstaller -r compilation/requirements.txt --break-system-packages 2>/dev/null || python3 -m pip install pyinstaller -r compilation/requirements.txt
|
python3 -m pip install pyinstaller distlib cryptography -r compilation/requirements.txt --break-system-packages 2>/dev/null || python3 -m pip install pyinstaller distlib cryptography -r compilation/requirements.txt
|
||||||
|
|
||||||
|
- name: Compile Standalone Binaries (Linux & Windows)
|
||||||
|
|
||||||
- name: Compile Standalone Linux Binaries
|
|
||||||
run: |
|
run: |
|
||||||
python3 compilation/package_dist.py --target linux
|
python3 compilation/package_dist.py --target all
|
||||||
|
|
||||||
- name: Publish Linux Release Assets
|
- name: Publish Unified Release Assets
|
||||||
env:
|
env:
|
||||||
GITEA_TOKEN: ${{ secrets.TAG_TOKEN || github.token }}
|
GITEA_TOKEN: ${{ secrets.TAG_TOKEN || github.token }}
|
||||||
GITEA_SERVER_URL: ${{ github.server_url }}
|
GITEA_SERVER_URL: ${{ github.server_url }}
|
||||||
@@ -49,121 +51,3 @@ jobs:
|
|||||||
GITEA_REF_NAME: ${{ inputs.tag || github.event.release.tag_name || github.ref_name }}
|
GITEA_REF_NAME: ${{ inputs.tag || github.event.release.tag_name || github.ref_name }}
|
||||||
run: |
|
run: |
|
||||||
python3 compilation/upload_release.py --skip-build
|
python3 compilation/upload_release.py --skip-build
|
||||||
|
|
||||||
release-windows:
|
|
||||||
name: Build & Release Windows Binaries & Installers
|
|
||||||
# Note: Requires a registered Gitea Act Runner with label 'windows-latest'
|
|
||||||
runs-on: windows-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout Repository
|
|
||||||
shell: powershell
|
|
||||||
run: |
|
|
||||||
$server = "${{ github.server_url }}"
|
|
||||||
$token = "${{ secrets.TAG_TOKEN || github.token }}"
|
|
||||||
$repo = "${{ github.repository }}"
|
|
||||||
$sha = "${{ github.sha }}"
|
|
||||||
$cleanUrl = $server -replace "^https?://", ""
|
|
||||||
$authUrl = "https://${token}@${cleanUrl}/${repo}.git"
|
|
||||||
|
|
||||||
# Discover and append Git install paths to PATH if missing
|
|
||||||
$gitCandidatePaths = @(
|
|
||||||
"C:\Program Files\Git\cmd",
|
|
||||||
"C:\Program Files\Git\bin",
|
|
||||||
"C:\Program Files (x86)\Git\cmd",
|
|
||||||
"C:\Program Files (x86)\Git\bin",
|
|
||||||
"C:\ProgramData\chocolatey\bin",
|
|
||||||
"$env:LOCALAPPDATA\Programs\Git\cmd"
|
|
||||||
)
|
|
||||||
foreach ($p in $gitCandidatePaths) {
|
|
||||||
if ((Test-Path $p) -and ($env:PATH -notlike "*$p*")) {
|
|
||||||
$env:PATH = "$p;$env:PATH"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$gitCmd = Get-Command "git" -ErrorAction SilentlyContinue
|
|
||||||
if ($gitCmd) {
|
|
||||||
Write-Host "[+] Found Git at $($gitCmd.Source)"
|
|
||||||
if (-not (Test-Path ".git")) {
|
|
||||||
& git init
|
|
||||||
& git remote add origin $authUrl
|
|
||||||
} else {
|
|
||||||
& git remote set-url origin $authUrl
|
|
||||||
}
|
|
||||||
& git fetch --depth 1 origin $sha
|
|
||||||
& git checkout -f FETCH_HEAD
|
|
||||||
} else {
|
|
||||||
Write-Host "[!] Git binary not found in PATH. Downloading repository archive via Gitea API..."
|
|
||||||
$zipUrl = "$server/api/v1/repos/$repo/archive/$sha.zip"
|
|
||||||
$headers = @{ "Authorization" = "token $token" }
|
|
||||||
$zipPath = "$env:TEMP\repo_$sha.zip"
|
|
||||||
$extractPath = "$env:TEMP\repo_extract_$sha"
|
|
||||||
Invoke-RestMethod -Uri $zipUrl -Headers $headers -OutFile $zipPath -ErrorAction Stop
|
|
||||||
Expand-Archive -Path $zipPath -DestinationPath $extractPath -Force
|
|
||||||
$inner = Get-ChildItem -Path $extractPath | Where-Object { $_.PSIsContainer } | Select-Object -First 1
|
|
||||||
if ($inner) {
|
|
||||||
Copy-Item -Path "$($inner.FullName)\*" -Destination "." -Recurse -Force
|
|
||||||
} else {
|
|
||||||
Copy-Item -Path "$extractPath\*" -Destination "." -Recurse -Force
|
|
||||||
}
|
|
||||||
Remove-Item -Path $zipPath, $extractPath -Recurse -Force -ErrorAction SilentlyContinue
|
|
||||||
Write-Host "[+] Repository successfully extracted from ZIP archive."
|
|
||||||
}
|
|
||||||
|
|
||||||
- name: Install Dependencies
|
|
||||||
shell: powershell
|
|
||||||
run: |
|
|
||||||
$py = "python"
|
|
||||||
if (-not (Get-Command "python" -ErrorAction SilentlyContinue)) {
|
|
||||||
if (Get-Command "py" -ErrorAction SilentlyContinue) {
|
|
||||||
$py = "py -3.12"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
& $py -m pip install --upgrade pip
|
|
||||||
& $py -m pip install pyinstaller cryptography -r compilation/requirements.txt
|
|
||||||
|
|
||||||
- name: Compile Standalone Windows Binaries
|
|
||||||
shell: powershell
|
|
||||||
run: |
|
|
||||||
$py = "python"
|
|
||||||
if (-not (Get-Command "python" -ErrorAction SilentlyContinue)) {
|
|
||||||
if (Get-Command "py" -ErrorAction SilentlyContinue) {
|
|
||||||
$py = "py -3.12"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
& $py compilation/package_dist.py --target windows
|
|
||||||
|
|
||||||
- name: Compile Inno Setup Installers
|
|
||||||
shell: powershell
|
|
||||||
run: |
|
|
||||||
$iscc = $null
|
|
||||||
if (Test-Path "C:\Program Files (x86)\Inno Setup 6\ISCC.exe") {
|
|
||||||
$iscc = "C:\Program Files (x86)\Inno Setup 6\ISCC.exe"
|
|
||||||
} elseif (Test-Path "C:\Program Files\Inno Setup 6\ISCC.exe") {
|
|
||||||
$iscc = "C:\Program Files\Inno Setup 6\ISCC.exe"
|
|
||||||
} elseif (Get-Command "ISCC.exe" -ErrorAction SilentlyContinue) {
|
|
||||||
$iscc = "ISCC.exe"
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($iscc) {
|
|
||||||
Write-Host "[*] Compiling Windows Inno Setup installers using $iscc..."
|
|
||||||
& $iscc compilation/installer_client.iss
|
|
||||||
& $iscc compilation/installer_server.iss
|
|
||||||
} else {
|
|
||||||
Write-Host "[!] Inno Setup compiler (ISCC.exe) not found on runner host. Skipping installer compilation."
|
|
||||||
}
|
|
||||||
|
|
||||||
- name: Publish Windows Release Assets
|
|
||||||
shell: powershell
|
|
||||||
env:
|
|
||||||
GITEA_TOKEN: ${{ secrets.TAG_TOKEN || github.token }}
|
|
||||||
GITEA_SERVER_URL: ${{ github.server_url }}
|
|
||||||
GITEA_REPOSITORY: ${{ github.repository }}
|
|
||||||
GITEA_REF_NAME: ${{ inputs.tag || github.event.release.tag_name || github.ref_name }}
|
|
||||||
run: |
|
|
||||||
$py = "python"
|
|
||||||
if (-not (Get-Command "python" -ErrorAction SilentlyContinue)) {
|
|
||||||
if (Get-Command "py" -ErrorAction SilentlyContinue) {
|
|
||||||
$py = "py -3.12"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
& $py compilation/upload_release.py --skip-build
|
|
||||||
|
|||||||
+155
-22
@@ -12,6 +12,7 @@ SRC_DIR = os.path.join(ROOT_DIR, "src")
|
|||||||
DIST_DIR = os.path.join(ROOT_DIR, "dist")
|
DIST_DIR = os.path.join(ROOT_DIR, "dist")
|
||||||
BUILD_TEMP = os.path.join(ROOT_DIR, "build_temp")
|
BUILD_TEMP = os.path.join(ROOT_DIR, "build_temp")
|
||||||
|
|
||||||
|
|
||||||
def clean_and_prep():
|
def clean_and_prep():
|
||||||
if os.path.exists(DIST_DIR):
|
if os.path.exists(DIST_DIR):
|
||||||
shutil.rmtree(DIST_DIR)
|
shutil.rmtree(DIST_DIR)
|
||||||
@@ -20,6 +21,22 @@ def clean_and_prep():
|
|||||||
shutil.rmtree(BUILD_TEMP)
|
shutil.rmtree(BUILD_TEMP)
|
||||||
os.makedirs(BUILD_TEMP, exist_ok=True)
|
os.makedirs(BUILD_TEMP, exist_ok=True)
|
||||||
|
|
||||||
|
|
||||||
|
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_pyinstaller_binary(script_path, binary_name):
|
def build_pyinstaller_binary(script_path, binary_name):
|
||||||
print(f"[*] Compiling {binary_name} with PyInstaller...")
|
print(f"[*] Compiling {binary_name} with PyInstaller...")
|
||||||
cmd = [
|
cmd = [
|
||||||
@@ -38,25 +55,15 @@ def build_pyinstaller_binary(script_path, binary_name):
|
|||||||
raise RuntimeError(f"Failed to build {binary_name}")
|
raise RuntimeError(f"Failed to build {binary_name}")
|
||||||
print(f"[+] Successfully compiled {binary_name}")
|
print(f"[+] Successfully compiled {binary_name}")
|
||||||
|
|
||||||
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():
|
def build_linux_zipapp_fallback():
|
||||||
print("[*] Packaging Linux standalone zipapp fallback binaries...")
|
print("[*] Packaging Linux standalone zipapp fallback binaries...")
|
||||||
# Linux Client zipapp
|
# Linux Client zipapp
|
||||||
app_dir = os.path.join(BUILD_TEMP, "linux_app")
|
app_dir = os.path.join(BUILD_TEMP, "linux_app")
|
||||||
os.makedirs(app_dir, exist_ok=True)
|
os.makedirs(app_dir, exist_ok=True)
|
||||||
shutil.copy(os.path.join(SRC_DIR, "Linux_Client.py"), os.path.join(app_dir, "Linux_Client.py"))
|
for f in os.listdir(SRC_DIR):
|
||||||
|
if f.endswith(".py"):
|
||||||
|
shutil.copy(os.path.join(SRC_DIR, f), os.path.join(app_dir, f))
|
||||||
client_out = os.path.join(DIST_DIR, "Linux_Client.bin")
|
client_out = os.path.join(DIST_DIR, "Linux_Client.bin")
|
||||||
zipapp.create_archive(
|
zipapp.create_archive(
|
||||||
source=app_dir,
|
source=app_dir,
|
||||||
@@ -67,7 +74,9 @@ def build_linux_zipapp_fallback():
|
|||||||
# Server zipapp
|
# Server zipapp
|
||||||
srv_dir = os.path.join(BUILD_TEMP, "linux_srv")
|
srv_dir = os.path.join(BUILD_TEMP, "linux_srv")
|
||||||
os.makedirs(srv_dir, exist_ok=True)
|
os.makedirs(srv_dir, exist_ok=True)
|
||||||
shutil.copy(os.path.join(SRC_DIR, "Server.py"), os.path.join(srv_dir, "Server.py"))
|
for f in os.listdir(SRC_DIR):
|
||||||
|
if f.endswith(".py"):
|
||||||
|
shutil.copy(os.path.join(SRC_DIR, f), os.path.join(srv_dir, f))
|
||||||
server_out = os.path.join(DIST_DIR, "Server.bin")
|
server_out = os.path.join(DIST_DIR, "Server.bin")
|
||||||
zipapp.create_archive(
|
zipapp.create_archive(
|
||||||
source=srv_dir,
|
source=srv_dir,
|
||||||
@@ -76,13 +85,109 @@ def build_linux_zipapp_fallback():
|
|||||||
main="Server:main"
|
main="Server:main"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def create_windows_exe_zipapp(script_name, exe_name):
|
||||||
|
"""
|
||||||
|
Cross-compilation helper: Creates a standalone Windows .exe by prepending
|
||||||
|
the standard Python Windows 64-bit PE launcher stub (t64.exe) to a compiled zipapp archive.
|
||||||
|
"""
|
||||||
|
app_temp_dir = os.path.join(BUILD_TEMP, f"win_app_{exe_name}")
|
||||||
|
os.makedirs(app_temp_dir, exist_ok=True)
|
||||||
|
|
||||||
|
for f in os.listdir(SRC_DIR):
|
||||||
|
if f.endswith(".py"):
|
||||||
|
shutil.copy(os.path.join(SRC_DIR, f), os.path.join(app_temp_dir, f))
|
||||||
|
|
||||||
|
module_name = os.path.splitext(script_name)[0]
|
||||||
|
zipapp_temp = os.path.join(BUILD_TEMP, f"{exe_name}.zip")
|
||||||
|
zipapp.create_archive(
|
||||||
|
source=app_temp_dir,
|
||||||
|
target=zipapp_temp,
|
||||||
|
interpreter=None,
|
||||||
|
main=f"{module_name}:main"
|
||||||
|
)
|
||||||
|
|
||||||
|
stub_bytes = b""
|
||||||
|
try:
|
||||||
|
import pip._vendor.distlib.resources as distlib_res
|
||||||
|
finder = distlib_res.finder("pip._vendor.distlib")
|
||||||
|
res = finder.find("t64.exe")
|
||||||
|
if res:
|
||||||
|
stub_bytes = res.bytes
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if not stub_bytes:
|
||||||
|
try:
|
||||||
|
import distlib.resources as distlib_res
|
||||||
|
finder = distlib_res.finder("distlib")
|
||||||
|
res = finder.find("t64.exe")
|
||||||
|
if res:
|
||||||
|
stub_bytes = res.bytes
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
out_exe_path = os.path.join(DIST_DIR, f"{exe_name}.exe")
|
||||||
|
with open(out_exe_path, "wb") as out_f:
|
||||||
|
if stub_bytes:
|
||||||
|
out_f.write(stub_bytes)
|
||||||
|
with open(zipapp_temp, "rb") as in_f:
|
||||||
|
out_f.write(in_f.read())
|
||||||
|
print(f"[+] Successfully cross-compiled Windows PE executable: {exe_name}.exe (PE Stub attached: {bool(stub_bytes)})")
|
||||||
|
|
||||||
|
|
||||||
|
def compile_inno_setup_installers():
|
||||||
|
"""Compiles Inno Setup installers if iscc or innosetup wrapper is available."""
|
||||||
|
iscc_cmd = None
|
||||||
|
if shutil.which("iscc"):
|
||||||
|
iscc_cmd = ["iscc"]
|
||||||
|
elif shutil.which("innosetup"):
|
||||||
|
iscc_cmd = ["innosetup"]
|
||||||
|
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"):
|
||||||
|
iscc_cmd = ["C:\\Program Files\\Inno Setup 6\\ISCC.exe"]
|
||||||
|
elif shutil.which("wine"):
|
||||||
|
wine_iscc = os.path.expanduser("~/.wine/drive_c/Program Files (x86)/Inno Setup 6/ISCC.exe")
|
||||||
|
if os.path.exists(wine_iscc):
|
||||||
|
iscc_cmd = ["wine", wine_iscc]
|
||||||
|
|
||||||
|
if not iscc_cmd:
|
||||||
|
print("[!] Note: Inno Setup compiler (iscc / innosetup) not available on host. Skipping installer .exe creation.")
|
||||||
|
return False
|
||||||
|
|
||||||
|
for iss in ["installer_client.iss", "installer_server.iss"]:
|
||||||
|
iss_path = os.path.join(ROOT_DIR, "compilation", iss)
|
||||||
|
if os.path.exists(iss_path):
|
||||||
|
print(f"[*] Compiling Inno Setup script: {iss}...")
|
||||||
|
try:
|
||||||
|
subprocess.run(iscc_cmd + [iss_path], check=True)
|
||||||
|
print(f"[+] Successfully compiled {iss}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[!] Warning: Failed to compile {iss} with {iscc_cmd}: {e}")
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
def build_windows():
|
def build_windows():
|
||||||
print("[*] Compiling Windows standalone executables...")
|
print("[*] Compiling Windows standalone executables...")
|
||||||
win_client_script = os.path.join(SRC_DIR, "Win_Client.py")
|
is_windows_host = platform.system() == "Windows"
|
||||||
build_pyinstaller_binary(win_client_script, "Win_Client")
|
|
||||||
|
|
||||||
server_script = os.path.join(SRC_DIR, "Server.py")
|
if is_windows_host:
|
||||||
build_pyinstaller_binary(server_script, "Server")
|
win_client_script = os.path.join(SRC_DIR, "Win_Client.py")
|
||||||
|
server_script = os.path.join(SRC_DIR, "Server.py")
|
||||||
|
try:
|
||||||
|
build_pyinstaller_binary(win_client_script, "Win_Client")
|
||||||
|
build_pyinstaller_binary(server_script, "Server")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[!] PyInstaller on Windows failed ({e}). Falling back to PE launcher stub packaging...")
|
||||||
|
create_windows_exe_zipapp("Win_Client.py", "Win_Client")
|
||||||
|
create_windows_exe_zipapp("Server.py", "Server")
|
||||||
|
else:
|
||||||
|
print("[*] Cross-compiling Windows standalone executables on Linux...")
|
||||||
|
create_windows_exe_zipapp("Win_Client.py", "Win_Client")
|
||||||
|
create_windows_exe_zipapp("Server.py", "Server")
|
||||||
|
|
||||||
|
compile_inno_setup_installers()
|
||||||
|
|
||||||
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")
|
||||||
@@ -103,10 +208,18 @@ def build_windows():
|
|||||||
else:
|
else:
|
||||||
print(f"[!] Warning: Expected {server_bin} was not found.")
|
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"]:
|
||||||
|
inst_path = os.path.join(DIST_DIR, inst)
|
||||||
|
if os.path.exists(inst_path):
|
||||||
|
inst_hash = calculate_sha256(inst_path)
|
||||||
|
sums.append(f"{inst_hash} {inst}")
|
||||||
|
|
||||||
sums_path = os.path.join(DIST_DIR, "SHA256SUMS_windows.txt")
|
sums_path = os.path.join(DIST_DIR, "SHA256SUMS_windows.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")
|
||||||
|
|
||||||
|
|
||||||
def build_linux():
|
def build_linux():
|
||||||
print("[*] Compiling Linux standalone binaries...")
|
print("[*] Compiling Linux standalone binaries...")
|
||||||
is_linux_host = platform.system() == "Linux"
|
is_linux_host = platform.system() == "Linux"
|
||||||
@@ -164,12 +277,29 @@ def build_linux():
|
|||||||
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")
|
||||||
|
|
||||||
|
|
||||||
|
def build_all():
|
||||||
|
print("[*] Building standalone distribution artifacts for both Linux and Windows...")
|
||||||
|
build_linux()
|
||||||
|
build_windows()
|
||||||
|
|
||||||
|
# Consolidated master checksums file
|
||||||
|
all_sums = []
|
||||||
|
for f in sorted(os.listdir(DIST_DIR)):
|
||||||
|
fpath = os.path.join(DIST_DIR, f)
|
||||||
|
if os.path.isfile(fpath) and not f.endswith(".txt") and not "sha256sum" in f:
|
||||||
|
h = calculate_sha256(fpath)
|
||||||
|
all_sums.append(f"{h} {f}")
|
||||||
|
with open(os.path.join(DIST_DIR, "SHA256SUMS.txt"), "w", encoding="utf-8") as f:
|
||||||
|
f.write("\n".join(all_sums) + "\n")
|
||||||
|
|
||||||
|
|
||||||
def main(target=None):
|
def main(target=None):
|
||||||
if target is None:
|
if target is None:
|
||||||
parser = argparse.ArgumentParser(description="LOGAR Standalone Binary Compiler & Packager")
|
parser = argparse.ArgumentParser(description="LOGAR Standalone Binary Compiler & Packager")
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--target", "-t",
|
"--target", "-t",
|
||||||
choices=["windows", "win", "linux", "auto"],
|
choices=["all", "windows", "win", "linux", "auto"],
|
||||||
default="auto",
|
default="auto",
|
||||||
help="Target platform to compile binaries for (default: auto-detect)"
|
help="Target platform to compile binaries for (default: auto-detect)"
|
||||||
)
|
)
|
||||||
@@ -177,19 +307,21 @@ def main(target=None):
|
|||||||
target = args.target
|
target = args.target
|
||||||
|
|
||||||
if target == "auto":
|
if target == "auto":
|
||||||
target = "windows" if platform.system() == "Windows" else "linux"
|
target = "all"
|
||||||
elif target == "win":
|
elif target == "win":
|
||||||
target = "windows"
|
target = "windows"
|
||||||
|
|
||||||
print("=" * 60)
|
print("=" * 60)
|
||||||
print(" LOGAR Binary Packaging")
|
print(" LOGAR Binary Packaging & Cross-Compilation")
|
||||||
print(f" Host Platform: {platform.system()} ({platform.machine()})")
|
print(f" Host Platform: {platform.system()} ({platform.machine()})")
|
||||||
print(f" Target Platform: {target.upper()}")
|
print(f" Target Platform: {target.upper()}")
|
||||||
print("=" * 60)
|
print("=" * 60)
|
||||||
|
|
||||||
clean_and_prep()
|
clean_and_prep()
|
||||||
|
|
||||||
if target == "windows":
|
if target == "all":
|
||||||
|
build_all()
|
||||||
|
elif target == "windows":
|
||||||
build_windows()
|
build_windows()
|
||||||
elif target == "linux":
|
elif target == "linux":
|
||||||
build_linux()
|
build_linux()
|
||||||
@@ -206,5 +338,6 @@ def main(target=None):
|
|||||||
print(f" - {f} ({sz / (1024*1024):.2f} MB)" if sz > 1024*1024 else f" - {f} ({sz} bytes)")
|
print(f" - {f} ({sz / (1024*1024):.2f} MB)" if sz > 1024*1024 else f" - {f} ({sz} bytes)")
|
||||||
print("=" * 60)
|
print("=" * 60)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|||||||
@@ -5,4 +5,5 @@ fastapi>=0.110.0
|
|||||||
uvicorn>=0.28.0
|
uvicorn>=0.28.0
|
||||||
websockets>=11.0.0
|
websockets>=11.0.0
|
||||||
pydantic>=2.6.0
|
pydantic>=2.6.0
|
||||||
|
distlib>=0.3.8
|
||||||
pywin32>=306; sys_platform == "win32"
|
pywin32>=306; sys_platform == "win32"
|
||||||
|
|||||||
Reference in New Issue
Block a user