Misc bugs and metadata table override functions. #608
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Build VPinFE (Cross-Platform) | |
| on: | |
| push: | |
| branches: [ master, vpinfe-2.0 ] | |
| tags: [ 'v*' ] | |
| pull_request: | |
| branches: [ master, vpinfe-2.0 ] | |
| permissions: | |
| contents: write | |
| env: | |
| FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true" | |
| jobs: | |
| build: | |
| env: | |
| DOF_VERSION: latest | |
| DOF_REPO: superhac/libdof-python | |
| DMDUTIL_VERSION: latest | |
| DMDUTIL_REPO: superhac/libdmdutil-python | |
| strategy: | |
| matrix: | |
| os: [ubuntu-latest, ubuntu-24.04-arm, windows-latest, macos-latest] | |
| runs-on: ${{ matrix.os }} | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - name: Ensure fetch scripts are executable | |
| if: runner.os != 'Windows' | |
| run: | | |
| chmod +x scripts/fetch_dof_bundle.sh | |
| chmod +x scripts/fetch_libdmdutil_bundle.sh | |
| shell: bash | |
| - name: Set up Python | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: '3.14' | |
| - name: Resolve DOF triplet | |
| run: | | |
| if [[ "$RUNNER_OS" == "Linux" ]]; then | |
| if [[ "$RUNNER_ARCH" == "X64" ]]; then | |
| echo "DOF_TRIPLET=linux-x64" >> "$GITHUB_ENV" | |
| elif [[ "$RUNNER_ARCH" == "ARM64" ]]; then | |
| echo "DOF_TRIPLET=linux-arm64" >> "$GITHUB_ENV" | |
| else | |
| echo "Unsupported Linux arch: $RUNNER_ARCH" | |
| exit 1 | |
| fi | |
| elif [[ "$RUNNER_OS" == "Windows" ]]; then | |
| echo "DOF_TRIPLET=win-x64" >> "$GITHUB_ENV" | |
| elif [[ "$RUNNER_OS" == "macOS" ]]; then | |
| echo "DOF_TRIPLET=macos-arm64" >> "$GITHUB_ENV" | |
| else | |
| echo "Unsupported OS: $RUNNER_OS" | |
| exit 1 | |
| fi | |
| shell: bash | |
| - name: Set app version from tag/commit | |
| run: | | |
| if [[ "${GITHUB_REF}" == refs/tags/v* ]]; then | |
| APP_VERSION="${GITHUB_REF_NAME}" | |
| else | |
| APP_VERSION="dev-${GITHUB_SHA::7}" | |
| fi | |
| printf '%s\n' \ | |
| '"""Build/version metadata for VPinFE."""' \ | |
| '' \ | |
| "APP_VERSION = \"${APP_VERSION}\"" \ | |
| '' \ | |
| 'def get_version() -> str:' \ | |
| ' return APP_VERSION' \ | |
| > common/app_version.py | |
| echo "APP_VERSION=${APP_VERSION}" >> "$GITHUB_ENV" | |
| echo "Using app version: ${APP_VERSION}" | |
| shell: bash | |
| - name: Fetch DOF bundle | |
| env: | |
| GITHUB_TOKEN: ${{ github.token }} | |
| run: | | |
| python scripts/fetch_dof_bundle.py \ | |
| --repo "${DOF_REPO}" \ | |
| --version "${DOF_VERSION}" \ | |
| --triplet "${DOF_TRIPLET}" \ | |
| --outdir third-party/dof | |
| shell: bash | |
| - name: Fetch libdmdutil bundle | |
| env: | |
| GITHUB_TOKEN: ${{ github.token }} | |
| run: | | |
| python scripts/fetch_libdmdutil_bundle.py \ | |
| --repo "${DMDUTIL_REPO}" \ | |
| --version "${DMDUTIL_VERSION}" \ | |
| --triplet "${DOF_TRIPLET}" \ | |
| --outdir third-party/libdmdutil | |
| shell: bash | |
| - name: Install Python dependencies | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install -r requirements.txt | |
| pip install pyinstaller | |
| - name: Create Chromium directories (Linux/macOS) | |
| if: runner.os != 'Windows' | |
| run: | | |
| mkdir -p chromium/linux chromium/windows chromium/mac | |
| shell: bash | |
| - name: Create Chromium directories (Windows) | |
| if: runner.os == 'Windows' | |
| run: | | |
| New-Item -ItemType Directory -Force -Path chromium\linux,chromium\windows,chromium\mac | |
| - name: Download Linux Chromium | |
| if: runner.os == 'Linux' && runner.arch == 'X64' | |
| run: | | |
| wget -O chromium/linux/chrome.zip "https://www.googleapis.com/download/storage/v1/b/chromium-browser-snapshots/o/Linux_x64%2F1568190%2Fchrome-linux.zip?generation=1768270474193258&alt=media" | |
| unzip -q chromium/linux/chrome.zip -d chromium/linux | |
| mv chromium/linux/chrome-linux chromium/linux/chrome | |
| chmod +x chromium/linux/chrome/chrome | |
| - name: Download ARM Linux Chromium | |
| if: runner.os == 'Linux' && runner.arch == 'ARM64' | |
| run: | | |
| wget -O chromium/linux/chrome.tar.xz "https://github.com/ungoogled-software/ungoogled-chromium-portablelinux/releases/download/144.0.7559.109-1/ungoogled-chromium-144.0.7559.109-1-arm64_linux.tar.xz" | |
| tar xvf chromium/linux/chrome.tar.xz -C chromium/linux/ | |
| mv chromium/linux/ungoogled-chromium-144.0.7559.109-1-arm64_linux chromium/linux/chrome | |
| chmod +x chromium/linux/chrome/chrome | |
| - name: Download Windows Chromium | |
| if: runner.os == 'Windows' | |
| run: | | |
| pwsh -Command "Invoke-WebRequest -Uri 'https://www.googleapis.com/download/storage/v1/b/chromium-browser-snapshots/o/Win_x64%2F1568195%2Fchrome-win.zip?generation=1768274160162696&alt=media' -OutFile 'chromium/windows/chrome.zip' -UseBasicParsing" | |
| pwsh -Command "Expand-Archive -Path 'chromium/windows/chrome.zip' -DestinationPath 'chromium/windows'" | |
| pwsh -Command "Remove-Item 'chromium/windows/chrome.zip'" | |
| - name: Download Mac Chromium | |
| if: runner.os == 'macOS' | |
| run: | | |
| mkdir -p chromium | |
| curl -L -o chrome-mac.zip "https://www.googleapis.com/download/storage/v1/b/chromium-browser-snapshots/o/Mac_Arm%2F1582847%2Fchrome-mac.zip?generation=1770766943434586&alt=media" | |
| unzip -q chrome-mac.zip | |
| mv chrome-mac/Chromium.app chromium/Chromium.app | |
| rm -rf chrome-mac chrome-mac.zip | |
| - name: Build app with PyInstaller | |
| run: | | |
| if [[ "$RUNNER_OS" == "Linux" ]]; then | |
| pyinstaller --onedir --noconfirm --name vpinfe \ | |
| --add-data "web:web" \ | |
| --add-data "managerui/static:managerui/static" \ | |
| --add-data "third-party/dof:third-party/dof" \ | |
| --add-data "third-party/libdmdutil:third-party/libdmdutil" \ | |
| --add-data "chromium/linux/chrome:chromium/linux/chrome" \ | |
| --hidden-import pynput.keyboard._xorg \ | |
| --hidden-import pynput.mouse._xorg \ | |
| main.py | |
| elif [[ "$RUNNER_OS" == "Windows" ]]; then | |
| pyinstaller --onedir --noconfirm --name vpinfe \ | |
| --add-data "web;web" \ | |
| --add-data "managerui/static;managerui/static" \ | |
| --add-data "third-party/dof;third-party/dof" \ | |
| --add-data "third-party/libdmdutil;third-party/libdmdutil" \ | |
| --add-data "chromium/windows;chromium/windows" \ | |
| main.py | |
| elif [[ "$RUNNER_OS" == "macOS" ]]; then | |
| pyinstaller --windowed -i icon/VPinFE.icns --osx-bundle-identifier com.vpinfe.main --noconfirm --name VPinFE \ | |
| --add-data "web:web" \ | |
| --add-data "managerui/static:managerui/static" \ | |
| --add-data "third-party/dof:third-party/dof" \ | |
| --add-data "third-party/libdmdutil:third-party/libdmdutil" \ | |
| main.py | |
| mkdir -p dist/VPinFE.app/Contents/Frameworks/chromium | |
| cp -R chromium/Chromium.app dist/VPinFE.app/Contents/Frameworks/chromium/Chromium.app | |
| chmod +x dist/VPinFE.app/Contents/Frameworks/chromium/Chromium.app/Contents/MacOS/Chromium | |
| rm -rf dist/vpinfe | |
| fi | |
| shell: bash | |
| - name: Ad-hoc sign the app (macOS) | |
| if: runner.os == 'macOS' | |
| run: | | |
| codesign --force --deep --sign - dist/VPinFE.app | |
| codesign --verify --verbose dist/VPinFE.app | |
| shell: bash | |
| - name: Remove extended attributes (macOS) | |
| if: runner.os == 'macOS' | |
| run: | | |
| sudo xattr -rc dist | |
| shell: bash | |
| - name: Install create-dmg | |
| if: runner.os == 'macOS' | |
| run: brew install create-dmg | |
| shell: bash | |
| - name: Package as DMG (macOS) | |
| if: runner.os == 'macOS' | |
| run: | | |
| create-dmg \ | |
| --volname "VPinFE" \ | |
| --volicon "icon/VPinFE.icns" \ | |
| --background "icon/DMG_background.png" \ | |
| --window-pos 200 120 \ | |
| --window-size 610 475 \ | |
| --icon-size 100 \ | |
| --icon "VPinFE.app" 175 190 \ | |
| --hide-extension "VPinFE.app" \ | |
| --app-drop-link 425 190 \ | |
| "dist/VPinFE.dmg" \ | |
| "dist/VPinFE.app" | |
| shell: bash | |
| - name: Copy Windows launcher | |
| if: runner.os == 'Windows' | |
| run: cp vpinfe.bat dist/vpinfe/ | |
| shell: bash | |
| - name: Upload full build artifact (macOS) | |
| if: runner.os == 'macOS' | |
| uses: actions/upload-artifact@v6 | |
| with: | |
| name: build-macos-arm64 | |
| path: dist/VPinFE.dmg | |
| - name: Upload full build artifact (Linux) | |
| if: runner.os == 'Linux' | |
| uses: actions/upload-artifact@v6 | |
| with: | |
| name: build-linux-${{ runner.arch == 'X64' && 'x64' || 'arm64' }} | |
| path: dist/ | |
| - name: Upload full build artifact (Windows) | |
| if: runner.os == 'Windows' | |
| uses: actions/upload-artifact@v6 | |
| with: | |
| name: build-win-x64 | |
| path: dist/ | |
| - name: Build slim app with PyInstaller (Linux) | |
| if: runner.os == 'Linux' | |
| run: | | |
| rm -rf build dist | |
| pyinstaller --onedir --noconfirm --name vpinfe \ | |
| --add-data "web:web" \ | |
| --add-data "managerui/static:managerui/static" \ | |
| --add-data "third-party/dof:third-party/dof" \ | |
| --add-data "third-party/libdmdutil:third-party/libdmdutil" \ | |
| --hidden-import pynput.keyboard._xorg \ | |
| --hidden-import pynput.mouse._xorg \ | |
| main.py | |
| shell: bash | |
| - name: Upload slim build artifact (Linux) | |
| if: runner.os == 'Linux' | |
| uses: actions/upload-artifact@v6 | |
| with: | |
| name: build-linux-${{ runner.arch == 'X64' && 'x64' || 'arm64' }}-slim | |
| path: dist/ | |
| - name: Build slim app with PyInstaller (Windows) | |
| if: runner.os == 'Windows' | |
| run: | | |
| Remove-Item -Recurse -Force build, dist -ErrorAction SilentlyContinue | |
| pyinstaller --onedir --noconfirm --name vpinfe ` | |
| --add-data "web;web" ` | |
| --add-data "managerui/static;managerui/static" ` | |
| --add-data "third-party/dof;third-party/dof" ` | |
| --add-data "third-party/libdmdutil;third-party/libdmdutil" ` | |
| main.py | |
| - name: Copy Windows launcher (slim) | |
| if: runner.os == 'Windows' | |
| run: cp vpinfe.bat dist/vpinfe/ | |
| shell: bash | |
| - name: Upload slim build artifact (Windows) | |
| if: runner.os == 'Windows' | |
| uses: actions/upload-artifact@v6 | |
| with: | |
| name: build-win-x64-slim | |
| path: dist/ | |
| - name: Build slim app with PyInstaller (macOS) | |
| if: runner.os == 'macOS' | |
| run: | | |
| rm -rf build dist | |
| pyinstaller --windowed -i icon/VPinFE.icns --osx-bundle-identifier com.vpinfe.main --noconfirm --name VPinFE \ | |
| --add-data "web:web" \ | |
| --add-data "managerui/static:managerui/static" \ | |
| --add-data "third-party/dof:third-party/dof" \ | |
| --add-data "third-party/libdmdutil:third-party/libdmdutil" \ | |
| main.py | |
| rm -rf dist/vpinfe | |
| shell: bash | |
| - name: Ad-hoc sign the app (macOS Slim) | |
| if: runner.os == 'macOS' | |
| run: | | |
| codesign --force --deep --sign - dist/VPinFE.app | |
| codesign --verify --verbose dist/VPinFE.app | |
| shell: bash | |
| - name: Remove extended attributes (macOS Slim) | |
| if: runner.os == 'macOS' | |
| run: | | |
| sudo xattr -rc dist | |
| shell: bash | |
| - name: Package as DMG (macOS Slim) | |
| if: runner.os == 'macOS' | |
| run: | | |
| create-dmg \ | |
| --volname "VPinFE" \ | |
| --volicon "icon/VPinFE.icns" \ | |
| --background "icon/DMG_background.png" \ | |
| --window-pos 200 120 \ | |
| --window-size 610 475 \ | |
| --icon-size 100 \ | |
| --icon "VPinFE.app" 175 190 \ | |
| --hide-extension "VPinFE.app" \ | |
| --app-drop-link 425 190 \ | |
| "dist/VPinFE.dmg" \ | |
| "dist/VPinFE.app" | |
| shell: bash | |
| - name: Upload slim build artifact (macOS) | |
| if: runner.os == 'macOS' | |
| uses: actions/upload-artifact@v6 | |
| with: | |
| name: build-macos-arm64-slim | |
| path: dist/VPinFE.dmg | |
| release_bundle: | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| needs: build | |
| runs-on: ubuntu-latest | |
| strategy: | |
| matrix: | |
| include: | |
| - artifact: build-linux-x64 | |
| triplet: linux-x64 | |
| - artifact: build-linux-arm64 | |
| triplet: linux-arm64 | |
| - artifact: build-win-x64 | |
| triplet: win-x64 | |
| - artifact: build-macos-arm64 | |
| triplet: macos-arm64 | |
| - artifact: build-linux-x64-slim | |
| triplet: linux-x64-slim | |
| - artifact: build-linux-arm64-slim | |
| triplet: linux-arm64-slim | |
| - artifact: build-win-x64-slim | |
| triplet: win-x64-slim | |
| - artifact: build-macos-arm64-slim | |
| triplet: macos-arm64-slim | |
| steps: | |
| - name: Download build artifact | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: ${{ matrix.artifact }} | |
| path: staging/${{ matrix.triplet }} | |
| - name: Create tagged release zip | |
| run: | | |
| mkdir -p release | |
| if [[ "${{ matrix.triplet }}" == linux-* ]]; then | |
| # Artifact download/extract can lose executable bits; restore Linux launch binaries. | |
| find "staging/${{ matrix.triplet }}" -type f -name vpinfe -exec chmod 755 {} + | |
| while IFS= read -r chrome_root; do | |
| find "$chrome_root" -type d -exec chmod 755 {} + | |
| for helper in chrome chrome_crashpad_handler chrome-sandbox nacl_helper nacl_helper_bootstrap; do | |
| if [[ -e "$chrome_root/$helper" ]]; then | |
| chmod 755 "$chrome_root/$helper" | |
| fi | |
| done | |
| done < <(find "staging/${{ matrix.triplet }}" -type d -path '*/_internal/chromium/linux/chrome') | |
| fi | |
| cd staging/${{ matrix.triplet }} | |
| zip -r ../../release/vpinfe-${GITHUB_REF_NAME}-${{ matrix.triplet }}.zip . | |
| - name: Upload release zip artifact | |
| uses: actions/upload-artifact@v6 | |
| with: | |
| name: release-zip-${{ matrix.triplet }} | |
| path: release/vpinfe-${{ github.ref_name }}-${{ matrix.triplet }}.zip | |
| publish_release: | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| needs: release_bundle | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v5 | |
| - name: Download release zip artifacts | |
| uses: actions/download-artifact@v8 | |
| with: | |
| pattern: release-zip-* | |
| path: release | |
| merge-multiple: true | |
| - name: Generate checksums.txt | |
| run: | | |
| cd release | |
| sha256sum vpinfe-${GITHUB_REF_NAME}-*.zip > checksums.txt | |
| - name: Generate manifest.json | |
| run: | | |
| python - <<'PY' | |
| import hashlib | |
| import json | |
| from pathlib import Path | |
| tag = "${{ github.ref_name }}" | |
| release_dir = Path("release") | |
| assets = {} | |
| for zip_path in sorted(release_dir.glob(f"vpinfe-{tag}-*.zip")): | |
| name = zip_path.name | |
| prefix = f"vpinfe-{tag}-" | |
| triplet = name[len(prefix):-4] | |
| sha = hashlib.sha256(zip_path.read_bytes()).hexdigest() | |
| assets[triplet] = { | |
| "file": name, | |
| "sha256": sha, | |
| } | |
| manifest = { | |
| "version": tag, | |
| "assets": assets, | |
| } | |
| (release_dir / "manifest.json").write_text( | |
| json.dumps(manifest, indent=2) + "\n", | |
| encoding="utf-8", | |
| ) | |
| PY | |
| - name: Publish GitHub release assets | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| assets=( | |
| release/vpinfe-${GITHUB_REF_NAME}-*.zip | |
| release/checksums.txt | |
| release/manifest.json | |
| ) | |
| if gh release view "${GITHUB_REF_NAME}" >/dev/null 2>&1; then | |
| gh release edit "${GITHUB_REF_NAME}" --notes-file RELEASE_NOTES.md | |
| gh release upload "${GITHUB_REF_NAME}" "${assets[@]}" --clobber | |
| else | |
| gh release create "${GITHUB_REF_NAME}" "${assets[@]}" \ | |
| --notes-file RELEASE_NOTES.md \ | |
| --verify-tag | |
| fi |