Flatpak-pakketten voor Linux zelf maken
Software eenvoudig installeren op alle distributies: het Flatpak-pakketformaat heeft veel voordelen. We laten zien hoe je zo’n softwarepakket zelf bouwt en inzet aan de hand van het voorbeeld van een kleine nieuwslezer.
De dagen dat je voor elke Linux-distributie een apart softwarepakket moest maken zijn voorbij. Om een zelfgeschreven programma beschikbaar te maken voor zoveel mogelijk Linux-varianten en hun verschillende versies, maak je er gewoon een Flatpak-pakket van. Op veel Linux-systemen – inclusief Linux Mint – is al support voor het pakketformaat aanwezig. Bij alle andere kan het snel worden toegevoegd.
Een Flatpak bevat de bibliotheken die nodig zijn om het te draaien, zodat hij niet in conflict komt met versies die al op het systeem staan. De Linux-community stimuleert het pakketformaat met steun van RedHat, het Fedora-team en het
Gnome-project. Beschikbaar gestelde build-tools helpen om je eigen software in te pakken.
COMPLEET ONTZORGD
Naast de eigenlijke toepassing bevatten Flatpak-pakketten alle componenten die nodig zijn om een programma te starten – naast de bibliotheken ook pictogrammen en afbeeldingen. Alleen de Linux-kernel zit er niet in. De verpakte applicatie draait dus op alle distributies die het Flatpak-formaat ondersteunen. Dat betekent wel dat de pakketten iets groter zijn dan de versies uit de pakketbronnen van de distributies.
Om de ruimtebehoefte te verminderen, vertrouwt Flatpak onder meer op zogeheten runtimes. Die pakketten bevatten vaak componenten die bij veel Flatpaks gebruikt worden, bijvoorbeeld in de Gnome-bibliotheken. Elk Flatpak-pakket maakt gebruik van tenminste één runtime, waarvan er meerdere in verschillende versies parallel geïnstalleerd kunnen zijn. Als ontwikkelaar heb je de vrije keuze. Heeft je programma andere biblio
theken nodig die ontbreken in de runtime, dan komen die ook allemaal in het Flatpak-pakket terecht.
Om ervoor te zorgen dat gebruikers de afzonderlijke pakketten niet op internet bij elkaar moeten vissen, zijn er Flatpak-repository’s zoals Flathub, dat door de Flatpak-community geëxploiteerd wordt. De pakketbeheerders halen ook de runtimes uit die repository. Ontwikkelaars hoeven zich nauwelijks zorgen te maken over de beschikbaarheid, want de meeste huidige distributies bevatten standaard de Flathub-repository.
AFGESLOTEN
De programma’s in Flatpak-pakketten draaien afgeschermd van elkaar, elk in een eigen sandbox, vergelijkbaar met een Docker-container. Het programma ziet alleen zijn eigen minimale Linuxsysteem en heeft niet makkelijk toegang tot de rest van de computerbronnen. Flatpak stelt de sandbox samen uit de gekozen runtime en de inhoud van het Flatpak-pakket. Ontwikkelaars hoeven zich niet te bekommeren over de technieken die op de achtergrond gebruikt worden. Je kunt daar in [1] meer informatie over lezen.
In he volgende voorbeeld laten we zien hoe je Flatpak-pakketten kunt bouwen, met als voorbeeld het Python-script newsfeed.py. Je hoeft geen Python te kennen om het voorbeeld te volgen, de paar regels van het script zijn redelijk duidelijk: import feedparser newsfeed = feedparser.parse( "https://»www.ct.nl/rss")
for i in range(0,5): entry = newsfeed.entries[i] print(entry.title.encode(‹ ›'ascii', 'replace'))
Die code haalt de nieuwsfeed van onze website op en print de koppen van de eerste vijf nieuwsberichten. Daar gebruikt het script de feedparserbibliotheek voor, die dus niet mag ontbreken in het pakket. Je kunt hem lokaal installeren met pip install feedparser. Het commando python3 newsfeed.py start de feedreader, dus moet de container ook een Python-omgeving bieden.
VOORBEREIDEND WERK
Om van de feedreader een Flatpak-pakket te maken, moet je eerst een unieke naam voor je toepassing bedenken. De app-ID moet het schema org.company.appname volgen. Helemaal achteraan staat de naam van de app, en in het midden de naam van de ontwikkelaar. De Flatpak-makers adviseren om de eerste twee componenten te kiezen uit een domeinnaam die eigendom is van de ontwikkelaar. Daarom noemen we de te verpakken toepassing in dit geval nl.ct.newsfeed.
Zorg er voor dat je distributie met Flathubrepository werkt:
flatpak remote-add --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo
Het bouwen van een Flatpak-pakket wordt gedaan door de tool flatpak-builder. Bij de meeste distributies is die al geïnstalleerd of kun je hem toevoegen via het softwarebeheer – bij Ubuntu bijvoorbeeld met sudo apt install flatpak flatpak-builder. Je kunt de tool ook als Flatpak-pakket installeren: flatpak install flathub org.flatpak.Builder
RUNTIME NEXT
Je hebt een geschikte runtime nodig. In het eenvoudigste geval volstaat org.freedesktop. Platform, dat basisbibliotheken zoals D-Bus, GLib, Gtk3, PulseAudio, X11, Wayland en een Python-omgeving biedt. De runtime org.gnome. Platform is voor alle Gnome-ontwikkelaars, KDE-Plasma programmeurs gebruiken org.kde. Platform. Als je je applicatie wilt vastpinnen op een specifieke versie van de runtime, voeg dan het nummer gescheiden door twee schuine streepjes toe aan de App-ID. Met org.freedesktop.Platform//20.08 krijg je de op dit moment laatste versie 20.08 van de runtime org.freedesktop. Platform.
De flatpak-builder maakt een sandbox met de geselecteerde runtime en compileert daar je broncode in. Om een programma te compileren is er voor elke runtime een SDK met alle ontwikkelaarsbestanden, compilers en debuggers. Dus tenzij je een shell-script in een Flatpak-pakket gaat zetten, heb je ook de SDK nodig.
Het volgende commando installeert zowel de runtime org.freedesktop.Platform//20.08 als de SDK: flatpak install flathub org.freedesktop. Platform//20.08 org.freedesktop.Sdk//20.08
INFORMATIE IN HET MANIFEST
Hoe flatpak-builder een programma moet compileren staat gedefinieerd in een manifestbestand
dat alle instellingen in JSON-formaat bevat. De bestandsnaam is de App-ID met de extensie .json. In het voorbeeld is dat nl.ct.newsfeed.json.
Maak een nieuw bestand aan en sla het op in de projectmap. De listing op een van de volgende pagina’s toont de inhoud van het bestand voor ons voorbeeld. Laat je niet afschrikken door de hoeveelheid aan informatie, het ziet er allemaal erger uit dan het is.
Je kunt de instellingen ook in YAML-formaat opslaan, maar in de documentatie van Flatpak wordt overal de JSON-notatie gebruikt, net als in het voorbeeld.
Het JSON-bestand bevat bovenaan wat basisinformatie: de app-id, de te gebruiken runtime
en de versie daarvan (achter runtime-version).
Als je de versie weglaat, pakt Flatpak de meest recente versie. Je moet de sdk ook benoemen.
Wanneer de applicatie later wordt gestart met flatpak run nl.ct.newsfeed, voert Flatpak het programma achter command in de sandbox uit. Flatpak verwacht daar precies één programmabestand zonder verdere parameters. De programma-oproep voor het Python-script is echter python3 newsfeed.py, dus moet je dat in een shell-script zetten. In het voorbeeld wordt die taak uitgevoerd door het bestand run.sh. Wanneer een gebruiker de newsfeed-applicatie oproept, start Flatpak dat script in de sandbox, dat vervolgens python3 newsfeed.py uitvoert. Je kunt het script run.sh zelf maken en aan het project toevoegen, of het aan de flatpak-builder overlaten om het te maken – waarover zo meer.
Flatpak sluit je programma op in een sandbox zodat het geen toegang heeft tot het hostsysteem. Onze voorbeeldtoepassing moet de nieuwsfeed echter van internet halen en heeft daarvoor toegang tot het netwerk nodig. Je geeft daar toestemming voor bij finish-args. De specificatie --share=network zorgt ervoor dat de applicatie via het netwerk mag communiceren. Een lijst met alle mogelijke extra rechten is te vinden in de Flatpak-documentatie – zie de link op de laatste pagina van dit artikel.
WAT MOET ER IN HET PAKKET
Vaak bestaat een applicatie uit meerdere onderdelen, zoals bibliotheken en afbeeldingen. Bij flatpak-builder heten die componenten modules. In het manifestbestand kun je bij modules meerdere modules opgeven die flatpak-builder automatisch bouwt. Ten minste één module moet daarbij het hoofdprogramma genereren.
In het voorbeeld bestaat de newsfeed-reader uit het bestand newsfeed.py en de bibliotheek feedparser. Daarom is er voor beide een aparte sectie in het manifestbestand onder module. Begin met de module voor newsfeed.py:
"name": "newsfeed",
"sources": [
{
"type": "file", "path": "newsfeed.py" },
Net als elke andere module krijgt hij een vrij te kiezen naam achter name. In het voorbeeld is dat gewoon newsfeed. Welke bestanden er allemaal bij de module behoren staat in de listing onder sources. Elk van de daar tussen haakjes vermelde bronnen heeft een type. In het voorbeeld is dat het bestand (file) newsfeed.py, dat door flatpak-builder naar de sandbox moet worden gekopieerd. Een volledige directory wordt in één keer overgenomen door het type dir. Je kunt flatpak-builder op dat punt ook een shell-script laten genereren, bijvoorbeeld met
{
"type": "script", "dest-filename": "run.sh", "commands": [ "python3 /app/bin/newsfeed.py"
] }
Dat creëert het shell-script met de bestandsnaam run.sh met daarin de achter commands vermelde commando’s. In het voorbeeld is dat slechts het uitvoeren van python3 /app/bin/newsfeed.py,
dat later de newsfeed-reader start. De directory-specificatie /app/bin is met opzet: je applicatie zal later een compleet Linux-bestandssysteem in de sandbox zien volgens de Filesystem Hierarchy Standard. Het programma zelf bevindt zich daarbij altijd in de directory /app en diens subdirectory’s.
Binaire programma’s horen thuis in de map /app/bin, die Flatpak later automatisch opneemt in de omgevingsvariabele $PATH en dus in het zoekpad. Ook newsfeed.py hoort thuis in de map /app/bin.
Hoe flatpak-builder de broncode van een module moet compileren en naar de juiste plaats moet kopiëren, wordt gedefinieerd in het buildsystem-gedeelte van het manifest: "buildsystem": "simple", "build-commands": [
"install -D newsfeed.py/app/bin/newsfeed.py",
"install -D run.sh /app/bin/run.sh" ]
Als daar simple staat, roept flatpak-builder eenvoudigweg de commando’s onder build-commands op.
Het voorbeeld kopieert alleen newsfeed.py en het shell-script run.sh naar de sandbox naar de juiste positie in /app/bin.
ARCHIEF OPNIEUW LADEN
Voor de newsfeed-reader in dit voorbeeld heb je nog steeds de bibliotheek feedparser nodig, die de tweede module downloadt:
"name": "python-feedparser", "sources": [{
"type": "archive",
"url": "https://files.pythonhosted.org/.../ feedparser-5.2.1.tar.gz",
"sha256": "bd03..." } ],
Daarbij kan flatpak-builder niet alleen met bestanden overweg, maar ook tar- en zip-archieven downloaden en automatisch uitpakken in de