diff --git a/.github/workflows/snap.yml b/.github/workflows/snap.yml new file mode 100644 index 000000000..bb8a16a8b --- /dev/null +++ b/.github/workflows/snap.yml @@ -0,0 +1,78 @@ +name: Build Snap package + +on: + push: + branches: [ master, main ] + tags: [ 'v*' ] + pull_request: + branches: [ master, main ] + workflow_dispatch: + +permissions: + contents: read + +jobs: + build-snap: + name: Build snap + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + submodules: recursive + + # snapcraft reads snap/snapcraft.yaml, builds against core26 in an LXD + # container and leaves klog__.snap in the workspace. + - name: Build snap + id: snapcraft + uses: snapcore/action-build@v1 + + - name: Check the package contents + run: | + sudo apt-get update + sudo apt-get install -y squashfs-tools + SNAP="${{ steps.snapcraft.outputs.snap }}" + echo "Built: $SNAP" + # Translations are silently skipped when LinguistTools is missing, + # which would ship an English-only KLog. + unsquashfs -l "$SNAP" | grep -q "usr/share/klog/translations/klog_.*\.qm" \ + || { echo "ERROR: no translations in the snap"; exit 1; } + # The map window needs the QtLocation QML module and the OSM plugin. + unsquashfs -l "$SNAP" | grep -q "qt6/qml/QtLocation" \ + || { echo "ERROR: QtLocation QML module missing"; exit 1; } + unsquashfs -l "$SNAP" | grep -q "qt6/plugins/geoservices" \ + || { echo "ERROR: geoservices plugins missing"; exit 1; } + # The logbook is a SQLite database. + unsquashfs -l "$SNAP" | grep -q "qt6/plugins/sqldrivers/libqsqlite" \ + || { echo "ERROR: Qt SQLite driver missing"; exit 1; } + + - name: Upload Artifacts + uses: actions/upload-artifact@v4 + with: + name: KLog-snap-package + path: ${{ steps.snapcraft.outputs.snap }} + + - name: Create Release + if: startsWith(github.ref, 'refs/tags/v') + uses: softprops/action-gh-release@v2 + with: + files: ${{ steps.snapcraft.outputs.snap }} + name: KLog ${{ github.ref_name }} + draft: false + prerelease: ${{ contains(github.ref_name, 'RC') || contains(github.ref_name, 'alpha') || contains(github.ref_name, 'beta') }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + # Publishing to the Snap Store needs the SNAPCRAFT_STORE_CREDENTIALS + # secret, created with: snapcraft export-login --snaps=klog \ + # --acls package_access,package_push,package_update,package_release - + # The step is skipped while the secret is not configured. + - name: Publish to the Snap Store + if: startsWith(github.ref, 'refs/tags/v') && env.SNAPCRAFT_STORE_CREDENTIALS != '' + uses: snapcore/action-publish@v1 + env: + SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAPCRAFT_STORE_CREDENTIALS }} + with: + snap: ${{ steps.snapcraft.outputs.snap }} + release: ${{ (contains(github.ref_name, 'RC') || contains(github.ref_name, 'alpha') || contains(github.ref_name, 'beta')) && 'beta' || 'stable' }} diff --git a/.gitignore b/.gitignore index e16b77028..505a12fca 100644 --- a/.gitignore +++ b/.gitignore @@ -339,3 +339,10 @@ tests/tst_qsodatacache/.qt/QtDeployTargets.cmake tests/tst_qsodatacache/resources.qrc.depends src/macOSDeploy-M.sh Testing/* + +# snapcraft build artefacts (snap/snapcraft.yaml itself is tracked) +/parts/ +/stage/ +/prime/ +.snapcraft/ +*.snap diff --git a/Changelog b/Changelog index 34a9806ae..f27c3a861 100644 --- a/Changelog +++ b/Changelog @@ -20,6 +20,7 @@ TBD - 2.6 - Bugfix: Fix BAND_RX export when RX band is empty (TNX YL3GBC) - Bugfix: Apply the same BAND_RX guard (skip empty, "0" and same-as-BAND values) to the Club Log real-time upload, which also fixes 2-character RX bands (6m/4m/2m) being dropped. - Maintenance: The ADIF file is now always produced by a single serializer (QSO::getADIF); removed the unused per-destination ADIF writers and moved the BAND/BAND_RX "0" check into Adif::getADIFField() so it is enforced in one single place. +- New feature: KLog can be packaged as a snap, so it can be installed on any GNU/Linux distribution with snapd regardless of the Qt version that distribution ships. The recipe is in snap/snapcraft.yaml, the build script in devscripts/snap-create-package.sh, and INSTALL-snap covers installing it, the interfaces that have to be connected for CAT control and printing, and where the logbook lives. A logbook already in ~/.klog is copied into the snap the first time it runs. July 2026 - 2.5.3 - Bugfix: BandRX was not synced with FreqRX if FreqRX was not defined and BandRX was same as BandTX. diff --git a/INSTALL-snap b/INSTALL-snap new file mode 100644 index 000000000..115719aad --- /dev/null +++ b/INSTALL-snap @@ -0,0 +1,284 @@ +Installing and building the KLog snap package +============================================= + +A snap is a self-contained package: it carries Qt6, Hamlib and everything +else KLog needs, so it installs on any GNU/Linux distribution with snapd +regardless of which Qt version that distribution ships. + +If you have any suggestion for this file, please contact me. (Contact +details in the AUTHORS file). + + +1. Installing +------------- + +From the Snap Store, once the package has been published: + + sudo snap install klog + +From a locally built or downloaded file: + + sudo snap install --dangerous klog_2.6-alpha_amd64.snap + +("--dangerous" is only needed because a local file is not signed by the +store; it says nothing about the package itself.) + +Then run it from your application menu, or from a terminal with: + + klog + + +2. Connecting the interfaces +---------------------------- + +A snap only gets the permissions it asks for. Most of the ones KLog uses +(the desktop session, the network, your home directory, removable media) +are connected automatically when you install it. Three are not, because +snapd never connects them without being asked: + + * CAT control over a USB adapter or a built-in USB radio interface: + + sudo snap connect klog:raw-usb + + * CAT control over a serial port. First find the slot for your radio: + + snap interface serial-port + + and then connect it, using the slot name from that listing: + + sudo snap connect klog:serial-port + + On most desktop distributions snapd creates one slot per USB-serial + adapter as you plug it in, so the slot only exists while the radio is + connected. + + * Printing the log: + + sudo snap connect klog:cups-control + +You can see the state of every interface at any time with: + + snap connections klog + + +3. Where the logbook lives +-------------------------- + +A strictly confined snap gets its own home directory, so KLog's data +directory is: + + ~/snap/klog/current/.klog + +not ~/.klog. The logbook, the settings and the downloaded cty.dat all live +there, and snapd includes it in "snap save" snapshots. + +The first time you run the snap, if you already have a ~/.klog from a .deb +or from a KLog you built yourself, it is copied into the snap's own +directory so your log is there waiting for you. The original ~/.klog is +never modified, and the copy only happens when the snap has no logbook of +its own yet. To start from an empty logbook instead: + + KLOG_SNAP_NO_MIGRATE=1 klog + +Note that the two copies are independent from that point on. If you keep +using both the .deb and the snap, they will drift apart. + + +4. Known limitations of the snap +-------------------------------- + + * Signing a LoTW upload calls the external TQSL program. A strictly + confined snap cannot run programs installed on the host, so the + "sign and upload to LoTW" button does not work from the snap. Export + the ADIF file and sign it with TQSL outside KLog, or use the .deb. + + * Serial ports only become visible after the serial-port interface has + been connected, so the port list in Setup -> Hamlib will be empty + until you do that. + + +5. Building the snap +-------------------- + +Install the tooling (LXD is the build backend snapcraft uses by default): + + sudo snap install snapcraft --classic + sudo snap install lxd + sudo lxd init --auto + sudo usermod -a -G lxd "$USER" + +Log out and back in so the group membership takes effect, then either run +the helper script: + + cd devscripts + bash snap-create-package.sh + +or call snapcraft directly from the top of the source tree: + + snapcraft pack + +Either way you end up with klog__.snap. The helper script +additionally checks that the translations made it into the package and +moves the result into devscripts/, next to the other packages. + +The recipe is snap/snapcraft.yaml and the run-time wrapper it installs is +snap/local/klog-launch. + +Note that the build host does not need any Qt6 or Hamlib development +package. snapcraft builds inside an LXD container running Ubuntu 26.04 and +installs the build dependencies in there, which is also why a Debian stable +machine can produce this package. + +5.1 Building it on Jenkins +--------------------------- + +devscripts/jenkins/Jenkinsfile.snap drives the build on the debian-stable +agent, in the same shape as the other platform jobs: power the VM on, build, +verify, upload to the NAS, power it off. Create the job as "klog-snap" with +Pipeline script from SCM and that file as the script path. + +It uses the same credentials as klog-debian-stable (esxi-ssh, esxi-host, +esxi-vmid-debian-stable, nas-host, nas-user, nas-password), so there is +nothing new to add to Jenkins. + +Set the agent up once, as root: + + apt install snapd squashfs-tools + ln -s /var/lib/snapd/snap /snap # Debian needs this for classic snaps + snap install snapcraft --classic + snap install lxd + lxd init --auto + usermod -aG lxd jenkins # the user the Jenkins agent runs as + +Then restart the Jenkins agent, otherwise it keeps the group list it started +with and snapcraft cannot reach LXD. Check it worked with: + + sudo -u jenkins lxc list + +The pipeline has a Preflight stage that tests exactly this and stops with +the missing command if anything is not in place, rather than failing later +in the middle of a build. + +Two things to expect on the first run: it is slow, because LXD has to fetch +the Ubuntu 26.04 image and snapcraft the core26 and mesa-2604 snaps, and the +VM needs enough disk for that (allow around 15 GB free). The Build stage has +a 90 minute timeout for this reason. + +klog-snap is deliberately not part of the klog-all orchestrator for now, so +run it on its own with Build Now. + +Should it be added there later, keep in mind that it shares the VM with +klog-debian-stable and the two must never run at the same time: each powers +the machine off when it finishes, so in parallel the first to end would pull +the VM out from under the other. Chain them inside the existing "Debian +stable" stage rather than adding a parallel branch, or give the snap build +an agent of its own. + + +6. Why the recipe uses base: core26 +----------------------------------- + +KLog links against Qt6 Location for the map window. Upstream Qt dropped +QtLocation for Qt 6.0 to 6.4 and only brought it back in 6.5, so it is +simply not in the Ubuntu 24.04 archive that core24 snaps are built from - +there is no qt6-location-dev or libqt6location6 package there at all. + +The KDE neon snapcraft extensions do provide a recent Qt, but they +explicitly do not ship QtCharts, which KLog needs for the statistics +widgets, so they would mean building Qt modules from source inside the +recipe. + +Ubuntu 26.04, which core26 is built from, carries the full Qt 6.10.2 set - +Charts, Location, Positioning, SerialPort, Quick - as well as Hamlib 4.6.5. +Every dependency therefore comes from the distribution archive: nothing is +built from source and no third-party apt repository is involved. + +The base is what KLog is built and run against, not what you have to be +running. snapd downloads the core26 base snap as a dependency, so the +package installs and runs the same on Ubuntu 22.04 or 24.04, on Debian, +Fedora, Arch or anywhere else snapd is available. That is the whole point +of picking the newest LTS base: KLog gets a current Qt everywhere, without +asking anyone to upgrade their distribution. core26 is also as far as this +can go - snap bases are only made from LTS releases, so there is no core +base for Ubuntu 26.10 or any other interim release. + +core26 does not have a GNOME or KDE desktop extension yet, so the work +those extensions normally do for a Qt application (Qt plugin and QML +search paths, fontconfig, the XDG data directories) is done by +snap/local/klog-launch. Hardware accelerated graphics for the QtQuick map +comes from the "gpu" extension. Once a desktop extension supports +core26, most of that wrapper can be dropped. + + +7. Publishing to the Snap Store +------------------------------- + +Building the snap needs no Snap Store account at all. Everything in this +section is only about publishing it. + +7.1 Logging in on a machine with no keyring +------------------------------------------- + +"snapcraft login" keeps its token in the system keyring, so on a build +server, in a container, or over SSH it fails with: + + No keyring found to store or retrieve credentials from. + +"snapcraft export-login" does not use the keyring. It asks for the same +email, password and second factor and writes the credentials out instead of +storing them, which is the supported way to authenticate on a headless +machine: + + snapcraft export-login ~/.klog-snap-credentials + export SNAPCRAFT_STORE_CREDENTIALS="$(cat ~/.klog-snap-credentials)" + snapcraft whoami + +Every snapcraft command run in that shell is then authenticated. The +credentials file is as good as a password: keep it at mode 600 and out of +the source tree. + +Do the first export without --snaps. Credentials can only be restricted to +a snap that already exists, so that flag cannot be used until the name has +been registered. + +If you would rather have a working keyring on that machine: + + sudo apt install gnome-keyring + dbus-run-session -- bash + gnome-keyring-daemon --unlock # type a password, then Ctrl-D + snapcraft login + +which only lasts for that D-Bus session. + +7.2 The registered name +------------------------ + +The name "klog" is already registered in the Snap Store to the KLog +account, and that is the name snap/snapcraft.yaml builds under, so there is +nothing to do here. It is kept for the record that a name is registered +once, by the account that will own it, with: + + snapcraft register + +or through https://snapcraft.io/account/register-snap, which needs no +working CLI login. + +7.3 Uploading +-------------- + + snapcraft upload --release=edge klog__.snap + +.github/workflows/snap.yml builds the snap on every push and uploads it as +a workflow artifact. On a v* tag it also attaches the .snap to the GitHub +release, and publishes it to the Snap Store if the repository has a +SNAPCRAFT_STORE_CREDENTIALS secret. Once the name is registered, create the +narrow credentials for that secret with: + + snapcraft export-login --snaps=klog \ + --acls package_access,package_push,package_update,package_release - + +The trailing "-" writes them to the terminal so they can be pasted into the +GitHub secret rather than left in a file. + + +73 diff --git a/INSTALL.txt b/INSTALL.txt index d0bfddb84..6d5d7b8af 100644 --- a/INSTALL.txt +++ b/INSTALL.txt @@ -4,6 +4,8 @@ Please read: INSTALL-linux.txt for linux installations. + INSTALL-snap for the snap package (any linux distribution with snapd). + INSTALL-macOS.txt for macOS installations. INSTALL-win.txt for Windows installations. diff --git a/README.md b/README.md index 3231ca812..eed22a2a0 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,19 @@ The Telegram chat group in Spanish: ## Install Read the INSTALL.txt for installation purposes. +On GNU/Linux KLog can also be built and installed as a snap package, which +bundles Qt6 and Hamlib and therefore runs on any distribution with snapd +regardless of the Qt version that distribution ships: + +``` +snapcraft pack +sudo snap install --dangerous klog_*.snap +``` + +Once the package is published in the Snap Store, `sudo snap install klog` will +be all that is needed. See [INSTALL-snap](INSTALL-snap) for the interfaces you +have to connect for CAT control and printing, and for where the logbook lives. + Please send all your suggestions & bug reports. I hope you enjoy KLog! diff --git a/devscripts/snap-create-package.sh b/devscripts/snap-create-package.sh new file mode 100755 index 000000000..982da38cc --- /dev/null +++ b/devscripts/snap-create-package.sh @@ -0,0 +1,145 @@ +#!/bin/bash +# Script to build the KLog snap package +# Can be run locally or called from Jenkins/GitHub Actions +# +# Usage: +# cd devscripts +# bash snap-create-package.sh +# +# Requirements: +# - snapd, snapcraft and a build backend (LXD is the default) +# sudo snap install snapcraft --classic +# sudo snap install lxd && sudo lxd init --auto +# sudo usermod -a -G lxd "$USER" # log out and back in afterwards +# - Must be run from the devscripts directory +# +# The recipe lives in snap/snapcraft.yaml and builds against core26 +# (Ubuntu 26.04), which is the first Ubuntu release carrying Qt6 Location. +# +#*************************************************************************** +# +# snap-create-package.sh +# ------------------- +# begin : aug 2026 +# copyright : (C) 2026 by Jaime Robles +# email : jaime@robles.es +# +#***************************************************************************** +# * This file is part of KLog. * +# * * +# * KLog is free software: you can redistribute it and/or modify * +# * it under the terms of the GNU General Public License as published by * +# * the Free Software Foundation, either version 3 of the License, or * +# * (at your option) any later version. * +# * * +# * KLog is distributed in the hope that it will be useful, * +# * but WITHOUT ANY WARRANTY; without even the implied warranty of * +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +# * GNU General Public License for more details. * +# * * +# * You should have received a copy of the GNU General Public License * +# * along with KLog. If not, see . * +# * * +#*****************************************************************************/ + +set -e + +DEVSCRIPTS_DIR="$(cd "$(dirname "$0")" && pwd)" +PROJECT_DIR="$(dirname "$DEVSCRIPTS_DIR")" + +# --- Read version from CMakeLists.txt (same source the recipe uses) --- +KLOG_VERSION=$(grep 'APP_PKGVERSION' "$PROJECT_DIR/CMakeLists.txt" | sed 's/.*"\(.*\)".*/\1/') +if [ -z "$KLOG_VERSION" ]; then + KLOG_VERSION=$(grep 'project(KLog VERSION' "$PROJECT_DIR/CMakeLists.txt" | awk '{print $3}') +fi + +echo "Building KLog $KLOG_VERSION snap package" + +# --- Check the toolchain is there --- +# Snap binaries live in /snap/bin, which is only added to PATH by a login +# shell. Jenkins and other CI runners use non-login shells. +case ":$PATH:" in + *:/snap/bin:*) ;; + *) PATH="/snap/bin:$PATH"; export PATH ;; +esac + +if ! command -v snapcraft >/dev/null 2>&1; then + echo "ERROR: snapcraft not found. Install it with:" + echo " sudo snap install snapcraft --classic" + echo " On Debian, classic snaps also need:" + echo " sudo ln -s /var/lib/snapd/snap /snap" + exit 1 +fi + +# KLog builds against core26, so snapcraft needs a container to build in: the +# host itself is only usable with --destructive-mode, and only if the host is +# Ubuntu 26.04. LXD is snapcraft's default backend for core22 and newer. +export SNAPCRAFT_BUILD_ENVIRONMENT="${SNAPCRAFT_BUILD_ENVIRONMENT:-lxd}" + +if [ "$SNAPCRAFT_BUILD_ENVIRONMENT" = "lxd" ]; then + if ! command -v lxc >/dev/null 2>&1; then + echo "ERROR: LXD not found. Install and initialise it with:" + echo " sudo snap install lxd" + echo " sudo lxd init --auto" + exit 1 + fi + if ! lxc list >/dev/null 2>&1; then + echo "ERROR: cannot talk to LXD as $(id -un). Add the user to the group:" + echo " sudo usermod -aG lxd $(id -un)" + echo " then log out and back in (or restart the CI agent) so the" + echo " new group takes effect." + exit 1 + fi +fi + +ARCH=$(dpkg --print-architecture 2>/dev/null || uname -m) +echo "Architecture: $ARCH" +echo "Build backend: $SNAPCRAFT_BUILD_ENVIRONMENT" + +# --- Clean previous build --- +echo "[1/3] Cleaning..." +rm -f "$DEVSCRIPTS_DIR"/klog_*.snap +# Nothing to clean on a fresh checkout, and that is not an error. +(cd "$PROJECT_DIR" && snapcraft clean) || true + +# --- Build --- +echo "[2/3] Building the snap (this pulls the core26 and mesa-2604 snaps the" +echo " first time and takes a while)..." +(cd "$PROJECT_DIR" && snapcraft pack) + +# --- Find whatever snapcraft generated and move it next to the other packages --- +echo "[3/3] Collecting the artifact..." +SNAP_FILE=$(find "$PROJECT_DIR" -maxdepth 1 -name "klog_*.snap" | head -1) +if [ -z "$SNAP_FILE" ]; then + echo "ERROR: snapcraft did not generate any .snap file" + exit 1 +fi + +# --- Check the translations made it into the package --- +# The .qm files are installed into usr/share/klog/translations, which is where +# KLog looks for them. If LinguistTools is missing they are silently skipped, +# and KLog would be shipped in English only. +if command -v unsquashfs >/dev/null 2>&1; then + if ! unsquashfs -l "$SNAP_FILE" | grep -q "usr/share/klog/translations/klog_.*\.qm"; then + echo "ERROR: $SNAP_FILE contains no KLog translation files" + echo " Check that Qt6 LinguistTools (lrelease) is available." + exit 1 + fi +else + echo "WARNING: unsquashfs not available, skipping the translations check" +fi + +mv "$SNAP_FILE" "$DEVSCRIPTS_DIR/" +FINAL_NAME=$(basename "$SNAP_FILE") + +echo "" +echo "Done! KLog $KLOG_VERSION -> devscripts/$FINAL_NAME" +echo "" +echo "Install it locally with:" +echo " sudo snap install --dangerous devscripts/$FINAL_NAME" +echo "" +echo "Then connect the interfaces that are not connected automatically:" +echo " sudo snap connect klog:raw-usb" +echo " sudo snap connect klog:cups-control" +echo " snap interface serial-port # find your radio's slot" +echo " sudo snap connect klog:serial-port " diff --git a/snap/local/klog-launch b/snap/local/klog-launch new file mode 100755 index 000000000..a47c3edeb --- /dev/null +++ b/snap/local/klog-launch @@ -0,0 +1,114 @@ +#!/bin/bash +#*************************************************************************** +# klog-launch +# ------------------- +# begin : aug 2026 +# copyright : (C) 2026 by Jaime Robles +# email : jaime@robles.es +# +#***************************************************************************** +# * This file is part of KLog. * +# * * +# * KLog is free software: you can redistribute it and/or modify * +# * it under the terms of the GNU General Public License as published by * +# * the Free Software Foundation, either version 3 of the License, or * +# * (at your option) any later version. * +# * * +# * KLog is distributed in the hope that it will be useful, * +# * but WITHOUT ANY WARRANTY; without even the implied warranty of * +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +# * GNU General Public License for more details. * +# * * +# * You should have received a copy of the GNU General Public License * +# * along with KLog. If not, see . * +# * * +#*****************************************************************************/ +# +# command-chain wrapper for the KLog snap. +# +# core26 has no GNOME/KDE snapcraft extension yet, so the environment those +# extensions would normally set up for a Qt application is set up here: plugin +# and QML search paths, the library path for the staged Qt, fontconfig and the +# XDG data directories. It also performs the one-time logbook migration +# described in INSTALL-snap. +# +# A command-chain entry must exec the next command in the chain, so this script +# always ends with `exec "$@"`. + +set -u + +# --------------------------------------------------------------------------- +# Multiarch directory of the staged libraries (x86_64-linux-gnu, +# aarch64-linux-gnu, ...). Derived at run time so the snap stays +# architecture independent. +# --------------------------------------------------------------------------- +arch_triplet="" +for dir in "$SNAP"/usr/lib/*-linux-gnu*; do + if [ -d "$dir/qt6" ]; then + arch_triplet="${dir##*/}" + break + fi +done + +if [ -z "$arch_triplet" ]; then + echo "klog: no Qt6 directory found under $SNAP/usr/lib - broken snap?" >&2 + exec "$@" +fi + +qt_libdir="$SNAP/usr/lib/$arch_triplet" + +# --------------------------------------------------------------------------- +# Qt runtime. The plugins (xcb/wayland platform, sqlite driver, OSM +# geoservices, image formats) and the QML modules used by the map window are +# dlopen()ed, so Qt has to be told where they are. +# --------------------------------------------------------------------------- +export QT_PLUGIN_PATH="$qt_libdir/qt6/plugins${QT_PLUGIN_PATH:+:$QT_PLUGIN_PATH}" +export QML_IMPORT_PATH="$qt_libdir/qt6/qml${QML_IMPORT_PATH:+:$QML_IMPORT_PATH}" +export QML2_IMPORT_PATH="$QML_IMPORT_PATH" + +# Prepended, never replaced: the gpu extension has already put the host's +# Mesa userspace drivers on the path and those must stay reachable. +export LD_LIBRARY_PATH="$qt_libdir:$SNAP/usr/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" + +# --------------------------------------------------------------------------- +# Desktop data: the .desktop entry, the icon and KLog's own .qm translations +# live under $SNAP/usr/share. +# --------------------------------------------------------------------------- +export XDG_DATA_DIRS="$SNAP/usr/share:${XDG_DATA_DIRS:-/usr/local/share:/usr/share}" + +# The desktop interface bind-mounts the host font directories into the snap; +# fontconfig itself is staged, and this is its configuration. +if [ -f "$SNAP/etc/fonts/fonts.conf" ]; then + export FONTCONFIG_PATH="$SNAP/etc/fonts" + export FONTCONFIG_FILE="$SNAP/etc/fonts/fonts.conf" +fi + +# --------------------------------------------------------------------------- +# One-time logbook migration. +# +# Under strict confinement HOME is $SNAP_USER_DATA (~/snap/klog/current), so +# KLog's QDir::homePath()+"/.klog" resolves inside the snap and a logbook made +# by the .deb or by a self-built KLog would appear to have vanished. Copy it +# across on the first run. The copy is only made when the snap has no logbook +# of its own yet, and the original is never touched. +# +# Set KLOG_SNAP_NO_MIGRATE=1 to start with an empty logbook instead. +# --------------------------------------------------------------------------- +if [ -z "${KLOG_SNAP_NO_MIGRATE:-}" ] && + [ -n "${SNAP_REAL_HOME:-}" ] && + [ -n "${HOME:-}" ] && + [ "$SNAP_REAL_HOME" != "$HOME" ] && + [ ! -e "$HOME/.klog" ] && + [ -d "$SNAP_REAL_HOME/.klog" ]; then + if cp -a "$SNAP_REAL_HOME/.klog" "$HOME/.klog.migrating" 2>/dev/null && + mv "$HOME/.klog.migrating" "$HOME/.klog" 2>/dev/null; then + echo "klog: copied the logbook from $SNAP_REAL_HOME/.klog to $HOME/.klog" >&2 + echo "klog: the original was left untouched; the snap uses its own copy from now on" >&2 + else + rm -rf "$HOME/.klog.migrating" + echo "klog: could not copy $SNAP_REAL_HOME/.klog, starting with an empty logbook" >&2 + echo "klog: is the home interface connected? (snap connect klog:home)" >&2 + fi +fi + +exec "$@" diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml new file mode 100644 index 000000000..89755775e --- /dev/null +++ b/snap/snapcraft.yaml @@ -0,0 +1,254 @@ +#*************************************************************************** +# snapcraft.yaml +# ------------------- +# begin : aug 2026 +# copyright : (C) 2026 by Jaime Robles +# email : jaime@robles.es +# +#***************************************************************************** +# * This file is part of KLog. * +# * * +# * KLog is free software: you can redistribute it and/or modify * +# * it under the terms of the GNU General Public License as published by * +# * the Free Software Foundation, either version 3 of the License, or * +# * (at your option) any later version. * +# * * +# * KLog is distributed in the hope that it will be useful, * +# * but WITHOUT ANY WARRANTY; without even the implied warranty of * +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +# * GNU General Public License for more details. * +# * * +# * You should have received a copy of the GNU General Public License * +# * along with KLog. If not, see . * +# * * +#*****************************************************************************/ +# +# Build with: snapcraft (see devscripts/snap-create-package.sh) +# Install with: sudo snap install --dangerous ./klog_*.snap +# +# Why base: core26 +# ---------------- +# KLog links against Qt6 Location (the world map in the Map window). QtLocation +# was dropped upstream for Qt 6.0-6.4 and only came back in Qt 6.5, so it is +# absent from the Ubuntu 24.04 archive that core24 is built from - there is no +# qt6-location-dev/libqt6location6 there at all. The KDE neon extensions are +# not an option either: they explicitly do not ship QtCharts, which KLog also +# needs for the statistics widgets. Ubuntu 26.04 (core26) carries the complete +# Qt 6.10.2 set - Charts, Location, Positioning, SerialPort, Quick - plus +# Hamlib 4.6.5, so every dependency comes from the distribution archive with +# nothing built from source and no third-party apt repositories. +# +# The base says what KLog is built and run against, not what the user has to +# be running: snapd pulls the core26 base snap in as a dependency, so this +# installs just as well on Ubuntu 22.04, Debian, Fedora or Arch. Snap bases +# only exist for LTS releases, so core26 is the newest one available. +# +# core26 has no GNOME/KDE desktop extension yet, so the desktop plumbing the +# extension would normally do (Qt plugin/QML search paths, fontconfig, XDG +# data dirs) is done by snap/local/klog-launch instead. Hardware accelerated +# graphics, needed by the QtQuick map, comes from the "gpu" extension. + +name: klog +adopt-info: klog +base: core26 +license: GPL-3.0-or-later +summary: Ham radio DX logging program +description: | + KLog is a free (as in freedom) hamradio logging program for GNU/Linux, + macOS and Windows. + + It provides general purpose DX logging support: + + * QSO logging with DXCC, WAZ, ITU zone and grid locator tracking + * ADIF import and export + * Statistics and charts (QSOs per band, mode, year, continent, DXCC ...) + * DX cluster client with a DX assistant + * eQSL, LoTW, ClubLog and QRZ.com logbook integration + * Satellite QSO support + * CAT control through Hamlib + * A UDP server that logs QSOs sent by WSJT-X and compatible programs + + The logbook lives in ~/snap/klog/current/.klog. On first run the snap copies + an existing ~/.klog logbook (from a .deb or a self-built KLog) into that + location so nothing is lost when moving to the snap; set + KLOG_SNAP_NO_MIGRATE=1 to skip that. + + Some interfaces are not connected automatically and are needed for CAT + control and printing: + + sudo snap connect klog:raw-usb + sudo snap connect klog:serial-port + sudo snap connect klog:cups-control + + See INSTALL-snap in the source tree for the details. + +# The store icon. The .desktop entry gets its own icon path at build time. +icon: src/img/klog_256x256.png + +website: https://github.com/ea4k/klog +source-code: https://github.com/ea4k/klog +issues: https://github.com/ea4k/klog/issues +contact: jaime@robles.es + +# "grade" says whether the revision may be released to the stable channel, not +# whether the KLog release itself is stable. Pre-releases are published to the +# edge/beta channels; the grade does not need to change for that. +grade: stable +confinement: strict +compression: lzo + +platforms: + amd64: + arm64: + +apps: + klog: + command: usr/bin/klog + command-chain: + - bin/klog-launch + desktop: usr/share/applications/io.github.ea4k.klog.desktop + common-id: io.github.ea4k.klog + # Mesa userspace drivers for the QtQuick map. On core26 this pulls in the + # mesa-2604 provider snap through the gpu-2604 content interface. + extensions: + - gpu + plugs: + # Desktop session: windowing, clipboard, notifications, xdg-open for the + # "look this callsign up on QRZ.com" links, and the host font set. + - desktop + - desktop-legacy + - wayland + - x11 + - unity7 + - opengl + # cty.dat and satellite data downloads, DX cluster telnet sessions and + # the eQSL/LoTW/ClubLog/QRZ.com web services. + - network + # UDP server listening for WSJT-X (default port 2237). + - network-bind + # ADIF/Cabrillo import and export outside the snap's own directory. + - home + - removable-media + # Hamlib CAT control over a serial or USB-serial link. Neither of these + # connects automatically; see INSTALL-snap. + - serial-port + - raw-usb + # Printing the log. Manual connection. + - cups-control + +parts: + klog: + plugin: cmake + source: . + source-type: local + cmake-parameters: + - -DCMAKE_BUILD_TYPE=Release + - -DCMAKE_INSTALL_PREFIX=/usr + - -DBUILD_TESTING=OFF + # Defaults to ON in CMakeLists.txt; there are no tests in this build. + - -DKLOG_COVERAGE=OFF + build-packages: + - build-essential + - cmake + - pkg-config + # Hamlib, found through pkg-config by cmake/FindHamlib.cmake. + - libhamlib-dev + # Qt6 modules KLog links against, in the order find_package() asks for + # them: Charts Concurrent Core Gui Location Network Positioning + # PrintSupport Qml Quick QuickWidgets SerialPort Sql Widgets. + - qt6-base-dev + - qt6-charts-dev + - qt6-declarative-dev + - qt6-declarative-private-dev + - qt6-location-dev + - qt6-positioning-dev + - qt6-serialport-dev + # LinguistTools (cmake config) and lrelease/lupdate, for qt_add_translations(). + - qt6-tools-dev + - qt6-tools-dev-tools + - qt6-l10n-tools + - libgl1-mesa-dev + - libxkbcommon-dev + - libudev-dev + stage-packages: + # Only the leaf libraries are listed; apt pulls libqt6core6t64, + # libqt6gui6, libqt6widgets6, libqt6network6, libqt6qml6, libqt6quick6 + # and the rest of the dependency tree in automatically. + - libqt6charts6 + - libqt6location6 + - libqt6positioning6 + - libqt6printsupport6 + - libqt6quickwidgets6 + - libqt6serialport6 + - libqt6svg6 + # Qt plugins are dlopen()ed, so they are never pulled in as a dependency + # and have to be requested by hand. + - libqt6sql6-sqlite # the logbook is a SQLite database + - qt6-qpa-plugins # xcb platform plugin + - qt6-wayland # wayland platform plugin + - qt6-location-plugins # OSM geoservices plugin used by the map + - qt6-image-formats-plugins + - qt6-translations-l10n # translations of Qt's own standard dialogs + # QML modules imported by src/widgets/map/*.qml. + - qml6-module-qtlocation + - qml6-module-qtpositioning + - qml6-module-qtquick + - qml6-module-qtquick-controls + - qml6-module-qtquick-layouts + - qml6-module-qtquick-shapes + - qml6-module-qtquick-templates + - qml6-module-qtquick-window + - libhamlib4t64 + # The desktop interface bind-mounts /usr/share/fonts and the fontconfig + # cache from the host into the snap, but fontconfig itself is not in the + # base, so the configuration it needs has to be staged here. + - fontconfig + - libxcb-cursor0 + override-pull: | + craftctl default + # Keep the snap version in step with APP_PKGVERSION in CMakeLists.txt. + version="$(sed -n 's/^set(APP_PKGVERSION[[:space:]]*"\(.*\)").*/\1/p' \ + "${CRAFT_PART_SRC}/CMakeLists.txt" | head -1)" + if [ -z "$version" ]; then + echo "ERROR: could not read APP_PKGVERSION from CMakeLists.txt" >&2 + exit 1 + fi + craftctl set version="$version" + override-build: | + craftctl default + + desktop="${CRAFT_PART_INSTALL}/usr/share/applications/io.github.ea4k.klog.desktop" + # "Icon=klog" resolves through the icon theme, which is not set up inside + # the snap. Point it at the file the install rules put in the snap. + sed -i 's|^Icon=klog$|Icon=${SNAP}/usr/share/pixmaps/klog.png|' "$desktop" + if ! grep -q '^Icon=\${SNAP}/usr/share/pixmaps/klog.png$' "$desktop"; then + echo "ERROR: failed to rewrite Icon= in $desktop" >&2 + exit 1 + fi + + # The .qm files are silently skipped when LinguistTools is missing, which + # would ship an English-only KLog. Same check as the .deb build script. + if ! ls "${CRAFT_PART_INSTALL}"/usr/share/klog/translations/klog_*.qm >/dev/null 2>&1; then + echo "ERROR: no translations were built into the snap" >&2 + exit 1 + fi + + # Command-chain wrapper: Qt search paths, fontconfig and the one-time + # logbook migration. Kept out of the klog part so a rebuild of the wrapper + # does not rebuild KLog. + launcher: + plugin: dump + source: snap/local + organize: + klog-launch: bin/klog-launch + stage: + - bin/klog-launch + override-build: | + craftctl default + chmod 755 "${CRAFT_PART_INSTALL}/klog-launch" + +layout: + # QLibraryInfo has /usr/share/qt6 compiled in, which inside the snap would be + # the (empty) core26 base. Qt's own translations live there. + /usr/share/qt6: + bind: $SNAP/usr/share/qt6 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 95901e432..35418b1c2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -222,6 +222,7 @@ set(KLOG_DOC ../COPYING ../INSTALL-es.txt ../INSTALL-linux + ../INSTALL-snap ../INSTALL.txt ../NEWS ../README