diff --git a/.github/workflows/omnipackage.yml b/.github/workflows/omnipackage.yml new file mode 100644 index 000000000..a1b1b6443 --- /dev/null +++ b/.github/workflows/omnipackage.yml @@ -0,0 +1,52 @@ +name: Build Linux packages (omnipackage) + +on: + workflow_dispatch: + push: + branches: [main] + +jobs: + list-distros: + runs-on: ubuntu-24.04 + outputs: + distros: ${{ steps.get-distros.outputs.distros }} + steps: + - name: Install omnipackage + run: | + echo 'deb https://repositories.omnipackage.org/omnipackage-rs/stable/ubuntu_24.04 stable/' | sudo tee /etc/apt/sources.list.d/omnipackage_omnipackage.list + curl -fsSL https://repositories.omnipackage.org/omnipackage-rs/stable/ubuntu_24.04/stable/Release.key | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/omnipackage_omnipackage.gpg > /dev/null + sudo apt-get update + sudo apt-get install -y omnipackage + + - uses: actions/checkout@v6 + + - name: Get distro list + id: get-distros + run: echo "distros=$(omnipackage info --list-distros . --format json)" >> "$GITHUB_OUTPUT" + + release: + needs: [list-distros] + runs-on: ubuntu-24.04 + concurrency: + group: omnipackage-${{ matrix.distro }} + cancel-in-progress: false + strategy: + fail-fast: false + matrix: + distro: ${{ fromJson(needs.list-distros.outputs.distros) }} + steps: + - name: Install omnipackage + run: | + echo 'deb https://repositories.omnipackage.org/omnipackage-rs/stable/ubuntu_24.04 stable/' | sudo tee /etc/apt/sources.list.d/omnipackage_omnipackage.list + curl -fsSL https://repositories.omnipackage.org/omnipackage-rs/stable/ubuntu_24.04/stable/Release.key | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/omnipackage_omnipackage.gpg > /dev/null + sudo apt-get update + sudo apt-get install -y omnipackage + + - uses: actions/checkout@v6 + with: + submodules: recursive + + - run: echo "${{ secrets.OMNIPACKAGE_DOTENV }}" > .env + + - name: Release packages for ${{ matrix.distro }} + run: omnipackage release . --distros "${{ matrix.distro }}" --repository "R2 test repo" diff --git a/.omnipackage/config.yml b/.omnipackage/config.yml new file mode 100644 index 000000000..069e6b314 --- /dev/null +++ b/.omnipackage/config.yml @@ -0,0 +1,212 @@ +# omnipackage config: native DEB/RPM packages for Librum (Qt6/QML e-book reader). +# Docs: https://docs.omnipackage.org +# +# Build notes: +# - Heavy dep mupdf (libs/mupdf) builds via scripts/mupdfwrap.py with a Python venv that +# pip-installs libclang/swig — the build container needs network (omnipackage has it). +# - Internal libs install to a hardcoded `lib`; the spec relocates them to %{_libdir} on lib64. +# - Matrix is limited to distros shipping Qt >= 6.5. +# +# To publish later: generate a signing key (omnipackage gpg generate ... --format base64), +# set GPG_KEY, and add a `repositories:` block (see the init scaffold / mpz config). + +# Real version lives in app_info.json (project(Librum VERSION 0.1) in CMakeLists is stale). +version_extractors: + - name: stable + provider: "file" + file: + file: "app_info.json" + regex: '"currentVersion":\s*"([0-9.]+)"' + - name: git + provider: "shell" + shell: + command: printf '0.99~next.%s.%s' $(git log -1 --format='%cd %h' --date=format:'%Y%m%d%H%M%S') + +common: &common + package_name: "librum" + maintainer: "Oleg Antonyan " + homepage: "https://librumreader.com" + description: "Modern e-book reader and library manager (Qt6/QML)" + +repositories: + - name: R2 test repo + provider: s3 + gpg_private_key_base64: "${GPG_PRIVATE_KEY_BASE64}" + <<: *common + s3: + bucket: repositories-test + path_in_bucket: "librum" + bucket_public_url: "https://repositories-test.omnipackage.org" + endpoint: "${CLOUDFLARE_R2_ENDPOINT}" + access_key_id: "${CLOUDFLARE_R2_ACCESS_KEY_ID}" + secret_access_key: "${CLOUDFLARE_R2_SECRET_ACCESS_KEY}" + region: auto + force_path_style: true + cloudflare_zone_id: "${CLOUDFLARE_ZONE_ID}" + cloudflare_api_token: "${CLOUDFLARE_API_TOKEN}" + + - name: Local test + gpg_private_key_base64: "${GPG_PRIVATE_KEY_BASE64}" + provider: localfs + <<: *common + localfs: + path: "${HOME}/librum-repositories" + + +# Files/dirs skipped when staging the source tree (gitignore-style; applies to rpm and deb). +ignore_source_files: + - .git + - .env + - .DS_Store + - "*.log" + - /build + - /libs/mupdf/build # stale host artifacts; the container rebuilds mupdf in-tree + - "venv-mupdfwrap-*" + +# Fedora / RHEL family naming. +fedora_rpm: &fedora_rpm + <<: *common + build_dependencies: + - gcc-c++ + - cmake + - make + - git + - unzip # mupdf docx_template_build.py shells out to unzip + - qt6-qtbase-devel + - qt6-qtdeclarative-devel + - qt6-qttools-devel + - libjpeg-turbo-devel + - mesa-libGL-devel + - python3 + - python3-pip + - pkgconf-pkg-config + runtime_dependencies: + - qt6-qtsvg # dlopened SVG imageformat plugin (app icons are SVG) + rpm: + spec_template: ".omnipackage/specfile.spec.liquid" + +# openSUSE (package names differ from Fedora). +opensuse_rpm: &opensuse_rpm + <<: *common + build_dependencies: + - gcc-c++ + - cmake + - make + - git + - unzip # mupdf docx_template_build.py shells out to unzip + - qt6-base-devel + - qt6-declarative-devel + - qt6-linguist-devel + - qt6-tools-devel + - libjpeg8-devel + - Mesa-libGL-devel + - python3 + - python3-pip + - pkg-config + runtime_dependencies: + - qt6-declarative-imports # QML import trees are a separate pkg, NOT auto-pulled here + - libQt6Svg6 # bundles the SVG imageformat plugin on openSUSE + rpm: + spec_template: ".omnipackage/specfile.spec.liquid" + +# Enterprise Linux 10 (Alma/Rocky): Qt6 lives in CRB(+EPEL), enabled after the base image, +# so it can't go in build_dependencies (installed before before_build_script). +el_rpm: &el_rpm + <<: *common + build_dependencies: + - gcc-c++ + - cmake + - make + - git + - unzip # mupdf docx_template_build.py shells out to unzip + before_build_script: >- + dnf install -y epel-release && + dnf install -y --nobest --enablerepo=crb + qt6-qtbase-devel qt6-qtdeclarative-devel qt6-qttools-devel + libjpeg-turbo-devel mesa-libGL-devel python3 python3-pip pkgconf-pkg-config + runtime_dependencies: + - qt6-qtsvg + rpm: + spec_template: ".omnipackage/specfile.spec.liquid" + +# Mageia (Mandriva naming) — DISABLED, not in `builds:` below. Two blockers: +# 1. cauldron repo metadata currently 404s on all mirrors (rolling-dev resync flakiness). +# 2. Mageia uses lib64-style names (qtbase6-common-devel, lib64qt6core-devel, lib64qt6quick-devel, +# lib64qt6qml-devel, lib64qt6tools-devel, ...) — the Fedora-style names below are placeholders. +# To re-enable: wait for the repo to recover, fix names via `omnipackage portal mageia_cauldron`, +# then add `- { distro: "mageia_cauldron", <<: *mageia_rpm }` to builds. +mageia_rpm: &mageia_rpm + <<: *common + build_dependencies: + - gcc-c++ + - cmake + - make + - git + - unzip + - qtbase6-common-devel + - lib64qt6core-devel + - lib64qt6gui-devel + - lib64qt6widgets-devel + - lib64qt6network-devel + - lib64qt6qml-devel + - lib64qt6quick-devel + - lib64qt6tools-devel + - lib64jpeg-devel + - python3 + - python3-pip + - pkgconf + runtime_dependencies: + - lib64qt6svg-devel + rpm: + spec_template: ".omnipackage/specfile.spec.liquid" + +# Debian / Ubuntu (Qt6). +deb: &deb + <<: *common + build_dependencies: + - build-essential + - cmake + - git + - unzip # mupdf docx_template_build.py shells out to unzip + - qt6-base-dev + - qt6-declarative-dev + - qt6-tools-dev + - qt6-l10n-tools + - libjpeg-dev + - libgl-dev + - python3 + - python3-venv + - python3-pip + - pkg-config + runtime_dependencies: + - qml6-module-qtquick + - qml6-module-qtquick-controls + - qml6-module-qtquick-dialogs + - qml6-module-qtquick-layouts + - qml6-module-qtquick-shapes + - qml6-module-qtcore + - qml6-module-qt-labs-platform + - qml6-module-qt-labs-qmlmodels + - qml6-module-qtqml-models + - qml6-module-qtqml-workerscript + - qt6-svg-plugins # ships the SVG imageformat plugin (libqsvg.so) + deb: + debian_templates: ".omnipackage/deb" + +# Only distros shipping Qt >= 6.5 (excludes Debian 12, Ubuntu 24.04, EL <=9, Leap 15.x, Fedora <=41). +builds: + - { distro: "fedora_42", <<: *fedora_rpm } + - { distro: "fedora_43", <<: *fedora_rpm } + - { distro: "fedora_44", <<: *fedora_rpm } + - { distro: "fedora_rawhide", <<: *fedora_rpm } + - { distro: "opensuse_tumbleweed", <<: *opensuse_rpm } + - { distro: "opensuse_16.0", <<: *opensuse_rpm } + - { distro: "almalinux_10", <<: *el_rpm } + - { distro: "rockylinux_10", <<: *el_rpm } + # mageia_cauldron disabled — see the mageia_rpm anchor note above (broken repo + unverified names) + - { distro: "debian_13", <<: *deb } + - { distro: "debian_testing", <<: *deb } + - { distro: "debian_unstable", <<: *deb } + - { distro: "ubuntu_25.04", <<: *deb } + - { distro: "ubuntu_25.10", <<: *deb } + - { distro: "ubuntu_26.04", <<: *deb } diff --git a/.omnipackage/deb/changelog.liquid b/.omnipackage/deb/changelog.liquid new file mode 100644 index 000000000..08c2891e5 --- /dev/null +++ b/.omnipackage/deb/changelog.liquid @@ -0,0 +1,5 @@ +{{ package_name }} ({{ version }}-0) stable; urgency=low + + * Release {{ version }} + + -- {{ maintainer }} {{ current_time_rfc2822 }} diff --git a/.omnipackage/deb/compat.liquid b/.omnipackage/deb/compat.liquid new file mode 100644 index 000000000..b1bd38b62 --- /dev/null +++ b/.omnipackage/deb/compat.liquid @@ -0,0 +1 @@ +13 diff --git a/.omnipackage/deb/control.liquid b/.omnipackage/deb/control.liquid new file mode 100644 index 000000000..a154b7e7e --- /dev/null +++ b/.omnipackage/deb/control.liquid @@ -0,0 +1,15 @@ +Source: {{ package_name }} +Section: text +Priority: optional +Maintainer: {{ maintainer }} +Build-Depends: debhelper (>= 13), {{ build_dependencies | join: ', ' }} +Standards-Version: 4.6.2 +Homepage: {{ homepage }} + +Package: {{ package_name }} +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends}, {{ runtime_dependencies | join: ', ' }} +Description: {{ description }} + Librum is a modern e-book reader and personal library manager. + It supports common formats (pdf, epub and more), themes, and a built-in + online library synced across devices. diff --git a/.omnipackage/deb/rules.liquid b/.omnipackage/deb/rules.liquid new file mode 100644 index 000000000..92ba3e943 --- /dev/null +++ b/.omnipackage/deb/rules.liquid @@ -0,0 +1,30 @@ +#!/usr/bin/make -f +# debian.rules — CMake build rules for Librum. Indents are TABS, not spaces! +# -*- makefile -*- + +export DESTROOT=$(CURDIR)/debian/{{ package_name }} +# export DH_VERBOSE=1 + +%: + dh $@ --parallel --buildsystem=cmake + +override_dh_auto_configure: + # Packaging-only QML fix (see .omnipackage/patch-qml.sh) — required for Qt 6.11+. + sh .omnipackage/patch-qml.sh + dh_auto_configure -- \ + -DCMAKE_BUILD_TYPE=Release \ + -DBUILD_TESTS=OFF + +# Tests are off; nothing to run. +override_dh_auto_test: + +override_dh_auto_install: + dh_auto_install + install -Dm644 com.librumreader.librum.metainfo.xml \ + $(DESTROOT)/usr/share/metainfo/com.librumreader.librum.metainfo.xml + rm -rf $(DESTROOT)/usr/include $(DESTROOT)/usr/lib/cmake + +# The internal libs and bundled libmupdfcpp.so have no shlibs entries (unversioned/private); +# resolve them within the package tree and tolerate the missing dependency info. +override_dh_shlibdeps: + dh_shlibdeps -l$(DESTROOT)/usr/lib -- --ignore-missing-info diff --git a/.omnipackage/patch-qml.sh b/.omnipackage/patch-qml.sh new file mode 100644 index 000000000..c715bae69 --- /dev/null +++ b/.omnipackage/patch-qml.sh @@ -0,0 +1,20 @@ +#!/bin/sh +# Build-time, packaging-only QML fix — runs against the STAGED source inside the build +# container, never the committed repo. Invoked from specfile.spec.liquid (%prep) and +# deb/rules.liquid (before configure). +# +# Why: several QML files use IconImage, a type from the *private* QtQuick.Controls.impl +# module, while importing only QtQuick.Controls. Qt < 6.11 leaked that type into the public +# namespace so it resolved; Qt 6.11+ does not -> runtime "IconImage is not a type" and a +# broken UI (first seen on openSUSE Tumbleweed). Injecting the missing import is safe on all +# Qt 6 (the impl module has existed since Qt 6.0; verified working on Qt 6.8 too). +# +# Idempotent: only patches files that use IconImage and lack the impl import. +set -eu + +for f in $(grep -rlE '\bIconImage\b' src --include='*.qml' 2>/dev/null || true); do + if ! grep -q 'QtQuick\.Controls\.impl' "$f"; then + sed -i '/^import QtQuick\.Controls$/a import QtQuick.Controls.impl' "$f" + echo "patch-qml: added QtQuick.Controls.impl import to $f" + fi +done diff --git a/.omnipackage/specfile.spec.liquid b/.omnipackage/specfile.spec.liquid new file mode 100644 index 000000000..8bf1ebf76 --- /dev/null +++ b/.omnipackage/specfile.spec.liquid @@ -0,0 +1,71 @@ +%define debug_package %{nil} +%define _build_id_links none + +Name: {{ package_name }} +Version: {{ version }} +Release: 1%{?dist} +Summary: {{ description }} +License: GPL-3.0-only +URL: {{ homepage }} +Source0: {{ source_folder_name }}.tar.gz +Vendor: OmniPackage + +BuildRequires: {{ build_dependencies | join: ' ' }} +{% for dep in runtime_dependencies %}Requires: {{ dep }} +{% endfor %} + +%description +{{ description }} + + +%prep +%setup -q -n {{ source_folder_name }} +# Packaging-only QML fix (see .omnipackage/patch-qml.sh) — required for Qt 6.11+. +sh .omnipackage/patch-qml.sh + + +%build +# mupdf is built from libs/mupdf via scripts/mupdfwrap.py during the CMake build; its Python +# venv pip-installs libclang/swig over the network (available in the build container). +cmake -S . -B _build \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX=/usr \ + -DBUILD_TESTS=OFF +cmake --build _build %{?_smp_mflags} + + +%install +DESTDIR=%{buildroot} cmake --install _build +# Upstream hardcodes DESTINATION lib; relocate to %{_libdir} so the loader finds the private +# libs on lib64 distros (no rpath needed — all DT_NEEDED entries are basenames). +if [ "%{_libdir}" != "/usr/lib" ] && [ -d %{buildroot}/usr/lib ]; then + mkdir -p %{buildroot}%{_libdir} + mv %{buildroot}/usr/lib/* %{buildroot}%{_libdir}/ + rmdir %{buildroot}/usr/lib || : +fi +# AppStream metainfo (upstream CMake does not install it). +install -Dm644 com.librumreader.librum.metainfo.xml \ + %{buildroot}%{_datadir}/metainfo/com.librumreader.librum.metainfo.xml +# Defensive: rapidfuzz installs nothing today, but guard against upstream churn. +rm -rf %{buildroot}/usr/include %{buildroot}%{_libdir}/cmake + + +%files +%license LICENSE.md +%{_bindir}/librum +%{_libdir}/libdomain.so +%{_libdir}/libapplication.so +%{_libdir}/libinfrastructure.so +%{_libdir}/libadapters.so +%{_libdir}/libpresentation.so +%{_libdir}/libmupdf.so +%{_libdir}/libmupdfcpp.so +%{_libdir}/mutool +%{_datadir}/applications/librum.desktop +%{_datadir}/pixmaps/librum.svg +%{_datadir}/metainfo/com.librumreader.librum.metainfo.xml + + +%changelog +* Mon Jun 08 2026 {{ maintainer }} - {{ version }} +- Automated build