# Створення пакунку Flatpak

Маю декілька улюблених програм, зокрема - пірингова платформа мікроблогів twister p2p та key/value база даних у блокчейн - KevaCoin, які доволі важко збираються на сучасних системах, тим не менше потребують нових юзерів для існування їх пірингових мереж. Раніше, робив для них локальні збірки у бінарному форматі та пакунках `deb`, але з часом вони втрачали свою актуальність через залежність від батьківського середовища. Тому врешті зібрався часом та створив два пакунки Flatpak, які обіцяють не старіти з часом, щонайменше, в осяжній перспективі.

Тема Flatpak - не нова, у цьому матеріалі я не стану вдаватись в детальні гайди і архітектуру, але поділюсь власним, першим досвідом роботи з цією системою пакунків, наведу декілька прикладів роботи а також спробою публікації на хостингу Flathub. Особисто мені не вистачало такого коротенького гайду, а попередні спроби перечитати документацію від і до, закінчувались нудьгою і відкладаннями на потім у моментах, які мені були одразу не очевидними без практики.

## Платформи

Екосистема Flatpak влаштована довкола так званих "рантаймів" або платформ - тобто програмних комплексів або середовищ, які характерні для певної операційної системи, на якій і засобами якої планується збірка програми:
=> https://docs.flatpak.org/en/latest/available-runtimes.html

Основною платформою є Freedesktop:
=> https://gitlab.com/freedesktop-sdk/freedesktop-sdk
можна сказати, це такий собі голий Linux, який підійде для програм, які не потребують характерних залежностей GTK чи Qt. Для останніх, існують окремі платформи, які по суті розширюють Freedesktop:
=> https://gitlab.gnome.org/GNOME/gnome-build-meta GNOME
=> https://invent.kde.org/packaging/flatpak-kde-runtime KDE

Для програм, які використовуватимуть дані фреймворки, специфічна платформа не обов'язкова, ви можете зібрати всі необхідні залежності з початкового коду для Freedesktop, якщо у вас звісно є таке бажання.

Кожна з платформ має версію релізу, і оновлюється як мені здається раз на рік, тому важливо актуалізовувати вашу програму, якщо ви не бажаєте вимагати від юзера ставити додаткову "операційну систему" лише задля запуску однієї вашої програми.

## Інкапсуляція

У контексті Flatpak, мабуть, правильніше використовувати поняття "пісочниці" або Sandbox:
=> https://docs.flatpak.org/en/latest/sandbox-permissions.html

Якщо описувати влаштування ізоляції програм і їх дозволів Flatpak, то воно має більше спільного з контейнеризацією, хоча автори не задумували проєкт як альтернативу Docker, орієнтуючись саме на користувачів "робочого столу" (Desktop). Чому це так, мені не відомо, адже логіка і принцип роботи Flatpak і Docker - доволі схожі, обидва проєкти мають спільні цілі і у відомих мені випадках можуть бути взаємозамінними.

Якщо коротко, то ізоляція програми Flatpak для кінцевого користувача зумовлена наступними базовими критеріями.

### Ідентифікатори програм

Назви програм, в екосистемі Flatpak, мають стандартизований формат назви, який запобігає конфліктам простору імен (і відповідно - файловими шляхами). Зокрема у випадку, якщо вони мають ідентичну назву, але походять від іншого постачальника або є однойменним форком існуючої програми. Повний перелік вимог до йменування є в документації Application ID:
=> https://docs.flathub.org/docs/for-app-authors/requirements#application-id

Тому при створенні програми і тим більше, якщо ви плануєте її подальшу публікацію на Flathub, важливо дотримуватись специфікації та мати можливість підтвердження володіння простором імен / доменом, в якому оголошено назву.

### Файлова система

Файлова система в контексті Flatpak характеризується специфікою її розташування відносно батьківської системи. А саме - в ізольованому просторі імен, що відноситься до умовної "програми" Flatpak. Більше того, щоб зберігати файли у батьківській системі (яка по суті для пісочниці є "зовнішньою") програмі Flatpak потрібно надати відповідний доступ при оголошенні маніфесту.

Наприклад, якщо програма в Linux стандартно зберігає дані профілю користувача в теці:
```
~/.app
```
то в маніфесті Flatpak цей шлях має бути оголошений атрибутом `--persist=.app` і таким чином, реальний шлях до профілю буде:
```
~/.var/app/org.domain.app-id/.app
```
Те само стосується й інших каталогів (`share`, `usr` і тд), що планується використовувати із-зовні.

Також, аргумент `persist` вказує на те, що дані потрібно зберегти після завершення роботи програми Flatpak, оскільки всі дані (окрім виконавчих файлів програми) в процесі роботи зберігаються у тимчасовому сховищі і будуть очищені. По цій причині, ви також не зможете просто дістатись до користувацьких ресурсів пісочниці, оскільки вони зберігатимуться десь у тимчасових файлах з рандомним хешем замість назви файлу, якщо не залінкувати їх на-зовні у маніфесті.

Окрім згаданого вище `persist`, існують і додаткові дозволи на використання певних каталогів, таких як наприклад ~/Download. Усі ці дозволи в процесі будуть підсвічені на Flathub (чи в центрі застосунків) як необхідні для роботи програми, і надмірне їх використання без зайвої необхідності може відлякувати юзерів, що не хочуть надавати невідомому застосунку забагато прав доступу. Тому варто їх вказувати тільки тоді, коли програма того дійсно потребує.

### Інтерфейси

Як і у випадку з файловою системою, потрібно також явно оголошувати які саме інтерфейси та сокети потрібні для роботи вашої програми. У більшості випадків, програма потребуватиме доступу до Інтернет, тому для неї вказується запит на `--share=network` або `--share=ipc`, якщо потрібен доступ до спільної пам'яті. Програми на базі серверу X11, потребуватимуть `--socket=x11` і так далі. Все це є в документації:
=> https://docs.flatpak.org/en/latest/sandbox-permissions.html#standard-permissions
тому в рамках даного матеріалу розглядати окремо не будемо.

## Маніфест

Маніфест в контексті Flatpak - це доволі простий, але й водночас - головний текстовий файл у форматі `.yml` або `.json`, у якому вказані:

* платформа та її версія
* SDK
* дозволи програми
* параметри зовнішніх інтерфейсів
* аргументи запуску
* перелік модулів та інструкції для їх послідовної збірки
* інструкції очищення після збірки пакунку

По суті, цього невеличкого файлу достатньо для запуску вашої програми з будь якого пристрою, підключеного до мережі Інтернет, оскільки його зміст вказує тільки на те, звідки завантажити компоненти, яка в них очікувана контрольна сума, та як саме їх зкомпілювати на вказаному у маніфесті середовищі.

Щоб не писати багато, пропоную приклад двох своїх маніфестів:

=> https://github.com/twisterarmy/twister/blob/main/io.github.twisterarmy.twister.json twister p2p
=> https://github.com/kvazar-network/kevacoin/blob/kvazar/io.github.kvazar_network.kevacoin-qt.json KevaCoin

Ви можете обрати будь який інший маніфест, що краще відповідає вимогам саме вашої програми - їх там наразі близько чотирьох тисяч:
=> https://github.com/orgs/flathub/repositories

Вважаю, що розглядати опції в рамках одного матеріалу немає сенсу, оскільки все має бути інтуїтивно зрозуміло для тих, хто цікавиться даною темою. Особисто я не користуюсь жодними CLI утилітами і просто створюю цей файл в ручну для проєкту, для якого планую створити збірку Flatpak. Якщо ви проєктуєте нову програму з нуля, а не портуєте спадковий код вже існуючої програми, то рекомендую базовий патерн https://gitlab.gnome.org/World/Rust/gtk-rust-template, за допомогою якого також можете згенерувати новий десктоп проєкт з CLI утилітою на Python, що постачається в репозиторії.

Для компіляції та встановлення програми з валідного маніфесту, достатньо однієї команди:

``` bash
flatpak-builder --force-clean build\
                --install-deps-from=flathub\
                --install\
                --repo=repo\
                --user\
                org.domain.app-id.json
```
* де `org.domain.app-id.json` - ваш файл маніфесту

## Збірка пакунку

Збірка, або бандл (bundle) - це зкомпільований та оптимізований в реліз файл з розширенням `.flatpak`, який по суті є аналогом пакунку встановлення `.exe` у системах Windows. На відміну від "сирого" маніфесту, де вам потрібно для запуску програми завантажувати первинний код та компілювати його на слабкому залізі, ви можете зробити те само на більш потужному пристрої і передати вже готовий файл збірки на флешці.

Наприклад, щоб зібрати пакунок, з теки, де знаходиться репозиторій маніфесту, виконується команда:

``` bash
flatpak build-bundle repo app-id.flatpak org.domain.app-id.json
```
* `repo` - тека з локальним репозиторієм Flatpak
* `app-id.flatpak` - назва пакунку для генерації
* `org.domain.app-id.json` - файл маніфесту

Цільовий пристрій, на якому запускається файл інсталяції, тільки дозавантажить необхідну платформу, якщо така не була встановлена раніше (при встановленні інших Flatpak застосунків). Для встановлення в користувацький простір (є ще варіант глобального встановлення від `root`)

``` bash
flatpak install --user app-id.flatpak
```
* де `app-id.flatpak` - назва файлу з попереднього кроку

Щоб не передавати пакунки `.flatpak` на флешках (і не тільки) й було створено хостинг Flathub, про який декілька слів нижче!

## Flathub

Flathub - це безкоштовний хостинг для пакунків Flatpak. Утім, не все з ним так просто як може здаватись, оскільки публікація пакунку на даній платформі потребує певного контролю якості та відповідності програми вимогам сервісу.

### Публікація

Суть публікації пакунку на Flathub полягає в створенні форку ініціативного репозиторію (https://github.com/flathub/flathub), в якому створюється окрема гілка для подальшого запиту на додавання (https://github.com/flathub/flathub/pulls).

До PR, окрім файлу маніфесту, додається ще один, схожий до маніфесту файл metainfo (https://docs.flathub.org/docs/for-app-authors/metainfo-guidelines) у форматі XML. Наприклад для twister p2p - він виглядає так
=> https://github.com/twisterarmy/flathub/blob/twister-bundle/io.github.twisterarmy.twister.metainfo.xml
* а саме: містить назву, опис проєкту, версію збірки а також скріншоти та деяку іншу інформацію, необхідну для коректного відображення на сайті каталогу.

Після модерації, ваш проєкт буде (або не буде) розміщено в офіційному списку постачальників (https://github.com/orgs/flathub/repositories) Flathub, а вам (у разі схвалення) - надано статус майнтейнера до відповідного репозиторію для його подальших оновлень.

Опціонально, постачальники можуть отримати верифікований статус та інші фічі для подальшого просування власного проєкту.

### Вимоги до публікації

Основною вимогою до усіх застосунків Flathub є наявність графічного інтерфейсу (GUI). Веб-інтерфейс (як у випадку з twister p2p) і тим паче CLI тут не проходять і модератори вимагатимуть від вас або веб-фрейм або лаунчер, по типу Steam. Веб-фрейми мені не подобаються, оскільки надаю перевагу браузеру. Саме тому, проєкт twister p2p я там досі не опублікував і пішов робити twister-control-center на базі GTK 4:
=> https://github.com/twisterarmy/twister-control-center
та додаткової ліби rust-twistercore-rpc:
=> https://github.com/twisterarmy/rust-twistercore-rpc
порт якої навіть не знаю коли завершу і чи завершу взагалі.

Натомість файл `.flatpak`, який просто запускає демон і відкриває вікно в браузері через `xdg-open`, було розміщено на GitHub, в розділі стабільних релізів:
=> https://github.com/twisterarmy/twister/releases/download/0.1.1/twister.flatpak

По-друге, модератори можуть приколупатись до заміни інструкцій `simple` на `autotools`. Це не зважаючи на те, що майже всі вже додані до їх репозиторію проєкти мають `make` в своїй імплементації. Звісно можна переписати, але я користуюсь офіційними інструкціями для модулів і мені ані цікаво, ані виглядає краще з їх побажанками у маніфесті.

По-третє, якщо з вимогами GUI чи оптимізацією команд маніфесту, модераторів можна зрозуміти, то таке явище як зміна сортування деяких (не array) елементів в маніфесті - для мене загадка. Наприклад, перенести `finish-args` на початок файлу (коли до цього конструкція була внизу) або побажання доопрацювати інструкції очищення `cleanup` при цьому не надаючи конкретних файлів, які не влаштовують.

Коротше таке, я спробував, але не в моїх інтересах туди пробиватись, для мене головне, щоб юзер міг скачати. Наразі він може зробити це на GitHub, в розділі релізів. Можливо, повернусь до питань модерації через рік-другий :) З іншого боку, може це й на краще, оскільки проєкт Flathub орієнтований на десктоп користувачів, і це мотивує програмістів створювати більш якісний контент, аніж публікація різноманітного сміття, як це часто відбувається на crates, packagist, npm - де взагалі ручна модерація відсутня.

## Висновки

В принципі, мій перший досвід виявився позитивним, після збірки вже другої програми, подумую над іншими проєктами, оскільки перевстановлюю системи часто і кожного разу доводиться звідкись збирати чи то Berkeley DB чи то Boost, або стару версію Qt. Тут же я можу просто зібрати пакунок на робочій станції і потім легко поставити його на будь якому пристрої та операційній системі, наприклад на слабкому ноутбуці не від'їдаючи батарею.

Сподіваюсь, матеріал буде комусь корисним, можливо щось згадаю то доповню!