diff --git a/.claude/gitea-ship.json b/.claude/gitea-ship.json new file mode 100644 index 0000000..8965ff5 --- /dev/null +++ b/.claude/gitea-ship.json @@ -0,0 +1,7 @@ +{ + "owner": "justin", + "runner_label": "windows-latest | self-hosted-mac | docker | arm64", + "deploy": "git-tag-release", + "version_source": "git-tag", + "notes": "Open-source desktop app (PySide6/pyqtgraph). CI = .gitea/workflows/release.yml builds PyInstaller binaries on the Windows / self-hosted-mac / docker (linux x86_64) / arm64 (Pi) runners; on a v* tag it publishes a Gitea Release with each platform binary attached (softprops/action-gh-release, GITEA_TOKEN). No containers/registry/Watchtower. Profiles are bundled via --add-data and found at runtime via sys._MEIPASS (obdcore/profile.py profiles_dir())." +} diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml new file mode 100644 index 0000000..a9cdd09 --- /dev/null +++ b/.gitea/workflows/release.yml @@ -0,0 +1,100 @@ +name: Build binaries + +# Build OBDash GUI binaries on each self-hosted runner. On a version tag +# (v*), publish a Gitea Release with every platform's binary attached. +# Manual runs (workflow_dispatch) build-only (no release) to verify compilation. +on: + push: + tags: ["v*"] + workflow_dispatch: {} + +jobs: + windows: + runs-on: windows-latest # self-hosted Windows runner + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: "3.12" + - name: Build OBDash.exe (PyInstaller) + shell: pwsh + run: | + python -m pip install --upgrade pip + pip install -r requirements-gui.txt pyinstaller + pyinstaller --noconfirm --onefile --windowed --name OBDash --add-data "profiles;profiles" run_gui.py + Copy-Item dist/OBDash.exe OBDash-windows.exe + - name: Publish to release + if: startsWith(github.ref, 'refs/tags/') + uses: softprops/action-gh-release@v2 + with: + files: OBDash-windows.exe + env: + GITHUB_TOKEN: ${{ secrets.GITEA_TOKEN }} + + macos: + runs-on: self-hosted-mac + steps: + - uses: actions/checkout@v4 + - name: Build OBDash.app (PyInstaller) + shell: bash + run: | + python3 -m venv .build-venv + . .build-venv/bin/activate + pip install --upgrade pip + pip install -r requirements-gui.txt pyinstaller + pyinstaller --noconfirm --windowed --name OBDash --add-data "profiles:profiles" run_gui.py + ditto -c -k --keepParent dist/OBDash.app OBDash-macos.zip + - name: Publish to release + if: startsWith(github.ref, 'refs/tags/') + uses: softprops/action-gh-release@v2 + with: + files: OBDash-macos.zip + env: + GITHUB_TOKEN: ${{ secrets.GITEA_TOKEN }} + + linux-amd64: + runs-on: docker # Linux x86_64 runner (container) + steps: + - uses: actions/checkout@v4 + - name: Build OBDash (PyInstaller) + shell: bash + run: | + # patchelf is needed for onefile; GL/EGL/xkb are runtime deps users need + (sudo apt-get update && sudo apt-get install -y python3-venv patchelf libgl1 libegl1 libxkbcommon0) \ + || (apt-get update && apt-get install -y python3-venv patchelf libgl1 libegl1 libxkbcommon0) || true + python3 -m venv .build-venv + . .build-venv/bin/activate + pip install --upgrade pip + pip install -r requirements-gui.txt pyinstaller + pyinstaller --noconfirm --onefile --name OBDash --add-data "profiles:profiles" run_gui.py + cp dist/OBDash OBDash-linux-x86_64 + - name: Publish to release + if: startsWith(github.ref, 'refs/tags/') + uses: softprops/action-gh-release@v2 + with: + files: OBDash-linux-x86_64 + env: + GITHUB_TOKEN: ${{ secrets.GITEA_TOKEN }} + + linux-arm64: + runs-on: arm64 # Raspberry Pi (aarch64) runner + steps: + - uses: actions/checkout@v4 + - name: Build OBDash (PyInstaller) + shell: bash + run: | + (sudo apt-get update && sudo apt-get install -y python3-venv patchelf libgl1 libegl1 libxkbcommon0) \ + || (apt-get update && apt-get install -y python3-venv patchelf libgl1 libegl1 libxkbcommon0) || true + python3 -m venv .build-venv + . .build-venv/bin/activate + pip install --upgrade pip + pip install -r requirements-gui.txt pyinstaller + pyinstaller --noconfirm --onefile --name OBDash --add-data "profiles:profiles" run_gui.py + cp dist/OBDash OBDash-linux-aarch64 + - name: Publish to release + if: startsWith(github.ref, 'refs/tags/') + uses: softprops/action-gh-release@v2 + with: + files: OBDash-linux-aarch64 + env: + GITHUB_TOKEN: ${{ secrets.GITEA_TOKEN }} diff --git a/.gitignore b/.gitignore index 00f2d38..5854bb9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,8 @@ __pycache__/ *.pyc .venv/ + +# PyInstaller build output +build/ +dist/ +*.spec diff --git a/obdcore/profile.py b/obdcore/profile.py index cacc276..b94fbd6 100644 --- a/obdcore/profile.py +++ b/obdcore/profile.py @@ -19,6 +19,7 @@ JSON schema (schema=1): import glob import json import os +import sys from dataclasses import dataclass, field from .formula import compile_formula @@ -42,6 +43,11 @@ class Profile: def profiles_dir(): + # In a PyInstaller bundle, profiles/ is added as data and unpacked under + # sys._MEIPASS; otherwise it's the repo's profiles/ next to obdcore/. + if getattr(sys, "frozen", False): + base = getattr(sys, "_MEIPASS", os.path.dirname(sys.executable)) + return os.path.join(base, "profiles") return os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "profiles")