From 8d5c564e75ad2928e77ea66decc979366ca5ccd5 Mon Sep 17 00:00:00 2001 From: Christophe Besson Date: Mon, 31 Aug 2026 10:49:45 +0200 Subject: feat(packaging): 4-package .deb/.rpm build system under /opt Shared venv architecture: meshbay-common owns the Python venv with all pip deps pre-installed; hub and node add only their code into it. Client is a standalone Electron app. No pip runs at install time. - Add build scripts (packaging/build/) for common, hub, node, client - Add orchestrator build-packages.sh with deb/rpm auto-detection - Add .deb control/postinst for all 4 packages - Add .rpm specs for all 4 packages (replaces python3-meshbay-common) - Add Gnome .desktop launcher and icon resizing - Add firewalld services (meshbay-cast, meshbay-node) and UFW profiles - Update systemd units to use /opt/meshbay-common/venv/bin/ paths - TMDB token baked into node package at build time via QE/node.env - Fix package-lock.json sync for protobufjs override Co-Authored-By: Claude Opus 4.6 --- packaging/build/build-client.sh | 116 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100755 packaging/build/build-client.sh (limited to 'packaging/build/build-client.sh') diff --git a/packaging/build/build-client.sh b/packaging/build/build-client.sh new file mode 100755 index 0000000..fbdf51e --- /dev/null +++ b/packaging/build/build-client.sh @@ -0,0 +1,116 @@ +#!/usr/bin/env bash +# Build the meshbay-client package: Electron app + .desktop launcher. +# +# Usage: ./build-client.sh [staging-dir] [--arm64] +# +# Requires Node >= 22. If not in PATH, set NODEJS_DIR=/opt/nodejs or similar. +set -euo pipefail + +REPO="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +STAGING="${1:-/tmp/meshbay-build}" +ROOT="$STAGING/meshbay-client-root" +CLIENT="$REPO/packages/meshbay-client" + +ARCH_FLAG="" +ELECTRON_ARCH="x64" +DEB_ARCH="amd64" +for arg in "$@"; do + if [ "$arg" = "--arm64" ]; then + ARCH_FLAG="--arm64" + ELECTRON_ARCH="arm64" + DEB_ARCH="arm64" + fi +done + +# Node.js version check +if [ -n "${NODEJS_DIR:-}" ]; then + export PATH="$NODEJS_DIR/bin:$PATH" +fi +NODE_VER=$(node --version 2>/dev/null || echo "none") +echo "==> meshbay-client (Node $NODE_VER, arch=$ELECTRON_ARCH)" + +if ! node --version >/dev/null 2>&1; then + echo "!! Node.js not found. Set NODEJS_DIR or install Node >= 22." >&2 + exit 1 +fi + +NODE_MAJOR=$(node -e "process.stdout.write(String(process.versions.node.split('.')[0]))") +if [ "$NODE_MAJOR" -lt 22 ]; then + echo "!! Node $NODE_VER is too old — need >= 22 for Electron" >&2 + exit 1 +fi + +rm -rf "$ROOT" +mkdir -p "$ROOT" + +# --- Build the Electron app ----------------------------------------------- +cd "$CLIENT" + +echo " npm ci" +npm ci --ignore-scripts 2>&1 | tail -3 + +echo " approving + installing electron" +npm approve-scripts electron 2>/dev/null || true +node node_modules/electron/install.js 2>&1 | tail -1 + +echo " syncing UI from hub package" +npm run sync-ui 2>&1 | tail -1 + +echo " electron-builder --dir $ARCH_FLAG" +npx electron-builder --dir --linux $ARCH_FLAG 2>&1 | tail -5 + +# Determine the unpacked output directory +if [ "$ELECTRON_ARCH" = "arm64" ]; then + UNPACKED="$CLIENT/dist/linux-arm64-unpacked" +else + UNPACKED="$CLIENT/dist/linux-unpacked" +fi + +[ -d "$UNPACKED" ] || { echo "!! electron-builder output not found at $UNPACKED" >&2; exit 1; } + +# --- Assemble the package tree -------------------------------------------- +echo " assembling /opt/meshbay-client/" +mkdir -p "$ROOT/opt/meshbay-client" +cp -a "$UNPACKED"/* "$ROOT/opt/meshbay-client/" + +# Rename the electron binary +if [ -f "$ROOT/opt/meshbay-client/meshbay-client" ]; then + mv "$ROOT/opt/meshbay-client/meshbay-client" "$ROOT/opt/meshbay-client/meshbay" +elif [ -f "$ROOT/opt/meshbay-client/electron" ]; then + mv "$ROOT/opt/meshbay-client/electron" "$ROOT/opt/meshbay-client/meshbay" +fi + +# Symlink in PATH +mkdir -p "$ROOT/usr/bin" +ln -sf /opt/meshbay-client/meshbay "$ROOT/usr/bin/meshbay" + +# --- Desktop launcher ----------------------------------------------------- +mkdir -p "$ROOT/usr/share/applications" +cp "$REPO/packaging/desktop/meshbay.desktop" "$ROOT/usr/share/applications/" + +# --- Icons ---------------------------------------------------------------- +ICON_SRC="$CLIENT/build/icon.png" +if [ -f "$ICON_SRC" ]; then + for size in 128 256 512; do + ICON_DIR="$ROOT/usr/share/icons/hicolor/${size}x${size}/apps" + mkdir -p "$ICON_DIR" + if command -v convert >/dev/null 2>&1; then + convert "$ICON_SRC" -resize "${size}x${size}" "$ICON_DIR/meshbay.png" + elif command -v magick >/dev/null 2>&1; then + magick "$ICON_SRC" -resize "${size}x${size}" "$ICON_DIR/meshbay.png" + else + # Fallback: copy the original at all sizes (better than no icon) + cp "$ICON_SRC" "$ICON_DIR/meshbay.png" + fi + done + echo " icons installed" +else + echo " !! icon.png not found at $ICON_SRC — no icons" >&2 +fi + +# --- Firewall profile (Chromecast) ---------------------------------------- +mkdir -p "$ROOT/usr/lib/firewalld/services" +cp "$REPO/packaging/firewall/firewalld/meshbay-cast.xml" \ + "$ROOT/usr/lib/firewalld/services/" + +echo "==> meshbay-client staging ready at $ROOT ($DEB_ARCH)" -- cgit v1.2.3