💾 Archived View for sysrq.in › en › gemlog › nitter.gmi captured on 2023-07-10 at 13:32:16. Gemini links have been rewritten to link to archived content

View Raw

More Information

⬅️ Previous capture (2023-01-29)

➡️ Next capture (2024-12-17)

-=-=-=-=-=-=-

Maintainer's thoughts: Twitter (but it's actually about Nim)

Elon Musk: *destroys Twitter*
Me, who put a lot of effort to packaging Nitter:

finger.jpg

So, this is my first gemlog item on the English variant of my capsule. I'd like to tell you how I packaged Nitter for Gentoo.

Nitter is written in Nim (hence the name):

https://nim-lang.org/

It was already packaged by xgqt so I could skip this step.

By the way, I really liked that language - it's very appealing and expressive!

Trying to make the official package manager work

The problem was their package manager/build system, called Nimble. It didn't work in network-sandboxed environments, didn't have staged installation support and there was no way to tell if build/test stage could be run without invoking these commands.

GNU Coding Standards: Support for Staged Installs

Implementing --offline flag was relatively easy, and it was accepted upstream:

Nimble PR #967: Add --offline option

I tried to add "dry run" support but implementing it neatly was not possible due to Nimble's architecture, so it was rejected:

Nimble PR #964: Add --dryRun option

Support for staged installs was done easily but upstream wasn't really fond of this idea, as they didn't understand that filesystem access is sandboxed in package managers. So I had to implement more complicated thing (that never went upstream).

Nimble PR #965: nimble install: add --destDir option

Nimble PR #969: Support multiple Nimble dirs

Writing my own build system

I did some research on how other distributions package Nim software. Arch, as always, did it the way upstream intended - using nimble. Debian specified all dependencies on the command line manually to avoid using nimble. Nix had its own helper package.

nim_builder: Custom Nim builder for Nixpkgs

I decided to write my own build system, as that was also a great opportunity to learn Ninja syntax. And then procrastinated a lot (a really lot). But suddenly I was hit with hypomania and started coding. I can't recreate the history exactly because I used "git rebase -i" many times. However, the main steps were:

Implementing a ninja.build generator

That was easy, as there's a Python module for generating ninja.build files in Ninja sources, and Nim syntax closely resembles Python.

ninja_syntax.py

Querying Nimble files

Nimble has its own format for package metadata. It lacks formal specification, but kind-of documented in ReadMe. There's also a deprecated format (which Nimble still uses internally) but I didn't want support for it, so I went for a newer NimScript-based one.

To make quuerying work, I had to copy the nimble file to a temporary directory and change its file extension to "nims". Weird bu ok.

Parsing versions

I copy-pasted this bit from Nimble and removed code that was not needed. Same with parsing command-line arguments and populating the list of files to install.

Finding dependencies

Finding packages by name is easy: just scan build root for matching ${pkgname}-${pkgver} directories.

But there are dependencies that are specified only by its URL. So I decided to put the canonical package URL to a nimblemeta.json file to use it later.

Setup action

My build system creates build targets for every binary and task specified in the nimble file. Output messages will certainly remind you of CMake :)

Also it generates scripts to be called by "ninja install" and "ninja test". They are written in NimScript to be portable.

Optimization for speed

Initally, every value was read by executing the nimble file. It was slow and inefficient.

I thought that multithreading could help but soon discovered that the number of bugs can be calculated using the formula "x = a^n", where n is the number of threads.

So I redesigned it again to read all values in batch.

Depfile support

I didn't like how binaries were being rebuilt every time, even when sources hadn't been changed. The solution mentioned in Ninja docs is makefile-syntax dependency files.

I prepared a "pull request" for Nim to add support for it, but upstream got angry at me and closed it. No wonders there's a hard fork of Nim floating around…

Nim PR #19960: Add depfile option

That led me into maintaing my patch as a separate project, see:

nim-patches git repository

Conclusion

So here am I, maintaining 30 Nim packages in ::guru ebuild repository. And Nitter (the main consumer) has very unclear fate since the Twitter deal.

My build system is called nimbus, although internally it's called NimBS.

nimbus website

You can ask me anything about it on #nimbus (at irc.oftc.net) or #nimbus:matrix.org.

I hope it will find use outside of Gentoo packaging.

Thanks for reading it!

--

🏠 sysrq's gemlog