1 |
Author: zmedico |
2 |
Date: 2009-06-19 20:19:30 +0000 (Fri, 19 Jun 2009) |
3 |
New Revision: 13655 |
4 |
|
5 |
Modified: |
6 |
main/trunk/pym/_emerge/__init__.py |
7 |
Log: |
8 |
Bug #264434 - Delay evaluation of all disjunctive (virtual and ||) |
9 |
dependencies. Evaluting disjuctions as late as possible allows better |
10 |
decisions since the graph is more complete when the decisions are made. |
11 |
Thanks to Sebastian Mingramm (few) <s.mingramm@×××.de> for the initial |
12 |
patch. |
13 |
|
14 |
|
15 |
Modified: main/trunk/pym/_emerge/__init__.py |
16 |
=================================================================== |
17 |
--- main/trunk/pym/_emerge/__init__.py 2009-06-19 19:34:38 UTC (rev 13654) |
18 |
+++ main/trunk/pym/_emerge/__init__.py 2009-06-19 20:19:30 UTC (rev 13655) |
19 |
@@ -4754,6 +4754,7 @@ |
20 |
self._unsatisfied_blockers_for_display = None |
21 |
self._circular_deps_for_display = None |
22 |
self._dep_stack = [] |
23 |
+ self._dep_disjunctive_stack = [] |
24 |
self._unsatisfied_deps = [] |
25 |
self._initially_unsatisfied_deps = [] |
26 |
self._ignored_deps = [] |
27 |
@@ -5035,16 +5036,21 @@ |
28 |
|
29 |
def _create_graph(self, allow_unsatisfied=False): |
30 |
dep_stack = self._dep_stack |
31 |
- while dep_stack: |
32 |
+ dep_disjunctive_stack = self._dep_disjunctive_stack |
33 |
+ while dep_stack or dep_disjunctive_stack: |
34 |
self.spinner.update() |
35 |
- dep = dep_stack.pop() |
36 |
- if isinstance(dep, Package): |
37 |
- if not self._add_pkg_deps(dep, |
38 |
- allow_unsatisfied=allow_unsatisfied): |
39 |
+ while dep_stack: |
40 |
+ dep = dep_stack.pop() |
41 |
+ if isinstance(dep, Package): |
42 |
+ if not self._add_pkg_deps(dep, |
43 |
+ allow_unsatisfied=allow_unsatisfied): |
44 |
+ return 0 |
45 |
+ continue |
46 |
+ if not self._add_dep(dep, allow_unsatisfied=allow_unsatisfied): |
47 |
return 0 |
48 |
- continue |
49 |
- if not self._add_dep(dep, allow_unsatisfied=allow_unsatisfied): |
50 |
- return 0 |
51 |
+ if dep_disjunctive_stack: |
52 |
+ if not self._pop_disjunction(allow_unsatisfied): |
53 |
+ return 0 |
54 |
return 1 |
55 |
|
56 |
def _add_dep(self, dep, allow_unsatisfied=False): |
57 |
@@ -5354,6 +5360,9 @@ |
58 |
debug = "--debug" in self.myopts |
59 |
strict = mytype != "installed" |
60 |
try: |
61 |
+ if not strict: |
62 |
+ portage.dep._dep_check_strict = False |
63 |
+ |
64 |
for dep_root, dep_string, dep_priority in deps: |
65 |
if not dep_string: |
66 |
continue |
67 |
@@ -5362,6 +5371,29 @@ |
68 |
print "Parent: ", jbigkey |
69 |
print "Depstring:", dep_string |
70 |
print "Priority:", dep_priority |
71 |
+ |
72 |
+ try: |
73 |
+ |
74 |
+ dep_string = portage.dep.paren_normalize( |
75 |
+ portage.dep.use_reduce( |
76 |
+ portage.dep.paren_reduce(dep_string), |
77 |
+ uselist=pkg.use.enabled)) |
78 |
+ |
79 |
+ dep_string = list(self._queue_disjunctive_deps( |
80 |
+ pkg, dep_root, dep_priority, dep_string)) |
81 |
+ |
82 |
+ except portage.exception.InvalidDependString, e: |
83 |
+ if pkg.installed: |
84 |
+ del e |
85 |
+ continue |
86 |
+ show_invalid_depstring_notice(pkg, dep_string, str(e)) |
87 |
+ return 0 |
88 |
+ |
89 |
+ if not dep_string: |
90 |
+ continue |
91 |
+ |
92 |
+ dep_string = portage.dep.paren_enclose(dep_string) |
93 |
+ |
94 |
vardb = self.roots[dep_root].trees["vartree"].dbapi |
95 |
try: |
96 |
selected_atoms = self._select_atoms(dep_root, |
97 |
@@ -5416,8 +5448,110 @@ |
98 |
portage.writemsg("!!! Please notify the package maintainer " + \ |
99 |
"that atoms must be fully-qualified.\n", noiselevel=-1) |
100 |
return 0 |
101 |
+ finally: |
102 |
+ portage.dep._dep_check_strict = True |
103 |
return 1 |
104 |
|
105 |
+ def _queue_disjunctive_deps(self, pkg, dep_root, dep_priority, dep_struct): |
106 |
+ """ |
107 |
+ Queue disjunctive (virtual and ||) deps in self._dep_disjunctive_stack. |
108 |
+ Yields non-disjunctive deps. Raises InvalidDependString when |
109 |
+ necessary. |
110 |
+ """ |
111 |
+ i = 0 |
112 |
+ while i < len(dep_struct): |
113 |
+ x = dep_struct[i] |
114 |
+ if isinstance(x, list): |
115 |
+ for y in self._queue_disjunctive_deps( |
116 |
+ pkg, dep_root, dep_priority, x): |
117 |
+ yield y |
118 |
+ elif x == "||": |
119 |
+ self._queue_disjunction(pkg, dep_root, dep_priority, |
120 |
+ [ x, dep_struct[ i + 1 ] ] ) |
121 |
+ i += 1 |
122 |
+ else: |
123 |
+ try: |
124 |
+ x = portage.dep.Atom(x) |
125 |
+ except portage.exception.InvalidAtom: |
126 |
+ if not pkg.installed: |
127 |
+ raise portage.exception.InvalidDependString( |
128 |
+ "invalid atom: '%s'" % x) |
129 |
+ else: |
130 |
+ # Note: Eventually this will check for PROPERTIES=virtual |
131 |
+ # or whatever other metadata gets implemented for this |
132 |
+ # purpose. |
133 |
+ if x.cp.startswith('virtual/'): |
134 |
+ self._queue_disjunction( pkg, dep_root, |
135 |
+ dep_priority, [ str(x) ] ) |
136 |
+ else: |
137 |
+ yield str(x) |
138 |
+ i += 1 |
139 |
+ |
140 |
+ def _queue_disjunction(self, pkg, dep_root, dep_priority, dep_struct): |
141 |
+ self._dep_disjunctive_stack.append( |
142 |
+ (pkg, dep_root, dep_priority, dep_struct)) |
143 |
+ |
144 |
+ def _pop_disjunction(self, allow_unsatisfied): |
145 |
+ """ |
146 |
+ Pop one disjunctive dep from self._dep_disjunctive_stack, and use it to |
147 |
+ populate self._dep_stack. |
148 |
+ """ |
149 |
+ pkg, dep_root, dep_priority, dep_struct = \ |
150 |
+ self._dep_disjunctive_stack.pop() |
151 |
+ depth = pkg.depth + 1 |
152 |
+ debug = "--debug" in self.myopts |
153 |
+ strict = pkg.type_name != "installed" |
154 |
+ dep_string = portage.dep.paren_enclose(dep_struct) |
155 |
+ |
156 |
+ if debug: |
157 |
+ print |
158 |
+ print "Parent: ", pkg |
159 |
+ print "Depstring:", dep_string |
160 |
+ print "Priority:", dep_priority |
161 |
+ |
162 |
+ try: |
163 |
+ selected_atoms = self._select_atoms(dep_root, |
164 |
+ dep_string, myuse=pkg.use.enabled, parent=pkg, |
165 |
+ strict=strict, priority=dep_priority) |
166 |
+ except portage.exception.InvalidDependString, e: |
167 |
+ show_invalid_depstring_notice(pkg, dep_string, str(e)) |
168 |
+ del e |
169 |
+ if pkg.installed: |
170 |
+ return 1 |
171 |
+ return 0 |
172 |
+ |
173 |
+ if debug: |
174 |
+ print "Candidates:", selected_atoms |
175 |
+ |
176 |
+ vardb = self.roots[dep_root].trees["vartree"].dbapi |
177 |
+ |
178 |
+ for atom in selected_atoms: |
179 |
+ try: |
180 |
+ |
181 |
+ atom = portage.dep.Atom(atom) |
182 |
+ |
183 |
+ mypriority = dep_priority.copy() |
184 |
+ if not atom.blocker and vardb.match(atom): |
185 |
+ mypriority.satisfied = True |
186 |
+ |
187 |
+ if not self._add_dep(Dependency(atom=atom, |
188 |
+ blocker=atom.blocker, depth=depth, parent=pkg, |
189 |
+ priority=mypriority, root=dep_root), |
190 |
+ allow_unsatisfied=allow_unsatisfied): |
191 |
+ return 0 |
192 |
+ |
193 |
+ except portage.exception.InvalidAtom, e: |
194 |
+ show_invalid_depstring_notice( |
195 |
+ pkg, dep_string, str(e)) |
196 |
+ del e |
197 |
+ if not pkg.installed: |
198 |
+ return 0 |
199 |
+ |
200 |
+ if debug: |
201 |
+ print "Exiting...", pkg |
202 |
+ |
203 |
+ return 1 |
204 |
+ |
205 |
def _priority(self, **kwargs): |
206 |
if "remove" in self.myparams: |
207 |
priority_constructor = UnmergeDepPriority |