1 |
On Sat, 03 Jun 2017 17:33:09 +0200 |
2 |
Michał Górny <mgorny@g.o> wrote: |
3 |
|
4 |
> On sob, 2017-06-03 at 13:00 +0200, Alexis Ballier wrote: |
5 |
> > This whole thing definitely needs more thought and feedback but for |
6 |
> > now those extra restrictions seem quite natural to me, allow easy |
7 |
> > solving on the PM side and allow to have useful feedback from |
8 |
> > repoman. |
9 |
> |
10 |
> Well, I'll try to figure out the magic you were telling me later but |
11 |
> as a quick note, my specific use case for this are Python targets, so |
12 |
> I'm going throw a few basic concepts that need to work for you to |
13 |
> play with ;-). |
14 |
> |
15 |
> In the following samples pt1,2,.. stands for PYTHON_TARGETS; |
16 |
> pst1,2,... for PYTHON_SINGLE_TARGET. Eventually I'd like to kill the |
17 |
> latter but that depends on how well the autosolving works. |
18 |
> |
19 |
> 1. ^^ ( pst1 pst2 pst3.. ) pst1? ( pt1 ) pst2? ( pt2 ) pst3? ( pt3 ).. |
20 |
|
21 |
the pt{1,2,...} part does not matter here: they all fail point 4 when |
22 |
compared as 2nd clause to the others (each ptX appears only once in the |
23 |
whole expression), so this boils down to solving n-ary ^^, and to how |
24 |
those are translated: you can have several translations but some would |
25 |
not work properly. Let's try: |
26 |
(a) pst1? ( !pst2 !pst3 ) |
27 |
(b) pst2? ( !pst3 ) |
28 |
(c) !pst3? ( !pst2? ( pst1 ) ) |
29 |
|
30 |
Between (a) and (c), points 1 to 3 hold (those points are reflexive). |
31 |
For point 4, "a q'_j is some p_i" will hold in both ways, so we do |
32 |
actually have a cycle between them. Bad luck. |
33 |
|
34 |
Let's write (c) as: |
35 |
(c) !pst3? ( !pst2? ( !pst1? ( pst1 ) ) ) |
36 |
|
37 |
Now, (c) can't break (a) because of point 1: pst1 in (a) vs !pst1 in |
38 |
(c). |
39 |
|
40 |
|
41 |
(b) can't break (a) because of point 2: q_i=!pst2 is the negation of |
42 |
p_j=pst2. |
43 |
|
44 |
(c) can't break (b) because pst2 vs !pst2 (point 1). |
45 |
|
46 |
|
47 |
So, this formulation works: |
48 |
(a) pst1? ( !pst2 !pst3 ) |
49 |
(b) pst2? ( !pst3 ) |
50 |
(c) !pst3? ( !pst2? ( !pst1? ( pst1 ) ) ) |
51 |
|
52 |
USE="pst1 whatever" will enable only pst1. USE="-pst1 pst2 whatever" |
53 |
will enable only pst2. USE="-pst1 -pst2 pst3" will leave it alone. |
54 |
USE="-pst{1,2,3}" will enable pst1. |
55 |
|
56 |
|
57 |
|
58 |
Note that "pst1? ( pt1 ) pst2? ( pt2 ) pst3? ( pt3 ) ^^ ( pst1 pst2 |
59 |
pst3.. )" is a different story: (c) expanded as above can break 'pst1? |
60 |
( pt1 )' (point 4: a q'_j is some p_i) and you can actually check that |
61 |
with USE="-pt* -pst*"; you'll need 2 passes to get the proper solution. |
62 |
Fortunately, this is still a DAG and repoman would be able to propose an |
63 |
ordering requiring only one pass. |
64 |
|
65 |
|
66 |
[...] |
67 |
> 2. ^^ ( pst1 pst2.. ) pst1? ( pt1 ) pst2? ( pt2 ).. ^^ ( pt1 pt2 ) |
68 |
> |
69 |
> This is a possible extension of the above for the migration period. |
70 |
> The idea is that exactly one PST must be selected, and only the |
71 |
> matching PT must be selected (others are implicitly disabled). |
72 |
|
73 |
If we expand '^^ ( pt1 pt2 )' as above we get: |
74 |
(d) pt1? ( !pt2 ) |
75 |
(e) !pt2? ( !pt1? ( pt1 ) ) |
76 |
|
77 |
Here, (d) is annoying: it can break and be broken by 'pst2? ( pt2 )'. |
78 |
There would be a cycle and this would be rejected/notified. |
79 |
|
80 |
If you think about it, this would mean I have set USE="-* pt1 pst2"; |
81 |
pst2 forcing to enable pt2 but '^^ ( pt1 pt2 )' with pt1 enabled would |
82 |
prefer pt1 and disable pt2 again... This hints the solution: You need |
83 |
to define who wins between pt and pst. |
84 |
|
85 |
Instead you could write it: |
86 |
^^ ( pst1 pst2.. ) pst1? ( pt1 !pt2 ... ) pst2? ( !pt1 pt2 ... ).. |
87 |
But then 'pst2? ( !pt1 pt2 ... )' can break each other with 'pst1? |
88 |
( pt1 !pt2 ... )' in the sense I defined because of point 4 (A q_i is |
89 |
the negation of a q_'j); you'll get the repoman notification about a |
90 |
cycle. This is a case of a perfectly valid constraint that is rejected |
91 |
by the restriction. |
92 |
|
93 |
It is valid because we know we are guaranteed exactly one pstX will |
94 |
be enabled. We can hint the solver with that by writing: |
95 |
^^ ( pst1 pst2.. ) |
96 |
pst1? ( pt1 !pt2 ... ) |
97 |
pst2? ( !pt1? ( pt2 !pt3 ... ) ) |
98 |
pst3? ( !pt1? ( !pt2? ( pt3 !pt4 ... ) ) ) |
99 |
|
100 |
|
101 |
Now we're good: For j>i, solving a pst{j} line does not break a pst{i} |
102 |
one because of point 2: A q_i (pt{i}) is the negation of a p'_j |
103 |
(!pt{i}). |
104 |
|
105 |
|
106 |
|
107 |
It's getting a bit ugly but it's probably bearable with good reporting |
108 |
from static checkers (repoman). |
109 |
|
110 |
|
111 |
|
112 |
> 3. doc? ( || ( pt3 pt4 ) ) || ( pt1 pt2 pt3 pt4 ) |
113 |
> |
114 |
> This is distutils-r1 with USE=doc requiring python2. Note that it's |
115 |
> an example where the second || is added via eclass [NB: we've checked |
116 |
> and PMS says eclass values are appended to ebuild value]. |
117 |
|
118 |
|
119 |
Much simpler here: |
120 |
(a) doc? ( !pt4? ( pt3 ) ) |
121 |
(b) !pt4? ( !pt3? ( !pt2? ( pt1 ) ) |
122 |
|
123 |
(b) can't break (a) because of point 4: Neither 'a q_i is |
124 |
the negation of a q_'j' nor 'a q'_j is some p_i' hold. We're good. |
125 |
|
126 |
|
127 |
USE="-* doc" will enable pt3 only. USE="-* pt{whatever} doc" will |
128 |
enable pt3 (if not enabled) unless pt{whatever} contains pt4. |
129 |
|
130 |
Alexis. |