I’m still working hard on my free time on the conversion of Ruby packages to the new eclasses as well as improving JRuby support over the place – for this reason I might do another shameless plug – and in particular, between yesterday and today, I ended up working on a set of packages for packaging bones in Gentoo.
Why is that a set of packages? Well, I had to commit together four different packages: bones, bones-extra, loquacious and little-plugger; a subset of them wasn’t possible at all. There are two interesting things to say about these, if you care about Ruby development. The first is that I wouldn’t actually count bad for it, as what it does is mandating an interface for Gems going a step further than Hoe, Echoe and Jeweler as it encompasses testing, documentation and packaging tasks. The second thing is that it comes from the codeforpeople project which consists of what can only be called a fuckload of different and almost unrelated packages, and as far as I know it used to be manned by a single person. Not even the most friendly of the blokes, to be honest: when I asked him a couple of questions about another project – session – the one-line reply I got was a link to a (newly created) GitHub repository.
So what is the problem here? Well, check out the depgraph on this page. I spoke about four packages before, but it lists four, one is not packaged and I’ll probably just package it if I’ll end up using Bones myself. Of the four packages, one is the “interface” one and is Bones itself, two are dependencies, and are generic libraries, the other two are “plugins” (extras and git) that provide optional functionalities; or at least sort-of-extra functionalities. Indeed, the extras plugin provides RSpec testing and RubyForge publishing support, which should probably be considered optional functionalities… on the other hand, if your package uses Bones, and defines the configuration keys for either, it will fail if the extras package is not installed. So much for the extras, then.
The runtime dependencies are actually quite linear: Bones needs the two libraries, and the two plugins need Bones, which is quite logical and very easy to deal with. But when you start considering the build-time dependencies you are way out of luck. All the packages including Bones itself would depend on Bones, and on the extras package (because all of them define the RubyForge project, and almost all use RSpec), for both documentation and testing purposes. Obviously, if you try to install Bones with
FEATURES=test, Portage will bail out because of the cyclic dependencies. And I don’t think I can fix it in any way for now. To be honest, this would have been much easier if Bones itself contained what is in the extras, as at that point you would have everything in the same package, which wouldn’t then require itself.
Or would it? To be honest if you look at the development dependencies as listed within the gems, all of the Bones-managed gems will require Bones, and that is true… for Bones as well! Indeed, in the image above, the dotted lines represent the officially-listed dependencies which we’re not following (for some strange, but welcome, reason, the
bones-git package is truly optional).
Somehow, it seems like many multi-package projects decided to go with similar ways of handling dependencies. For instance, take prawn, a PDF-writing gem: when I added it to Portage (as dependency of a webapp I worked on last summer), it was a single gem, depending on another gem by the same author for its testing. Now, it’s actually a simple wrapper gem for three split gems… and you most likely will need all of them for doing most non-trivial stuff. Or a much more common gem: Rails! The activerecord, actionpack, activesupport and actionmailer gems are so interdependent that I’m not surprised most projects just bundle Rails in their own sources (albeit this is very bad from the quality point of view).