diff --git a/Dockerfile.rpmbuild b/Dockerfile.rpmbuild new file mode 100644 index 0000000..01201c1 --- /dev/null +++ b/Dockerfile.rpmbuild @@ -0,0 +1,108 @@ +# syntax=docker/dockerfile:1 +FROM fedora:42 + +# rpmbuild in a container does not auto-install BuildRequires. Since we're +# building directly in Docker (not mock), we pre-install the common deps that +# Fedora's pyproject macros will require for Bouquin. +# +# NOTE: bouquin also needs python3dist(sqlcipher4) at build time (because +# %pyproject_buildrequires includes runtime deps). That one is NOT in Fedora; +# we install it from /deps. +RUN set -eux; \ + dnf -y update; \ + dnf -y install \ + rpm-build rpmdevtools \ + redhat-rpm-config \ + gcc \ + make \ + findutils \ + tar \ + gzip \ + rsync \ + python3 \ + python3-devel \ + python3-pip \ + python3-setuptools \ + python3-wheel \ + pyproject-rpm-macros \ + python3-rpm-macros \ + python3-poetry-core \ + desktop-file-utils \ + python3-requests \ + python3-markdown \ + python3-pyside6 \ + xcb-util-cursor ; \ + dnf -y clean all + +RUN set -eux; cat > /usr/local/bin/build-rpm <<'EOF' +#!/usr/bin/env bash +set -euo pipefail + +SRC="${SRC:-/src}" +WORKROOT="${WORKROOT:-/work}" +OUT="${OUT:-/out}" +DEPS_DIR="${DEPS_DIR:-/deps}" + +# Install bouquin-sqlcipher4 from local rpm +# Filter out .src.rpm and debug* subpackages if present. +if [ -d "${DEPS_DIR}" ] && compgen -G "${DEPS_DIR}/*.rpm" > /dev/null; then + mapfile -t rpms < <(ls -1 "${DEPS_DIR}"/*.rpm | grep -vE '(\.src\.rpm$|-(debuginfo|debugsource)-)') + if [ "${#rpms[@]}" -gt 0 ]; then + echo "Installing dependency RPMs from ${DEPS_DIR}:" + printf ' - %s\n' "${rpms[@]}" + dnf -y install "${rpms[@]}" + dnf -y clean all + else + echo "NOTE: Only src/debug RPMs found in ${DEPS_DIR}; nothing installed." >&2 + fi +else + echo "NOTE: No RPMs found in ${DEPS_DIR}. If the build fails with missing python3dist(sqlcipher4)," >&2 + echo " mount your bouquin-sqlcipher4 RPM directory as -v :/deps" >&2 +fi + +mkdir -p "${WORKROOT}" "${OUT}" +WORK="${WORKROOT}/src" +rm -rf "${WORK}" +mkdir -p "${WORK}" + +rsync -a --delete \ + --exclude '.git' \ + --exclude '.venv' \ + --exclude 'dist' \ + --exclude 'build' \ + --exclude '__pycache__' \ + --exclude '.pytest_cache' \ + --exclude '.mypy_cache' \ + "${SRC}/" "${WORK}/" + +cd "${WORK}" + +# Determine version from pyproject.toml unless provided +if [ -n "${VERSION:-}" ]; then + ver="${VERSION}" +else + ver="$(grep -m1 '^version = ' pyproject.toml | sed -E 's/version = "([^"]+)".*/\1/')" +fi + +TOPDIR="${WORKROOT}/rpmbuild" +mkdir -p "${TOPDIR}"/{BUILD,BUILDROOT,RPMS,SOURCES,SPECS,SRPMS} + +tarball="${TOPDIR}/SOURCES/bouquin-${ver}.tar.gz" +tar -czf "${tarball}" --transform "s#^#bouquin/#" . + +cp -v "rpm/bouquin.spec" "${TOPDIR}/SPECS/bouquin.spec" + +rpmbuild -ba "${TOPDIR}/SPECS/bouquin.spec" \ + --define "_topdir ${TOPDIR}" \ + --define "upstream_version ${ver}" + +shopt -s nullglob +cp -v "${TOPDIR}"/RPMS/*/*.rpm "${OUT}/" || true +cp -v "${TOPDIR}"/SRPMS/*.src.rpm "${OUT}/" || true +echo "Artifacts copied to ${OUT}" +EOF + +RUN chmod +x /usr/local/bin/build-rpm + +WORKDIR /work +ENTRYPOINT ["/usr/local/bin/build-rpm"] diff --git a/README.md b/README.md index 4a52ef4..7d4e55f 100644 --- a/README.md +++ b/README.md @@ -101,6 +101,25 @@ sudo apt update sudo apt install bouquin ``` +### Fedora 42 + +```bash +sudo rpm --import https://mig5.net/static/mig5.asc + +sudo tee /etc/yum.repos.d/mig5.repo > /dev/null << 'EOF' +[mig5] +name=mig5 Repository +baseurl=https://rpm.mig5.net/rpm/$basearch +enabled=1 +gpgcheck=1 +repo_gpgcheck=1 +gpgkey=https://mig5.net/static/mig5.asc +EOF + +sudo dnf upgrade --refresh +sudo dnf install bouquin +``` + ### From PyPi/pip * `pip install bouquin` diff --git a/poetry.lock b/poetry.lock index d2932af..c320489 100644 --- a/poetry.lock +++ b/poetry.lock @@ -640,4 +640,4 @@ zstd = ["backports-zstd (>=1.0.0)"] [metadata] lock-version = "2.0" python-versions = ">=3.10,<3.14" -content-hash = "0241cd7378c45e79da728a23b89defa18f776ada9af1e60f2a19b0d90f3a2c19" +content-hash = "0ce61476b8c35f864d395ab3a4ee4645a1ad2e16aa800cba5e77e5bfee23d6a6" diff --git a/pyproject.toml b/pyproject.toml index f4592bc..9adca9a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -13,8 +13,8 @@ include = ["bouquin/locales/*.json", "bouquin/keys/mig5.asc", "bouquin/fonts/Not python = ">=3.10,<3.14" pyside6 = ">=6.8.1,<7.0.0" bouquin-sqlcipher4 = "^4.12.0" -requests = "^2.32.5" -markdown = "^3.10" +requests = "^2.32.3" +markdown = "^3.7" [tool.poetry.scripts] bouquin = "bouquin.__main__:main" diff --git a/release.sh b/release.sh index 2fab9ac..d358e80 100755 --- a/release.sh +++ b/release.sh @@ -69,4 +69,28 @@ for dist in ${DISTS[@]}; do reprepro -b /home/user/git/repo includedeb "${release}" "${debfile}" done +# RPM +sudo apt-get -y install createrepo-c rpm +docker build -f Dockerfile.rpmbuild -t bouquin-rpm:f42 --progress=plain . +docker run --rm -v "$PWD":/src -v "$PWD/dist/rpm":/out -v "$HOME/git/bouquin-sqlcipher4/dist/rpm":/deps:ro bouquin-rpm:f42 +REPO_ROOT="${HOME}/git/repo_rpm" +RPM_REPO="${REPO_ROOT}/rpm/x86_64" +BUILD_OUTPUT="${HOME}/git/bouquin/dist" +REMOTE="letessier.mig5.net:/opt/repo_rpm" +KEYID="00AE817C24A10C2540461A9C1D7CDE0234DB458D" + +echo "==> Updating RPM repo..." +mkdir -p "$RPM_REPO" +cp "${BUILD_OUTPUT}/rpm/"*.rpm "$RPM_REPO/" + +createrepo_c "$RPM_REPO" + +echo "==> Signing repomd.xml..." +qubes-gpg-client --local-user "$KEYID" --detach-sign --armor "$RPM_REPO/repodata/repomd.xml" > "$RPM_REPO/repodata/repomd.xml.asc" + +echo "==> Syncing repo to server..." +rsync -aHPvz --exclude=.git --delete "$REPO_ROOT/" "$REMOTE/" + +echo "Done!" + ssh wolverine.mig5.net "echo ${VERSION} | tee /opt/www/mig5.net/bouquin/version.txt" diff --git a/rpm/bouquin.spec b/rpm/bouquin.spec new file mode 100644 index 0000000..341d80d --- /dev/null +++ b/rpm/bouquin.spec @@ -0,0 +1,86 @@ +# bouquin Fedora 42 RPM spec using Fedora's pyproject RPM macros (Poetry backend). +# +# NOTE: Bouquin depends on "bouquin-sqlcipher4" project, but the RPM actually +# provides the Python distribution/module as "sqlcipher4". To keep Fedora's +# auto-generated python3dist() Requires correct, we rewrite the dependency key in +# pyproject.toml at build time. +%global upstream_version 0.8.0 + +Name: bouquin +Version: %{upstream_version} +Release: 1%{?dist}.bouquin1 +Summary: A simple, opinionated notebook application (Python/Qt/SQLCipher) + +License: GPL-3.0-or-later +URL: https://git.mig5.net/mig5/bouquin +Source0: %{name}-%{version}.tar.gz + +BuildArch: noarch + +BuildRequires: pyproject-rpm-macros +BuildRequires: python3-devel +BuildRequires: python3-poetry-core +BuildRequires: desktop-file-utils + +# Non-Python runtime dep (Fedora equivalent of Debian's libxcb-cursor0) +Requires: xcb-util-cursor + +# Make sure private repo dependency is pulled in by package name as well. +Requires: python3-sqlcipher4 >= 4.12.0 + +%description +Bouquin is a simple, opinionated notebook application written in Python and Qt, +storing data using SQLCipher. + +%prep +%autosetup -n bouquin + +# Patch dependency name so Fedora's python dependency generator targets the +# provider from bouquin-sqlcipher4 RPM (python3dist(sqlcipher4)). +%{python3} - <<'PY' +from pathlib import Path +import re + +p = Path("pyproject.toml") +txt = p.read_text(encoding="utf-8") + +pattern = re.compile(r'(?ms)(^\[tool\.poetry\.dependencies\]\n.*?)(^\[|\Z)') +m = pattern.search(txt) +if not m: + raise SystemExit("Could not locate [tool.poetry.dependencies] in pyproject.toml") + +deps_block = m.group(1) +deps_block2 = re.sub(r'(?m)^bouquin-sqlcipher4\s*=\s*(".*?")\s*$', r'sqlcipher4 = \1', deps_block) +if deps_block == deps_block2: + raise SystemExit("Did not find bouquin-sqlcipher4 dependency to rewrite") + +p.write_text(txt[:m.start(1)] + deps_block2 + txt[m.end(1):], encoding="utf-8") +PY + +desktop-file-validate debian/bouquin.desktop + +%generate_buildrequires +%pyproject_buildrequires + +%build +%pyproject_wheel + +%install +%pyproject_install +%pyproject_save_files bouquin + +# Desktop integration (mirrors debian/bouquin.install) +install -Dpm 0644 debian/bouquin.desktop %{buildroot}%{_datadir}/applications/bouquin.desktop +install -Dpm 0644 bouquin/icons/bouquin.svg %{buildroot}%{_datadir}/icons/hicolor/scalable/apps/bouquin.svg + +%files -f %{pyproject_files} +%license LICENSE +%doc README.md CHANGELOG.md +%{_bindir}/bouquin + +%{_datadir}/applications/bouquin.desktop +%{_datadir}/icons/hicolor/scalable/apps/bouquin.svg + +%changelog +* Wed Dec 24 2025 Miguel Jacq - %{version}-%{release} +- Initial RPM packaging for Fedora 42