Browse Source

feat: add Flatpak packaging and private repo helpers

master
Matteo Benedetto 2 weeks ago
parent
commit
f5216b1733
  1. 3
      .gitignore
  2. 54
      README.md
  3. 4
      cellar-gtk.py
  4. 4
      flatpak/cellar-launcher.sh
  5. 11
      flatpak/net.enne2.Cellar.desktop
  6. 39
      flatpak/net.enne2.Cellar.metainfo.xml
  7. BIN
      flatpak/net.enne2.Cellar.png
  8. 27
      net.enne2.Cellar.yaml
  9. 45
      scripts/build-flatpak-repo.sh
  10. 38
      scripts/publish-flatpak-repo.sh

3
.gitignore vendored

@ -21,6 +21,9 @@ env/
*.egg-info/
dist/
build/
flatpak-build/
flatpak-repo/
*.flatpak
# Test caches
.pytest_cache/

54
README.md

@ -57,7 +57,7 @@ Not implemented yet:
- [docker-compose.yml](docker-compose.yml) — local deployment
- [requirements.txt](requirements.txt) — Python dependencies
- [client.py](client.py) — minimal CLI client
- [gtk_client.py](gtk_client.py) — GTK4 desktop client
- [cellar-gtk.py](cellar-gtk.py) — GTK4 desktop client
- [app/main.py](app/main.py) — API routes
- [app/models.py](app/models.py) — SQLAlchemy model
- [app/schemas.py](app/schemas.py) — API response schemas
@ -163,6 +163,56 @@ Interactive API docs are available at:
---
## Flatpak package
The repository now includes a Flatpak manifest for the GTK client:
- [net.enne2.Cellar.yaml](net.enne2.Cellar.yaml)
Flatpak packaging assets are stored in [flatpak/](flatpak/):
- desktop entry
- AppStream metadata
- launcher script
- icon generated from [cellar.jpg](cellar.jpg)
Typical local build flow:
1. install `flatpak-builder`
2. install the required runtimes:
- `org.gnome.Platform//47`
- `org.gnome.Sdk//47`
3. run:
`flatpak-builder --user --install --force-clean flatpak-build net.enne2.Cellar.yaml`
Then launch it with:
`flatpak run net.enne2.Cellar`
To export a private Flatpak repository and a single-file bundle, use:
`./scripts/build-flatpak-repo.sh`
This creates:
- `flatpak-repo/` — OSTree/Flatpak repository ready to publish
- `dist/net.enne2.Cellar.flatpak` — installable Flatpak bundle
### Publish on `brain.local`
If `brain.local` serves static files, copy the generated repository there, for example:
`./scripts/publish-flatpak-repo.sh brain.local /var/www/html/flatpak/cellar`
Then clients can add the remote and install the app with:
`flatpak remote-add --if-not-exists --user --no-gpg-verify brain-local http://brain.local/flatpak/cellar`
`flatpak install --user brain-local net.enne2.Cellar`
---
## Environment configuration
Current environment variables used by the API container:
@ -257,7 +307,7 @@ Use a custom Bottles directory:
Run:
`python gtk_client.py`
`python cellar-gtk.py`
The GUI lets you:

4
cellar-gtk.py

@ -42,6 +42,7 @@ gi.require_version("Adw", "1")
from gi.repository import Adw, Gdk, GLib, Gtk # type: ignore[import-not-found]
# ── Constants ───────────────────────────────────────────────────
APP_ID = "net.enne2.Cellar"
CONFIG_PATH = Path.home() / ".config" / "cellar" / "gtk_client.json"
APP_CSS = """\
@ -448,6 +449,7 @@ class CellarWindow(Adw.ApplicationWindow):
def __init__(self, app: Adw.Application):
super().__init__(application=app, title="Cellar")
self.set_icon_name(APP_ID)
self.config = load_config()
self.settings_window: SettingsWindow | None = None
self.rows: list[ArchiveRow] = []
@ -824,7 +826,7 @@ class CellarWindow(Adw.ApplicationWindow):
# ── Application ─────────────────────────────────────────────────
class CellarApplication(Adw.Application):
def __init__(self) -> None:
super().__init__(application_id="com.cellar.gtkclient")
super().__init__(application_id=APP_ID)
def do_activate(self) -> None:
_load_css()

4
flatpak/cellar-launcher.sh

@ -0,0 +1,4 @@
#!/bin/sh
set -eu
export PYTHONPATH="/app/share/cellar${PYTHONPATH:+:$PYTHONPATH}"
exec python3 /app/share/cellar/cellar-gtk.py "$@"

11
flatpak/net.enne2.Cellar.desktop

@ -0,0 +1,11 @@
[Desktop Entry]
Type=Application
Name=Cellar
Comment=Browse and restore Bottle archives from a Cellar server
Exec=cellar
Icon=net.enne2.Cellar
Terminal=false
Categories=Utility;Archiving;GTK;
Keywords=bottles;backup;archive;restore;wine;
StartupNotify=true
StartupWMClass=net.enne2.Cellar

39
flatpak/net.enne2.Cellar.metainfo.xml

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<component type="desktop-application">
<id>net.enne2.Cellar</id>
<name>Cellar</name>
<summary>Browse and restore Bottle archives from a self-hosted server</summary>
<metadata_license>CC0-1.0</metadata_license>
<project_license>LicenseRef-proprietary</project_license>
<developer id="net.enne2">
<name>Matteo Benedetto</name>
</developer>
<launchable type="desktop-id">net.enne2.Cellar.desktop</launchable>
<url type="homepage">https://git.enne2.net/enne2/cellar</url>
<url type="bugtracker">https://git.enne2.net/enne2/cellar/issues</url>
<provides>
<binary>cellar</binary>
</provides>
<description>
<p>Cellar is a small GTK application for browsing and restoring archives stored on a self-hosted Bottle archive server.</p>
<p>It can refresh the remote catalog, search archives locally, and reinstall archived Bottles environments with progress feedback.</p>
</description>
<categories>
<category>Utility</category>
<category>Archiving</category>
</categories>
<screenshots>
<screenshot type="default">
<caption>Cellar application artwork</caption>
<image type="source" width="1024" height="1024">https://git.enne2.net/enne2/cellar/raw/branch/master/cellar.jpg</image>
</screenshot>
</screenshots>
<branding>
<color type="primary" scheme_preference="light">#5b0f11</color>
<color type="primary" scheme_preference="dark">#d8b27d</color>
</branding>
<content_rating type="oars-1.1" />
<releases>
<release version="1.0.0" date="2026-03-08" />
</releases>
</component>

BIN
flatpak/net.enne2.Cellar.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 739 KiB

27
net.enne2.Cellar.yaml

@ -0,0 +1,27 @@
app-id: net.enne2.Cellar
branch: stable
runtime: org.gnome.Platform
runtime-version: '47'
sdk: org.gnome.Sdk
command: cellar
finish-args:
- --share=ipc
- --share=network
- --socket=wayland
- --socket=fallback-x11
- --device=dri
- --filesystem=home
modules:
- name: cellar
buildsystem: simple
build-commands:
- install -Dm755 flatpak/cellar-launcher.sh /app/bin/cellar
- install -Dm644 cellar-gtk.py /app/share/cellar/cellar-gtk.py
- install -Dm644 client.py /app/share/cellar/client.py
- install -Dm644 cellar.jpg /app/share/cellar/cellar.jpg
- install -Dm644 flatpak/net.enne2.Cellar.desktop /app/share/applications/net.enne2.Cellar.desktop
- install -Dm644 flatpak/net.enne2.Cellar.metainfo.xml /app/share/metainfo/net.enne2.Cellar.metainfo.xml
- install -Dm644 flatpak/net.enne2.Cellar.png /app/share/icons/hicolor/512x512/apps/net.enne2.Cellar.png
sources:
- type: dir
path: .

45
scripts/build-flatpak-repo.sh

@ -0,0 +1,45 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
APP_ID="net.enne2.Cellar"
BRANCH="stable"
MANIFEST="${ROOT_DIR}/net.enne2.Cellar.yaml"
BUILD_DIR="${ROOT_DIR}/flatpak-build"
REPO_DIR="${ROOT_DIR}/flatpak-repo"
BUNDLE_PATH="${ROOT_DIR}/dist/${APP_ID}.flatpak"
if ! command -v flatpak-builder >/dev/null 2>&1; then
echo "flatpak-builder not found. Install it first." >&2
exit 1
fi
if ! command -v flatpak >/dev/null 2>&1; then
echo "flatpak not found. Install it first." >&2
exit 1
fi
mkdir -p "${ROOT_DIR}/dist"
rm -rf "${BUILD_DIR}"
mkdir -p "${REPO_DIR}"
flatpak-builder \
--force-clean \
--repo="${REPO_DIR}" \
"${BUILD_DIR}" \
"${MANIFEST}"
flatpak build-bundle "${REPO_DIR}" "${BUNDLE_PATH}" "${APP_ID}" "${BRANCH}"
cat <<EOF
Flatpak repository ready:
${REPO_DIR}
Flatpak bundle ready:
${BUNDLE_PATH}
Example private remote setup:
flatpak remote-add --if-not-exists --user --no-gpg-verify brain-local http://brain.local/flatpak/cellar
flatpak install --user brain-local ${APP_ID}
EOF

38
scripts/publish-flatpak-repo.sh

@ -0,0 +1,38 @@
#!/usr/bin/env bash
set -euo pipefail
if [[ $# -lt 2 || $# -gt 3 ]]; then
echo "Usage: $0 <host> <remote-path> [public-url]" >&2
exit 1
fi
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
REPO_DIR="${ROOT_DIR}/flatpak-repo"
HOST="$1"
REMOTE_PATH="$2"
PUBLIC_URL="${3:-}"
if [[ ! -d "${REPO_DIR}" ]]; then
echo "Repository not found at ${REPO_DIR}. Run ./scripts/build-flatpak-repo.sh first." >&2
exit 1
fi
if ! command -v rsync >/dev/null 2>&1; then
echo "rsync not found. Install it first." >&2
exit 1
fi
rsync -av --delete "${REPO_DIR}/" "${HOST}:${REMOTE_PATH%/}/"
if [[ -n "${PUBLIC_URL}" ]]; then
cat <<EOF
Published to ${HOST}:${REMOTE_PATH}
Clients can add the remote with:
flatpak remote-add --if-not-exists --user --no-gpg-verify brain-local ${PUBLIC_URL}
EOF
else
echo
echo "Published to ${HOST}:${REMOTE_PATH}"
fi
Loading…
Cancel
Save