A dive into requires with ranges


Disclaimer: I am aware that python does not allow easy installation of 2 libraries in parallel. It is just an example.

Let’s say you have an upstream requirement "needs pyfoo >= 1.6.0 but smaller than 2". Sounds easy right?
Our naive solution will be:

Requires: python-pyfoo >= 1.6.0
Requires: python-pyfoo < 2

so far … so good. If your repository has only one version of pyfoo available we will probably get the package you want. now lets say we have more than one version available.

So I would install python-pyfoo-1.5.0 and python-pyfoo-2.1.0. the 2.1.0 fulfills the >= 1.6.0 and the 1.5.0 fulfills < 2.

Requires: python-pyfoo >= 1.6.0
Conflicts: python-pyfoo > 2

Would probably work but be pretty hardcore. In the python case with no version library paths. It would probably solve the issue.

Thinking outside of the box

But what about language which actually allow installing multiple versions of the same library at the same time? Ruby comes to mind. Ruby even has a special operator to define ranged requires: ~>. Let us look at some examples first:

“rbfoo ~> 1.2.3” translates into "rbfoo >= 1.2.3 && rbfoo < 1.3"
“rbfoo ~> 1.2” translates into “rbfoo >= 1.2 && rbfoo < 2”.

So for us the ranged requires is a very common thing. How did we solve it? Every package has a few special provides:

rubygem(ruby:2.2.0:rbfoo) = 1.2.5
rubygem(ruby:2.2.0:rbfoo:1) = 1.2.5
rubygem(ruby:2.2.0:rbfoo:1.2) = 1.2.5
rubygem(ruby:2.2.0:rbfoo:1.2.5) = 1.2.5

So if we need to express ~> 1.2.3. all we do is:

Requires: rubygem(ruby:2.2.0:rbfoo:1.2) >= 1.2.3

We can not handle the full flexibility of all the “>= && <” combinations you can think of, but the ones we usually need.