1 |
Hello, everyone. |
2 |
|
3 |
Following my earlier threads, I'd like to propose a first complete |
4 |
solution for new version restrictions for package dependencies. I |
5 |
honestly doubt it's going to be approved since it's a major change. |
6 |
Nevertheless, I think it's an interesting topic for consideration. |
7 |
|
8 |
What is included: |
9 |
|
10 |
- conjunctive version ranges, |
11 |
- revision-free and revision-oriented comparisons, |
12 |
- full set of (blocker-free) logical operators. |
13 |
|
14 |
What isn't included: |
15 |
|
16 |
- disjunctive version ranges, |
17 |
- complete lower bound problem solution, |
18 |
- extensions for prefix matching, |
19 |
- some convenience shortcuts like Ruby's ~> op. |
20 |
|
21 |
|
22 |
Backwards compatibility [recommended] |
23 |
===================================== |
24 |
|
25 |
For backwards compatibility, package dependency specifications using |
26 |
old-style restrictions will still be accepted. Those specifications |
27 |
will retain the old behavior, and have no new features. |
28 |
|
29 |
|
30 |
New package dependency syntax |
31 |
============================= |
32 |
|
33 |
New-style package dependencies use the following syntax: |
34 |
|
35 |
<cat> "/" <pkg> [":" <slot>] ["[" <vers> "]"] ["[" <usedep> "]"] |
36 |
|
37 |
with <vers> now using the following sub-syntax: |
38 |
|
39 |
<op> <version> ["," <op> <version>...] |
40 |
|
41 |
The version restriction operator is removed from the front and all |
42 |
package dependency specifications start with the category and package |
43 |
name, followed by optional package slot. This can be followed by |
44 |
optional version restrictions and USE flag restrictions. |
45 |
|
46 |
The version constraints (if present) must *always* be placed inside |
47 |
square brackets, even for a single constraint. Each constraint starts |
48 |
with an operator followed by a version string. Multiple constraints are |
49 |
separated using "," character, and are conjunctive (AND-ed). |
50 |
|
51 |
The operators are not valid for beginning of a USE dependency string, |
52 |
therefore the version constraint can be clearly distinguished from USE |
53 |
contraints. |
54 |
|
55 |
The version and USE flag constraints are always disjoint. If both are |
56 |
present, they must be surrounded by separate pairs of brackets. |
57 |
|
58 |
Examples: |
59 |
|
60 |
dev-foo/bar:13[foo] # slot + USE |
61 |
dev-foo/bar[>=3] # single version constraint |
62 |
dev-foo/bar:4[>=4.11,<4.20] # slot + version range |
63 |
dev-foo/bar[>=3][foo] # version + USE |
64 |
|
65 |
|
66 |
Version restrictions |
67 |
==================== |
68 |
|
69 |
Each version restriction consists of an operator followed by a version |
70 |
string. |
71 |
|
72 |
The following revision-free version comparison operators are provided: |
73 |
|
74 |
== exact version match, or prefix match (with *) |
75 |
!= exact version non-match, or prefix non-match (with *) |
76 |
< version less than match |
77 |
<= version less or equal to match |
78 |
> version greater than match |
79 |
>= version greater or equal to match |
80 |
|
81 |
All those operators compare on versions ignoring the revision part. |
82 |
They must be followed by a valid version with no revision part. |
83 |
Additionally, the == and != operators can accept a version followed by |
84 |
* to indicate prefix match. |
85 |
|
86 |
The following revision-oriented version comparison operators are |
87 |
provided: |
88 |
|
89 |
=== exact version+revision match |
90 |
!== exact version+revision non-match |
91 |
<== version+revision less or equal to match |
92 |
>== version+revision greater or equal to match |
93 |
|
94 |
Those operators include both version and revision in the comparison. |
95 |
They must be followed by a valid version with an optional revision |
96 |
part. No revision is equal to -r0. Prefix match is not allowed. |
97 |
|
98 |
Examples: |
99 |
|
100 |
[==1.3.3] version 1.3.3, any revision |
101 |
[>1.3.3] version >1.3.3 (e.g. 1.3.3.1 or 1.3.4...) |
102 |
[<=1.3.3] version <=1.3.3 (incl. any revision of 1.3.3) |
103 |
[===1.3.3] 1.3.3-r0 |
104 |
[>==1.3.3-r2] 1.3.3-r2 or newer |
105 |
[>=1.2,!=1.3.3] version >=1.2 but not 1.3.3 (any revision) |
106 |
[>=1.2,<1.4] version >=1.2 but <1.4 |
107 |
[==1.2*] any version starting with 1.2 prefix |
108 |
[>=1.2,<1.8,!=1.6*] version >=1.2 but <1.8, also excluding 1.6* |
109 |
|
110 |
|
111 |
Mapping from existing dependency syntax |
112 |
======================================= |
113 |
|
114 |
It should be noted that whenever revision match is desired, one of *== |
115 |
operators need to be used. They do not include '<' or '>' variants, so |
116 |
the revision needs to be decreased or increased appropriately for <== |
117 |
or >==. |
118 |
|
119 |
The behavior of current '~' operator is now equal to '==', so the |
120 |
former is removed. |
121 |
|
122 |
=foo-1.2.3 ===1.2.3 |
123 |
=foo-1.2.3-r3 ===1.2.3-r3 |
124 |
=foo-1.2.3* ==1.2.3* |
125 |
~foo-1.2.3 ==1.2.3 |
126 |
>foo-1.2.3 >==1.2.3-r1 |
127 |
>foo-1.2.3-r9999 >1.2.3 |
128 |
>=foo-1.2.3 >=1.2.3 or >==1.2.3 |
129 |
>=foo-1.2.3-r3 >==1.2.3-r3 |
130 |
<foo-1.2.3 <1.2.3 |
131 |
<foo-1.2.3-r4 <==1.2.3-r3 |
132 |
<=foo-1.2.3 <==1.2.3 |
133 |
<=foo-1.2.3-r3 <==1.2.3-r3 |
134 |
<=foo-1.2.3-r9999 <=1.2.3 |
135 |
|
136 |
|
137 |
Solutions to other problems |
138 |
=========================== |
139 |
|
140 |
The provided operators make it possible to quite conveniently express |
141 |
common types of dependencies. The remaining kinds can be constructed |
142 |
using conjunctive ranges combined with existing operators. |
143 |
In particular, for this specific reason the != and !== operators are |
144 |
provided. |
145 |
|
146 |
Disjunctive version ranges were considered needed rarely. If specific |
147 |
versions needs to be excluded from the base version range, the != |
148 |
and !== operators (optionally in the prefix matching mode) can be used |
149 |
to do so. |
150 |
|
151 |
[>=1.2,<1.6,!=1.4*,!=1.5*] |
152 |
|
153 |
While I agree that this is not perfect and can become quite verbose at |
154 |
times, the use cases for it are rather limited. |
155 |
|
156 |
Revision ranges can be easily constructed using version ranges: |
157 |
|
158 |
[>==1.3-r3,<==1.3-r7] |
159 |
|
160 |
Not that I see any real use for them. |
161 |
|
162 |
Pre-release version ranges can be achieved using the relatively safe |
163 |
_alpha_alpha or _p_p suffixes, or just predicting the upstream version |
164 |
use. |
165 |
|
166 |
The convenience Ruby ~> operator needs to be expanded to the verbose |
167 |
range: |
168 |
|
169 |
[>=1.3.4,<1.4] or [>=1.3.4,==1.3*] |
170 |
|
171 |
|
172 |
Rationale |
173 |
========= |
174 |
|
175 |
The key goal behind this concept is to optimize for upstream version |
176 |
specifications, and provide the minimal reasonable, clear, symmetric |
177 |
set of tools needed to achieve the correct dependencies. |
178 |
|
179 |
The version syntax changes are necessary to be able to clearly express |
180 |
version ranges, and also to distinguish old and new operators. |
181 |
Furthermore, they increase the readability and usefulness of package |
182 |
dependency specifications. The square braces and ordering are based |
183 |
after Exherbo but can be changed if necessary. |
184 |
|
185 |
The "," separator for versions is copied from USE dependencies which |
186 |
are conjunctive as well. The disjunctive variant was not included since |
187 |
our research has shown that it is used very rarely (i.e. only once |
188 |
in the few base Exherbo repositories we've checked). Any more complex |
189 |
logic would only make the dependencies less readable for unlikely |
190 |
benefit. |
191 |
|
192 |
The default behavior for new operators is meant to accommodate |
193 |
the common necessity of expressing upstream version restrictions |
194 |
in ebuilds. Its major advantage is that all the operators behave |
195 |
symmetrically now (i.e. you don't have to add -r9999 to some of them to |
196 |
match upstream constraints). |
197 |
|
198 |
The additional ===, !==, >==, <== operators are provided to accommodate |
199 |
Gentoo-specific revision constraints, and distinguish them from plain |
200 |
upstream version constraints. No variant for '<' and '>' is provided |
201 |
since the resulting syntax would be colliding or confusing, and all |
202 |
possible revisions can be already expressed clearly using existing |
203 |
operators. |
204 |
|
205 |
Negations were added for the == and === equality operators to help |
206 |
constructing version ranges. They also provide major readability |
207 |
(and behavior) benefit over the current necessity of disallowing |
208 |
single versions via blockers. |
209 |
|
210 |
The prefix matching behavior was retained since it has its use cases. |
211 |
Furthermore, it becomes useful with conjunctive version ranger to |
212 |
disallow single versions matching a generic range. |
213 |
|
214 |
-- |
215 |
Best regards, |
216 |
Michał Górny |
217 |
<http://dev.gentoo.org/~mgorny/> |