Патчим на живую: разборки с Flatpak
«Плевое дело», «тут работы на пару минут» — знакомо? Конечно знакомо, еще не родился программист, не дающий такую оценку чужим задачам направо и налево.
Рассказываю на конкретном примере чем это может закончиться.
Постановка
Существует на свете такое банальное интересное приложение Evince, универсальный просмотрщик документов разных форматов.
Разрабатывается в рамках проекта Gnome, выглядит как-то так:
Вообщем так получилось, что ввиду специфики Gnome, а именно их подхода к тотальному урезанию и упрощению интерфейса, в данной программе не сделали никакого способа поменять цвет фона страницы:
он либо ярко белый с черными буквами, либо черный, белыми — т. н. «ночной режим».
Вот такой вот программный фашизм.
Но внезапно оказалось, что помимо слепых и дальтоников, на свете существуют еще и слабовидящие — люди с ослабленным зрением (различной степени), которым белый фон выдерживать уже тяжело, а полностью темный пока еще не нужен.
Вот так и возникла эта задача, с поста на одном известном форуме.
Я конечно же решил, что столь серьезному джентельмену поправить такое — как «сходить до ветру»: быстро, просто и без последствий.
Но конечно дальше начались сплошные будни разведки разработки и разнообразные сложности.
Эти самые цвета фона страницы разработчики зашили непросредственно в код, без возможности изменения через стили оформления Gtk (графический фреймворк, на котором реализован интерфейс) или тему самого окружения Gnome.
Так что нужно было сделать правку и сборку приложения, сгенерировав еще и финальный пакет для установки.
Надо сказать что обойтись «малой кровью» — подсказками по сборке для пользователя, который все это затеял не вышло.
С одной стороны была нехватка опыта (пользователь был самым обычным пользователем, не разработчиком), с другой — оочень большая специфика этого проекта и очевидное отсутствие документации.
Так что пришлось проходить правку и сборку целиком своими силами.
Сборка проекта реализована через новомодные и стандартные для новых выпусков Gnome meson и ninja, а итоговый дистрибьютив это образ Flatpak — все «как в лучших домах Парижу», но разумеется п#здец и ужас для всех непричастных.
Все манипуляции проводились на Mageia Linux 9
Хотя первую успешную сборку evince я сделал все же на FreeBSD, по традиции.
Правка
Собственно правки кода всего две, в разных местах одного и того же файла libdocument/ev-document-misc.c, обе достаточно тривиальны.
Первая в районе 485й строки:
void ev_document_misc_invert_surface (cairo_surface_t *surface) { cairo_t *cr; cr = cairo_create (surface); /* white + DIFFERENCE -> invert */ // заменяем вот эти два вызова // cairo_set_operator (cr, CAIRO_OPERATOR_DIFFERENCE); // cairo_set_source_rgb (cr, 1., 1., 1.); // на вот такие: cairo_set_operator (cr, CAIRO_OPERATOR_DARKEN); cairo_set_source_rgb (cr, 0.8, 0.9098, 0.8117647); cairo_paint(cr); cairo_destroy (cr); }
Эта правка заставит использовать «мразотно-зеленый» (не знаю как правильно он называется) цвет фона вместо черного при включении «ночного режима».
Вторая правка находится в районе 512й строки:
void ev_document_misc_invert_pixbuf (GdkPixbuf *pixbuf) { guchar *data, *p; guint width, height, x, y, rowstride, n_channels; n_channels = gdk_pixbuf_get_n_channels (pixbuf); g_assert (gdk_pixbuf_get_colorspace (pixbuf) == GDK_COLORSPACE_RGB); g_assert (gdk_pixbuf_get_bits_per_sample (pixbuf) == 8); /* First grab a pointer to the raw pixel data. */ data = gdk_pixbuf_get_pixels (pixbuf); /* Find the number of bytes per row (could be padded). */ rowstride = gdk_pixbuf_get_rowstride (pixbuf); width = gdk_pixbuf_get_width (pixbuf); height = gdk_pixbuf_get_height (pixbuf); for (x = 0; x < width; x++) { for (y = 0; y < height; y++) { /* Calculate pixel's offset into the data array. */ p = data + x * n_channels + y * rowstride; /* Change the RGB values*/ // заменяем вот это: //p[0] = 255 - p[0]; //p[1] = 255 - p[1]; //p[2] = 255 - p[2]; // на это: p[0] = 204; /* cc */ p[1] = 232; /* e8 */ p[2] = 207; /* cf */ } } }
Результат этих правок выглядит вот так:
Все счастливы и довольны, если бы не одно но:
сборка «дистрибьютива» в виде образа Flatpak.
Быстрое решение или Gnome Builder
Поскольку я не следил особо за прогрессом разработки проекта Gnome — не был в курсе о существовании аж целой специализированной IDE, которая команда создала и поддерживает для своих проектов.
С ее помощью весь процесс от скачивания исходников, внесения изменений и до генерации .flatpak файла оказался тривиальным:
- Открываешь Gnome builder
- Нажимаешь Clone repository.. и вставляешь ссылку в поле Repository URL: https://gitlab.gnome.org/GNOME/evince.git и жмешь Clone repository
- Делаешь свои правки
- Жмешь Run, чтобы собрать и проверить работоспособность
- Жмешь Creating flatpak bundle
Вот так выглядит открытый и собранный проект:
Повторюсь что я не знал о существовании сего замечательного инструмента, поэтому полез делать сборку и упаковку вручную.
Собственно я постоянно так делаю, еще временами ору Гойдааа! во весь голос.
Особенности профессии, что поделать.
Пох#й пляшем: долгое и сложное решение
Первым делом клонируем репозиторий с исходниками:
git clone https://gitlab.gnome.org/GNOME/evince.git
Поскольку мы настоящие джентельмены — никаких релизных веток использовать не будем, только trunk master current main, только хардкор!
meson -Dlibhandy:examples=false -Dlibhandy:tests=false -Dlibhandy:vapi=false -Dlibhandy:glade_catalog=disabled -Dlibhandy:introspecti on=disabled _build
Внимательно смотрим вывод, поскольку будут сыпаться ошибки об отсутствующих библиотеках — их все последовательно придется ставить в систему.
После того как meson отработает без ошибок, надо запустить ninja:
ninja -C _build all
Это уже непосредственно компиляция.
Обе полные команды сборки находятся в файле .gitlab-ci.yml откуда их можно вытащить при изменениях.
_build это название временного каталога, в который пишется результат сборки. После того как ninja отработает без ошибок, пожно попробовать запустить результат:
./_build/shell/evince
К сожалению evince использует динамическую загрузку своих библиотек из заранее определенного пути, поэтому при попытке запуска будет вот такая ошибка:
(evince:7168): EvinceDocument-WARNING **: 22:14:12.259: Error opening directory “/usr/local/lib64/evince/4/backends”: No such file or directory
Чтобы это обойти можно поставить «системый» evince из репозитория ОС, тогда собранный успешно подхватит эти библиотеки и запустится:
Если вы дошли до этого места — поздравляю, ибо это была лишь подготовка.
Теперь возьмемся всерьез за Flatpak.
Файлы, описывающие сборку находятся в папке build-aux/flatpak,основной это org.gnome.Evince.json и нам нужно будет его поправить.
Ключевая проблема с Flatpak заключается в том что он «слишком умный», поэтому сам выкачивает все зависимости, сам собирает и сам упаковывает.
Естественно из-за столь большого круга задач он лажает и падает.
Простой совет авторам, который они конечно никогда не услышат и не поймут. (поскольку не говорят по-русски)
Именно поэтому мы выше запускали meson и ninja вручную.
Второй важный момент в flatpak это использование репозитория git в качестве источника для сборки. Поскольку наши правки локальны, то это немедленно создает проблему:
изменения в исходниках не попадают в сборку.
Чтобы решить эту проблему и заодно разобраться со стадиями Flatpak, мы берем и выносим сборку Flatpak из проекта — в совершенно отдельную папку.
Создаем новый каталог, вне структуры проекта, пусть для примера будет:
/opt/work/tmp/evince-build
Копируем внутрь скрипты сборки:
cp /opt/src/evince/build-aux/*.json /opt/work/tmp/evince-build
И правим последний блок в org.gnome.Evince.json, меняем вот это:
"sources": [ { "type": "git", "branch": "main", "url": "https://gitlab.gnome.org/GNOME/evince.git" } ]
"sources": [ { "type": "dir", "path": "/opt/src/evince" } ]
Где в path указываем полный путь до исходников.
После этого будут подхватываться ваши правки в коде без необходимости их коммита в репозиторий.
flatpak-builder --keep-build-dirs --user --disable-rofiles-fuse stage1 org.gnome.Evince.json
Пару слов о том откуда взялась эта команда со всеми параметрами.
Вот отсюда.
Дело в том что совсем недавно проект Gnome реализовал для себя специальный плагин для Gitlab CI, поэтому вместо явных команд сборки и упаковки в файле проекта теперь лишь вызов этого плагина:
flatpak: extends: .flatpak stage: build variables: MANIFEST_PATH: "build-aux/flatpak/org.gnome.Evince.json" RUNTIME_REPO: "https://nightly.gnome.org/gnome-nightly.flatpakrepo" FLATPAK_MODULE: "evince" MESON_ARGS: "-Dnautilus=false -Dgtk_doc=false" APP_ID: "org.gnome.Evince" artifacts: # Rewrite paths and reports to "remove" testlog.txt and junit files, # which do not exists in evince build, yet. paths: - "${BUNDLE}" - 'repo.tar' - '.flatpak-builder/build/${FLATPAK_MODULE}/_flatpak_build/meson-logs/meson-log.txt' reports: junit: []
Удачи разобраться, как говорится. Не зная этого момента, вызвать правильно сборку вручную не выйдет. Вот такое тут убойное веселье.
flatpak build-export stage2 stage1
flatpak build-bundle stage2 evince-patched.flatpak
В результате в корне текущего каталога будет файл evince-patched.flatpak — это и есть тот самый готовый образ, который можно распространять и ставить в другие ОС:
flatpak install evince-patched.flatpak
Поскольку это development-версия, в ее зависимостях указаны development- версии библиотек Gnome, которые выкладываются в специальном репозитории.
Без указания этого репозитория установка не пройдет:
flatpak remote-add gnome-nightly https://nightly.gnome.org/gnome-nightly.flatpakrepo
Команду выше нужно выполнить лишь раз но на всех машинах, где будет разворачиваться этот .flatpak файл.
Эпилог
Эта статья идеально иллюстрирует хитровы#банность сложность современного софта, где давно уже недостаточно знать один лишь язык на котором написана программа, а актуальные знания включают в себя опыт работы с линуксами, средами разработки, инструментами сборки, ядерными реакторами и чертом лысым — словом со всей возможной дичью, встречающейся на просторах ИТ-индустрии последние десять-двадцать лет.
Я потратил примерно 5 минут на саму правку, еще 10 на сборку и блин три дня горячей #бли на итоговую сборку .flatpak файла!
Имейте ввиду такие расклады при оценке сроков в ваших проектах, ибо подобная разбивка, где 5% это сама работа, а 95% — непонятная долбильня головой в стену встречается все чаще и чаще.