Skip to content

Add Linux packaging: deb, rpm, archlinux and a reproducible build path - #152

Open
jidckii wants to merge 8 commits into
ergohaven:mainfrom
jidckii:feat/linux-packages
Open

Add Linux packaging: deb, rpm, archlinux and a reproducible build path#152
jidckii wants to merge 8 commits into
ergohaven:mainfrom
jidckii:feat/linux-packages

Conversation

@jidckii

@jidckii jidckii commented Aug 16, 2026

Copy link
Copy Markdown

Первый из серии небольших PR, на которые разрезан #143. Здесь только Linux: точка входа сборки, воспроизводимый контейнер и нативные пакеты. release.yml не тронут, src/ не тронут, публикации пакетов пока нет — она приедет отдельным PR после того, как Windows и macOS переедут в этот же flow.

Ни одного из четырёх блокеров из ревью #143 этот PR не касается: фильтр тегов остаётся v0.*, имена macOS-артефактов не меняются, Inno Setup на месте, релизные пути не трогаются.

RU

Что появляется

  • task linux:all.deb, .rpm, .pkg.tar.zst (nfpm) и AppImage в dist/linux/.
  • task docker:linux — те же четыре артефакта из пиннутого образа, на любом хосте с Docker и без единого установленного инструмента.
  • task prepare — ставит необходимое на текущем хосте; знает пакетные менеджеры Debian/Ubuntu, openSUSE, Fedora, Arch и Alpine.

Пакет несёт бинарник, .desktop, AppStream-метаданные, udev-правило и иконки hicolor. AppImage раздаёт ровно те же файлы, поэтому приложение, поставленное пакетом, и оно же из AppImage описывают себя одинаково — раньше AppImage генерировал .desktop инлайном и нёс синий плейсхолдер вместо логотипа.

Почему Docker здесь, а не отдельным шагом

Сам по себе Taskfile — обёртка над cargo build, проверять в нём нечего. Вместе с контейнером и пакетами он даёт одно законченное проверяемое утверждение: Linux-артефакты собираются одинаково у разработчика и в CI. Разрезать это ещё мельче — значит мержить две половины, ни одна из которых сама по себе не работает.

Зависимости пакетов выписаны руками

У бинарника ровно три ELF-зависимости — libc, libm и libgcc_s. Весь GUI-стек (libGL, xkbcommon, X11/xcb, wayland) грузится через dlopen, hidapi собран с чисто растовым hidraw-бэкендом вместо libudev, а файловые диалоги идут через xdg-desktop-portal, а не GTK. Автоопределение объявило бы почти пустой список, и пакет ставился бы, но не запускался.

Для rpm зависимости объявлены провайдами по soname (libX11.so.6()(64bit)), а не именами пакетов: имена разъезжаются между дистрибутивами (libX11 в Fedora против libX11-6 в openSUSE), soname — нет.

Иконки

assets/icons/hicolor/ раскладывается из уже лежащего в репозитории assets/entropy.ico и коммитится рядом с ним, поэтому упаковка не требует никакого графического тулинга. В .ico есть отрисованные вручную варианты 16, 32 и 48 — они копируются как есть, ресайзом из кадра 256 добираются только недостающие размеры. Перегенерация — task icons, при смене логотипа.

Что меняется в существующих файлах

  • scripts/build_linux_appimage.sh — переиспользует общие .desktop, metainfo и иконки; кэш инструмента переехал в .cache/tools (общий с nfpm, переживает cargo clean). Логика проверки и загрузки appimagetool не тронута: три теста из Verify AppImage packaging tool downloads #111 проходят без единой правки в самих тестах.
  • Оттуда же убран libudev.so.1, который копировался с хоста сборки и подставлялся через LD_LIBRARY_PATH. Бинарник его не линкует, а LD_LIBRARY_PATH перебивает системные библиотеки у всего, что подгрузится позже, — чистый риск ABI без выгоды.
  • build.yml — добавлены шаги сборки пакетов в существующую Linux-джобу и отдельная джоба на контейнер. Матрица, имена джоб и шаг с тестами Verify AppImage packaging tool downloads #111 не тронуты.

Проверено

  • task clean && task linux:all и task docker:linux с нуля: все четыре артефакта, содержимое каждого проверено scripts/test_linux_packages.sh.
  • После контейнерной сборки все файлы принадлежат вызвавшему пользователю, root-owned мусора не остаётся.
  • desktop-file-validate и appstreamcli validate проходят (единственное замечание — pedantic-уровня releases-info-missing; секцию <releases> имеет смысл генерировать из CHANGELOG.md, это отдельная задача).
  • Пины nfpm, go-task и appimagetool сверены с официальными checksums.txt; путь загрузки nfpm прогнан вживую.
  • shellcheck по всем скриптам чистый, cargo test — 565 тестов.

Не проверено: установка .deb на живой Debian/Ubuntu — это делает CI отдельным шагом, apt-get install ./*.deb. Именно он проверяет, что руками выписанные Depends существуют в архиве и разрешаются; распаковка такого не ловит.

На решение мейнтейнеров

maintainer: в packaging/nfpm/nfpm.yaml сейчас Ergohaven <ergohaven@users.noreply.github.com> — для deb это обязательное поле, и адрес стоит заменить на реальный.

EN

The first of the small PRs #143 is being split into. Linux only: the build entry point, a reproducible container and native packages. release.yml untouched, src/ untouched, no package publishing yet — that comes in a later PR, once Windows and macOS have moved into the same flow.

None of the four blocking points from the #143 review are touched here: the tag filter stays v0.*, macOS artifact names are unchanged, Inno Setup stays, and no release path is modified.

What lands

  • task linux:all.deb, .rpm, .pkg.tar.zst (nfpm) and the AppImage in dist/linux/.
  • task docker:linux — the same four artifacts from a pinned toolchain image, on any host with Docker and nothing else installed.
  • task prepare — installs the prerequisites for the current host across the Debian/Ubuntu, openSUSE, Fedora, Arch and Alpine package managers.

Packages ship the binary, the .desktop entry, AppStream metainfo, the udev rule and the hicolor icons. The AppImage now ships exactly the same files, so an app installed from a package and one launched from the AppImage describe themselves identically — previously the AppImage generated its .desktop inline and carried a blue placeholder instead of the logo.

Why Docker rides along

A Taskfile on its own is just a wrapper around cargo build — there is nothing to verify in it. Together with the container and the packages it makes one complete, testable claim: Linux artifacts build the same way locally and in CI. Splitting it further would mean merging two halves, neither of which works alone.

Dependencies are declared by hand

The binary has exactly three ELF dependencies — libc, libm and libgcc_s. The whole GUI stack is loaded through dlopen, hidapi uses its pure-Rust hidraw backend instead of libudev, and file dialogs go through xdg-desktop-portal rather than GTK. Auto-detection would declare almost nothing and the package would install and then fail to start. The rpm dependencies use soname provides rather than package names, because those names differ between rpm distros while the sonames do not.

Icons

assets/icons/hicolor/ is generated from the already-committed assets/entropy.ico and committed next to it, so packaging needs no image tooling at all. The .ico carries hand-drawn 16, 32 and 48 pixel variants; those are copied as-is and only the missing sizes are scaled from the 256 pixel frame. Regenerate with task icons when the logo changes.

Changes to existing files

scripts/build_linux_appimage.sh reuses the shared desktop entry, metainfo and icons, and its tool cache moves to .cache/tools. The appimagetool verification and download logic is untouched — the three tests from #111 pass with no changes to the tests themselves. The bundled libudev.so.1 and its LD_LIBRARY_PATH are dropped: the binary does not link it, and forcing host libraries ahead of system ones is an ABI risk with no upside. In build.yml the matrix, job names and the #111 test step are unchanged; only new steps and one new job are added.

Validation

Full task linux:all and task docker:linux from scratch, contents of all four artifacts asserted by scripts/test_linux_packages.sh, no root-owned files left after the container run, desktop-file-validate and appstreamcli validate clean, every tool pin checked against the upstream checksums.txt, shellcheck clean, cargo test green (565 tests). Installing the .deb on a real Debian/Ubuntu is done by CI via apt-get install ./*.deb — that step is what proves the hand-written Depends actually resolve.

Related: #143

Единый источник описания приложения для всех Linux-форматов: .desktop,
AppStream-метаданные, udev-правило и набор иконок hicolor. Конфиг nfpm
собирает из них deb, rpm и archlinux.

Зависимости выписаны руками, а не определяются автоматически. У бинарника
ровно три ELF-зависимости — libc, libm и libgcc_s: весь GUI-стек (libGL,
xkbcommon, X11/xcb, wayland) грузится через dlopen, hidapi собран с чисто
растовым hidraw-бэкендом вместо libudev, а файловые диалоги идут через
xdg-desktop-portal, а не GTK. Автоопределение объявило бы почти пустой
список, и пакет ставился бы, но не запускался.

Для rpm зависимости объявлены провайдами по soname (libX11.so.6()(64bit)),
а не именами пакетов: имена разъезжаются между дистрибутивами (libX11 в
Fedora против libX11-6 в openSUSE), soname — нет.

Иконки hicolor раскладываются из assets/entropy.ico скриптом
generate_icons.sh и коммитятся рядом с ним, поэтому упаковка не требует
никакого графического тулинга. В .ico есть отрисованные вручную варианты
16, 32 и 48 — они копируются как есть, ресайзом из кадра 256 добираются
только недостающие размеры.

Правило udev ставится в /usr/lib/udev и не конфликтует с копией в
/etc/udev, которую пишет linux/udev/install-vial-rules.sh для сборок из
исходников: копия в /etc по-прежнему имеет приоритет.
`task linux:all` собирает deb, rpm, archlinux и AppImage; `task prepare`
ставит всё необходимое для этого на текущем хосте, зная пакетные менеджеры
Debian/Ubuntu, openSUSE, Fedora, Arch и Alpine.

Метка архитектуры в пакете — обещание пользователю, поэтому PKG_ARCH
следует хосту, а не считается равным amd64, и сверяется с бинарником через
readelf. Пакет с меткой amd64 и arm64-бинарником внутри ставится и не
запускается, так что расхождение роняет сборку.

VERSION по умолчанию берётся из Cargo.toml и переопределяется снаружи —
это понадобится релизному workflow, чтобы имена артефактов совпадали с
тегом, а не с ещё не поднятой версией крейта. Разбор Cargo.toml сделан
средствами самого shell: встроенный интерпретатор go-task внешние утилиты
не подменяет, и с awk/sed весь Taskfile не читался бы на хосте без них.

nfpm скачивается в .cache/tools и сверяется по SHA-256 из tool_pins.sh, а
не ставится в систему; PATH дополняется только на время команды, и уже
установленный у разработчика nfpm имеет приоритет.

Бинарник стажируется в target/nfpm/entropy, а не подставляется в конфиг:
nfpm раскрывает ${...} в скалярных полях, но не в contents.src, поэтому
альтернативой был бы генерируемый конфиг и зависимость от envsubst.
AppImage описывал себя сам: .desktop и иконка генерировались скриптом
инлайном, причём иконка была синим плейсхолдером, а не логотипом Entropy.
Из-за этого приложение, поставленное пакетом, и оно же, запущенное из
AppImage, выглядели и назывались по-разному.

Теперь берутся те же packaging/linux/entropy.desktop, metainfo и иконки
hicolor, что уходят в deb/rpm/arch. X-AppImage-Version дописывается к копии
в корне AppDir — это метаданные самого формата, и в пакетах им не место.

Заодно убран libudev.so.1, который копировался с хоста сборки и
подставлялся через LD_LIBRARY_PATH. Бинарник его не линкует (hidapi собран
с растовым hidraw-бэкендом), а LD_LIBRARY_PATH перебивает системные
библиотеки у всего, что подгрузится позже, — то есть чистый риск ABI без
выгоды.

Кэш инструмента переехал из target/tools в .cache/tools: там же лежит
nfpm, и каталог переживает cargo clean. Тесты из ergohaven#111 задают APPIMAGETOOL
явно и проходят без изменений.
PR-гейт теперь собирает все четыре артефакта тем же путём, которым их
собирает разработчик, и проверяет результат.

test_linux_packages.sh сверяет, что каждый из трёх форматов действительно
несёт бинарник, .desktop, AppStream-метаданные, udev-правило, иконки и
лицензию: ошибки такого рода иначе всплывают только после установки на
живой системе. .deb приходится распаковывать в два прохода — это ar-архив,
и libarchive показывает у него только data.tar/control.tar.

Отдельным шагом .deb ставится по-настоящему через apt-get. Только это
проверяет, что руками выписанные Depends существуют в архиве Ubuntu и
разрешаются; распаковка такого не ловит.

Собранные пакеты выкладываются артефактом сборки, чтобы их можно было
скачать из PR и поставить у себя.
BUILD.md описывает задачи go-task, состав пакета, откуда берутся
зависимости и почему они выписаны руками, а также поведение версий:
предрелизный суффикс nfpm разворачивает в 0.3.10~rc.1 для deb и rpm, но у
pacman тильды нет, и Arch-пакет получает 0.3.10rc.1 — то есть считается
новее стабильного релиза. Это стоит знать до публикации Arch-пакетов для
release candidate.

README получает короткую врезку в разделе Development со ссылкой на
BUILD.md. Списки загрузок и таблица платформ не тронуты: релизный workflow
пакеты пока не публикует.
`task docker:linux` собирает те же deb, rpm, archlinux и AppImage на любом
хосте с Docker и без единого установленного инструмента. Задачи внутри
контейнера те же самые, что запускает разработчик, — образ фиксирует
тулчейн, а не подменяет путь сборки.

Базовый образ пиннится дайджестом, а не тегом: rust:1.97-bookworm
пересобирается апстримом, и без дайджеста один и тот же Dockerfile давал бы
разный тулчейн в разные дни. nfpm, go-task и appimagetool берутся из тех же
пинов, что использует хостовая подготовка, поэтому два пути не разъезжаются.

Контейнер запускается от UID хозяина каталога: иначе всё созданное внутри
остаётся root:root, и следующая локальная задача падает на правах. По той
же причине образ удаляет за собой root-only кэш cargo-реестра. На
SELinux-системах добавляется --security-opt label=disable — каталог
репозитория помечен user_home_t, и контейнер его иначе не прочитает.

CI получает отдельную джобу, которая гоняет ровно `task docker:linux` и
проверяет содержимое собранных пакетов: без неё образ был бы кодом, который
никто не выполняет.

@kissetfall kissetfall left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for splitting the Linux packaging work into a focused PR. The direction is useful, and keeping release.yml and src/ out of scope is the right boundary. I reproduced several packaging-contract blockers on current main, so this needs another pass before merge.

Blocking changes:

  1. Update the branch onto current main. It is 25 commits behind and conflicts in .github/workflows/build.yml and .gitignore; preserve both the current layout-indicator/macOS HID tests, Nix workflow/ignores, and the new packaging steps.

  2. Fix installed package correctness:

    • add the exact # Entropy Vial hidraw access v2 marker to the packaged udev rule, otherwise Entropy rejects it as stale;
    • explicitly set non-executable payload modes to 0644 (the generated packages currently inherit 0664);
    • complete the X11/Wayland runtime dependency closure and account for libgcc_s;
    • publish/build against an explicit glibc baseline. The current ubuntu-latest path can emit a GLIBC_2.39 binary while the deb declares only bare libc6;
    • scope the post-install udev trigger to hidraw and replace the placeholder maintainer address.
  3. Fix package version semantics. With the pinned nFPM 2.47, 0.3.21-rc.1 and stable 0.3.21 both produce Arch .PKGINFO with pkgver = 0.3.21-1. Add format-specific version handling and automated RC-to-stable ordering tests for deb, rpm, and Arch.

  4. Either make the reproducibility claim true or narrow it. Same-input package builds currently produce different hashes, the Docker apt layer is floating, and host/container Rust and Task versions diverge. Use one exact toolchain, a fixed or explicitly declared dependency snapshot, commit-derived SOURCE_DATE_EPOCH, upload the canonical fixed-baseline container artifacts, and add a build-twice/hash-compare check.

  5. Harden Taskfile and architecture behavior. Quote and validate all externally overridable variables, keep clean constrained to known repository paths, and resolve the "any host" claim: native ARM docker:linux currently always reaches the x86-only AppImage failure.

  6. Expand package tests: clean-install and launch the deb/rpm/Arch packages in matching minimal images, and extract/smoke-test the real AppImage while asserting its binary, desktop entry, metainfo, root icon, and hicolor payload. The current deb test runs after build dependencies are already installed, and the AppImage check only tests the executable bit.

After that, please run the current Build 4/4 and Nix 2/2 matrices plus the package/runtime matrix. The packaging direction is worth keeping; these are correctness and distribution-contract issues rather than objections to the feature.

# Conflicts:
#	.github/workflows/build.yml
#	.gitignore

@kissetfall kissetfall left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reviewed at 3d5b70982ce95034acf3c6c9b2b9314fdcf6daa7 after the merge from current main.

The branch synchronization/conflicts from the previous review are resolved, but the packaging-contract blockers remain unchanged:

  • packaging/linux/59-vial.rules still lacks the exact # Entropy Vial hidraw access v2 marker required by the app's installed-rule check.
  • Non-executable payload modes are not explicitly fixed to 0644; the placeholder maintainer is still present; runtime dependency/baseline handling remains incomplete, including the canonical ubuntu-latest artifacts versus an explicit glibc baseline.
  • RC-to-stable ordering is still not encoded/tested per deb/rpm/Arch format.
  • The reproducibility claim is still not enforced with one canonical pinned build path plus a build-twice/hash comparison.
  • Task variables/cleanup remain insufficiently constrained, and the native ARM path still ends at the x86-only AppImage failure.
  • Package tests still verify mostly archive paths; the deb is installed on the build host after build dependencies, while rpm/Arch clean installs and real AppImage extraction/startup are not exercised.

Please address these remaining items before merge. The packaging direction itself remains useful.

Ревью ergohaven#152 назвало шесть блокеров — все про контракт с пакетным
менеджером, а не про саму идею упаковки. Здесь закрыты все шесть.

Корректность установленного пакета:

- в packaging/linux/59-vial.rules добавлен маркер
  «# Entropy Vial hidraw access v2». Без него linux_vial_udev_rules_installed()
  считает правило устаревшим, и приложение продолжает просить настроить
  доступ, хотя пакет его уже настроил. Ловится тестом
  packaged_udev_rule_is_accepted, который прогоняет сам файл через ту же
  функцию, что и рантайм;
- режимы неисполняемого содержимого заданы в nfpm.yaml явно (0644): без
  file_info nfpm наследует права рабочей копии, и в пакет уезжало 0664 от
  umask сборщика;
- зависимости расширены до полного замыкания того, что бинарник реально
  грузит через dlopen: libEGL, libX11-xcb, libXcursor, libXi, libXrender,
  libxkbcommon-x11, libwayland-egl — плюс libgcc_s, настоящая NEEDED-запись.
  Список сверен со строками сонеймов в самом бинарнике;
- граница glibc объявляется явно и считается по бинарнику
  (scripts/glibc_baseline.sh, readelf -V): «libc6» без версии позволяет
  поставить пакет на систему, где приложение не стартует. Публикуемые
  артефакты при этом собираются только в контейнере с bookworm;
- udevadm trigger в postinstall сужен до --subsystem-match=hidraw: полный
  trigger переприменяет правила ко всем устройствам системы;
- maintainer заменён на Ergohaven <hello@eh.works>.

Версии по форматам (scripts/pkg_version.sh):

nfpm с семверным prerelease теряет суффикс в арховом .PKGINFO, и 0.3.21-rc.1
со стабильной 0.3.21 дают один и тот же pkgver = 0.3.21-1 — апгрейда для
pacman просто не существует. Теперь версия считается до nfpm и своя для
каждого формата: 0.3.21~rc.1 для deb и rpm (там '~' сортируется перед
пустотой) и 0.3.21rc.1 для arch (у pacman '~' нет, зато в его vercmp
остаток из букв проигрывает пустоте). Перевод проверяет
test_pkg_version.sh, а сам порядок — родные компараторы дистрибутивов
внутри clean-install теста.

Воспроизводимость перестала быть утверждением на слово:

- SOURCE_DATE_EPOCH берётся из времени коммита и доезжает и до nfpm, и до
  AppImage (mtimes AppDir нормализуются до mksquashfs, .DirIcon создаётся
  до нормализации, а не appimagetool'ом после неё);
- apt в образе смотрит в датированный слепок snapshot.debian.org, а не в
  катящееся зеркало;
- канонические артефакты собирает только контейнер: у хост-джобы Rust
  плавающий, и её пакеты больше никуда не публикуются;
- test_toolchain_pins.sh падает, если .tool-versions, Dockerfile и версия
  setup-task в CI разъедутся;
- task linux:repro (в CI — docker:repro) собирает дважды и сравнивает
  суммы, и в артефакты уходит именно проверенная сборка.

Taskfile:

внешние переменные ходят по задачам окружением, а не подстановкой в текст
команды, и проверяются в linux:validate до того, как попадут в имя файла
или в пакет; clean работает по литеральным путям, а не по $DIST; на arm64
linux:all собирает пакеты и вслух пропускает AppImage вместо того, чтобы
всегда падать на x86-only appimagetool.

Тесты:

- test_linux_packages.sh теперь проверяет режимы, маркер udev-правила и
  версию, записанную каждым форматом, а AppImage распаковывает и
  запускает — исполняемый бит сам по себе ничего не доказывал;
- test_linux_install.sh ставит пакеты в пиннутые минимальные образы Debian,
  Fedora и Arch их же пакетными менеджерами, запускает приложение и удаляет
  пакет. Только чистый образ проверяет, что руками выписанные зависимости
  разрешаются: на хосте сборки всё названное уже стоит как build-зависимость.
@jidckii

jidckii commented Sep 8, 2026

Copy link
Copy Markdown
Author

All six blockers are addressed. Details of what changed and, more importantly, what now checks each one.

1. Branch sync — resolved by the merge at 3d5b709.

2. Installed package correctness

  • packaging/linux/59-vial.rules now starts with # Entropy Vial hidraw access v2. The new Rust test packaged_udev_rule_is_accepted feeds the packaged file itself through vial_udev_rule_is_current, so the marker cannot silently drift again. The Nix module already carried it; packaging was the only path missing it.
  • Every non-executable entry in nfpm.yaml sets file_info.mode: 0644 (the binary 0755). Asserted from the archive listing and again from the installed filesystem.
  • Runtime dependency closure completed from the sonames the binary actually loads: libEGL, libX11-xcb, libXcursor, libXi, libXrender, libxkbcommon-x11, libwayland-egl, plus libgcc_s — a real NEEDED entry that was missing.
  • The glibc baseline is derived from the binary (scripts/glibc_baseline.sh, readelf -V) and declared per format: for the current tree libc6 (>= 2.35), libc.so.6(GLIBC_2.35)(64bit), glibc>=2.35. It therefore follows the binary being packaged rather than the machine that packaged it, and the published artifacts are built only in the pinned bookworm container.
  • udevadm trigger --subsystem-match=hidraw; maintainer is now Ergohaven <hello@eh.works>.

3. Version semantics

Confirmed your finding against nFPM 2.47: with a semver prerelease it drops the suffix from the Arch .PKGINFO entirely, so rc and stable both land as pkgver = 0.3.21-1 and pacman sees no upgrade at all. The version is now computed before nFPM, per format, in scripts/pkg_version.sh:

Format 0.3.21-rc.1 0.3.21 Why
deb 0.3.21~rc.1 0.3.21 dpkg sorts ~ before the empty string
rpm 0.3.21~rc.1 0.3.21 rpm ≥ 4.10 sorts ~ the same way
archlinux 0.3.21rc.1 0.3.21 pacman has no ~, but its vercmp lets a trailing alphabetic segment lose to none

scripts/test_pkg_version.sh covers the mapping; the ordering itself is asserted inside each distro image with its own comparator — dpkg --compare-versions, rpmdev-vercmp, vercmp — rather than a re-implementation.

4. Reproducibility — now enforced rather than claimed

  • SOURCE_DATE_EPOCH derived from the commit, honoured by nFPM and by the AppImage.
  • AppDir mtimes normalised before mksquashfs, and .DirIcon is created by us: appimagetool adds that symlink after normalisation, and it was the last source of drift.
  • apt in the image points at a dated snapshot.debian.org instead of the rolling mirror (DEBIAN_SNAPSHOT).
  • Canonical artifacts come only from the container. The host job keeps task linux:all as a smoke test of the developer path but no longer uploads or installs anything, so the floating stable Rust never reaches a published package. scripts/test_toolchain_pins.sh fails the build if .tool-versions, the Dockerfile and the CI setup-task version disagree — that one caught the 3.x pin immediately.
  • task linux:repro / task docker:repro builds twice and compares SHA-256, and CI publishes the build it verified.

5. Taskfile and architecture

Externally overridable values reach commands through the environment rather than string interpolation, and are validated in linux:validate before they can reach a filename or a package. clean uses literal paths instead of $DIST. On arm64 linux:all (and therefore docker:linux) builds the three packages and skips the AppImage out loud, instead of always failing on the x86-only appimagetool.

6. Package tests

  • scripts/test_linux_packages.sh now checks payload modes, the udev marker and the version each format recorded, and extracts and runs the AppImage — asserting the binary, both desktop entries, the metainfo, the root icon, .DirIcon and the hicolor payload, then starting it and requiring it to reach its own startup log rather than fail on a missing library.
  • scripts/test_linux_install.sh installs the packages into pinned minimal Debian, Fedora and Arch images with their own package managers, starts the app there, checks the version ordering and removes the package again. The host-side apt-get install ./*.deb is gone: on a build host everything the dependencies name is already present as a build dependency.

Verified locally before pushing

cargo test --all-targets 694 green · task linux:all + task linux:test · task linux:repro 4/4 identical · task docker:repro 4/4 identical · task linux:install-test OK on Debian, Fedora and Arch against the container-built packages · shellcheck clean on all scripts · the three #111 AppImage tests unchanged and green · desktop-file-validate and appstreamcli validate clean (one pedantic releases-info-missing).

CI matrices are on you to trigger — the workflow is manual/PR-only.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants