feat: add GSD Pi Config Flatpak packaging

- Flatpak manifest using GNOME 48 SDK (webkit2gtk-4.1)
- Build script that vendors npm + Cargo deps for offline sandbox build
- tauri-plugin-localhost for asset serving in WebKit2GTK sandbox
- Desktop entry, AppStream metadata, and SVG icon
- WEBKIT_DISABLE_DMABUF_RENDERER=1 for Wayland compat
This commit is contained in:
John Smith
2026-06-02 12:23:21 -04:00
parent 7af64d24fb
commit 2a4d82003e
10 changed files with 299 additions and 59 deletions
+8
View File
@@ -29,3 +29,11 @@ vendor/
coverage/
.cache/
tmp/
# Flatpak build artifacts
gsd-pi-config-src/
cargo-vendor/
.flatpak-builder/
build-dir/
repo/
*.flatpak
+67
View File
@@ -0,0 +1,67 @@
# Flatpak for GSD Pi Config
Flatpak packaging for [GSD Pi Config](https://github.com/open-gsd/gsd-pi-config), a Tauri v2 desktop app.
## Structure
```
gsd-pi-config/
com.opengsd.pi.yaml Flatpak manifest
com.opengsd.pi.desktop Desktop entry
com.opengsd.pi.metainfo.xml AppStream metadata
com.opengsd.pi.svg App icon
cargo-config.toml Cargo config for vendored deps
build.sh Build script (vendors deps + builds)
create-bundle.sh Creates .flatpak bundle for distribution
```
## Prerequisites
```bash
# Flatpak + builder
sudo apt install flatpak flatpak-builder
# Flathub remote
flatpak remote-add --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo
# GNOME SDK (includes webkit2gtk-4.1)
flatpak install flathub org.gnome.Sdk//48 org.gnome.Platform//48
```
## Build & Install
```bash
./build.sh # Uses cached clone if available
./build.sh --clone # Fresh clone + build
```
## Run
```bash
flatpak run com.opengsd.pi
```
## Create Bundle
```bash
./create-bundle.sh
```
## How It Works
The build script clones the app repo, vendors npm + Cargo dependencies
on the host (where DNS works), then `flatpak-builder` builds inside the
sandbox fully offline.
Key details:
- **`npx tauri build`** (not `cargo build`) is used so Tauri properly
embeds frontend assets into the binary
- **`tauri-plugin-localhost`** serves bundled assets via HTTP since the
`tauri://` custom protocol doesn't work in WebKit2GTK inside Flatpak
- **`WEBKIT_DISABLE_DMABUF_RENDERER=1`** fixes a Wayland protocol crash
in the sandbox
## Updating
1. Update `APP_COMMIT` in `build.sh` to the new commit hash
2. Run `./build.sh --clone`
+45
View File
@@ -0,0 +1,45 @@
#!/bin/bash
# Build script for Flatpak
#
# Vendors npm + Cargo deps from the app repo, then builds inside
# the Flatpak sandbox (no network needed).
#
# Usage: ./build.sh [--clone]
# --clone Clone the repo fresh before building
set -e
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
APP_REPO="$SCRIPT_DIR/gsd-pi-config-src"
APP_URL="https://github.com/open-gsd/gsd-pi-config.git"
APP_COMMIT="b40e19f"
# Optionally clone fresh
if [ "$1" = "--clone" ] || [ ! -d "$APP_REPO" ]; then
echo "=== Cloning app repo ==="
rm -rf "$APP_REPO"
git clone --depth 1 "$APP_URL" "$APP_REPO"
cd "$APP_REPO"
git fetch --depth 1 origin "$APP_COMMIT"
git checkout "$APP_COMMIT"
cd "$SCRIPT_DIR"
fi
echo "=== Vendoring npm dependencies ==="
cd "$APP_REPO"
rm -rf node_modules
npm ci 2>&1 | tail -5
echo ""
echo "=== Vendoring Cargo crates ==="
rm -rf "$SCRIPT_DIR/cargo-vendor"
cargo vendor --versioned-dirs --manifest-path src-tauri/Cargo.toml "$SCRIPT_DIR/cargo-vendor" 2>&1 | tail -3
echo ""
echo "=== Building Flatpak ==="
cd "$SCRIPT_DIR"
rm -rf .flatpak-builder build-dir
flatpak-builder --user --install --force-clean build-dir com.opengsd.pi.yaml
echo ""
echo "Done! Run with: flatpak run com.opengsd.pi"
+5
View File
@@ -0,0 +1,5 @@
[source.crates-io]
replace-with = "vendored-sources"
[source.vendored-sources]
directory = "vendor"
+7
View File
@@ -0,0 +1,7 @@
[Desktop Entry]
Name=Pi
Exec=pi
Icon=com.opengsd.pi
Type=Application
Categories=Development;Utility;
Keywords=tauri;desktop;config;
+27
View File
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<component type="desktop-application">
<id>com.opengsd.pi</id>
<metadata_license>MIT</metadata_license>
<project_license>MIT</project_license>
<name>Pi</name>
<summary>A Tauri v2 desktop application</summary>
<description>
<p>
Pi is a desktop application built with Tauri v2.
It provides a modern, secure interface for configuration and management.
</p>
</description>
<url type="homepage">https://github.com/open-gsd/gsd-pi-config</url>
<url type="bugtracker">https://github.com/open-gsd/gsd-pi-config/issues</url>
<provides>
<binary>pi</binary>
</provides>
<content_rating type="oars-1.1" />
<releases>
<release version="0.1.0" date="2026-06-02">
<description>
<p>Initial release with basic functionality.</p>
</description>
</release>
</releases>
</component>
+50
View File
@@ -0,0 +1,50 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1024" height="1024">
<defs>
<!-- Background gradient: deep black with subtle cyan tint at top -->
<linearGradient id="bgGrad" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" stop-color="#0a1420"/>
<stop offset="40%" stop-color="#000000"/>
<stop offset="100%" stop-color="#000000"/>
</linearGradient>
<!-- Cyan glow filter -->
<filter id="cyanGlow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur stdDeviation="28" result="blur"/>
<feFlood flood-color="#7dcfff" flood-opacity="0.6"/>
<feComposite in2="blur" operator="in" result="glow"/>
<feMerge>
<feMergeNode in="glow"/>
<feMergeNode in="SourceGraphic"/>
</feMerge>
</filter>
<!-- Inner stroke highlight -->
<linearGradient id="strokeGrad" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" stop-color="rgba(125, 207, 255, 0.3)"/>
<stop offset="100%" stop-color="rgba(125, 207, 255, 0.05)"/>
</linearGradient>
<style>
.wordmark {
font-family: 'SF Mono', 'JetBrains Mono', 'Fira Code', 'Menlo', monospace;
font-weight: 800;
letter-spacing: -0.04em;
fill: #7dcfff;
}
</style>
</defs>
<!-- Rounded square background (macOS convention ~22% corner radius) -->
<rect x="0" y="0" width="1024" height="1024" rx="224" ry="224" fill="url(#bgGrad)"/>
<!-- Inner stroke for depth -->
<rect x="4" y="4" width="1016" height="1016" rx="220" ry="220"
fill="none" stroke="url(#strokeGrad)" stroke-width="2"/>
<!-- Giant "2" with glow, perfectly centered -->
<g filter="url(#cyanGlow)">
<text class="wordmark" x="512" y="720" font-size="760" text-anchor="middle">
2
</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

+78
View File
@@ -0,0 +1,78 @@
app-id: com.opengsd.pi
runtime: org.gnome.Platform
runtime-version: '48'
sdk: org.gnome.Sdk
command: pi
finish-args:
- --share=ipc
- --socket=fallback-x11
- --socket=wayland
- --socket=pulseaudio
- --device=dri
- --filesystem=xdg-run/keyring
- --share=network
- --env=WEBKIT_DISABLE_DMABUF_RENDERER=1
build-options:
env:
CARGO_HOME: /run/build/pi/cargo
modules:
# Node.js runtime
- name: nodejs
buildsystem: simple
build-commands:
- mkdir -p /app/share/nodejs
- mv * /app/share/nodejs/
- mkdir -p /app/bin
- ln -s /app/share/nodejs/bin/node /app/bin/node
- ln -s /app/share/nodejs/bin/npm /app/bin/npm
- ln -s /app/share/nodejs/bin/npx /app/bin/npx
sources:
- type: archive
url: https://nodejs.org/dist/v22.16.0/node-v22.16.0-linux-x64.tar.xz
sha256: f4cb75bb036f0d0eddf6b79d9596df1aaab9ddccd6a20bf489be5abe9467e84e
# Build frontend + Tauri binary
- name: pi
buildsystem: simple
build-options:
append-path: /app/share/nodejs/bin:/usr/lib/sdk/rust-stable/bin
build-commands:
# Build frontend
- npm run build
# Set up vendored cargo deps
- mkdir -p src-tauri/.cargo
- cp cargo-config.toml src-tauri/.cargo/config.toml
# Build with tauri (embeds frontend assets into binary)
- CARGO_NET_OFFLINE=true npx tauri build --no-bundle
# Install binary
- mkdir -p ${FLATPAK_DEST}/bin
- cp src-tauri/target/release/gsd-pi-config ${FLATPAK_DEST}/bin/pi
# Install desktop entry, icon, and metadata (from local sources)
- mkdir -p ${FLATPAK_DEST}/share/applications
- cp com.opengsd.pi.desktop ${FLATPAK_DEST}/share/applications/
- mkdir -p ${FLATPAK_DEST}/share/icons/hicolor/scalable/apps
- cp com.opengsd.pi.svg ${FLATPAK_DEST}/share/icons/hicolor/scalable/apps/
- mkdir -p ${FLATPAK_DEST}/share/metainfo
- cp com.opengsd.pi.metainfo.xml ${FLATPAK_DEST}/share/metainfo/
sources:
# App source from git
- type: git
url: https://github.com/open-gsd/gsd-pi-config.git
commit: b40e19f
# Vendored cargo crates
- type: dir
path: cargo-vendor
dest: src-tauri/vendor
# Cargo config for vendored deps
- type: file
path: cargo-config.toml
# Flatpak metadata (local)
- type: file
path: com.opengsd.pi.desktop
- type: file
path: com.opengsd.pi.svg
- type: file
path: com.opengsd.pi.metainfo.xml
+12
View File
@@ -0,0 +1,12 @@
#!/bin/bash
# Create a release bundle for Flathub submission
set -e
cd "$(dirname "$0")"
flatpak-builder --repo=repo --force-clean build-dir com.opengsd.pi.yaml
flatpak build-bundle repo com.opengsd.pi.flatpak com.opengsd.pi
echo "Bundle created: com.opengsd.pi.flatpak"
echo "Upload to Flathub or host on your own repo."
-59
View File
@@ -1,59 +0,0 @@
{
"version": 1,
"skills": {
"code-review-excellence": {
"source": "wshobson/agents",
"sourceType": "github",
"skillPath": "plugins/developer-essentials/skills/code-review-excellence/SKILL.md",
"computedHash": "0f585a4ad2f6d8353069ca9051c6f0e8865abb9d3a6a268d423784c3c3852962"
},
"docx": {
"source": "anthropics/skills",
"sourceType": "github",
"skillPath": "skills/docx/SKILL.md",
"computedHash": "6962db07127ee540a56e4677f65576d0727668a1d67f7da8bc978f10791c2bfe"
},
"error-handling-patterns": {
"source": "wshobson/agents",
"sourceType": "github",
"skillPath": "plugins/developer-essentials/skills/error-handling-patterns/SKILL.md",
"computedHash": "73f0570edd3ddc740ba5411932a67954df375530bbffbe7fa0cecd8e59b0711e"
},
"find-skills": {
"source": "vercel-labs/skills",
"sourceType": "github",
"skillPath": "skills/find-skills/SKILL.md",
"computedHash": "9e1c8b3103f92fa8092568a44fe64858de7c5c9dc65ce4bea8f168080e889cfd"
},
"git-advanced-workflows": {
"source": "wshobson/agents",
"sourceType": "github",
"skillPath": "plugins/developer-essentials/skills/git-advanced-workflows/SKILL.md",
"computedHash": "f4d0569096237c09b1c07896770fe487d7224c549f7aab0c6551a4f330fcf160"
},
"pdf": {
"source": "anthropics/skills",
"sourceType": "github",
"skillPath": "skills/pdf/SKILL.md",
"computedHash": "cfbc539377088ca7e44a813b30c306327385bbd973cd7a721e1743f60837dd62"
},
"pptx": {
"source": "anthropics/skills",
"sourceType": "github",
"skillPath": "skills/pptx/SKILL.md",
"computedHash": "6b8b859d26f93aa059c9870d1ab76b44ab69e3d6757ce4a03cc94cb760888073"
},
"skill-creator": {
"source": "anthropics/skills",
"sourceType": "github",
"skillPath": "skills/skill-creator/SKILL.md",
"computedHash": "5ea13a6d9f0d4bb694405d79acd00cadec0d21bb138c4dd10fcf3c500cb835c2"
},
"xlsx": {
"source": "anthropics/skills",
"sourceType": "github",
"skillPath": "skills/xlsx/SKILL.md",
"computedHash": "efd0c8011cf0677d8075cf93867ecec804f9a8754a777e1d2fdb46197e9c247f"
}
}
}