How Not To Design A Package Manager

09 Jul 2015

The following is a rant about a couple of things I see being constantly screwed up by various package managers. In an ideal world, authors of package managers to be written would read this and do better, but mostly I’m just venting.


Package managers basically fall into two categories:

System package managers are used to manage software installed on an operating system. For Linux distributions, this usually means everything, from that dumb little app you started playing with the other day, down through the kernel. For other operating systems where there’s more of a division between the base system and “extra” software, these sometimes only cover the extras. Examples: apt, rpm, pacman, portage, the BSDs’ ports systems, Homebrew for OS X…

Language package managers are used to manage (primarily) libraries for a particular programming language, or sometimes a runtime environment like the JVM or Erlang’s BEAM VM. They often integrate a build system as well. Examples: gem (ruby), pip (python), cabal (haskell), opam (ocaml), go get (go. I don’t know of an official name for this tool), maven (JVM), npm (javascript/node.js), hex (beam)…

Most of the impetus for this post comes from language package managers, but some of these complaints are equally applicable to system package managers, so I’ve snuck those in as well. Here are a couple really common things that annoy the heck out of me:

No straightforward way to host packages yourself


This is particularly insidious when you need to have a human approve the addition of new packages in the main tree; usually not an issue for language package managers, but having to go through a code review process just to get my tool up somewhere where I can easily install it on future boxes is… ick.

go get deserves special mention for getting this right in a language package manager; It’s not only documented and supported, but it’s essentially mandatory — you import by URL, and while there are some special case rules for common hosting sites (e.g. github), setting things up to be imported via a different URL is really easy.

Overly restrictive metadata

This is easiest to explain by way of some examples:

  1. Write some custom build logic to run the parser generator command during the build. This makes go get not work, since there’s no good way to express that the custom command needs to be run.
  2. Commit the resulting file to the repository. This is pretty gross, and makes it possible to end up using a stale version of the file, since the generation isn’t integrated into the normal build process.

Both of these options suck.


Please, for the love of God, if you’re responsible for writing a package manager, learn from the mistakes of others.