1 |
Hello, |
2 |
|
3 |
For a long time we seem to be missing appropriate tools to handle USE |
4 |
flag constraints efficiently. EAPI 4 brought REQUIRED_USE but all things |
5 |
considered, it has proven to be far from an optimal solution. I would |
6 |
therefore like to discuss adding a better tool to amend or replace it, |
7 |
to allow for automated handling of USE flag constraints. |
8 |
|
9 |
|
10 |
1. Motivation |
11 |
============= |
12 |
|
13 |
[[This section is purely informational. It is not up for discussion. If |
14 |
you really can't help yourself and need to discuss superiority of |
15 |
example A over example B, then please have mercy and wait for a few days |
16 |
to give developers a chance to stay focused on the proposal at hand.]] |
17 |
|
18 |
EAPI 4 provides REQUIRED_USE as a simple tool to enforce USE flag |
19 |
constraints for packages. It can be used to express dependencies between |
20 |
flags (e.g. A requires B). However, it poses a few problems which |
21 |
results in developers being reluctant to use them and which limit their |
22 |
use cases. Most notably: |
23 |
|
24 |
1. They require an explicit action from the user. A large number of USE |
25 |
flag constraints can be frustrating, especially when most of them are |
26 |
trivial to solve. |
27 |
|
28 |
2. They can cause a significant clutter in package.use. As a result, |
29 |
changing past decisions becomes hard as the user may need to find |
30 |
past USE flag changes and revert them. |
31 |
|
32 |
3. The constraint output is sometimes considered hard to comprehend. |
33 |
|
34 |
Those issues have resulted in developers sometimes avoiding REQUIRED_USE |
35 |
in favor of other solutions such as implicit behavior (ignoring USE |
36 |
flags), additional control flags (think PYTHON_SINGLE_TARGET) or |
37 |
pkg_pretend() (which is horribly slow). |
38 |
|
39 |
I think that the problems are most visible when dealing with 'provider |
40 |
flags', that is USE flags that are used to choose between different |
41 |
libraries providing the same feature. There are three basic approaches |
42 |
to the problem: |
43 |
|
44 |
A. Binary provider flags (+ feature flags), e.g.: |
45 |
|
46 |
USE='[ssl] libressl' -> use LibreSSL |
47 |
USE='[ssl] -libressl' -> use OpenSSL |
48 |
USE='-ssl' -> disable SSL/TLS (USE=libressl ignored) |
49 |
|
50 |
B. Unary provider flags with REQUIRED_USE: |
51 |
|
52 |
USE='libressl -openssl' -> use LibreSSL |
53 |
USE='-libressl openssl' -> use OpenSSL |
54 |
USE='libressl openssl' -> invalid |
55 |
USE='-libressl -openssl' -> disable SSL/TLS or invalid |
56 |
|
57 |
C. Unary provider flags without REQUIRED_USE: |
58 |
|
59 |
USE='libressl -openssl' -> use LibreSSL |
60 |
USE='-libressl openssl' -> use OpenSSL |
61 |
USE='libressl openssl' -> use LibreSSL or OpenSSL, depending on pkg |
62 |
USE='-libressl -openssl' -> disable SSL/TLS or as above |
63 |
|
64 |
Sometimes solutions B and C are amended with additional feature flags to |
65 |
reduce the confusion. |
66 |
|
67 |
Each of these solutions has its disadvantages. What's worse, they are |
68 |
sometimes not even used consistently within a single ecosystem -- going |
69 |
as far as using the same USE flag with slightly different meaning. |
70 |
The Gentoo developer attitude 'my package, my way' does not help here. |
71 |
|
72 |
Solving all of the listed problems is not possible with the existing |
73 |
tools as each of the possible solutions has its own issues, and it is |
74 |
impossible to get developers to agree on one of them. |
75 |
|
76 |
|
77 |
2. Specification |
78 |
================ |
79 |
|
80 |
2.1. Forced USE flag constraints |
81 |
================================ |
82 |
|
83 |
This proposal introduces USE flag constraints that are meant to be |
84 |
solved automatically by the package manager. This is somewhat similar to |
85 |
REQUIRED_USE, except that it does not require the user to take any |
86 |
explicit action. In that regard, it is closer to conditional |
87 |
package.use.force/mask. |
88 |
|
89 |
In the basic form, it can be used to conditionally force a specific flag |
90 |
to be enabled or disabled. For example: |
91 |
|
92 |
foo? ( bar ) |
93 |
|
94 |
would mean that the bar flag is implicitly enabled (forced) if foo is |
95 |
enabled as well. Appropriately: |
96 |
|
97 |
foo? ( !bar ) |
98 |
|
99 |
would mean that the bar flag is implicitly disabled (masked) in that |
100 |
case. |
101 |
|
102 |
It can also be used with multi-flag ??, ^^ and || constraints, i.e.: |
103 |
|
104 |
- ?? means that at most one of the flags can be enabled. If user |
105 |
configuration causes more than one of the flags to be enabled, |
106 |
additional flags are implicitly disabled (masked) to satisfy |
107 |
the constraint. |
108 |
|
109 |
- || means that at least one of the flags must be enabled. If user |
110 |
configuration causes none of the flags to be enabled, one of them is |
111 |
enabled implicitly (forced). |
112 |
|
113 |
- ^^ means that exactly one of the flags must be enabled. The behavior |
114 |
is a combination of both above constraints. |
115 |
|
116 |
The automated solving of USE constraints would require the developers to |
117 |
consider the implicit effect of the constraints they are writing. |
118 |
|
119 |
|
120 |
2.2. UI implications |
121 |
==================== |
122 |
|
123 |
The automated flag handling would require an appropriate UI changes, to |
124 |
clearly indicate whenever the flags are being altered automatically. |
125 |
Otherwise, users might be confused of their requested USE flags not |
126 |
being applied correctly. |
127 |
|
128 |
In the most basic form, a solution similar to use.force/use.mask can be |
129 |
used, e.g.: |
130 |
|
131 |
USE="[bar] [-baz] foo" |
132 |
|
133 |
with square brackets indicating that the flags have been forced/masked |
134 |
by other USE flags on the list. It would also be necessary for |
135 |
the package manager to provide more verbose information on USE flag |
136 |
constraints being applied, either implicitly or on request. |
137 |
|
138 |
For simple constraints, the visual presentation can be even included |
139 |
in place, e.g.: |
140 |
|
141 |
USE="foo -> [bar -baz]" |
142 |
|
143 |
indicating that both constraints were forced by the flag 'foo' (i.e. |
144 |
that disabling 'foo' would loosen them). |
145 |
|
146 |
For multi-flag constraints (??, ^^, ||), the package manager could even |
147 |
go as far to group the flags together with explicit constraint notation, |
148 |
e.g.: |
149 |
|
150 |
USE="^^ [ foo -bar -baz ]" |
151 |
|
152 |
The exact UI design is left to the package manager developers. Those are |
153 |
merely proof-of-concept ideas. |
154 |
|
155 |
|
156 |
2.3. Configuration bits |
157 |
======================= |
158 |
|
159 |
In its most basic form, this proposal does not require explicit |
160 |
configuration -- all flags are applied automatically. However, a few |
161 |
bits might be useful. |
162 |
|
163 |
Firstly, the package manager might provide a way to explicitly forbid |
164 |
switching specific flags or automatically applying the constraints |
165 |
completely. If the user uses that, it will just fail in the same way as |
166 |
REQUIRED_USE fails now. |
167 |
|
168 |
Secondly, it might be reasonable to provide configurable priorities for |
169 |
solving multi-flag constraints. For example, we could use rightmost- |
170 |
preferred logic for package.use, e.g.: |
171 |
|
172 |
*/* PROVIDER_SSL: openssl gnutls |
173 |
dev-util/foo PROVIDER_SSL: polarssl |
174 |
|
175 |
which would mean that for all packages, gnutls is preferred over openssl |
176 |
(i.e. if ?? or ^^ applies, openssl will be disabled and gnutls will be |
177 |
used), and polarssl is additionally preferred over everything else for |
178 |
dev-util/foo. |
179 |
|
180 |
|
181 |
2.4. Backwards compatibility |
182 |
============================ |
183 |
|
184 |
Before choosing the exact way of implementing this, we need to answer |
185 |
how far we want to provide backwards compatibility. In particular: |
186 |
|
187 |
a. Do we need the REQUIRED_USE requiring explicit user selection? Or can |
188 |
we rely completely on other solutions (automatic solving, |
189 |
pkg_pretend())? |
190 |
|
191 |
b. Would changing REQUIRED_USE behavior in place cause unintended side |
192 |
effects? Are we going to accept those effects until the packages are |
193 |
fixed? (e.g. selecting less preferred solution of constraint) |
194 |
|
195 |
If we can agree on doing the change in place (retroactively), I think we |
196 |
can start solving a few major issues. For example, I would be really |
197 |
happy to kill PYTHON_SINGLE_TARGET flags in favor of constraints on |
198 |
PYTHON_TARGETS being solved automatically. We could also look into |
199 |
unifying provider flags into PROVIDER_SSL, PROVIDER_AV etc. |
200 |
|
201 |
I should point out that strictly speaking, PMS does not define any |
202 |
specific handling of REQUIRED_USE. It only defines that the ebuild must |
203 |
not be used if the constraints are not met: |
204 |
|
205 |
| If the package manager encounters a package version where REQUIRED_USE |
206 |
| assertions are not met, it must treat this package version as if |
207 |
it |
208 |
| was masked. No phase functions must be |
209 |
called. |
210 |
|
211 |
|
212 |
In other words, it does not define whether the package manager should |
213 |
request the user to explicitly solve the problem or whether it should be |
214 |
solved automatically. However, from past discussions I recall that |
215 |
the original intent of REQUIRED_USE was for machine processing, and so I |
216 |
would consider it reasonable to start using it. |
217 |
|
218 |
|
219 |
2.5. Ebuild interface |
220 |
===================== |
221 |
|
222 |
This section is most flexible as I don't really care how it's done, |
223 |
as long as it's done. Depending on our preferences, and the answers to |
224 |
questions in the preceding section, the options include: |
225 |
|
226 |
1. changing behavior of REQUIRED_USE retroactively -- i.e. making |
227 |
Portage start solving USE constraints automatically, and being able to |
228 |
rely on that a few months from now, |
229 |
|
230 |
2. changing behavior of REQUIRED_USE in a future EAPI, |
231 |
|
232 |
3. adding ENFORCED_USE with the new behavior in a future EAPI |
233 |
(and either keeping or removing REQUIRED_USE), |
234 |
|
235 |
4. adding special syntax to REQUIRED_USE to indicate which constraints |
236 |
can be solved automatically, |
237 |
|
238 |
5. adding special syntax to IUSE to indicate which flags can be enabled |
239 |
or disabled automatically via REQUIRED_USE (a little different from |
240 |
the exact proposal), |
241 |
|
242 |
6. adding a dedicated variable to indicate USE_EXPAND sets that can be |
243 |
solved automatically via REQUIRED_USE (partial solution). |
244 |
|
245 |
|
246 |
3. Rationale |
247 |
============ |
248 |
|
249 |
I believe this solution to be quite optimal. It solves most of |
250 |
the issues with the REQUIRED_USE, making it a feasible solution to many |
251 |
of the existing problems, including those that were not even worth |
252 |
considering with the current REQUIRED_USE semantics. |
253 |
|
254 |
Reusing the existing syntax has the advantage of lowering the learning |
255 |
curve and simplifying the specification. We can even enable the new |
256 |
semantics without changing the PMS (provided that variant 1. is chosen), |
257 |
or with as little duplication as possible. However, the developers will |
258 |
be required to start considering the implicit effects of their |
259 |
constraints (as a matter of policy). |
260 |
|
261 |
Automatically solving USE constraints solve all three fore-mentioned |
262 |
issues with REQUIRED_USE. By default, no user intervention is required |
263 |
to solve USE constraints and package.use needs to be modified only to |
264 |
enforce a non-standard solutons. While the 'readability of output' is |
265 |
not really changed per se, most of the time users wouldn't have to read |
266 |
it. |
267 |
|
268 |
As pointed out throughout the text, automatically solved USE constraints |
269 |
can be used to replace existing hacks for different kinds of problems: |
270 |
|
271 |
A. Packages supporting selecting a subset of possible targets, e.g. |
272 |
Python implementations. Currently we have packages supporting 'any |
273 |
number of implementations', 'one implementation only' and 'one python2* |
274 |
+ one python3*'. For user convenience, we hacked the second into |
275 |
separate PYTHON_SINGLE_TARGET flags which encumbered the implementation |
276 |
seriously, and we discouraged the third case completely. With |
277 |
automatically solved USE constraints, we'd just use PYTHON_TARGETS for |
278 |
everything, and let the constraints handle invalid combinations, e.g.: |
279 |
|
280 |
PYTHON_TARGETS="python2_7 python3_5 {-python3_4} {-python3_6} ..." |
281 |
|
282 |
B. Provider flags. With automatically solved constraints, we can easily |
283 |
move them all into unary USE_EXPAND sets with USE constraints, and let |
284 |
the PM handle selecting the one most preferred automatically, e.g.: |
285 |
|
286 |
USE="[ssl]" PROVIDER_SSL="gnutls {-openssl} {-libressl} ..." |
287 |
|
288 |
What's important, the automatic flags have the advantage of being both |
289 |
clearer in meaning than implicit flags, and more convenient than |
290 |
REQUIRED_USE. In other words, the user clearly sees which implementation |
291 |
(provider) is used, and can change that in a relatively easy way. |
292 |
|
293 |
Furthermore, the explicit visibility of selection reduces the number of |
294 |
USE flag combinations in binary packages. That is, we can easily reduce |
295 |
the number of different apparent sets of USE flags that build the same |
296 |
package, making it easier for binary packages to match. |
297 |
|
298 |
|
299 |
4. Comments |
300 |
=========== |
301 |
|
302 |
What do you think? |
303 |
|
304 |
|
305 |
-- |
306 |
Best regards, |
307 |
Michał Górny |