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
- Language package managers
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
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
- Most language package managers
- FreeBSD ports (and probably other ports systems) — everything
pretty much has to be pushed to the main repo
- nix (which is a really cool project, this flaw notwithstanding) — it seems like there probably is a way to build your own channel, but it isn’t clear from the docs how you’d go about that.
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:
Cabal does not provide the ability to depend upon packages that supply a command; dependencies must be libraries. The upshot of this is that packages which need alex and/or happy (lexer/parser generators, respectively) cannot specify this, and thus users will frequently get cryptic error messages when trying to install a package that needs one of them
go getdoesn’t provide good facilities for doing anything special at build time. This is arguably a build system issue, not a package manager one, except that it’s only a problem for the package manager. As an example, if an author of a library or program wants to use a parser generator as part of their build, they have two options:
- Write some custom build logic to run the parser generator command during
the build. This makes
go getnot work, since there’s no good way to express that the custom command needs to be run.
- 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.
- Write some custom build logic to run the parser generator command during the build. This makes
Please, for the love of God, if you’re responsible for writing a package manager, learn from the mistakes of others.