diff --git a/.gitignore b/.gitignore index f3e00148..9a0fdab8 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,4 @@ result corporate_erp/ .codex-scheduled/ debian-dist/ +flatpak-dist/ diff --git a/client-gui2 b/client-gui2 index 3f9ae042..643de2b0 160000 --- a/client-gui2 +++ b/client-gui2 @@ -1 +1 @@ -Subproject commit 3f9ae04294d66d8455bcc0eeca50a4321f129764 +Subproject commit 643de2b0b0c862e6916c53c5e9922bb629475171 diff --git a/packaging/flatpak/README.md b/packaging/flatpak/README.md new file mode 100644 index 00000000..2cc87270 --- /dev/null +++ b/packaging/flatpak/README.md @@ -0,0 +1,59 @@ +# Combined Linux Flatpak + +This packaging builds `server` with `full-embed` and `client-gui2` inside the +GNOME 50 Flatpak SDK, then exports a single x86_64 Flatpak bundle. It is an +additive alternative to the AppImage packaging; the existing AppImage build is +unchanged. + +The build uses the official Flatpak Rust and Node SDK extensions. Cargo and +Yarn resolve the committed lockfiles inside the build sandbox with network +access. The PostgreSQL 17.10.0 archive, Typst 0.13.1 binary and protoc 21.12 +binary are downloaded by `flatpak-builder` as checksum-pinned sources. + +## Build + +Install `flatpak` and `flatpak-builder` through the host package manager, then +run from the repository root: + +```sh +packaging/flatpak/build.sh +``` + +The script configures the per-user Flathub remote when necessary, installs the +GNOME SDK and SDK extensions through `flatpak-builder`, retains its reusable +cache below `${XDG_CACHE_HOME:-$HOME/.cache}/komp-ac-flatpak-builder`, and +creates: + +```text +flatpak-dist/KompAC-embedded-x86_64.flatpak +``` + +An alternative output directory and filename may be supplied: + +```sh +packaging/flatpak/build.sh /path/to/releases KompAC-0.8.50-x86_64.flatpak +``` + +## Install and run + +On the destination machine, install Flatpak through the system package manager +and configure Flathub if it is not already available. Then install and run: + +```sh +flatpak install ./KompAC-embedded-x86_64.flatpak +flatpak run com.kompac.client +``` + +The bundle records Flathub as the source of its GNOME runtime. The first +installation therefore downloads the runtime when it is not already installed. +For an offline destination, transfer the runtime through a Flatpak repository +or offline-update workflow as well as the application bundle. + +Application configuration and embedded database state live in Flatpak's +per-user persistent XDG directories. Typst is included for document rendering; +no host Typst installation or `.env` file is required. + +The manifest deliberately grants build-time network access for the locked +Cargo and Yarn dependency graphs. This keeps private bundle builds automatic. +A Flathub submission should replace that build permission with generated Cargo +and Yarn source manifests from `flatpak-builder-tools`. diff --git a/packaging/flatpak/build.sh b/packaging/flatpak/build.sh new file mode 100755 index 00000000..982e997b --- /dev/null +++ b/packaging/flatpak/build.sh @@ -0,0 +1,77 @@ +#!/bin/bash + +set -euo pipefail + +if [[ $# -gt 2 ]]; then + echo "Usage: $0 [OUTPUT_DIRECTORY] [OUTPUT_FILENAME]" >&2 + exit 2 +fi + +script_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +repo_root="$(cd -- "$script_dir/../.." && pwd)" +output_directory="${1:-$repo_root/flatpak-dist}" +output_name="${2:-KompAC-embedded-x86_64.flatpak}" + +if [[ "$output_name" == */* || "$output_name" != *.flatpak ]]; then + echo "OUTPUT_FILENAME must be a portable filename ending in .flatpak" >&2 + exit 2 +fi +if [[ "$(uname -m)" != x86_64 ]]; then + echo "The Flatpak production build currently supports x86_64 only" >&2 + exit 1 +fi +for command in flatpak flatpak-builder; do + if ! command -v "$command" >/dev/null 2>&1; then + echo "$command is required to build the Flatpak" >&2 + exit 1 + fi +done + +mkdir -p "$output_directory" +output_directory="$(cd -- "$output_directory" && pwd)" + +cache_home="${XDG_CACHE_HOME:-${HOME:?HOME is not set}/.cache}" +state_dir="$cache_home/komp-ac-flatpak-builder" +mkdir -p "$state_dir" + +work_dir="$(mktemp -d /tmp/komp-ac-flatpak-build.XXXXXX)" +cleanup() { + case "$work_dir" in + /tmp/komp-ac-flatpak-build.*) + rm -rf -- "$work_dir" + ;; + *) + echo "Refusing to remove unexpected Flatpak workspace: $work_dir" >&2 + ;; + esac +} +trap cleanup EXIT INT TERM HUP + +flathub_repository=https://dl.flathub.org/repo/flathub.flatpakrepo +flatpak remote-add --user --if-not-exists flathub "$flathub_repository" + +echo "Building Komp AC against the GNOME 50 Flatpak runtime" +echo " output: $output_directory/$output_name" +echo " cache: $state_dir" +echo + +cd "$script_dir" +flatpak-builder \ + --user \ + --install-deps-from=flathub \ + --force-clean \ + --state-dir="$state_dir" \ + --repo="$work_dir/repository" \ + "$work_dir/build" \ + com.kompac.client.yml + +flatpak build-bundle \ + --runtime-repo="$flathub_repository" \ + "$work_dir/repository" \ + "$work_dir/$output_name" \ + com.kompac.client \ + stable + +cp -- "$work_dir/$output_name" "$output_directory/$output_name" + +echo "Created $output_directory/$output_name" diff --git a/packaging/flatpak/com.kompac.client.desktop b/packaging/flatpak/com.kompac.client.desktop new file mode 100644 index 00000000..0f5642fc --- /dev/null +++ b/packaging/flatpak/com.kompac.client.desktop @@ -0,0 +1,8 @@ +[Desktop Entry] +Type=Application +Name=Komp AC +Comment=Accounting application +Exec=komp-ac +Icon=com.kompac.client +Terminal=false +Categories=Office;Finance; diff --git a/packaging/flatpak/com.kompac.client.metainfo.xml b/packaging/flatpak/com.kompac.client.metainfo.xml new file mode 100644 index 00000000..29b4770e --- /dev/null +++ b/packaging/flatpak/com.kompac.client.metainfo.xml @@ -0,0 +1,20 @@ + + + com.kompac.client + Komp AC + Accounting application + CC0-1.0 + GPL-3.0-or-later AND AGPL-3.0-or-later + + Filip Priečinský + + https://gitlab.com/filipriec/komp_ac + +

Komp AC is an accounting application with an embedded PostgreSQL database.

+
+ com.kompac.client.desktop + + + + +
diff --git a/packaging/flatpak/com.kompac.client.yml b/packaging/flatpak/com.kompac.client.yml new file mode 100644 index 00000000..db78ada9 --- /dev/null +++ b/packaging/flatpak/com.kompac.client.yml @@ -0,0 +1,117 @@ +id: com.kompac.client +branch: stable +runtime: org.gnome.Platform +runtime-version: "50" +sdk: org.gnome.Sdk +command: komp-ac + +sdk-extensions: + - org.freedesktop.Sdk.Extension.node22 + - org.freedesktop.Sdk.Extension.rust-stable + +finish-args: + - --share=ipc + - --share=network + - --socket=wayland + - --socket=fallback-x11 + - --device=dri + - --env=GTK_USE_PORTAL=1 + - --talk-name=org.a11y.Bus + +build-options: + append-path: /usr/lib/sdk/node22/bin:/usr/lib/sdk/rust-stable/bin + +modules: + - name: komp-ac + buildsystem: simple + build-options: + strip: true + no-debuginfo: true + build-args: + - --share=network + env: + HOME: /run/build/komp-ac + CARGO_HOME: /run/build/komp-ac/cargo-home + CARGO_TARGET_DIR: /run/build/komp-ac/target/server + COREPACK_HOME: /run/build/komp-ac/corepack + POSTGRESQL_VERSION: "=17.10.0" + PROTOC: /app/bin/protoc + PROTOC_INCLUDE: /app/include + RUSTFLAGS: "" + SQLX_OFFLINE: "true" + YARN_CACHE_FOLDER: /run/build/komp-ac/yarn-cache + sources: + - type: dir + path: ../.. + skip: + - .git + - .agents + - .codex + - .codex-scheduled + - .direnv + - .env + - .env.* + - .env_* + - .envrc + - .idea + - .vscode + - "*.log" + - target + - "*/target" + - node_modules + - "*/node_modules" + - client-gui2/dist + - client-gui2/dist-ssr + - client-gui2/coverage + - client-gui2/.vite + - debian-dist + - flatpak-dist + - result + - result-* + - tantivy_indexes + - "*/tantivy_indexes" + - dumps + - "*/dumps" + - .postgres-data + - "*/.postgres-data" + - benchmark-results + - "*/benchmark-results" + - testing + - run_bins + - corporate_erp + - type: archive + url: https://github.com/protocolbuffers/protobuf/releases/download/v21.12/protoc-21.12-linux-x86_64.zip + sha256: 3a4c1e5f2516c639d3079b1586e703fc7bcfa2136d58bda24d1d54f949c315e8 + dest: protoc-source + - type: file + url: https://github.com/theseus-rs/postgresql-binaries/releases/download/17.10.0/postgresql-17.10.0-x86_64-unknown-linux-gnu.tar.gz + sha256: 333937dac26a33d367810b0db20892bbca6cf244f670e26f54f3e0b57dcb50b6 + dest: postgresql-cache + dest-filename: postgresql-17.10.0-x86_64-unknown-linux-gnu.tar.gz + - type: archive + url: https://github.com/typst/typst/releases/download/v0.13.1/typst-x86_64-unknown-linux-musl.tar.xz + sha256: 7d214bfeffc2e585dc422d1a09d2b144969421281e8c7f5d784b65fc69b5673f + dest: typst-source + build-commands: + - install -Dm755 protoc-source/bin/protoc /app/bin/protoc + - install -d /app/include + - cp -a protoc-source/include/. /app/include/ + - mkdir -p "$HOME/.theseus/postgresql" + - cp postgresql-cache/postgresql-17.10.0-x86_64-unknown-linux-gnu.tar.gz "$HOME/.theseus/postgresql/" + - cargo build --locked --release --package server --features full-embed + - cd client-gui2 && corepack yarn install --frozen-lockfile --non-interactive + - cd client-gui2 && CARGO_TARGET_DIR=/run/build/komp-ac/target/gui corepack yarn tauri build --no-bundle + - install -Dm755 /run/build/komp-ac/target/server/release/server /app/bin/komp-ac-server + - install -Dm755 /run/build/komp-ac/target/gui/release/client-gui2 /app/bin/client-gui2 + - install -Dm755 packaging/flatpak/launcher.sh /app/bin/komp-ac + - install -Dm755 typst-source/typst-x86_64-unknown-linux-musl/typst /app/bin/typst + - install -d /app/lib/komp_ac/themes + - cp -a client/runtime/themes/. /app/lib/komp_ac/themes/ + - install -Dm644 packaging/flatpak/com.kompac.client.desktop /app/share/applications/com.kompac.client.desktop + - install -Dm644 packaging/flatpak/com.kompac.client.metainfo.xml /app/share/metainfo/com.kompac.client.metainfo.xml + - install -Dm644 client-gui2/src-tauri/icons/32x32.png /app/share/icons/hicolor/32x32/apps/com.kompac.client.png + - install -Dm644 client-gui2/src-tauri/icons/128x128.png /app/share/icons/hicolor/128x128/apps/com.kompac.client.png + - install -Dm644 client-gui2/src-tauri/icons/128x128@2x.png /app/share/icons/hicolor/256x256/apps/com.kompac.client.png + cleanup: + - /bin/protoc + - /include diff --git a/packaging/flatpak/launcher.sh b/packaging/flatpak/launcher.sh new file mode 100755 index 00000000..0fe2c418 --- /dev/null +++ b/packaging/flatpak/launcher.sh @@ -0,0 +1,105 @@ +#!/bin/bash + +set -u + +umask 077 + +data_home="${XDG_DATA_HOME:-${HOME:?HOME is not set}/.local/share}" +data_root="${KOMP_AC_DATA_DIR:-$data_home/komp_ac}" +postgres_root="$data_root/postgresql" +dump_root="$data_root/dumps" +tantivy_root="$data_root/tantivy_indexes" +secret_file="$data_root/jwt.secret" +log_file="$data_root/server.log" +lock_dir="$data_root/flatpak.lock" +server=/app/bin/komp-ac-server +gui=/app/bin/client-gui2 + +mkdir -p "$data_root" "$postgres_root" "$dump_root" "$tantivy_root" + +if [[ ! -s "$secret_file" ]]; then + secret_tmp="$secret_file.$$" + if ! od -An -N 48 -tx1 /dev/urandom | tr -d ' \n' > "$secret_tmp"; then + rm -f -- "$secret_tmp" + echo "Komp AC: could not generate the local server secret" >&2 + exit 1 + fi + chmod 600 "$secret_tmp" + if [[ -e "$secret_file" ]]; then + rm -f -- "$secret_tmp" + else + mv -- "$secret_tmp" "$secret_file" + fi +fi + +if ! mkdir "$lock_dir" 2>/dev/null; then + lock_pid="" + if [[ -r "$lock_dir/pid" ]]; then + read -r lock_pid < "$lock_dir/pid" || true + fi + if [[ "$lock_pid" =~ ^[0-9]+$ ]] && kill -0 "$lock_pid" 2>/dev/null; then + echo "Komp AC is already running (launcher PID $lock_pid)." >&2 + exit 1 + fi + rm -f -- "$lock_dir/pid" + if ! rmdir "$lock_dir" 2>/dev/null || ! mkdir "$lock_dir" 2>/dev/null; then + echo "Komp AC: could not acquire the application lock at $lock_dir" >&2 + exit 1 + fi +fi +printf '%s\n' "$$" > "$lock_dir/pid" + +server_pid="" +cleanup() { + status=$? + trap - EXIT INT TERM HUP + if [[ -n "$server_pid" ]] && kill -0 "$server_pid" 2>/dev/null; then + kill -TERM "$server_pid" 2>/dev/null || true + wait "$server_pid" 2>/dev/null || true + fi + rm -f -- "$lock_dir/pid" + rmdir "$lock_dir" 2>/dev/null || true + exit "$status" +} +trap cleanup EXIT +trap 'exit 130' INT +trap 'exit 143' TERM +trap 'exit 129' HUP + +export GRPC_ENDPOINT=http://127.0.0.1:50051 +export KOMP_AC_TYPST=/app/bin/typst + +if (exec 3<>/dev/tcp/127.0.0.1/50051) 2>/dev/null; then + echo "Komp AC: local port 50051 is already in use" >&2 + exit 1 +fi + +RUST_DB_MODE=embedded \ +KOMP_AC_POSTGRES_DIR="$postgres_root" \ +PG_DUMP_DIR="$dump_root" \ +TANTIVY_INDEX_DIR="$tantivy_root" \ +JWT_SECRET="$(<"$secret_file")" \ +GRPC_LISTEN_ADDRESS=127.0.0.1:50051 \ +"$server" server >> "$log_file" 2>&1 & +server_pid=$! + +ready=false +for ((attempt = 0; attempt < 600; attempt++)); do + if ! kill -0 "$server_pid" 2>/dev/null; then + wait "$server_pid" || true + echo "Komp AC: the bundled server failed to start; see $log_file" >&2 + exit 1 + fi + if (exec 3<>/dev/tcp/127.0.0.1/50051) 2>/dev/null; then + ready=true + break + fi + sleep 0.1 +done + +if [[ "$ready" != true ]]; then + echo "Komp AC: the bundled server did not become ready; see $log_file" >&2 + exit 1 +fi + +"$gui"