Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
182 changes: 182 additions & 0 deletions .github/workflows/appimage.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
name: AppImage

on:
push:
pull_request:
workflow_dispatch:

permissions:
contents: write

jobs:
appimage:
name: "AppImage"
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4

- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y \
meson \
ninja-build \
python3 \
python3-pip \
python3-pybind11 \
libglib2.0-dev \
libgtk-4-dev \
libadwaita-1-dev \
desktop-file-utils \
appstream \
wget \
file \
cmake \
libvtk9-dev \
libopengl-dev \
fuse \
elfutils \
patchelf \
gettext \
itstool \
librsvg2-bin \
libhdf5-dev \
libnetcdf-dev \
libaec-dev

- name: Install F3D from pip (prebuilt wheel, matches Exhibit 3.5 API)
run: |
sudo pip3 install --break-system-packages f3d
find /usr -name "f3d" -type d 2>/dev/null || true
find /usr -name "f3d*.so" 2>/dev/null || true

- name: Download appimagetool
run: |
wget https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage || exit 1
chmod +x appimagetool-x86_64.AppImage

- name: Build project
run: |
rm -rf AppDir builddir
meson setup builddir --prefix=/usr
DESTDIR="$(pwd)/AppDir" ninja -C builddir install

- name: Build AppImage
run: |
# Bundle Python 3.12 + GI (host is 3.14, f3d extension is 3.12), but use host GLib/GTK to avoid mismatch
mkdir -p AppDir/usr/bin AppDir/usr/lib
cp -L /usr/bin/python3 AppDir/usr/bin/python3 2>/dev/null || true
cp -r /usr/lib/python3.* AppDir/usr/lib/ 2>/dev/null || true
cp /usr/lib/x86_64-linux-gnu/libpython3.*so* AppDir/usr/lib/ 2>/dev/null || true
mkdir -p AppDir/usr/lib/python3/dist-packages
cp -r /usr/lib/python3/dist-packages/gi AppDir/usr/lib/python3/dist-packages/ 2>/dev/null || true
# Use host GI typelibs (bundled 24.04 typelibs mismatch host 26.04 libs)

# Copy f3d Python module and library
find /usr /usr/local "$HOME/.local" /tmp/f3d-pip -name "f3d" -type d -path "*/python*" 2>/dev/null | head -5
find /usr /usr/local "$HOME/.local" /tmp/f3d-pip -name "f3d" -type d -path "*/python*" -exec cp -r {} AppDir/usr/lib/python3/dist-packages/ \; 2>/dev/null || true
# Also copy from user site-packages explicitly
cp -r $HOME/.local/lib/python*/site-packages/f3d AppDir/usr/lib/python3/dist-packages/ 2>/dev/null || true
cp -r /tmp/f3d-pip/f3d AppDir/usr/lib/python3/dist-packages/ 2>/dev/null || true
cp /usr/lib/x86_64-linux-gnu/libf3d.so* AppDir/usr/lib/ 2>/dev/null || true
cp /usr/local/lib/libf3d.so* AppDir/usr/lib/ 2>/dev/null || true
cp /usr/lib/x86_64-linux-gnu/libvtkext.so AppDir/usr/lib/ 2>/dev/null || true
# Copy VTK libraries that f3d depends on
cp /usr/lib/x86_64-linux-gnu/libvtk*.so* AppDir/usr/lib/ 2>/dev/null || true
# Copy f3d data and plugins
cp -r /usr/share/f3d AppDir/usr/share/ 2>/dev/null || true
cp -r /usr/lib/f3d AppDir/usr/lib/ 2>/dev/null || true
cp -r /usr/local/lib/f3d AppDir/usr/lib/ 2>/dev/null || true
find /usr/lib -name "libf3d*.so*" -exec cp -L -n {} AppDir/usr/lib/ \; 2>/dev/null || true
find /usr/local/lib -name "libf3d*.so*" -exec cp -L -n {} AppDir/usr/lib/ \; 2>/dev/null || true
# Copy known f3d transitive deps as fallback (ldd closure below covers the rest)
cp /usr/lib/x86_64-linux-gnu/libtbb*.so* AppDir/usr/lib/ 2>/dev/null || true
cp /usr/lib/x86_64-linux-gnu/libimath*.so* AppDir/usr/lib/ 2>/dev/null || true
cp /usr/lib/x86_64-linux-gnu/libhdf5*.so* AppDir/usr/lib/ 2>/dev/null || true
cp /usr/lib/x86_64-linux-gnu/libdraco*.so* AppDir/usr/lib/ 2>/dev/null || true
cp /usr/lib/x86_64-linux-gnu/libdeflate.so* AppDir/usr/lib/ 2>/dev/null || true
cp /usr/lib/x86_64-linux-gnu/libopenexr*.so* AppDir/usr/lib/ 2>/dev/null || true
cp /usr/lib/x86_64-linux-gnu/libilmbase*.so* AppDir/usr/lib/ 2>/dev/null || true
cp /usr/lib/x86_64-linux-gnu/libassimp*.so* AppDir/usr/lib/ 2>/dev/null || true
cp /usr/lib/x86_64-linux-gnu/libalembic*.so* AppDir/usr/lib/ 2>/dev/null || true
cp /usr/lib/x86_64-linux-gnu/libopensubdiv*.so* AppDir/usr/lib/ 2>/dev/null || true
cp /usr/lib/x86_64-linux-gnu/libusd*.so* AppDir/usr/lib/ 2>/dev/null || true
cp /usr/lib/x86_64-linux-gnu/libboost_*.so* AppDir/usr/lib/ 2>/dev/null || true
cp /usr/lib/x86_64-linux-gnu/libjsoncpp.so* AppDir/usr/lib/ 2>/dev/null || true
cp /usr/lib/x86_64-linux-gnu/libGL*.so* AppDir/usr/lib/ 2>/dev/null || true
cp /usr/lib/x86_64-linux-gnu/libEGL*.so* AppDir/usr/lib/ 2>/dev/null || true
cp /usr/lib/x86_64-linux-gnu/libX*.so* AppDir/usr/lib/ 2>/dev/null || true
cp /usr/lib/x86_64-linux-gnu/libnetcdf.so* AppDir/usr/lib/ 2>/dev/null || true
cp /usr/lib/x86_64-linux-gnu/libsz.so* AppDir/usr/lib/ 2>/dev/null || true
cp /usr/lib/x86_64-linux-gnu/libaec.so* AppDir/usr/lib/ 2>/dev/null || true
cp /usr/lib/x86_64-linux-gnu/libGLEW.so* AppDir/usr/lib/ 2>/dev/null || true
cp /usr/lib/x86_64-linux-gnu/libmpi*.so* AppDir/usr/lib/ 2>/dev/null || true
cp /usr/lib/x86_64-linux-gnu/libopen-pal.so* AppDir/usr/lib/ 2>/dev/null || true
cp /usr/lib/x86_64-linux-gnu/libopen-rte.so* AppDir/usr/lib/ 2>/dev/null || true
cp /usr/lib/x86_64-linux-gnu/libhwloc.so* AppDir/usr/lib/ 2>/dev/null || true
cp /usr/lib/x86_64-linux-gnu/libevent*.so* AppDir/usr/lib/ 2>/dev/null || true
# Bundle Wand (Python ImageMagick) for Exhibit - required at runtime (window.py imports wand)
pip3 install --no-deps --target=AppDir/usr/lib/python3/dist-packages Wand 2>/dev/null || pip3 install --break-system-packages --target=AppDir/usr/lib/python3/dist-packages Wand 2>/dev/null || true

# Rename original exhibit script and create wrapper
mv AppDir/usr/bin/exhibit AppDir/usr/bin/exhibit.real
cat > AppDir/usr/bin/exhibit << 'EOF'
#!/usr/bin/env python3
import os
import sys
appdir = os.environ.get('APPDIR', '')
if appdir:
os.environ['PYTHONPATH'] = os.path.join(appdir, 'usr/share/exhibit') + ':' + os.environ.get('PYTHONPATH', '')
sys.argv[0] = os.path.join(appdir, 'usr/bin/exhibit.real')
exec(open(os.path.join(appdir, 'usr/bin/exhibit.real') if appdir else '/usr/bin/exhibit.real').read())
EOF
chmod +x AppDir/usr/bin/exhibit

# Patch the real script to use APPDIR for paths
sed -i "s|^pkgdatadir = '/usr/share/exhibit'|pkgdatadir = os.path.join(os.environ.get('APPDIR', ''), 'usr/share/exhibit') if os.environ.get('APPDIR') else '/usr/share/exhibit'|" AppDir/usr/bin/exhibit.real
sed -i "s|^localedir = '/usr/share/locale'|localedir = os.path.join(os.environ.get('APPDIR', ''), 'usr/share/locale') if os.environ.get('APPDIR') else '/usr/share/locale'|" AppDir/usr/bin/exhibit.real

# Copy desktop file and icon
cp AppDir/usr/share/applications/io.github.nokse22.Exhibit.desktop AppDir/
cp AppDir/usr/share/icons/hicolor/scalable/apps/io.github.nokse22.Exhibit.svg AppDir/.DirIcon 2>/dev/null || cp AppDir/usr/share/icons/hicolor/scalable/apps/io.github.nokse22.Exhibit.svg AppDir/ 2>/dev/null || true
rsvg-convert AppDir/.DirIcon -o AppDir/io.github.nokse22.Exhibit.png 2>/dev/null || true

# Create AppRun
cat > AppDir/AppRun << 'EOF'
#!/bin/bash
export PATH="${APPDIR}/usr/bin:${PATH}"
export LD_LIBRARY_PATH="${APPDIR}/usr/lib:${APPDIR}/usr/lib/x86_64-linux-gnu:${LD_LIBRARY_PATH}"
export PYTHONPATH="${APPDIR}/usr/share/exhibit:${APPDIR}/usr/lib/python3/dist-packages:${PYTHONPATH}"
# Use host GI_TYPELIB_PATH (bundled GTK would mismatch host 26.04)
export XDG_DATA_DIRS="${APPDIR}/usr/share:${XDG_DATA_DIRS}"
export GSETTINGS_SCHEMA_DIR="${APPDIR}/usr/share/glib-2.0/schemas:${GSETTINGS_SCHEMA_DIR}"
exec "${APPDIR}/usr/bin/exhibit" "$@"
EOF
chmod +x AppDir/AppRun

# Extract and run appimagetool
./appimagetool-x86_64.AppImage --appimage-extract 2>/dev/null || true
ARCH=x86_64 ./squashfs-root/AppRun AppDir

- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: Exhibit-x86_64.AppImage
path: Exhibit-*.AppImage

- name: Fetch release notes from upstream
if: startsWith(github.ref, 'refs/tags/')
run: |
TAG=${GITHUB_REF#refs/tags/}
curl -s https://api.github.com/repos/Nokse22/Exhibit/releases/tags/${TAG} | jq -r '.body // empty' > release_notes.md || true

- name: Release
if: startsWith(github.ref, 'refs/tags/')
uses: softprops/action-gh-release@v1
with:
files: Exhibit-*.AppImage
body_path: release_notes.md
draft: false
prerelease: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
82 changes: 82 additions & 0 deletions .github/workflows/deb.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
name: Build deb package

on:
push:
pull_request:
workflow_dispatch:

permissions:
contents: write

jobs:
deb:
name: "deb"
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4

- name: Install build dependencies
run: |
sudo apt-get update
sudo apt-get install -y \
build-essential \
debhelper-compat \
meson \
ninja-build \
python3 \
python3-gi \
libglib2.0-dev \
libgtk-4-dev \
libadwaita-1-dev \
desktop-file-utils \
appstream \
gettext \
itstool \
librsvg2-bin \
libvtk9-dev \
libopengl-dev \
cmake \
python3-pybind11

- name: Build deb package
run: |
dpkg-buildpackage -us -uc -b

- name: Copy deb to workspace
run: |
cp ../exhibit_*.deb .

- name: Install and test deb package
run: |
sudo dpkg -i exhibit_*.deb
export XDG_DATA_HOME="$HOME/.local/share"
export XDG_CONFIG_HOME="$HOME/.config"
export XDG_CACHE_HOME="$HOME/.cache"
mkdir -p "$HOME/.local/share"
# Install f3d and wand via pip for testing
pip3 install --break-system-packages f3d Wand
exhibit --version || echo "Version check failed"
exhibit --help || echo "Help check failed"

- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: exhibit-deb
path: exhibit_*.deb

- name: Fetch release notes from upstream
if: startsWith(github.ref, 'refs/tags/')
run: |
TAG=${GITHUB_REF#refs/tags/}
curl -s https://api.github.com/repos/Nokse22/Exhibit/releases/tags/${TAG} | jq -r '.body' > release_notes.md

- name: Release
if: startsWith(github.ref, 'refs/tags/')
uses: softprops/action-gh-release@v1
with:
files: exhibit_*.deb
body_path: release_notes.md
draft: false
prerelease: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
105 changes: 105 additions & 0 deletions PACKAGING_TROUBLESHOOTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# Packaging Troubleshooting Guide

This guide provides solutions for common issues when installing Exhibit via Debian package (.deb).

## Debian Package (.deb) Issues

### Installation Fails with Dependency Errors

If you encounter dependency errors during installation:

```sh
sudo apt-get install -f
```

This will attempt to fix broken dependencies.

### ModuleNotFoundError: No module named 'f3d'

The deb package requires Python dependencies that are not bundled due to version compatibility. Install them with pip:

```sh
pip install --break-system-packages f3d Wand
```

If you prefer not to use `--break-system-packages`, create a virtual environment:

```sh
python3 -m venv ~/.local/venvs/exhibit
source ~/.local/venvs/exhibit/bin/activate
pip install f3d Wand
```

### ImportError: undefined symbol: _PyThreadState_UncheckedGet

This error occurs when the Python version used to build f3d doesn't match your system Python version. Reinstall f3d to build it for your Python version:

```sh
pip install --break-system-packages --force-reinstall f3d
```

### XDG_DATA_HOME KeyError

If you encounter `KeyError: 'XDG_DATA_HOME'`, ensure the environment variable is set:

```sh
export XDG_DATA_HOME="$HOME/.local/share"
export XDG_CONFIG_HOME="$HOME/.config"
export XDG_CACHE_HOME="$HOME/.cache"
```

Or add these to your `~/.bashrc` or `~/.zshrc` file.

## General Python Issues

### Externally Managed Environment Error

If you get an error about externally managed Python environment, use:

```sh
pip install --break-system-packages f3d Wand
```

Or use a virtual environment as described above.

### pip Not Found

Install pip:

```sh
sudo apt-get install python3-pip
```

## System-Specific Issues

### Ubuntu/Debian

Ensure you have the required system packages:

```sh
sudo apt-get update
sudo apt-get install python3 python3-pip libgtk-4-1 libadwaita-1-0 libvtk9-1
```

### Fedora/RHEL

```sh
sudo dnf install python3 python3-pip gtk4 libadwaita vtk
```

### Arch Linux

```sh
sudo pacman -S python python-pip gtk4 libadwaita vtk
```

## Getting Help

If you continue to experience issues:

1. Check the [GitHub Issues](https://github.com/Nokse22/Exhibit/issues) for similar problems
2. Create a new issue with:
- Your Linux distribution and version
- Python version (`python3 --version`)
- Exact error messages
- Steps to reproduce the issue
Loading