diff --git a/.claude/skills/fix-issue/references/verification-linux.md b/.claude/skills/fix-issue/references/verification-linux.md index fba253e687..d34d389934 100644 --- a/.claude/skills/fix-issue/references/verification-linux.md +++ b/.claude/skills/fix-issue/references/verification-linux.md @@ -33,7 +33,7 @@ Cargo prints one "test result:" line per test binary and never adds them up, thr ## Translations and data -- **`l10n` checks the file list and the catalog**, not the template. Extracting the template needs gettext 0.24 or later, which reads Rust; an older `xgettext` reads it with the C lexer and produces a template that must not be committed. CI's Translations job is the gate for it. +- **`l10n` checks the file list and the catalog**, not the template. Extracting the template needs gettext 1.0 or later: 0.24 to 0.26 read Rust but skip path-qualified calls such as `crate::i18n::gettext(...)`, and an older `xgettext` reads it with the C lexer. Neither template may be committed. CI's Translations job is the gate for it. - **`i18n_catalog` needs the `en_US.UTF-8` locale and `msgfmt`**: `localedef -i en_US -f UTF-8 en_US.UTF-8` when the locale is missing. - **`data` skips a validator whose tool is not installed** (`desktop-file-validate`, `appstreamcli`, `glib-compile-schemas`) and reports it. diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index 5a00770d71..42cb5423f9 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -369,11 +369,14 @@ jobs: if: needs.detect.outputs.linux == 'true' runs-on: ubuntu-24.04 timeout-minutes: 30 - # fedora:44 ships gettext 0.26; 0.24 is the first release whose - # xgettext reads Rust. An older one falls back to its C lexer and - # misreads lifetimes. + # ubuntu:26.10 ships gettext 1.0, the first release whose xgettext + # reads a call through a path such as crate::i18n::gettext. 0.24 to + # 0.26 read Rust but skip those calls, and an older one falls back to + # its C lexer. container: - image: fedora:44 + image: ubuntu:26.10 + env: + DEBIAN_FRONTEND: noninteractive defaults: run: working-directory: linux @@ -383,7 +386,8 @@ jobs: # read. - name: Install git run: | - dnf install -y --setopt=install_weak_deps=False git + apt-get update + apt-get install -y --no-install-recommends ca-certificates git git config --global --add safe.directory "$GITHUB_WORKSPACE" working-directory: / - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 @@ -391,11 +395,11 @@ jobs: persist-credentials: false - name: Install system dependencies run: | - dnf install -y --setopt=install_weak_deps=False \ - gcc pkgconf meson ninja-build gettext \ - desktop-file-utils appstream glib2-devel \ - gtk4-devel libadwaita-devel gtksourceview5-devel \ - sqlite-devel krb5-devel clang-devel cargo rust + apt-get install -y --no-install-recommends \ + build-essential pkgconf meson ninja-build gettext \ + desktop-file-utils appstream libglib2.0-bin libglib2.0-dev libxml2-utils \ + libgtk-4-dev libadwaita-1-dev libgtksourceview-5-dev \ + libsqlite3-dev libkrb5-dev clang libclang-dev cargo rustc - name: POTFILES.in is current run: | git ls-files 'crates/app/src/*.rs' 'data/resources/*.ui' 'data/*.desktop.in.in' \ @@ -410,7 +414,7 @@ jobs: run: | meson compile -C _build tablepro-pot if ! git diff --exit-code --ignore-matching-lines='^"POT-Creation-Date: ' -- po/tablepro.pot; then - echo "::error::po/tablepro.pot does not match the strings in the code: run meson compile -C _build tablepro-pot with gettext 0.24 or newer, or take the tablepro-pot artifact of this run, and commit it" + echo "::error::po/tablepro.pot does not match the strings in the code: run meson compile -C _build tablepro-pot with gettext 1.0 or newer, or take the tablepro-pot artifact of this run, and commit it" exit 1 fi - name: Keep the regenerated template diff --git a/linux/docs/testing.md b/linux/docs/testing.md index dc4c0bbd1f..bb63361a1f 100644 --- a/linux/docs/testing.md +++ b/linux/docs/testing.md @@ -361,7 +361,7 @@ GitHub Actions (`.github/workflows/build-linux.yml`), Ubuntu runners. It runs on 1. **Fast checks**: `meson setup`, `cargo fmt --all -- --check`, the source greps (no `thread_local!` in services, no blocking file I/O under `ui`, no action group inserted as `win`, no `set_qdata`, no em dash in user-facing text), `scripts/check-doc-symbols.sh` over the docs that name code, clippy with and without default features, `meson compile`, `xvfb-run -a dbus-run-session -- meson test --print-errorlogs`, a Secret Service step under `gnome-keyring-daemon`, then `meson dist`. Runs in an `ubuntu:26.04` container, which ships GLib 2.88 plus the meson, appstream and desktop-file-utils packages. A failed run keeps `_build/meson-logs/testlog.txt` as the `meson-testlog` artifact. [CONTRIBUTING.md](../CONTRIBUTING.md#fast-job-commands) lists the same commands. 2. **Docker tests** (`integration`, `integration-session`, `integration-app`): runs after fast checks pass, and keeps each package's JUnit report as a `junit-` artifact. One matrix entry per package with docker tests (the PostgreSQL driver with PgBouncer, the MySQL driver with MariaDB, the SQL Server and ClickHouse drivers, all four with their TLS suites, `tablepro-ssh` against an OpenSSH server container, and `tablepro-test-fixtures` for the fixtures themselves) runs that package's ignored docker tests through cargo-nextest on the host runner's Docker, one test at a time per package. `tablepro-session` builds storage, which needs GLib 2.88, so its job runs in the fast job's `ubuntu:26.04` image with the host's Docker socket mounted. The app's docker tests (`crates/app/tests/tracker_save_postgres.rs`) run the same way, since the app links GTK; that job names its test targets, because the app's `startup` test needs Meson. The SQLite driver needs no container: its suites run in the fast job. 3. **Supply chain**: `cargo deny check` against `deny.toml` (advisories, bans, licenses and sources, with every feature, both Linux targets and the dev-dependencies), `cargo shear` for unused or misplaced dependencies, and `build-aux/update-third-party-licenses.sh`, failing when `data/licenses`, `build-aux/debian/copyright` or the spec's `License` tag differ from what it writes. Then `zizmor` over the three Linux workflows. -4. **Translations**: in `fedora:44`, whose gettext reads Rust. `po/POTFILES.in` must match `git ls-files`, `meson setup --fatal-meson-warnings` must pass, and `po/tablepro.pot` must match a fresh `meson compile -C _build tablepro-pot` in everything but its creation date. Regenerating it locally needs gettext 0.24 or newer. A failed run keeps the template it wrote as the `tablepro-pot` artifact. +4. **Translations**: in `ubuntu:26.10`, whose gettext 1.0 reads path-qualified Rust calls such as `crate::i18n::gettext(...)`. `po/POTFILES.in` must match `git ls-files`, `meson setup --fatal-meson-warnings` must pass, and `po/tablepro.pot` must match a fresh `meson compile -C _build tablepro-pot` in everything but its creation date. Regenerating it locally needs gettext 1.0 or newer (`po/README.md`). A failed run keeps the template it wrote as the `tablepro-pot` artifact. 5. **Documentation links**: lychee, offline, over every Markdown file under `linux/`, with heading anchors checked. 6. **Flatpak Devel**: the Devel manifest built in the `gnome-51` Flatpak image for x86_64 and aarch64, with every Meson suite run inside the build sandbox from a tree with no `.git`. The x86_64 job lints the manifest with `flatpak-builder-lint` and `build-aux/flatpak/lint-exceptions.json`. The repository holds no Flathub manifest ([ADR 0018](decisions/0018-ppa-copr-and-flathub-later.md)). 7. **Minimum Rust version**: in `ubuntu:26.04`, `build-aux/packaging/add-rust-toolchain-ppa.sh` adds `ppa:rust-toolchain/staging`, `apt-get build-dep -P nocheck` installs the .deb's build dependencies without the test-only ones, and `cargo-1.97 check --workspace --all-targets --locked` runs with and without default features: the compiler the PPA builds with, at the workspace `rust-version`. diff --git a/linux/po/README.md b/linux/po/README.md index 1481450793..a877e545cd 100644 --- a/linux/po/README.md +++ b/linux/po/README.md @@ -76,11 +76,14 @@ the committed file differs in anything but its creation date. It then uploads the template it wrote as the `tablepro-pot` artifact, which can be committed as it is. -This needs **gettext 0.24 or newer**, which is the first release whose -xgettext reads Rust. Fedora 44 ships 0.26; Ubuntu 26.04 ships 0.23.2. An -older xgettext falls back to its C lexer, which misreads lifetimes such as -`'static` as character constants and produces a template you should not -commit. `meson setup` warns when the xgettext it found is too old. +This needs **gettext 1.0 or newer**, the first release whose xgettext +reads a call through a path such as `crate::i18n::gettext(...)`, the way +most of the app calls it. Ubuntu 26.10 ships 1.0; Fedora 44 ships 0.26 and +Ubuntu 26.04 0.23.2. gettext 0.24 to 0.26 read Rust but skip every +path-qualified call, and anything older falls back to its C lexer, which +misreads lifetimes such as `'static` as character constants. Neither +template should be committed. `meson setup` warns when the xgettext it +found is too old. Use `msgmerge` to fold new strings into existing translations: diff --git a/linux/po/meson.build b/linux/po/meson.build index 45b46838be..ae9f606c64 100644 --- a/linux/po/meson.build +++ b/linux/po/meson.build @@ -2,9 +2,9 @@ xgettext = find_program('xgettext', required: false) if xgettext.found() xgettext_version = run_command(xgettext, '--version', check: false).stdout().split('\n')[0].split(' ')[-1] - if xgettext_version.version_compare('< 0.24') + if xgettext_version.version_compare('< 1.0') warning( - 'xgettext @0@ predates 0.24, which taught xgettext to read Rust. Regenerating the POT needs 0.24 or newer.'.format( + 'xgettext @0@ predates 1.0, the first that reads a call through a path such as crate::i18n::gettext. Regenerating the POT needs 1.0 or newer.'.format( xgettext_version, ), )