diff --git a/.github/workflows/deploy-pypi.yml b/.github/workflows/deploy-pypi.yml index 43c513a..883d71f 100644 --- a/.github/workflows/deploy-pypi.yml +++ b/.github/workflows/deploy-pypi.yml @@ -78,33 +78,65 @@ jobs: uses: pypa/gh-action-pypi-publish@release/v1 deploy-binaries: - name: Deploy binaries on ${{ matrix.os }} Python ${{ matrix.python-version }} + name: Deploy ${{ matrix.id }} on ${{ matrix.os }} Python ${{ matrix.python-version }} runs-on: ${{ matrix.os }} - continue-on-error: true strategy: + fail-fast: false matrix: - os: [ ubuntu-22.04, ubuntu-22.04-arm, windows-2025, macos-15-intel, macos-14 ] - python-version: [ "3.11", "3.13" ] - exclude: - - os: ubuntu-22.04 - python-version: "3.11" - - os: windows-2025 - python-version: "3.11" - - os: macos-15-intel - python-version: "3.11" - - os: macos-14 - python-version: "3.11" - - os: ubuntu-22.04-arm - python-version: "3.13" include: - - os: windows-2025 - id: win7 + - id: linux-amd64 + os: ubuntu-24.04 + python-version: "3.13" + python-architecture: x64 + pyside6-version: "6.8.3" + windows-compatibility: "" + windows-architecture: "" + - id: linux-arm64 + os: ubuntu-24.04-arm + python-version: "3.11" + python-architecture: arm64 + pyside6-version: "6.8.3" + windows-compatibility: "" + windows-architecture: "" + - id: windows7-amd64 + os: windows-2025 + python-version: "3.13" + python-architecture: x64 + pyside6-version: "6.8.3" + windows-compatibility: windows7 + windows-architecture: amd64 + - id: windows10-amd64 + os: windows-2025 + python-version: "3.13" + python-architecture: x64 + pyside6-version: "6.8.3" + windows-compatibility: windows10 + windows-architecture: amd64 + - id: windows-arm64 + os: windows-11-vs2026-arm + python-version: "3.13" + python-architecture: arm64 + pyside6-version: "6.11.2" + windows-compatibility: "" + windows-architecture: arm64 + - id: macos-intel + os: macos-15-intel + python-version: "3.13" + python-architecture: x64 + pyside6-version: "6.8.3" + windows-compatibility: "" + windows-architecture: "" + - id: macos-arm64 + os: macos-14 + python-version: "3.13" + python-architecture: arm64 + pyside6-version: "6.8.3" + windows-compatibility: "" + windows-architecture: "" env: - # Last PySide6 version that supports macOS 10.9 & Python 3.11 - PYSIDE6_LEGACY_VERSION: "6.4.3" - PYSIDE6_TARGET_VERSION: "6.8.3" - # PySide6 has Windows ARM64 build since 6.9.0 - PYSIDE6_LATEST_VERSION: "6.9.1" + GO_WIN7_VERSION: "1.26.7" + WIX_VERSION: "6.0.2" + WIX_INSTALLER_SHA256: "A8A5CC7443353CEF3AB900C60CD7A3A5EE601746319D104AC7B12AD0CED2345C" steps: - uses: actions/checkout@v7 - name: Install macOS dependencies @@ -121,125 +153,497 @@ jobs: - name: Install Linux dependencies run: | sudo apt update - sudo apt install -y libxcb-cursor0 qt6-base-dev patchelf ccache zlib1g-dev + + if [ "$RUNNER_ARCH" == "ARM64" ]; then + if apt-cache show libminizip1t64 >/dev/null 2>&1; then + minizip_package='libminizip1t64' + else + minizip_package='libminizip1' + fi + + sudo apt install -y \ + libevent-2.1-7 \ + libwebp7 \ + "$minizip_package" + fi + + sudo apt install -y \ + libxcb-cursor0 \ + qt6-base-dev \ + patchelf \ + ccache \ + zlib1g-dev sudo apt install -y flatpak flatpak-builder elfutils patchelf sudo apt install -y rpm - echo "QMAKE=$(which qmake6)" >> $GITHUB_ENV flatpak remote-add --if-not-exists --user flathub https://flathub.org/repo/flathub.flatpakrepo flatpak update flatpak install -y flathub org.kde.Platform//6.8 org.kde.Sdk//6.8 if [ "$RUNNER_ARCH" == "X64" ]; then - linuxdeploy_arch="x86_64" + appimage_arch="x86_64" elif [ "$RUNNER_ARCH" == "ARM64" ]; then - linuxdeploy_arch="aarch64" + appimage_arch="aarch64" else echo "Unknown runner architecture: $RUNNER_ARCH" exit 1 fi - echo "linuxdeploy architecture is $linuxdeploy_arch" - linuxdeploy_name=".linuxdeploy-bin" - mkdir ${linuxdeploy_name} - echo "${PWD}/${linuxdeploy_name}" >> $GITHUB_PATH - wget -P ${linuxdeploy_name} https://github.com/linuxdeploy/linuxdeploy/releases/latest/download/linuxdeploy-${linuxdeploy_arch}.AppImage - wget -P ${linuxdeploy_name} https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/latest/download/linuxdeploy-plugin-qt-${linuxdeploy_arch}.AppImage - wget -P ${linuxdeploy_name} https://github.com/AppImage/appimagetool/releases/latest/download/appimagetool-${linuxdeploy_arch}.AppImage - chmod +x ${linuxdeploy_name}/* + appimage_tools=".appimage-tools" + mkdir "$appimage_tools" + echo "${PWD}/${appimage_tools}" >> "$GITHUB_PATH" + + wget -P "$appimage_tools" \ + "https://github.com/AppImage/appimagetool/releases/latest/download/appimagetool-${appimage_arch}.AppImage" + chmod +x "$appimage_tools"/* if: runner.os == 'Linux' - name: Install Windows dependencies + shell: pwsh run: | - if [ "$RUNNER_ARCH" == "X64" ]; then - toolset_arch="x64" - elif [ "$RUNNER_ARCH" == "ARM64" ]; then - toolset_arch="arm64" - else - echo "Unknown runner architecture: $RUNNER_ARCH" - exit 1 - fi + $toolsetArchitecture = switch ($env:RUNNER_ARCH) { + 'X64' { 'x64' } + 'ARM64' { 'arm64' } + default { throw "Unknown runner architecture: $env:RUNNER_ARCH" } + } - winget install --id WiXToolset.WiXCLI --version 6.0.2.0 -e --source winget --accept-package-agreements --accept-source-agreements - echo "C:/Program Files/WiX Toolset v6.0/bin" >> $GITHUB_PATH - echo "C:/Program Files/WiX Toolset v6.0/bin/${toolset_arch}" >> $GITHUB_PATH + $installer = Join-Path $env:RUNNER_TEMP 'wix-cli-x64.msi' + $installerUrl = "https://github.com/wixtoolset/wix/releases/download/v$env:WIX_VERSION/wix-cli-x64.msi" + Invoke-WebRequest -Uri $installerUrl -OutFile $installer + + $installerHash = (Get-FileHash -Algorithm SHA256 -LiteralPath $installer).Hash + + if ($installerHash -ne $env:WIX_INSTALLER_SHA256) { + throw "Unexpected WiX installer SHA-256: $installerHash" + } + + $msi = Start-Process msiexec.exe -ArgumentList @( + '/i', + $installer, + '/quiet', + '/norestart', + '/log', + (Join-Path $env:RUNNER_TEMP 'wix-install.log') + ) -WindowStyle Hidden -Wait -PassThru + + if ($msi.ExitCode -notin @(0, 3010)) { + throw "WiX installation failed with exit code $($msi.ExitCode)" + } + + $toolsetRoot = 'C:\Program Files\WiX Toolset v6.0\bin' + $toolsetRoot | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append + (Join-Path $toolsetRoot $toolsetArchitecture) | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append if: runner.os == 'Windows' - name: Check Windows dependencies run: | wix --version - wix extension add WixToolset.UI.wixext/6.0.2 + wix extension add -g "WixToolset.UI.wixext/${WIX_VERSION}" + wix extension list -g if: runner.os == 'Windows' - name: Set up Python for Windows7 uses: LorenEteval/setup-python-win7@v1 with: python-version: ${{ matrix.python-version }} check-latest: true - if: matrix.id == 'win7' + if: matrix.id == 'windows7-amd64' - name: Set up Python uses: actions/setup-python@v7 with: python-version: ${{ matrix.python-version }} + architecture: ${{ matrix.python-architecture }} check-latest: true - if: matrix.id != 'win7' + if: matrix.id != 'windows7-amd64' + - name: Verify runner and Python architecture + env: + EXPECTED_ARCHITECTURE: ${{ matrix.python-architecture }} + run: | + python - <<'PY' + import os + import platform + import struct + import sys + + aliases = { + 'x64': {'amd64', 'x86_64'}, + 'arm64': {'arm64', 'aarch64'}, + } + expected = os.environ['EXPECTED_ARCHITECTURE'] + runner_architecture = os.environ.get('RUNNER_ARCH', '').casefold() + machine = platform.machine().casefold() + pointer_width = struct.calcsize('P') * 8 + + print(f'RUNNER_OS={os.environ.get("RUNNER_OS")}') + print(f'RUNNER_ARCH={os.environ.get("RUNNER_ARCH")}') + print(f'Python={sys.version}') + print(f'platform.machine()={platform.machine()}') + print(f'pointer width={pointer_width}') + + if runner_architecture != expected: + raise SystemExit( + f'expected {expected} runner, got {runner_architecture or "unknown"}' + ) + + if machine not in aliases[expected] or pointer_width != 64: + raise SystemExit( + f'expected native {expected} Python, got {machine}/{pointer_width}-bit' + ) + PY - name: Set up PySide6 for Windows7 uses: LorenEteval/setup-pyside6-win7@v1 with: - pyside6-version: ${{ env.PYSIDE6_TARGET_VERSION }} - if: matrix.id == 'win7' - - name: Download Python dependencies & latest asset files + pyside6-version: ${{ matrix.pyside6-version }} + if: matrix.id == 'windows7-amd64' + - name: Install Python build and runtime dependencies run: | python -c "import sys; print(sys.version)" python -m pip install --upgrade pip python -m pip install setuptools wheel + + python - <<'PY' + import re + from pathlib import Path + + excluded = { + 'pyside6-addons', + 'pyside6-essentials', + 'xray-core', + 'hysteria', + 'hysteria2', + 'tun2socks', + } + + requirements = [] + + for line in Path('requirements.txt').read_text(encoding='utf-8').splitlines(): + match = re.match(r'\s*([A-Za-z0-9_.-]+)', line) + + if match and match.group(1).casefold().replace('_', '-') in excluded: + continue + + requirements.append(line) + + Path('.binary-requirements.txt').write_text( + '\n'.join(requirements) + '\n', + encoding='utf-8', + ) + PY + + if [[ "${{ matrix.id }}" != "windows7-amd64" ]]; then + if [[ "$RUNNER_OS" == "Windows" ]]; then + pyside_binary_policy="--only-binary=PySide6-Essentials,PySide6-Addons" + else + pyside_binary_policy="" + fi + + python -m pip install \ + ${pyside_binary_policy} \ + "PySide6-Essentials==${{ matrix.pyside6-version }}" \ + "PySide6-Addons==${{ matrix.pyside6-version }}" + fi + if [ "$RUNNER_OS" == "Linux" ] && [ "$RUNNER_ARCH" == "ARM64" ]; then python -m pip install "numpy<2" - python -m pip install PySide6-Essentials==6.5.3 - else - python -m pip install PySide6-Essentials==${PYSIDE6_TARGET_VERSION} fi - python -m pip install -r requirements.txt + + python -m pip install -r .binary-requirements.txt python -m pip install nuitka imageio requests - python Deploy.py --download - - name: Set up go + python -c "import importlib.metadata; print('zxing-cpp', importlib.metadata.version('zxing-cpp'))" + python -c "from PySide6 import QtCore; print(f'PySide6/Qt {QtCore.__version__}')" + - name: Install patched Go for Windows7 + run: | + go_name="go-for-win7-windows-amd64" + go_file="${go_name}.zip" + + curl --fail --location --output "${go_file}" \ + "https://github.com/XTLS/go-win7/releases/download/patched-${GO_WIN7_VERSION}/${go_file}" + 7z x "${go_file}" "-o${go_name}" -y + + go_root="$(cygpath -w "$PWD/${go_name}")" + echo "GOROOT=${go_root}" >> $GITHUB_ENV + echo "CGO_ENABLED=1" >> $GITHUB_ENV + echo "${go_root}\\bin" >> $GITHUB_PATH + if: matrix.id == 'windows7-amd64' + - name: Set up Go for Windows10 uses: actions/setup-go@v7 with: go-version: "1.26" check-latest: true - if: matrix.id != 'win7' - - name: Install go dependencies + cache: false + if: matrix.id == 'windows10-amd64' + - name: Build Windows AMD64 bindings from source + shell: pwsh + env: + CC: gcc + CXX: g++ + CGO_ENABLED: "1" + CMAKE_BUILD_PARALLEL_LEVEL: "2" + GOPROXY: https://proxy.golang.org,direct run: | - if [[ "${{ matrix.id }}" == "win7" ]]; then - go_name="go-for-win7-windows-amd64" - go_file="${go_name}.zip" + $ErrorActionPreference = 'Stop' + $PSNativeCommandUseErrorActionPreference = $true - curl -L -o ${go_file} https://github.com/XTLS/go-win7/releases/download/patched-1.26.7/${go_file} - 7z x ${go_file} -o${go_name} -y + Write-Output "Go executable: $((Get-Command go -ErrorAction Stop).Source)" + go version + go env GOROOT GOOS GOARCH CGO_ENABLED + Write-Output "GCC executable: $((Get-Command gcc -ErrorAction Stop).Source)" + gcc -dumpmachine - export GOROOT="$PWD/${go_name}" - export CGO_ENABLED=1 - export PATH="${GOROOT}/bin:$PATH" + $temporaryDirectory = Join-Path $env:RUNNER_TEMP 'bindings' + New-Item -ItemType Directory -Force -Path $temporaryDirectory | Out-Null + foreach ($name in 'TMPDIR', 'TEMP', 'TMP') { + Set-Item -Path "Env:$name" -Value $temporaryDirectory + } + + Write-Output "Configured temporary directory: $temporaryDirectory" + python -c "import tempfile; print(f'Python temporary directory: {tempfile.gettempdir()}')" + + python -m pip install ` + "setuptools>=68" ` + wheel ` + "cmake>=3.15" ` + "pybind11>=3.0.1,<3.1" + + $wheelDirectory = Join-Path $temporaryDirectory 'wheels' + New-Item -ItemType Directory -Force -Path $wheelDirectory | Out-Null + + $bindings = @( + 'Xray-core' + 'hysteria2' + 'tun2socks' + ) + + foreach ($binding in $bindings) { + python -m pip wheel ` + --no-cache-dir ` + --no-build-isolation ` + --no-deps ` + --no-binary=:all: ` + --wheel-dir $wheelDirectory ` + $binding + } + + $wheels = @( + Get-ChildItem -LiteralPath $wheelDirectory -Filter '*.whl' -File | + Sort-Object Name + ) + Write-Output 'Locally built wheels:' + + foreach ($wheel in $wheels) { + Write-Output " $($wheel.Name)" + } + + $unexpectedWheels = @($wheels | Where-Object Name -NotLike '*win_amd64.whl') + + if ($wheels.Count -ne 3 -or $unexpectedWheels.Count -ne 0) { + throw 'Expected exactly three locally built win_amd64 wheels' + } + + $wheelPaths = @($wheels.FullName) + python -m pip install ` + --no-index ` + --force-reinstall ` + --no-deps ` + $wheelPaths + if: matrix.id == 'windows7-amd64' || matrix.id == 'windows10-amd64' + - name: Install pre-built Hysteria1 wheel + run: | + python -m pip install \ + --only-binary=hysteria \ + --no-cache-dir \ + --no-deps \ + hysteria + if: matrix.id == 'windows7-amd64' || matrix.id == 'windows10-amd64' + - name: Install supported binding wheels + run: | + if [[ "$RUNNER_OS" == "Windows" ]]; then + binary_policy="--only-binary=Xray-core,hysteria,hysteria2,tun2socks" + else + binary_policy="" fi - go version - python -m pip install "Xray-core >= 1.8.8" - python -m pip install "hysteria2 >= 2.0.4" - python -m pip install "tun2socks > 2.5.2" - - name: Set up go legacy - uses: actions/setup-go@v7 - with: - go-version: "1.20" - check-latest: true - - name: Install go legacy dependencies + + python -m pip install \ + ${binary_policy} \ + --no-cache-dir \ + --no-deps \ + Xray-core \ + hysteria \ + hysteria2 \ + tun2socks + if: matrix.id != 'windows7-amd64' && matrix.id != 'windows10-amd64' + - name: Verify Windows native and UI imports run: | - go version - python -m pip install "hysteria > 1.3.5" + python - <<'PY' + import importlib + + for name in ('xray', 'hysteria', 'hysteria2', 'tun2socks'): + module = importlib.import_module(name) + print(f'{name}: {module.__file__}') + + # Native extension imports fail here if a wheel has the wrong machine type. + print('All native bindings imported successfully') + + # Some Windows PySide6 distributions intentionally omit Qt WebEngine. + # The application must still import and use its non-WebEngine map fallback. + from Furious.Widget.EndpointInfoWidget import EndpointInfoWidget + + print(f'Endpoint UI imported successfully: {EndpointInfoWidget.__name__}') + PY + if: runner.os == 'Windows' + - name: Verify Qt WebEngine imports + if: runner.os != 'Windows' + run: | + python - <<'PY' + from PySide6 import QtWebChannel, QtWebEngineCore, QtWebEngineWidgets + + print(f'QtWebChannel imported successfully: {QtWebChannel.__name__}') + print(f'QtWebEngineCore imported successfully: {QtWebEngineCore.__name__}') + print(f'QtWebEngineWidgets imported successfully: {QtWebEngineWidgets.__name__}') + PY + - name: Download latest asset files + run: | + python Deploy.py --download - name: Run deploy script + env: + APPIMAGE_EXTRACT_AND_RUN: "1" run: | - if [[ "${{ matrix.id }}" == "win7" ]]; then - export WIN_VER_COMPATIBLE="windows" + if [[ -n "${{ matrix.windows-compatibility }}" ]]; then + export WIN_VER_COMPATIBLE="${{ matrix.windows-compatibility }}" fi python Deploy.py + - name: Verify macOS application bundle + if: runner.os == 'macOS' + shell: bash + run: | + app='app/Furious-GUI.app' + source_app='Furious-Deploy/Furious-GUI.app' + macos_root="${app}/Contents/MacOS" + qt_root="${macos_root}/PySide6/Qt" + webengine_framework="${qt_root}/lib/QtWebEngineCore.framework" + relocated_qt_root="${app}/Contents/Frameworks/PySide6/Qt" + relocated_webengine_framework="${relocated_qt_root}/lib/QtWebEngineCore.framework" + webengine_helper="${relocated_webengine_framework}/Helpers/QtWebEngineProcess.app/Contents/MacOS/QtWebEngineProcess" + failures=0 + + check() { + local description="$1" + local status + shift + + echo "::group::${description}" + + if "$@"; then + status=0 + echo "PASS: ${description} (exit code ${status})" + else + status=$? + echo "::error title=macOS bundle verification::FAIL: ${description} (exit code ${status})" + failures=$((failures + 1)) + fi + + echo '::endgroup::' + } + + echo "Application bundle: ${app}" + echo "Qt runtime root: ${qt_root}" + echo "Relocated Qt root: ${relocated_qt_root}" + echo "WebEngine framework link: ${webengine_framework}" + echo "Relocated WebEngine framework: ${relocated_webengine_framework}" + echo "WebEngine helper: ${webengine_helper}" + + check 'Application bundle exists' test -d "${app}" + check 'Nuitka source application bundle exists' test -d "${source_app}" + framework_paths=( + "${webengine_framework}" + "${relocated_webengine_framework}" + "${relocated_webengine_framework}/Versions/Current" + "${relocated_webengine_framework}/QtWebEngineCore" + ) + check 'Relocated framework paths can be inspected' ls -ld "${framework_paths[@]}" + check 'MacOS WebEngine framework entry is a symbolic link' test -L "${webengine_framework}" + check 'Framework Current version is a symbolic link' test -L "${relocated_webengine_framework}/Versions/Current" + check 'Framework top-level binary is a symbolic link' test -L "${relocated_webengine_framework}/QtWebEngineCore" + check 'WebEngine process helper is executable' test -x "${webengine_helper}" + resource_paths=( + "${macos_root}/icudtl.dat" + "${macos_root}/qtwebengine_resources.pak" + ) + check 'WebEngine resource metadata can be inspected' ls -l@ "${resource_paths[@]}" + check 'Chromium ICU data exists' test -f "${resource_paths[0]}" + check 'Chromium resource pack exists' test -f "${resource_paths[1]}" + check 'Nuitka source code signature is valid' codesign --verify --deep --strict --verbose=2 "${source_app}" + check 'Staged application code signature is valid' codesign --verify --deep --strict --verbose=2 "${app}" + size_paths=( + "${app}" + "${app}/Contents/Frameworks" + "${app}/Contents/MacOS" + ) + check 'Application bundle sizes can be measured' du -sh "${size_paths[@]}" + + if ((failures > 0)); then + echo "::error title=macOS bundle verification::${failures} check(s) failed" + exit 1 + fi + - name: Verify packaged Windows binaries + env: + EXPECTED_WINDOWS_ARCHITECTURE: ${{ matrix.windows-architecture }} + WINDOWS_COMPATIBILITY: ${{ matrix.windows-compatibility }} + run: | + python - <<'PY' + import os + import struct + from pathlib import Path + + machineCodes = { + 'amd64': 0x8664, + 'arm64': 0xAA64, + } + expected = os.environ['EXPECTED_WINDOWS_ARCHITECTURE'] + expectedMachine = machineCodes[expected] + root = Path('Furious-Deploy/Furious.dist') + compatibilityDll = root / 'api-ms-win-core-path-l1-1-0.dll' + + if ( + os.environ['WINDOWS_COMPATIBILITY'] == 'windows7' + and not compatibilityDll.is_file() + ): + raise SystemExit(f'Windows 7 compatibility DLL is missing: {compatibilityDll}') + + binaries = sorted( + { + *root.rglob('*.exe'), + *root.rglob('*.pyd'), + *([compatibilityDll] if compatibilityDll.is_file() else []), + } + ) + + if not binaries: + raise SystemExit(f'no packaged Windows binaries found below {root}') + + for binary in binaries: + with binary.open('rb') as stream: + if stream.read(2) != b'MZ': + raise SystemExit(f'{binary} is not a PE binary') + + stream.seek(0x3C) + peOffset = struct.unpack('\n' f'\n' f' \n' - f' \n' + f' \n' f' \n' f' \n' f'\n' + f' \n' + f' \n' + f' \n' + f' \n' + f'\n' f' \n' f' \n' f' \n' @@ -606,8 +644,9 @@ def main(): [ 'wix', 'build', - msifolder / 'FuriousFiles.wxs', msifolder / 'Product.wxs', + '-arch', + WINDOWS_WIX_ARCHITECTURE, '-o', ROOT_DIR / f'{ARTIFACT_NAME}.msi', '-ext', @@ -646,10 +685,32 @@ def main(): raise - shutil.copytree( - ROOT_DIR / DEPLOY_DIR_NAME / 'Furious-GUI.app', - MAC_APP_DIR / 'Furious-GUI.app', - ) + sourceApp = ROOT_DIR / DEPLOY_DIR_NAME / 'Furious-GUI.app' + stagedApp = MAC_APP_DIR / 'Furious-GUI.app' + + try: + result = runExternalCommand( + ( + 'ditto', + '--rsrc', + '--extattr', + str(sourceApp), + str(stagedApp), + ), + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + check=True, + ) + except subprocess.CalledProcessError as err: + logger.error(f'stage macOS app failed with returncode {err.returncode}') + + printStandardStream(err.stdout, err.stderr) + + sys.exit(EXIT_FAILURE) + else: + logger.info('stage macOS app success') + + printStandardStream(result.stdout, result.stderr) logger.info('generating dmg') @@ -722,18 +783,32 @@ def main(): raise + appRun = LINUX_APP_DIR / 'AppRun' + + with open(appRun, 'w', encoding='utf-8') as file: + file.write( + '#!/bin/sh\n' + 'APPDIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"\n' + f'exec "$APPDIR/usr/bin/{APPLICATION_NAME}.bin" "$@"\n' + ) + + appRun.chmod(0o755) + logger.info('generating AppImage') - # https://github.com/linuxdeploy/linuxdeploy-plugin-appimage/blob/master/README.md - os.environ['LDAI_OUTPUT'] = LINUX_APPIMAGE_FILENAME - os.environ['LINUXDEPLOY_OUTPUT_VERSION'] = APPLICATION_VERSION + if LINUX_APPIMAGE_BUILDER == 'linuxdeploy': + os.environ['LDAI_OUTPUT'] = LINUX_APPIMAGE_FILENAME + os.environ['LINUXDEPLOY_OUTPUT_VERSION'] = APPLICATION_VERSION + else: + # Nuitka's standalone directory already owns its complete Qt runtime. + # appimagetool packages it as-is instead of harvesting Qt a second time. + os.environ['ARCH'] = PLATFORM_MACHINE try: result = runExternalCommand( LINUX_CREATE_APPIMAGE_CMD, stdout=subprocess.PIPE, stderr=subprocess.PIPE, - shell=True, check=True, ) except subprocess.CalledProcessError as err: diff --git a/pyproject.toml b/pyproject.toml index 886396d..fca5644 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,7 +20,7 @@ dependencies = [ "segno", "icmplib", "mss", - "zxing-cpp<3", + "zxing-cpp", "pillow", "Xray-core", "hysteria", diff --git a/requirements.txt b/requirements.txt index 25f90b0..9a078ab 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,7 +5,7 @@ pybase64 segno icmplib mss -zxing-cpp<3 +zxing-cpp pillow Xray-core hysteria