Yes I’m writing again about Ruby after a very long hiatus… it feels like there’s a pattern behind this it seems.
After my recent changes, Hans approached me today with two issues: the first is that I should stop adding
virtual/ruby-test-unit dependencies on ebuilds since (finally!) Ruby 1.9 gained a completely compatible test-unit implementation, which means you can rely on packages to behave correctly without adding extra dependencies, and old, stale, and darcs-mantained gems to keep around — hopefully, at least. The other issue is more troublesome, and relates to bug #380409 where users are being forced to get Ruby Enterprise installed in their system.
Why would this happen? Well, as you can see in that bug, once the version of
ruby-rdoc that references Ruby Enterprise (this applies to the other virtuals as well, though) was marked stable, Portage wanted to update it, causing the new implementation to be requested by the dependency tree. You can easily guess that we didn’t have in mind this behaviour when we decided to go with the virtuals. So what’s going on?
When a package, such as
redmine (which I fixed yesterday to do this) requires the
virtual/ruby-ssl ebuild (which relates to a Ruby implementation that includes the ssl extension, an USE flag for the C-based implementations, but a separate package for JRuby), the expanded dependencies appear like this:
ruby_targets_ruby18? ( virtual/ruby-ssl[ruby_targets_ruby18] ) … since each one of those virtuals lives in a different slot, and only supports one target, you get requested one ebuild for each target you requested … and the target definition on those is forced on.
Since the dependencies resolve to a straight slot, Portage wouldn’t try to “update” the virtual to get the highest-version one .. which would then bring in a different Ruby implementation altogether. So why is bug #380409 there? As Hans points out the problem has to be that the virtuals are added to the world set: being in the world set (unbound from a slot) means that Portage will try to get the highest-version of the package installed, no matter which slot it belongs to. Incidentally, this is also why you got Python 3 installed on every system even though you didn’t ask for it, unless you mask it explicitly.
Handling of world set’s content is fishy at its best; when you install a package with a straight
emerge command, you’re “selecting” the package, and that adds it to the world set; if you want to avoid that, you have to do so with
emerge -1 .. and most people forget about that. This is probably why the bug entered on users’ systems.
So how do you clean up the situation so that it behaves as expected instead? Well, it’s actually easier than you’d expect:
qlist -IC virtual/ruby | xargs emerge --deselect
This removes the packages from the world file, but keeps them installed, so that you won’t be asked to merge them again later. And it handles all the Ruby virtuals at once, so even if in your case the problem was with
rubygems, this will fix it.
-1 for emerge was one of the first things I learned.Unfortunately by that point there was already quite a mess in the world file.Also I hadn’t seen that option mentioned in the documentation, though maybe I just missed it (since the internet I’ve grown too impatient to read documentation. Before it often was the best way to learn new stuff. Strange how fast some things change).