Avoid cabal hell: find nirvana

March 6, 2012

GravatarBy Michael Snoyman

Cabal dependency hell has been around for a while now, and it has especially caused issues for larger projects with lots of dependencies (e.g., Yesod). We've put a lot of effort into finding ways to avoid it, but we've still be plagued by problems. This has had the effect of both hindering existing users, and preventing new users from being able to use Yesod.

Fortunately, the answer is simple: to avoid hell, you just need to find nirvana. (Note: There have been two very large discussions on this issue recently, one on the Yesod mailing list and another on Google+. The discussions there may help explain some of the motivations if you're left wanting more at the end of this blog post.)

The problem

Simply stated, Hackage is a zoo. Anyone can upload anything at any time. If I write some code that depends on foobar version 0.1, and someone comes along and makes a breaking change in 0.1.1, my code will (generally) break. We also have the issue of different packages using different versions of the same underlying packages (e.g., baz requires foobar 0.1, and bin requires foobar 0.2), and therefore they cannot be installed side-by-side.

Distributions, such as Debian, Nix, and Fedora, need to solve this problem themselves by hand-selecting which packages will be included. This solves the problem completely, but is relatively labor intensive. The bigger problem is that everyone is solving the same problem separately. Also, this work only benefits people using distributions for installing their software; normal cabal users are still left with the wild west.

I say none of this "zoo" and "wild west" stuff as an affront to Hackage: Hackage is exactly as it should be, and I don't wish to change it. The problem is, we need an extra layer to provide more stability.

The solution

There's an obvious solution to the problem as stated: have a centralized list of stable/compatible/blessed packages, and have everyone use it. Making that list is an important issue, and one I'm hoping to engage the community on. But assuming we had that list, all the distributions could use it, and we'd have a much nicer stable system.

But we still need one more thing: a solution for cabal users. That's where cabal-nirvana comes in. It's an incredibly simple (101 sloc at last count) program that adds a bunch of version constraints to you cabal config file. It gets the list of necessary constraints from some site (currently I set up a basic one for Yesod at: www.snoyman.com/cabal-nirvana/yesod, which is being used as the default). That way, you will never get dependency hell on the packages covered by the list.

I've just uploaded the first version to Hackage (warning: alpha quality software). To get started, you can use the commands:

cabal install cabal-nirvana
cabal-nirvana fetch # get the most recent list of blessed packages
cabal-nirvana start # apply the downloaded list to your config file

Two other commands are stop (remove all constraints) and test, which will try (via cabal-dev) to install all of the packages in your config file simultaneously.

I've written cabal-nirvana with all of the bad practices I normally fight against: it uses String instead of Text or ByteString, uses the HTTP package instead of http-conduit, and uses the standard type FilePath = [Char] instead of system-filepath. The reason is simple: we want to have the barest number of dependencies possible, to make sure our cabal-hell-defeater is not itself defeated by cabal hell.

The repo also has another (optional) executable to help you generate one of these lists of blessed packages. You give it a list of packages you want covered, and it will generate a list of all of the deep dependencies, together with the most recent version of them available from Hackage. After generating this file, you should use cabal-nirvana test on it to confirm that this is a compatible list. To build this executable (cabal-nirvana-generate), pass in the -fgenerate option when building.

What's next

This is a very preliminary release, mostly intended to start getting feedback and working to a real solution. Some thoughts I've had is that we should have built-in support for different stability profiles (stable, beta, alpha, bleeding), and automatically detect the GHC version and switch lists appropriately.

If you're out there using Yesod, please give this tool a try and let me know if it solves your dependency problems (or causes others). If you want to collaborate with me on getting a wider selection of packages into the list, be in touch as well.

Future enhancements


comments powered by Disqus