diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml index 172acf6..303a84d 100644 --- a/.gitea/workflows/release.yml +++ b/.gitea/workflows/release.yml @@ -26,30 +26,14 @@ jobs: - name: Install System and Cross-Compilation Build Dependencies run: | if command -v apt-get >/dev/null 2>&1; then - echo "[*] Installing Python shared libraries, headers, Wine, and build dependencies..." + echo "[*] Installing Python shared libraries, headers, NSIS, and build dependencies..." SUDO="" if [ "$(id -u)" -ne 0 ] && command -v sudo >/dev/null 2>&1; then SUDO="sudo" fi - $SUDO dpkg --add-architecture i386 || true $SUDO apt-get update && $SUDO apt-get install -y --no-install-recommends \ - python3-dev libpython3-dev python3-all-dev "libpython3.*" \ - wine wine64 innoextract curl tar gzip || true - - # Setup Inno Setup compiler under Wine if not present - if ! command -v iscc >/dev/null 2>&1 && command -v innoextract >/dev/null 2>&1; then - echo "[*] Setting up portable Inno Setup 6 compiler for Wine..." - mkdir -p /tmp/inno_setup - curl -fsSL https://files.jrsoftware.org/is/6/innosetup-6.2.2.exe -o /tmp/inno_setup/innosetup.exe || true - if [ -f /tmp/inno_setup/innosetup.exe ]; then - $SUDO innoextract -d /opt/innosetup /tmp/inno_setup/innosetup.exe || true - if [ -f /opt/innosetup/app/ISCC.exe ]; then - $SUDO sh -c 'printf "#!/bin/sh\nWINEDEBUG=-all wine /opt/innosetup/app/ISCC.exe \"\$@\"\n" > /usr/local/bin/iscc' - $SUDO chmod +x /usr/local/bin/iscc - echo "[+] Inno Setup compiler iscc configured successfully at /usr/local/bin/iscc" - fi - fi - fi + python3-dev libpython3-dev libpython3.9 libpython3.9-dev libpython3.10 libpython3.10-dev libpython3.11 libpython3.11-dev "libpython3.*" \ + nsis curl tar gzip zip || true fi 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 diff --git a/compilation/installer_client.nsi b/compilation/installer_client.nsi new file mode 100644 index 0000000..6f1b897 --- /dev/null +++ b/compilation/installer_client.nsi @@ -0,0 +1,42 @@ +!include "MUI2.nsh" + +Name "LOGAR Client" +OutFile "..\dist\LOGAR-Client-Setup.exe" +InstallDir "$PROGRAMFILES64\LOGAR" +RequestExecutionLevel admin + +!insertmacro MUI_PAGE_WELCOME +!insertmacro MUI_PAGE_DIRECTORY +!insertmacro MUI_PAGE_INSTFILES +!insertmacro MUI_PAGE_FINISH + +!insertmacro MUI_UNPAGE_CONFIRM +!insertmacro MUI_UNPAGE_INSTFILES + +!insertmacro MUI_LANGUAGE "English" + +Section "Install" + SetOutPath "$INSTDIR" + File "..\dist\Win_Client.exe" + File "..\compilation\nssm.exe" + + CreateDirectory "$COMMONAPPDATA\LOGAR" + + # Install and configure service via NSSM + ExecWait '"$INSTDIR\nssm.exe" install LOGAR_Client "$INSTDIR\Win_Client.exe"' + ExecWait '"$INSTDIR\nssm.exe" set LOGAR_Client AppDirectory "$INSTDIR"' + ExecWait '"$INSTDIR\nssm.exe" set LOGAR_Client AppStdout "$COMMONAPPDATA\LOGAR\client.log"' + ExecWait '"$INSTDIR\nssm.exe" set LOGAR_Client AppStderr "$COMMONAPPDATA\LOGAR\client_err.log"' + ExecWait '"$INSTDIR\nssm.exe" start LOGAR_Client' + + WriteUninstaller "$INSTDIR\uninstall.exe" +SectionEnd + +Section "Uninstall" + ExecWait '"$INSTDIR\nssm.exe" stop LOGAR_Client' + ExecWait '"$INSTDIR\nssm.exe" remove LOGAR_Client confirm' + Delete "$INSTDIR\Win_Client.exe" + Delete "$INSTDIR\nssm.exe" + Delete "$INSTDIR\uninstall.exe" + RMDir "$INSTDIR" +SectionEnd diff --git a/compilation/installer_server.nsi b/compilation/installer_server.nsi new file mode 100644 index 0000000..135f6e5 --- /dev/null +++ b/compilation/installer_server.nsi @@ -0,0 +1,42 @@ +!include "MUI2.nsh" + +Name "LOGAR Server" +OutFile "..\dist\LOGAR-Server-Setup.exe" +InstallDir "$PROGRAMFILES64\LOGAR-Server" +RequestExecutionLevel admin + +!insertmacro MUI_PAGE_WELCOME +!insertmacro MUI_PAGE_DIRECTORY +!insertmacro MUI_PAGE_INSTFILES +!insertmacro MUI_PAGE_FINISH + +!insertmacro MUI_UNPAGE_CONFIRM +!insertmacro MUI_UNPAGE_INSTFILES + +!insertmacro MUI_LANGUAGE "English" + +Section "Install" + SetOutPath "$INSTDIR" + File "..\dist\Server.exe" + File "..\compilation\nssm.exe" + + CreateDirectory "$COMMONAPPDATA\LOGAR-Server" + + # Install and configure service via NSSM + ExecWait '"$INSTDIR\nssm.exe" install LOGAR_Server "$INSTDIR\Server.exe"' + ExecWait '"$INSTDIR\nssm.exe" set LOGAR_Server AppDirectory "$INSTDIR"' + ExecWait '"$INSTDIR\nssm.exe" set LOGAR_Server AppStdout "$COMMONAPPDATA\LOGAR-Server\server.log"' + ExecWait '"$INSTDIR\nssm.exe" set LOGAR_Server AppStderr "$COMMONAPPDATA\LOGAR-Server\server_err.log"' + ExecWait '"$INSTDIR\nssm.exe" start LOGAR_Server' + + WriteUninstaller "$INSTDIR\uninstall.exe" +SectionEnd + +Section "Uninstall" + ExecWait '"$INSTDIR\nssm.exe" stop LOGAR_Server' + ExecWait '"$INSTDIR\nssm.exe" remove LOGAR_Server confirm' + Delete "$INSTDIR\Server.exe" + Delete "$INSTDIR\nssm.exe" + Delete "$INSTDIR\uninstall.exe" + RMDir "$INSTDIR" +SectionEnd diff --git a/compilation/package_dist.py b/compilation/package_dist.py index 7d93fdc..a09cced 100644 --- a/compilation/package_dist.py +++ b/compilation/package_dist.py @@ -136,6 +136,33 @@ def create_windows_exe_zipapp(script_name, exe_name): print(f"[+] Successfully cross-compiled Windows PE executable: {exe_name}.exe (PE Stub attached: {bool(stub_bytes)})") +def compile_nsis_installers(): + """Compiles NSIS installers if makensis is available (native Linux/Windows).""" + makensis_cmd = None + if shutil.which("makensis"): + makensis_cmd = ["makensis"] + elif os.path.exists(r"C:\Program Files (x86)\NSIS\makensis.exe"): + makensis_cmd = [r"C:\Program Files (x86)\NSIS\makensis.exe"] + elif os.path.exists(r"C:\Program Files\NSIS\makensis.exe"): + makensis_cmd = [r"C:\Program Files\NSIS\makensis.exe"] + + if not makensis_cmd: + return False + + success = True + for nsi in ["installer_client.nsi", "installer_server.nsi"]: + nsi_path = os.path.join(ROOT_DIR, "compilation", nsi) + if os.path.exists(nsi_path): + print(f"[*] Compiling NSIS script: {nsi} via {makensis_cmd[0]}...") + try: + subprocess.run(makensis_cmd + [nsi_path], check=True) + print(f"[+] Successfully compiled {nsi}") + except Exception as e: + print(f"[!] Warning: Failed to compile {nsi} with {makensis_cmd}: {e}") + success = False + return success + + def compile_inno_setup_installers(): """Compiles Inno Setup installers if iscc or innosetup wrapper is available.""" iscc_cmd = None @@ -173,6 +200,11 @@ def compile_inno_setup_installers(): return True +def compile_windows_installers(): + if not compile_nsis_installers(): + compile_inno_setup_installers() + + def build_windows(): print("[*] Compiling Windows standalone executables...") is_windows_host = platform.system() == "Windows" @@ -192,7 +224,7 @@ def build_windows(): create_windows_exe_zipapp("Win_Client.py", "Win_Client") create_windows_exe_zipapp("Server.py", "Server") - compile_inno_setup_installers() + compile_windows_installers() client_bin = os.path.join(DIST_DIR, "Win_Client.exe") server_bin = os.path.join(DIST_DIR, "Server.exe")