Introduction
Hey everyone,
I recently joined Codethink and I am contributing to the improvements being made to GNOME OS, through the Sovereign Tech Fund (STF), to make it easier and more useful in day-to-day development and testing tasks, among other things.
For those who haven’t heard of GNOME OS, it’s an immutable Linux distribution that ships the latest in-development GNOME desktop, core applications, and stack, aimed at developers and testers.
An overview of what we’re proposing here is the following:
- A story that would allow developers to hack and test system components in a more efficient and safer way.
- An utility that would make that story compelling.
Ultimately, we want these improvements to be useful to all other immutable and non-immutable OSes out there.
Rationale
In case you missed it, Jordan Petridis previously shared an insightful blog post about developing software on immutable OSes. A rough summary would be the following: on the applications development front, we’re in a pretty good shape thanks to Flatpak. Unfortunately, not so much on the system components development front.
Luckily, as Jordan’s demonstrates, there’s an alternative thanks to systemd-sysext which allow us to extend the host /usr
with system extensions images, while keeping all the benefits of an immutable OS intact.
Therefore, we’re currently working on this proposal around systemd-sysext in hopes that it would bring the system components development experience closer to the applications.
The proposal looks roughly like this:
- Spin an instance of GNOME OS and pull all the core development tools (if you haven’t already).
- Hack system components and build a sysext image out of those.
- Deploy the sysext image and tests these components (alternatively, deploy these to a GNOME OS virtual machine).
- Share that sysext image with others to try it out (if you have a need for that).
- Remove the sysext image, forget these changes ever happened and smile at the that fact you didn’t have to build an entire OS.
Given the success of Flatpak, this proposal draws some conceptual parallels to it, where GNOME OS acts as the Platform and Sdk runtimes, while a sysext image acts as the application bundle.
Sample scenarios
This proposal is primarily aimed at system components, e.g., mutter, GNOME Shell, etc.
- As a mutter developer, I want to develop and test my changes on cutting-edge components like a newer version of wayland.
- As a GNOME Shell developer, I want to develop and test my changes on cutting-edge components like a newer version of systemd.
All the above while working on an immutable OS like GNOME OS, and without the risk of breaking it permanently.
State of the art
The recommended way in which these system components are developed and tested is through the use of Toolbx, see the following examples:
Unfortunately, the Toolbx approach alone is not sufficient for those scenarios described above. At least not in a way that isn’t painful. Thus, there’s a need for alternatives.
Pieces of a proposal
The proposal being presented here is built on top of previous improvements to GNOME OS e.g., switching to systemd-sysupdate and enabling the development tree as a sysext, other systemd features like systemd-repart and systemd-importctl, BuildStream and other common tools for building software for GNOME.
Putting these pieces together
To understand how these pieces fit together, let’s go through different aspects of this proposal.
What would be the development environment?
The primary option in this proposal is to use the regular version of GNOME OS, plus the development tree sysext, which comes with all the development dependencies to build any core GNOME project.
The fact that the development tree sysext comes with Toolbx provides extra flexibility, and is what many of us using immutable OSes have already been doing for the last few years.
Talking about containers, there’s also the core GNOME OS OCI which would be useful in scenarios where building the sysext images occurs elsewhere, like in continuous integration pipelines.
How do we build things?
Having the development tree sysext ensures that we’re provided with all core dependencies and tools to build any GNOME project. Of course, that doesn’t account for anything else. But that’s another reason for having Toolbx around.
In any case, the developer can use BuildStream and checkout the artifacts, or clone a particular core GNOME repository and build it manually with meson plus a custom DESTDIR
.
Besides the artifacts we build e.g, mutter artifacts, what we would be ultimately building are sysext images that can extend the host. As noted by Jordan, having a single image file would make things easier to manage. Specially in near-future scenarios related to continuous integration (keeping that parallel to Flatpak in mind, imagine flatpak-github-actions or Flathub’s build bot).
Building these images could be done with an extended version of Jordan’s snippet, a proof of concept for gnome-build-meta (which uses systemd-repart to build the images), or even a combination of both.
Ultimately, what we want is some form of:
$ cli-tool build-sysext <name> </path/to/input/artifact/> </path/to/output/images/>
An example using BuildStream would look like the following:
$ bst build sdk/gtk.bst
$ bst artifact checkout --deps=none --directory sdk/gtk/
$ cli-tool build-sysext gtk ./sdk/gtk/ .
$ ls gtk.sysext.raw
How do we run what we build?
This one is simple. Once the host has been extended with the sysext images, the developer can access these artifacts in the exact same way they would access any other component of the host system. In fact, there’s no distinction at that point.
How do we manage these sysext images?
Once a sysext image is created, it does not take much to import it. See the following example:
$ importctl import-raw --class=sysext gtk.sysext.raw gtk
$ systemd-sysext refresh
Similarly, to remove it:
$ rm /var/lib/extensions/gtk.raw
$ systemd-sysext refresh
Although these steps might not seem like much, it would quickly become tedious. Specially when considering other details like pulling images from remote locations and handling integration steps like recompiling schemas, etc.
Therefore, similarly to the image building step, we could consider other ways to automate these details behind something in the form of:
$ cli-tool add-sysext gtk.sysext.raw
$ cli-tool remove-sysext gtk
A developer story
Putting together all what was mentioned above, a more detailed proposal looks like this:
- A developer installs the sysupdate version of GNOME OS.
- Turns that installation in to a development environment by using systemd-sysupdate to import the development tree sysext.
- Having all the development tools available, the developer would build their projects in a way that finds most convenient.
- Once the artifacts are available, the developer would make use of
$ cli-tool build-sysext
to obtain a sysext image. - Then, the developer would run
$ cli-tool add-sysext
to test these artifacts from host itself. - Lastly, the developer removes the sysext image by running
$ cli-tool remove-sysext
.
An early proof of concept for this proposal is being reviewed in gnome-build-meta MR #2886.
What else could be done?
Given that the $ cli-tool
mentioned here only covers steps related to the creation and management of these sysext images, I wonder if more is needed to make that story compelling.
E.g., should we cover the artifacts building steps behind something in the form of:
$ cli-tool build-artifact /path/to/output/artifact/ bst ...
$ cli-tool build-artifact /path/to/output/artifact/ meson ...
Something completely different perhaps?
Your feedback is needed
I have been reaching out to some you for different types of feedback related to this, and I am also sharing this proposal here in hopes that it would reach to even more of you.
Your thoughts and ideas would help greatly to set this project on the right track.
You can also follow curent discussions and progress on gnome-build-meta, issues #819 and #825.