"cabal gen-bounds": easy generation of dependency version bounds

In my last post I showed how release dates are not a good way of inferring version bounds. The package repository should not make assumptions about what versions you have tested against. You need to tell it. But from what I've seen there are two problems with specifying version bounds:

  1. Lack of knowledge about how to specify proper bounds
  2. Unwillingness to take the time to do so

Early in my Haskell days, the first time I wrote a cabal file I distinctly remember getting to the dependencies section and having no idea what to put for the version bounds. So I just ignored them and moved on. The result of that decision is that I can no longer build that app today. I would really like to, but it's just not worth the effort to try.

It wasn't until much later that I learned about the PVP and how to properly set bounds. But even then, there was still an obstacle. It can take some time to add appropriate version bounds to all of a package's dependencies. So even if you know the correct scheme to use, you might not want to take the time to do it.

Both of these problems are surmountable. And in the spirit of doing that, I would like to propose a "cabal gen-bounds" command. It would check all dependencies to see which ones are missing upper bounds and output correct bounds for them. I have implemented this feature and it is available at https://github.com/mightybyte/cabal/tree/gen-bounds. Here is what it looks like to use this command on the cabal-install package:

$ cabal gen-bounds
Resolving dependencies...

The following packages need bounds and here is a suggested starting point.
You can copy and paste this into the build-depends section in your .cabal
file and it should work (with the appropriate removal of commas).

Note that version bounds are a statement that you've successfully built and
tested your package and expect it to work with any of the specified package
versions (PROVIDED that those packages continue to conform with the PVP).
Therefore, the version bounds generated here are the most conservative
based on the versions that you are currently building with.  If you know
your package will work with versions outside the ranges generated here,
feel free to widen them.

network      >= 2.6.2 && < 2.7,
network-uri  >= 2.6.0 && < 2.7,

The user can then paste these lines into their build-depends file. They are formatted in a way that facilitates easy editing as the user finds more versions (either newer or older) that the package builds with. This serves to both educate users and automate the process. I think this removes one of the main frustrations people have about upper bounds and is a step in the right direction of getting more hackage packages to supply them. Hopefully it will be merged upstream and be available in cabal-install in the future.


Santino said…
Is there a reason we shouldn't just have exact package versions and not worry about all of these upper bounds?
mightybyte said…
Yes. Exact package versions are too restrictive. You usually want to automatically allow new versions if those versions just fix bugs and don't change the external API. This is exactly what the Package Version Policy is designed to do. Hackage packages are expected to conform to the PVP and under that assumption, the bounds generated by this tool are the ones you want to start with. You can expand those bounds as you verify that your package builds with more versions, but they work as a good starting point.
Bergey said…
This is excellent! It's how I usually set bounds, and it's tedious. Looking forward to using this soon.

I keep meaning to write a script that tests the stated lower bounds, to make sure my code is still build able. Too often I start relying on some function without noticing when it was added.

Popular posts from this blog

On Haskell Documentation

A Hopefully Fair and Useful Comparison of Haskell Web Frameworks