Mailinglist Archive: opensuse-ruby (8 mails)

< Previous Next >
[opensuse-ruby] ruby packaging quo vadis

see $attachment. comments & critics welcome.


openSUSE - SUSE Linux is my linux
openSUSE is good for you
1. Goals

* multiple versions in parallel
* allow building ruby extension packages for all available ruby packages

2. Multiple ruby versions in parallel

Some people suggested we dont need this. We should just upgrade the ruby to 1.9
and be done with it. While this might work for factory, it wont be a solution
for e.g. ruby 1.9 on SLES. there we cant just say "then you have to pick on of
the two versions". Given that some of our products think about moving to 1.9, we
have to solve the problem of parallel installations.

2.1. Potential problems

2.1.1 Suffixed binaries and update-alternatives

The only really overlapping part of 2 ruby installations are the binaries.
this can be solved quite easily with

./configure --program-suffix=1.8 --with-soname=ruby1.8
./configure --program-suffix=1.9 --with-soname=ruby1.9

It would need to be discussed if we want to use the ruby abi version was
suffix. In that case the 1.9 commandline would change to:

./configure --program-suffix=1.9.1 --with-soname=ruby1.9.1

To offer the users a default /usr/bin/ruby, we would use update-alternatives to
manage the symlinks.

2.1.2 Shebang lines and multiple ruby versions

But with that we cant just leave the she bang lines in scripts at
"/usr/bin/ruby". we would need to change it to the ruby version we build
against. So this might require some build time patching.

For gem packages and extensions installed via setup.rb this shouldnt be a
problem, but scripts in other packages might be affected.

3. Extensions and multiple ruby versions

Most of the ruby extensions come as gems nowadays. So i will mainly focus on
gems here.

Our goals for the extensions packaging:

* handle ~> and the semanatics nicely
* package gems for multiple ruby packages without duplicated spec files or a lot
of manual work

3.1 Naming

My suggestion for naming would be:


packages without %{rb_suffix} could be used as wrapper to pull our default

3.2 Gem versioning fun - or how we got the gem_version_suffix

One of the greatest fun factors with gem packaging is the ~> operator:

package ~> 1.0.0 -> package >= 1.0.0 && package < 1.1
package ~> 1.0 -> package >= 1.0 && package < 2

(From my experience so far we have mostly the first form with 3 digits.)

RPM doesnt have an equivalent operator itself. The solution from gem2rpm
upstream basically maps out the dependencies as shown in the explaination.

But this leads to problems if you have multiple packages providing that symbol

Requires: rubygem-foo >= 1.0.0 rubygem-foo < 1.1

rubygem-foo-0.9: Provides: rubygem-foo = 0.9
rubygem-foo-1.0: Provides: rubygem-foo = 1.0
rubygem-foo-1.1: Provides: rubygem-foo = 1.1

So on a system with 0.9 and 1.1 installed rubygem-foo-1.1 satisfies the >=
1.0.0 part and rubygem-foo-0.9 satisfies the < 1.1 part but neither of them is
a version that would satisfy the gem dependency.

A cleaner solution might be converting it to a "=" requirement but that adds a
lot of work on the maintainer.

Or adding the requires on the versioned package name
Requires: rubygem-foo-1.0 >= 1.0.0

For the rails 3.1 packages[0] i went with the last solution. i have a gem2rpm
branch at github[1], that automatically converts all ~> dependencies into the
versioned pattern. Will push the package to dlre after todays discussion.

I always used the rubygem-gemname-x_y version as I saw the form with 2 digits
only once. For some packages (like rubygem-tzinfo) i went with a provides in the
package as both rails version can be satisfied by the same version. But for
requires we should always use the suffixed versions.

3.3 Packaging for multiple ruby packages

Ideally we want to have exactly one spec file that will handle multiple ruby
versions for us. We could adapt some of the work that was already done by the
kernel team for KMP packages

The first step will be to get a list of wanted ruby versions to build against.
That could either be through /etc/rpm/macros.ruby%{rb_suffix} files appending
their version to a %ruby_versions variable or through some prjconf entry.

The ruby_version variable can be overwritten in the spec file to limit the
number e.g. for 1.9 only gems.

For each entry in the ruby_version variable we create a subpackage in the spec
file, either via gem2rpm or automatically as with %lang_pack/%debug_package.

Our build section could look something like this

for $ruby_version in %{ruby_versions} ; do
%gem_install %{S:0}

with the macros defined as
%gem_install /usr/bin/gem${ruby_version} install
--verbose --local --build-root=%{buildroot}
%gem_cleanup /usr/bin/gem_build_cleanup

That leaves us with finding a solution for the buildrequires/requires.
At the moment the list of those 2 is created by gem2rpm when we create the spec.

While the list of requires can be easily created at build time with hooking into
rpms findprovides/-requires mechanic, we cant do the same easily for the

In factory we can just drop a files into /usr/lib/rpm/fileattrs/ and are done.
For older distros we would need to overwrite the findprovides/findrequires, but
we can easily hook that into our existing rubygems_requires macro.

That leaves us with the buildrequires. We could continue to generate them out in
the gem2rpm phase. That means we would need some kind of external config for
gem2rpm, where we would configure which ruby versions we want to build a package
for and then generate the buildrequires for those. The same config could also be
used to set the license header e.g. A macro based solution like

BuildRequires: %rubygem(foo, '~>', '1.0.0')

which expands to (pseudo code)

BuildRequires: $ {|rb_ver|
Gem::Requirement.rpm_version_transform_opensuse("ruby${rb_ver}gem-#{$1}", $2,
$3) }.join(" ")

might not really be supported by the OBS (TODO: talk to mls about if we could
add such feature to the OBS)

The worst case solution would be generating out all the subpackages in gem2rpm.
I dont thing we will ever have to go for multiple spec files for solving the
problem. *knocks on wood*

< Previous Next >
List Navigation