Keeping track of my packages

Translations: br
Publication date: May 20, 2021
Tags: sysadmin, python

As I previously mentioned in the "Moving to Wayland" post, I recently moved to a new computer. Moving can be very annoying if you use a heavily configured system and don't have all the configurations easily available to just move over. Since I do regular backups of my files, which include a dotfiles folder with all (or almost all) configuration files for the programs I use, I thought it would be straightforward.

While moving though, I noticed I didn't have an easy way to see and install all the programs I use. At that point I started to wonder about using a distro like NixOS that uses a declarative package manager at its heart precisely to make it easy to reproduce a system. But I like Arch Linux a lot, and there honestly isn't a reason I can't have that feature with it.

Declarative package management

So the aim was to have declarative package management to make future moves easier. Also, since then the packages are listed in a file, by versioning it in my backups I also gain the ability to rewind to an old version for free (if I want to revert some mistake in the package list, for example).

But having a simple list of the installed packages isn't the greatest thing about declarative package management. The greatest benefit is that you can organize that list in a way that makes sense to you, by reordering and grouping the packages. And you can leave comments all over the file, which is particularly useful to register the reason each package is installed, so that in the future you can use that information to remove a package when no longer needed.

A quick search on the web for declarative package managers for Arch Linux revealed aconfmgr and decpac. The former is more complete, featuring built-in configuration management as well, but that's overkill for me and it's in bash, so it's a no-go. The latter is very simple, you basically just have a file with the commands to install the packages and the packages themselves in a syntax similar to JSON. And it's written in python.

decpac also allows you to install from the AUR by relying on the yay tool. The AUR packages are identified by a simple markup before the package name.

decpac is almost perfect, but I didn't like that it did the command configuration and package listing in the same file, which made it need a more complex syntax, that is similar to JSON but not quite.

That's why I decided to create my own, which I called, very creatively, pcmn.

pcmn

pcmn is really simple, with less than 200 lines of python code. It is heavily inspired by decpac with the main difference being the simpler syntax. And it is very simple indeed:

  • one package per line (but lines with no packages are allowed as well of course)
  • everything after a # is a comment
  • optionally the package's group can be written inside brackets before the package name. When no group is specified the default is assumed, which installs from the official repository. The only other group is aur, which informs the package should be installed from the AUR using yay.

There are only two commands:

  • generate creates a new package list from the currently explicitly installed packages (that is, dependencies won't appear in the list, which is fine since pacman will resolve them).
  • apply applies the package list, that is, packages not listed will be uninstalled and packages in the list that aren't present will be installed.

A separate config file in JSON can be used to change the commands that are used for both the default and the aur group, to list, install and remove the packages.

I've been using it for a few months now and I'm really happy with it. As I mentioned, the main difference from decpac is that I split the configuration and the package list and I think it makes a world of difference. The package list is really clean and easy to add to. Here's a sample of mine:

#
# Utilities
#

# Backups
borg
borgmatic
python-llfuse # Needed to mount an archive

# Notifications
libnotify
mako

# Keyboard (Custom)
interception-caps2esc # Switch Caps with ESC
[aur] interception-space2meta # Use Space as Meta

Every time I notice I need a new package for something I add it to the list, together with a comment with the reason why, and run pcmn apply so that it gets installed. When I need to install a package temporarily just do something quick or some test, I install it manually using pacman as usual, so that the next time I run an apply it automatically gets uninstalled.

If you found pcmn interesting, check out its repository for some more information. It's also easily installable from the AUR, which means that after you generate the package list, [aur] pcmn-git will appear in its own package list. I find that funny for some reason 😝.

And that's why I like python so much. With less than 200 lines of code I wrote a program that solves a real problem I was having. And it was fun to write too!