I Walked Right Into the YAML Trap

Today I was creating a Flatpak version of a simple digital painting application that I developed last year, and I walked right into a notorious pitfall that YAML has. Usually these are the kind of silly issues that can cost hours, but thankfully, this time it became apparent within a couple of seconds and left me with an interesting post to share.

Vara is a minimalist digital painting application that has support for pressure-sensitive brushes. I developed a fairly useful version of it last year within a month, as a technology demonstration of nguigen, one of my other projects. I had provided binary tarballs and .deb files right away, as I always do. Then I stopped working on Vara for a while because I had to shift my focus back to some other projects as well as my academic activities.

Recently I became in a position to revisit the project, and realized it was a perfect opportunity to gain hands-on experience on relatively new packaging methods like Flatpak and Snap. I do not have any comments on the technical pros and cons of these compared to the traditional methods for the time being, but I believe that getting your application on places like Flathub and Snap Store is important in reaching a wider Desktop GNU/Linux userbase.

The Process

I started experimenting with Flatpak building inside Fedora 40 with GNOME inside a VM created using virt-manager. I created a VM because in my experience, Fedora is the best distro to do cutting-edge Gtk/GNOME development. The packages are up-to-date and the whole experience is smooth compared to Debian or even Ubuntu. This was the first time I used virt-manager; I usually use KVM/Qemu directly or create VMs in my rack server that runs Proxmox. I've been wanting to try something portable and easy like VirtualBox that isn't VirtualBox, but never got GNOME Boxes running on any of the machines I tried, not even once. That's how I decided to give virt-manager a try, and I regret not doing it a bit sooner. It is extremely easy and fast for any basic use case (I don't know about advanced cases).

Thanks to the excellent documentation, I learned the basics of Flatpak creation yesterday, and started working on packaging Vara today. I released Vara's source code as part of it, a step that got delayed only because of tight schedule.

After successful builds and tests, I submitted the package to Flathub. I got first responses within a couple of hours, and the volunteers were really friendly and helpful. The review cycle is still in progress as I write this post.

The Pitfall

Flatpak accepts build commands in the manifest file, and I'd given all my commands as a one-liner like command1 && command2 && .... The metadata file was in YAML format and the commands could be given as an array. So one of the reviewers suggested me to break down the commands into multiple lines (meaning distinct array elements). That was easy, but did Flatpak guarantee that the build process would terminate when one of the commands failed? The documentation wasn't saying anything about this (just filed a PR). I was sure that the reviewer knew what he was talking about, but still, wanted to try and make sure.

It is easy to perform a test with a command that fails, for Unix provides a command called false. So I modified the build-commands section in my metadata file from this:

build-commands:
  - make -C src
  - install -D -s src/vara /app/bin/vara
  - cp -r usr/* /app/
  - install -D in.co.nandakumar.vara.metainfo.xml /app/share/metainfo/in.co.nandakumar.vara.metainfo.xml

to this:

build-commands:
  - make -C src
  - install -D -s src/vara /app/bin/vara
  - false
  - cp -r usr/* /app/
  - install -D in.co.nandakumar.vara.metainfo.xml /app/share/metainfo/in.co.nandakumar.vara.metainfo.xml

What happens to the build now? It finishes without any errors! But it should, for false is meant to fail. I just ran false; echo $? to make sure it returns 1 (meaning failure), yet the build succeeds. Since I wasn't so sure about false, I decided to try some command that actually tries to perform something and fails. So I replaced false with mkdir /tmp/p/q which would fail because /tmp/p was nonexistent. And this time the build failed, unlike with false!

This is when I really started doubting false. Is it treated differently because it is a dummy command?

Then it occured to me: YAML is notorious for its interpretation of true, false, yes, no, etc. So the entry false that I gave as a command was probably being treated as the Boolean value True. This isn't something that I didn't know, but false as an element in a string array getting reinterpreted as bool caught me off-guard.

Why Flatpak Builder was unable to detect an element being a different type is another question that I do not want to get into now. All I wanted to share in this post was an interesting case of YAML Boolean gotcha that might cause one to misjudge the behaviour of programs, including basic and well-known commands like false.

NOTE: Flatpak supports JSON as well; I went for YAML simply because the official tutorial was using it.

Read more from Nandakumar at nandakumar.org/blog/