Building a Flatpak

What is it about? #

I’ve been a proponent of Flatpaks since Fedora, because they actually run stress-free on every distribution without having to add additional package sources. Also, if you rely on a stable system like Debian, but still want to run more up-to-date applications than the package sources offer, Flatpak is excellent.

Since Fedora Silverblue or openSUSE MicroOS, Immutable Distributions are getting more interesting, because they offer some advantages and in my opinion are the right way to make GNU/Linux more attractive on the desktop. Flatpak is ideal as a software center for typical desktop applications without losing the distribution diversity.

Despite the extensive support, not all applications are available on Flathub. Technically, any application can be packaged as a Flatpak, but there is a lack of volunteers to cover the huge variety.

So that I can also give something back to the FLOSS community, I took a look at the newsreader SABnzbd. On the download page there are already some packages, including an RPM package, which requires the inclusion of a third party source. However, the version stored there is older than the current one and the repository was officialy created for Fedora 33.

How to begin? #

The official Flatpak documentation offers a good first start, which sounds quite simple at first: Build your first Flatpak.

Unfortunately the help is not sufficient for more extensive applications, since probably few want to package a shell script. Here is my summary and procedure for the packaging of SABnzbd. A more detailed information (naming conventions etc.) can be read in the official documentation.

Install environment (latest version 22.08) #

  1. First install Flatpak itself

  2. Install runtimes in the latest version 22.08:

flatpak install flathub org.freedesktop.Platform//22.08 org.freedesktop.Sdk//22.08

I decided to use the latest version, because some Python runtimes are more recent here. This avoids conflicts I ran into before, more on that later.

  1. Create files
mkdir flatpak-sabnzbd
cd flatpak-sabnzbd
touch org.sabnzbd.SABnzbd.yml
  1. Download Linux tarball and output hash value
wget https://github.com/sabnzbd/sabnzbd/releases/download/3.6.1/SABnzbd-3.6.1-src.tar.gz
sha256sum SABnzbd-3.6.1-src.tar.gz

org.sabnzbd.SABnzbd.yml #

Basically all the magic happens in the org.sabnzbd.SABnzbd.yml. Instead of YAML you can also use JSON, I chose the former because of readability.

nano org.sabnzbd.SABnzbd.yml
id: org.sabnzbd.SABnzbd
command: SABnzbd.py
runtime: org.freedesktop.Platform
runtime-version: '22.08'
sdk: org.freedesktop.Sdk
modules:
- name: sabnzbdplus
  buildsystem: simple
  build-commands:
  sources:
    - type: archive
      url: https://github.com/sabnzbd/sabnzbd/releases/download/3.6.1/SABnzbd-3.6.1-src.tar.gz
      sha256: e365e4581c594aac445b9fb229aa80c0a1ed299deca511045bb78bd55d2ece9e

This is how the basic structure would look like with customized values. SABnzbd is a Python application, so we will run SABnzbd.py.

As build system there are several options to choose from, I chose buildsystem: simple here. When we build the package, the archive is automatically unpacked.

However, we can’t do much with the config until now, so we complete the whole thing as follows:

id: org.sabnzbd.SABnzbd
command: SABnzbd.py
runtime: org.freedesktop.Platform
runtime-version: '22.08'
sdk: org.freedesktop.Sdk
finish-args:
  - --socket=x11
  - --share=ipc
  - --share=network
  - --talk-name=org.freedesktop.Notifications
  - --talk-name=org.kde.StatusNotifierWatcher
  - --filesystem=xdg-download
modules:
- name: sabnzbdplus
  buildsystem: simple
  build-commands:
   - cp -r * /app/bin/
  sources:
    - type: archive
      url: https://github.com/sabnzbd/sabnzbd/releases/download/3.6.1/SABnzbd-3.6.1-src.tar.gz
      sha256: e365e4581c594aac445b9fb229aa80c0a1ed299deca511045bb78bd55d2ece9e

Since Flatpak runs the applications isolated, we need to give some permissions in the finish-args field. The selected build system asks us for commands, I just said here that the unpacked content should be placed under /app/bin, which is the Flatpak program directory. Since SABnzbd does not need to be compiled, this fits so far.

We can trigger the build process and installation as follows:

flatpak-builder build-dir org.sabnzbd.SABnzbd.yml
flatpak-builder --user --install --force-clean build-dir org.sabnzbd.SABnzbd.yml
flatpak run org.sabnzbd.SABnzbd.yml

However, if we start the package, we get error messages because some Python dependencies are missing:

$ flatpak run org.sabnzbd.SABnzbdtut 
Not all required Python modules are available, please check requirements.txt
Missing module: Cheetah
You can read more at: https://sabnzbd.org/wiki/installation/install-off-modules
If you still experience problems, remove all .pyc files in this folder and subfolders

Install dependencies #

Since SABnzbd comes with some dependencies, it would be very time consuming to enter all the Python modules manually in the .yml config, so we use a more elegant way.

To find out which dependencies we need at all, we unpack the SABnzbd-3.6.1-src.tar.gz. There you will find a list of all dependencies in requirements.txt.

With the help of a Python application you can create an automatically generated config file, which generates all dependencies, including URL/hash value: flatpak-pip-generator

The generator will be downloaded and executed:

wget https://github.com/flatpak/flatpak-builder-tools/blob/master/pip/flatpak-pip-generator
python3 flatpak-pip-generator --requirements-file=requirements.txt

After a few seconds we get a python3-requests.json, here is an excerpt:

{
    "name": "python3-requirements",
    "buildsystem": "simple",
    "build-commands": [],
    "modules": [
        {
            "name": "python3-sabyenc3",
            "buildsystem": "simple",
            "build-commands": [
                "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"sabyenc3==5.4.3\" --no-build-isolation"
            ],
            "sources": [
                {
                    "type": "file",
                    "url": "https://files.pythonhosted.org/packages/c3/21/30c4111f7ad9188229b5c21f04881f845a507904cb8717368f79a4bfb845/sabyenc3-5.4.3.tar.gz",
                    "sha256": "7a2fd29d58383b2e9c0413f1835e2530c40181b351e0583469afbcb150536346"
                }
            ]
        },
        {
            "name": "python3-cheetah3",
            "buildsystem": "simple",
            "build-commands": [
                "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"cheetah3==3.2.6\" --no-build-isolation"
            ],
            "sources": [
                {
                    "type": "file",
                    "url": "https://files.pythonhosted.org/packages/ee/6f/29c6d74d8536dede06815eeaebfad53699e3f3df0fb22b7a9801a893b426/Cheetah3-3.2.6.tar.gz",
                    "sha256": "f1c2b693cdcac2ded2823d363f8459ae785261e61c128d68464c8781dba0466b"
                }
            ]
        },
[...]

We now include this in our org.sabnzbd.SABnzbd.yml config:

id: org.sabnzbd.SABnzbd
command: SABnzbd.py
runtime: org.freedesktop.Platform
runtime-version: '22.08'
sdk: org.freedesktop.Sdk
finish-args:
  - --socket=x11
  - --share=ipc
  - --share=network
  - --talk-name=org.freedesktop.Notifications
  - --talk-name=org.kde.StatusNotifierWatcher
  - --filesystem=xdg-download
modules:
- python3-requirements.json
- name: sabnzbdplus
  buildsystem: simple
  build-commands:
   - cp -r * /app/bin/
  sources:
    - type: archive
      url: https://github.com/sabnzbd/sabnzbd/releases/download/3.6.1/SABnzbd-3.6.1-src.tar.gz
      sha256: e365e4581c594aac445b9fb229aa80c0a1ed299deca511045bb78bd55d2ece9e

We restart the build process, which takes a little longer for the first time:

rm -r build-dir/
flatpak remove org.sabnzbd.SABnzbd -y
flatpak-builder build-dir org.sabnzbd.SABnzbd.yml
flatpak-builder --user --install --force-clean build-dir org.sabnzbd.SABnzbd.yml

And run our application again to be greeted by the following error message:

$ flatpak run org.sabnzbd.SABnzbd.yml
[...]
2022-10-23 22:23:25,101::ERROR::[SABnzbd:450] par2 binary... NOT found!
2022-10-23 22:23:25,102::ERROR::[SABnzbd:465] unrar binary... NOT found!
2022-10-23 22:23:25,102::INFO::[SABnzbd:475] 7za binary... NOT found!
[...]

Install other dependencies #

par2 binary #

Source:
https://github.com/flathub/org.gnome.FileRoller/blob/master/org.gnome.FileRoller.json
https://github.com/Parchive/par2cmdline

- name: gnustep-make
  buildsystem: simple
  build-commands:
    - ./configure --prefix=/app
    - make -j $FLATPAK_BUILDER_N_JOBS install
  sources:
    - type: archive
      url: https://github.com/gnustep/tools-make/releases/download/make-2_9_0/gnustep-make-2.9.0.tar.gz
      sha256: a0b066c11257879c7c85311dea69c67f6dc741ef339db6514f85b64992c40d2a
      
- name: gnustep
  buildsystem: simple
  build-commands:
    - ./configure --prefix=/app
    - make -j $FLATPAK_BUILDER_N_JOBS install
    - ls /app/include
  sources:
    - type: archive
      url: https://github.com/gnustep/libs-base/releases/download/base-1_28_0/gnustep-base-1.28.0.tar.gz
      sha256: c7d7c6e64ac5f5d0a4d5c4369170fc24ed503209e91935eb0e2979d1601039ed

- name: unrar
  buildsystem: simple
  build-commands:
    - make
    - cp ${PWD}/unrar /app/bin/
  sources:
    - type: archive
      url: https://www.rarlab.com/rar/unrarsrc-6.1.7.tar.gz
      sha256: de75b6136958173fdfc530d38a0145b72342cf0d3842bf7bb120d336602d88ed

unrar binary #

Source:
https://www.linuxfromscratch.org/blfs/view/svn/general/unrar.html

- name: par2
  buildsystem: simple
  build-commands:
    - ./configure --prefix=/app
    - make
    - cp ${PWD}/par2 /app/bin/    
  sources:
    - type: archive
      url: https://github.com/Parchive/par2cmdline/releases/download/v0.8.1/par2cmdline-0.8.1.tar.gz
      sha256: 7b2fcc19b54c7080939fc2cbaca33ae40ac33759a526292933c94a85ba850d11

7za binary #

Source:
https://github.com/flathub/io.github.peazip.PeaZip/blob/master/formats/7-zip.yml

- name: 7-zip
  buildsystem: simple
  build-commands:
    - |
      for bundle in Alone2 SFXCon; do
        pushd CPP/7zip/Bundles/${bundle}
        make -j ${FLATPAK_BUILDER_N_JOBS} -f ../../cmpl_gcc.mak
        popd
      done
    - install -Dm755 CPP/7zip/Bundles/Alone2/b/g/7zz   $FLATPAK_DEST/bin/7z
    - install -Dm755 CPP/7zip/Bundles/SFXCon/b/g/7zCon $FLATPAK_DEST/bin/7zCon.sfx
  sources:
    - type: archive
      strip-components: 0
      url: https://7-zip.org/a/7z2201-src.tar.xz
      sha256: 393098730c70042392af808917e765945dc2437dee7aae3cfcc4966eb920fbc5

Icons und Appinfos #

In order to get a decent launcher with icon, we need to make some adjustments here. I have oriented myself to already existing Flatpaks from GitHub.

 build-commands:
   - cp -r * /app/bin/
   - install -Dm644 ${PWD}/linux/org.sabnzbd.sabnzbd.appdata.xml /app/share/appdata/$FLATPAK_ID.xml
   - install -Dm644 ${PWD}/icons/logo-arrow.svg /app/share/icons/hicolor/scalable/apps/$FLATPAK_ID.svg
   - install -Dm644 ${PWD}/linux/sabnzbd.desktop /app/share/applications/$FLATPAK_ID.desktop
   - desktop-file-edit --set-icon=${FLATPAK_ID} /app/share/applications/${FLATPAK_ID}.desktop
   - sed -i 's|Exec=/opt/sabnzbd/SABnzbd.py --browser 1 %F|Exec=SABnzbd.py|g' /app/share/applications/${FLATPAK_ID}.desktop

Final config #

org.sabnzbd.SABnzbd.yml

id: org.sabnzbd.SABnzbd
command: SABnzbd.py
runtime: org.freedesktop.Platform
runtime-version: '22.08'
sdk: org.freedesktop.Sdk
finish-args:
  - --socket=x11
  - --share=ipc
  - --share=network
  - --talk-name=org.freedesktop.Notifications
  - --talk-name=org.kde.StatusNotifierWatcher
  - --filesystem=xdg-download
modules:
- python3-requirements.json

- name: gnustep-make
  buildsystem: simple
  build-commands:
    - ./configure --prefix=/app
    - make -j $FLATPAK_BUILDER_N_JOBS install
  sources:
    - type: archive
      url: https://github.com/gnustep/tools-make/releases/download/make-2_9_0/gnustep-make-2.9.0.tar.gz
      sha256: a0b066c11257879c7c85311dea69c67f6dc741ef339db6514f85b64992c40d2a
      
- name: gnustep
  buildsystem: simple
  build-commands:
    - ./configure --prefix=/app
    - make -j $FLATPAK_BUILDER_N_JOBS install
    - ls /app/include
  sources:
    - type: archive
      url: https://github.com/gnustep/libs-base/releases/download/base-1_28_0/gnustep-base-1.28.0.tar.gz
      sha256: c7d7c6e64ac5f5d0a4d5c4369170fc24ed503209e91935eb0e2979d1601039ed

- name: unrar
  buildsystem: simple
  build-commands:
    - make
    - cp ${PWD}/unrar /app/bin/
  sources:
    - type: archive
      url: https://www.rarlab.com/rar/unrarsrc-6.1.7.tar.gz
      sha256: de75b6136958173fdfc530d38a0145b72342cf0d3842bf7bb120d336602d88ed

- name: par2
  buildsystem: simple
  build-commands:
    - ./configure --prefix=/app
    - make
    - cp ${PWD}/par2 /app/bin/    
  sources:
    - type: archive
      url: https://github.com/Parchive/par2cmdline/releases/download/v0.8.1/par2cmdline-0.8.1.tar.gz
      sha256: 7b2fcc19b54c7080939fc2cbaca33ae40ac33759a526292933c94a85ba850d11

- name: 7-zip
  buildsystem: simple
  build-commands:
    - |
      for bundle in Alone2 SFXCon; do
        pushd CPP/7zip/Bundles/${bundle}
        make -j ${FLATPAK_BUILDER_N_JOBS} -f ../../cmpl_gcc.mak
        popd
      done
    - install -Dm755 CPP/7zip/Bundles/Alone2/b/g/7zz   $FLATPAK_DEST/bin/7z
    - install -Dm755 CPP/7zip/Bundles/SFXCon/b/g/7zCon $FLATPAK_DEST/bin/7zCon.sfx
  sources:
    - type: archive
      strip-components: 0
      url: https://7-zip.org/a/7z2201-src.tar.xz
      sha256: 393098730c70042392af808917e765945dc2437dee7aae3cfcc4966eb920fbc5

- name: sabnzbdplus
  buildsystem: simple
  build-commands:
   - cp -r * /app/bin/
   - install -Dm644 ${PWD}/linux/org.sabnzbd.sabnzbd.appdata.xml /app/share/appdata/$FLATPAK_ID.xml
   - install -Dm644 ${PWD}/icons/logo-arrow.svg /app/share/icons/hicolor/scalable/apps/$FLATPAK_ID.svg
   - install -Dm644 ${PWD}/linux/sabnzbd.desktop /app/share/applications/$FLATPAK_ID.desktop
   - desktop-file-edit --set-icon=${FLATPAK_ID} /app/share/applications/${FLATPAK_ID}.desktop
   - sed -i 's|Exec=/opt/sabnzbd/SABnzbd.py --browser 1 %F|Exec=SABnzbd.py|g' /app/share/applications/${FLATPAK_ID}.desktop
  sources:
    - type: archive
      url: https://github.com/sabnzbd/sabnzbd/releases/download/3.6.1/SABnzbd-3.6.1-src.tar.gz
      sha256: e365e4581c594aac445b9fb229aa80c0a1ed299deca511045bb78bd55d2ece9e

How to build #

flatpak install flathub org.freedesktop.Platform//22.08 org.freedesktop.Sdk//22.08
flatpak-builder build-dir org.sabnzbd.SABnzbd.yml
flatpak-builder --user --install --force-clean build-dir org.sabnzbd.SABnzbd.yml
flatpak run org.sabnzbd.SABnzbd

Feel free to contribute or clone the code in my GitHub repository.