Bug 1389871

Summary: [RFE] version range dependency
Product: [Fedora] Fedora Reporter: Remi Collet <fedora>
Component: rpmAssignee: Packaging Maintenance Team <packaging-team-maint>
Status: CLOSED RAWHIDE QA Contact: Fedora Extras Quality Assurance <extras-qa>
Severity: unspecified Docs Contact:
Priority: unspecified    
Version: rawhideCC: carl, ffesti, ignatenko, jistone, kardos.lubos, ngompa13, novyjindrich, packaging-team-maint, pknirsch, pmatilai, randy, vondruch
Target Milestone: ---Keywords: Reopened
Target Release: ---   
Hardware: Unspecified   
OS: Unspecified   
Whiteboard:
Fixed In Version: Doc Type: If docs needed, set a value
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2017-08-23 14:20:41 UTC Type: Bug
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:

Description Remi Collet 2016-10-29 06:55:18 UTC
This is mostly an bug open for discussion.

In PHP world (composer) dependencies are described, according to semver.org as a version range.

Ex:           "justinrainbow/json-schema": "^1.6 || ^2.0",

Which means version compatible with 1.6 or 2.0, so >= 1.6 and < 3

For now, we use:

    Requires:  php-composer(justinrainbow/json-schema) >= 1.6
    Requires:  php-composer(justinrainbow/json-schema) <  3

But this is a bit messy, especially as we now have a lot of packages with multi-versions available

Ex:

- php-JsonSchema provides php-composer(justinrainbow/json-schema) = 1.6.1
- php-justinrainbow-json-schema provides php-composer(justinrainbow/json-schema) = 2.0.5

Of course, we can switch to package name, but this looks like a workaround.

What is the best way to describe such dependency ?

AFAIK, boolean can help but cannot (for now) apply on the same dependency, right ?

Comment 1 Panu Matilainen 2016-11-09 05:58:21 UTC
I don't think there's any shorthand syntax for it (existing or planned) but you could use a macro to shorten it a bit, eg something like: 

%define rangedep() ((%3 %2 %1) and (%3 %4 %5))
Requires: %rangedep 2.0 >= foo < 5.0

which becomes:
Requires: ((foo >= 2.0) and (foo < 5.0))

OTOH its all a bit academic since rich dependencies are not permitted in requires in Fedora at the moment. I can't say what works best in the php case.

Closign as there's no bug here, discussion on this is better done on eg fedora-packaging.

Comment 2 Vít Ondruch 2016-11-09 08:43:51 UTC
Panu, is it really that simple and does it actually work? Please take a look at bug 1287594.

Comment 3 Remi Collet 2016-11-09 09:13:14 UTC
IIC, for now, we can only have 2 constraints, so which can be indeed resolved by 2 different packages (#1287594)

While the initial idea for this RFE is to have a single constraint, so which must be resolved by the "same" package.

Comment 4 Florian Festi 2016-11-09 10:19:05 UTC
Reopening. This is a valid RFE.

We had a brief discussion on adding this as part of the rich dependencies but decided not to. Not so much because it is not needed but to not complicate the change further. The way to solve we need an operator and demands the same package matching for all the subterms. This could either be done with the proposed syntax or by exposing the operator in the syntax rich deps syntax.

Comment 5 Neal Gompa 2016-11-09 14:06:32 UTC
(In reply to Panu Matilainen from comment #1)
>
> Requires: ((foo >= 2.0) and (foo < 5.0))
> 

I don't think that works like you'd expect it to. The semantic versioning construct that Remi is describing is designed to express simultaneous Requires/Conflicts.

As Vit points out with bug 1287594, you get weird results with that logic.

In the Ruby, PHP, Golang, Rust, and increasingly the Python world, there are native constructs for handling semantically versioned dependencies.

Currently, in RPM, we do not have a way to properly represent the simultaneous Requires and Conflicts that this represents.

We can sort of do this by saying:
Requires: foo >= %min_ver
Conflicts: foo >= %max_ver

If rich dependencies allowed expressing Requires and Conflicts under a single stanza, you could get closer to this semantic. Though I'm not sure that it is needed.

Ideally, a clear and clean way to map this structure with an operator would also make it possible for multiversion dependencies to be better expressed in rich dependencies.

Comment 6 Neal Gompa 2016-11-09 14:08:52 UTC
(In reply to Neal Gompa from comment #5)
> 
> We can sort of do this by saying:
> Requires: foo >= %min_ver
> Conflicts: foo >= %max_ver
>

Also note that the build-time equivalent would be:

BuildRequires: foo >= %min_ver
BuildConflicts: foo >= %max_ver

Comment 7 Remi Collet 2016-11-09 14:17:52 UTC
I don't think (Build)Conflicts solves the issue
This is only a possible "workaround" for build, not for runtime.

When multiple versions exist, and can be installed in parallel, you need to constraint the one you need, without conflict, as the other can be required by another package.

Comment 8 Neal Gompa 2016-11-10 16:06:23 UTC
(In reply to Remi Collet from comment #7)
> I don't think (Build)Conflicts solves the issue
> This is only a possible "workaround" for build, not for runtime.
> 
> When multiple versions exist, and can be installed in parallel, you need to
> constraint the one you need, without conflict, as the other can be required
> by another package.

Then the only way to do that would be to do:

    Requires:  ((php-composer(justinrainbow/json-schema) < 3) and php-(composer(justinrainbow/json-schema) >= 1.6))

(Ordering above indicates preference for newest over oldest)

However, since all of our tools blow up whenever we want to use rich dependencies in Requires, Conflicts, and Recommends, you can't do it just yet.

Comment 9 Neal Gompa 2016-11-10 16:07:00 UTC
Err...

Requires:  ((php-composer(justinrainbow/json-schema) < 3) and (php-(composer(justinrainbow/json-schema) >= 1.6))

Comment 10 Remi Collet 2016-11-11 09:10:07 UTC
An example showing why boolean doesn't not solves "range version" dependency:

# rpm -q rpm
rpm-4.13.0-1.fc25.x86_64

# rpm -i bar-1-1.fc25.remi.noarch.rpm 
error: Failed dependencies:
	((foo >= 2) and (foo <= 3)) is needed by bar-1-1.fc25.remi.noarch

# rpm -i foo1-1-1.fc25.remi.noarch.rpm 
# rpm -q --provides foo1
foo = 1
foo1 = 1-1.fc25.remi

# rpm -i foo4-4-1.fc25.remi.noarch.rpm 
# rpm -q --provides foo4
foo = 4
foo4 = 4-1.fc25.remi

# pm -ivh bar-1-1.fc25.remi.noarch.rpm 
Preparing...                          ################################# [100%]
Updating / installing...
   1:bar-1-1.fc25.remi                ################################# [100%]

Last command works, when we expect a way to disallow it.

Comment 11 Vít Ondruch 2016-11-11 09:28:35 UTC
(In reply to Remi Collet from comment #10)
> An example showing why boolean doesn't not solves "range version" dependency:

Thank you for confirming my suspicion from comment #2. At least the behavior is consistent ;)

Comment 12 Igor Gnatenko 2016-11-16 08:26:30 UTC
*** Bug 1287594 has been marked as a duplicate of this bug. ***

Comment 13 Panu Matilainen 2017-08-23 14:20:41 UTC
This has been implemented in rpm as of >= 4.13.90 which is in rawhide/f27 now, using the new "with" rich dependency syntax:

Requires: (foo >= 1.0 with foo < 2.0)