Add Linux packaging: deb, rpm, archlinux and a reproducible build path - #152
Open
jidckii wants to merge 6 commits into
Open
Add Linux packaging: deb, rpm, archlinux and a reproducible build path#152jidckii wants to merge 6 commits into
jidckii wants to merge 6 commits into
Conversation
Единый источник описания приложения для всех 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` и проверяет содержимое собранных пакетов: без неё образ был бы кодом, который никто не выполняет.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Первый из серии небольших 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.desktop-file-validateиappstreamcli validateпроходят (единственное замечание — pedantic-уровняreleases-info-missing; секцию<releases>имеет смысл генерировать изCHANGELOG.md, это отдельная задача).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.ymluntouched,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 indist/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
.desktopentry, 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.desktopinline 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,libmandlibgcc_s. The whole GUI stack is loaded throughdlopen, 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-committedassets/entropy.icoand committed next to it, so packaging needs no image tooling at all. The.icocarries 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 withtask iconswhen the logo changes.Changes to existing files
scripts/build_linux_appimage.shreuses 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 bundledlibudev.so.1and itsLD_LIBRARY_PATHare dropped: the binary does not link it, and forcing host libraries ahead of system ones is an ABI risk with no upside. Inbuild.ymlthe matrix, job names and the #111 test step are unchanged; only new steps and one new job are added.Validation
Full
task linux:allandtask docker:linuxfrom scratch, contents of all four artifacts asserted byscripts/test_linux_packages.sh, no root-owned files left after the container run,desktop-file-validateandappstreamcli validateclean, every tool pin checked against the upstreamchecksums.txt,shellcheckclean,cargo testgreen (565 tests). Installing the.debon a real Debian/Ubuntu is done by CI viaapt-get install ./*.deb— that step is what proves the hand-writtenDependsactually resolve.Related: #143