1 |
Author: grobian |
2 |
Date: 2008-07-31 13:30:22 +0000 (Thu, 31 Jul 2008) |
3 |
New Revision: 11302 |
4 |
|
5 |
Modified: |
6 |
main/branches/prefix/cnf/make.globals |
7 |
main/branches/prefix/cnf/sets.conf |
8 |
main/branches/prefix/doc/config/sets.docbook |
9 |
main/branches/prefix/pym/_emerge/__init__.py |
10 |
main/branches/prefix/pym/_emerge/help.py |
11 |
main/branches/prefix/pym/portage/__init__.py |
12 |
main/branches/prefix/pym/portage/sets/dbapi.py |
13 |
Log: |
14 |
Merged from trunk 11287:11300 |
15 |
|
16 |
| 11288 | Bug #233421 - Fix grammar, missing "be" in --update | |
17 |
| zmedico | description. Thanks to Mikael Magnusson for this patch. | |
18 |
|
19 |
| 11289 | Split out a _spawn_fetch() function that will be useful for | |
20 |
| zmedico | implementing a userpriv testcase for bug #233303. | |
21 |
|
22 |
| 11290 | Fixes in portage.fetch() for bugs #233303 and #94133: * | |
23 |
| zmedico | Totally skip $DISTDIR creation if the fetch_to_ro feature is | |
24 |
| | enabled. * Don't touch $DISTDIR permissions unless unless | |
25 |
| | usepriv and/or userfetch are enabled. * When usepriv and/or | |
26 |
| | userfetch are enabled, test whether or not a process that | |
27 |
| | has dropped privileges is able to create a file in the | |
28 |
| | directory, and only adjust permissions if the test fails. * | |
29 |
| | Completely | |
30 |
|
31 |
| 11291 | disable default IONICE command as it breaks for non-root, | |
32 |
| genone | and ionice might not always be available | |
33 |
|
34 |
| 11292 | Implement a new @live-ebuilds which is generated from | |
35 |
| zmedico | installed packages that inherit from know live eclasses such | |
36 |
| | as cvs, darcs, git, mercurial, and subversion. The list of | |
37 |
| | eclasses is controlled by an "inherits" attribute that is | |
38 |
| | configure in sets.conf for and instance of InheritSet. This | |
39 |
| | set serves a purpose similar to the -scm ebuild suffix that | |
40 |
| | has been proposed in GLEP 54. | |
41 |
|
42 |
| 11293 | Add a new @module-rebuild set which emulates the behavior of | |
43 |
| zmedico | the module-rebuild tool. The /lib/modules path is set in | |
44 |
| | sets.conf via a "files" attribute of an OwnerSet instance. | |
45 |
| | This can be easily used to define similar sets based on | |
46 |
| | paths on installed files. | |
47 |
|
48 |
| 11294 | Remove quotes since the seem to cause incorrect results. | |
49 |
| zmedico | | |
50 |
|
51 |
| 11295 | * Rename @live-ebuilds to @live-rebuild, for consistency | |
52 |
| zmedico | with the other *-rebuild sets. * Document the new sets. | |
53 |
|
54 |
| 11296 | Describe InheritSet and OwnerSet. | |
55 |
| zmedico | | |
56 |
|
57 |
| 11297 | Bug #233458 - Fix AsynchronousTask exit listener handling so | |
58 |
| zmedico | that an exit listener will never get called after it's been | |
59 |
| | passed into removeExitListener(), since the caller of | |
60 |
| | removeExitListener() needs to be able to be able to trust | |
61 |
| | that the given exit listener will not be called under any | |
62 |
| | circumstances. | |
63 |
|
64 |
| 11298 | Always invalidate results from | |
65 |
| zmedico | _userpriv_test_write_file_cache when adjusting permissions | |
66 |
| | on a given directory. | |
67 |
|
68 |
| 11299 | Bug #233253 - Implement a @downgrade set which selects | |
69 |
| zmedico | packages for which the highest visible ebuild version is | |
70 |
| | lower than the currently installed version. This is useful | |
71 |
| | if you have installed packages from an overlay and you want | |
72 |
| | to downgrade to the highest visible after removing the | |
73 |
| | overlay, even though the packages that will be dowgraded are | |
74 |
| | not necessarily masked in any way. | |
75 |
|
76 |
| 11300 | Fix DowngradeSet so it's safe for cases when no ebuild is | |
77 |
| zmedico | available. | |
78 |
|
79 |
|
80 |
Modified: main/branches/prefix/cnf/make.globals |
81 |
=================================================================== |
82 |
--- main/branches/prefix/cnf/make.globals 2008-07-31 13:26:41 UTC (rev 11301) |
83 |
+++ main/branches/prefix/cnf/make.globals 2008-07-31 13:30:22 UTC (rev 11302) |
84 |
@@ -63,7 +63,8 @@ |
85 |
PORTAGE_FETCH_RESUME_MIN_SIZE="350K" |
86 |
|
87 |
# Command called to adjust the io priority of portage and it's subprocesses. |
88 |
-PORTAGE_IONICE_COMMAND="ionice -c 3 -p \${PID}" |
89 |
+# Note: should be wrapped inside a uid check |
90 |
+#PORTAGE_IONICE_COMMAND="ionice -c 3 -p \${PID}" |
91 |
|
92 |
# Number of times 'emerge --sync' will run before giving up. |
93 |
PORTAGE_RSYNC_RETRIES="3" |
94 |
|
95 |
Modified: main/branches/prefix/cnf/sets.conf |
96 |
=================================================================== |
97 |
--- main/branches/prefix/cnf/sets.conf 2008-07-31 13:26:41 UTC (rev 11301) |
98 |
+++ main/branches/prefix/cnf/sets.conf 2008-07-31 13:30:22 UTC (rev 11302) |
99 |
@@ -41,3 +41,21 @@ |
100 |
[preserved-rebuild] |
101 |
class = portage.sets.libs.PreservedLibraryConsumerSet |
102 |
world-candidate = False |
103 |
+ |
104 |
+# Installed ebuilds that inherit from known live eclasses. |
105 |
+[live-rebuild] |
106 |
+class = portage.sets.dbapi.InheritSet |
107 |
+world-candidate = False |
108 |
+inherits = cvs darcs git mercurial subversion |
109 |
+ |
110 |
+# Installed packages that own files inside /lib/modules. |
111 |
+[module-rebuild] |
112 |
+class = portage.sets.dbapi.OwnerSet |
113 |
+world-candidate = False |
114 |
+files = /lib/modules |
115 |
+ |
116 |
+# Installed packages for which the highest visible ebuild |
117 |
+# version is lower than the currently installed version. |
118 |
+[downgrade] |
119 |
+class = portage.sets.dbapi.DowngradeSet |
120 |
+world-candidate = False |
121 |
|
122 |
Modified: main/branches/prefix/doc/config/sets.docbook |
123 |
=================================================================== |
124 |
--- main/branches/prefix/doc/config/sets.docbook 2008-07-31 13:26:41 UTC (rev 11301) |
125 |
+++ main/branches/prefix/doc/config/sets.docbook 2008-07-31 13:30:22 UTC (rev 11302) |
126 |
@@ -453,6 +453,41 @@ |
127 |
</para> |
128 |
</sect3> |
129 |
</sect2> |
130 |
+ <sect2 id='config-set-classes-InheritSet'> |
131 |
+ <title>portage.sets.dbapi.InheritSet</title> |
132 |
+ <para> |
133 |
+ Package set which contains all packages |
134 |
+ that inherit one or more specific eclasses. |
135 |
+ This class supports the following options: |
136 |
+ <itemizedlist> |
137 |
+ <listitem><varname>inherits</varname>: Required. A list of eclass names |
138 |
+ which should be used to create the package set. |
139 |
+ </listitem> |
140 |
+ </itemizedlist> |
141 |
+ </para> |
142 |
+ </sect2> |
143 |
+ <sect2 id='config-set-classes-OwnerSet'> |
144 |
+ <title>portage.sets.dbapi.OwnerSet</title> |
145 |
+ <para> |
146 |
+ Package set which contains all packages |
147 |
+ that own one or more files. |
148 |
+ This class supports the following options: |
149 |
+ <itemizedlist> |
150 |
+ <listitem><varname>files</varname>: Required. A list of file paths |
151 |
+ that should be used to create the package set. |
152 |
+ </listitem> |
153 |
+ </itemizedlist> |
154 |
+ </para> |
155 |
+ </sect2> |
156 |
+ <sect2 id='config-set-classes-DowngradeSet'> |
157 |
+ <title>portage.sets.dbapi.DowngradeSet</title> |
158 |
+ <para> |
159 |
+ Package set which contains all packages |
160 |
+ for which the highest visible ebuild version is lower than |
161 |
+ the currently installed version. |
162 |
+ This class doesn't support any extra options. |
163 |
+ </para> |
164 |
+ </sect2> |
165 |
<sect2 id='config-set-classes-PreservedLibraryConsumerSet'> |
166 |
<title>portage.sets.libs.PreservedLibraryConsumerSet</title> |
167 |
<para> |
168 |
@@ -490,6 +525,9 @@ |
169 |
<listitem><varname>security</varname>: uses <classname>NewAffectedSet</classname> with default options</listitem> |
170 |
<listitem><varname>everything</varname>: uses <classname>EverythingSet</classname></listitem> |
171 |
<listitem><varname>preserved-rebuild</varname>: uses <classname>PreservedLibraryConsumerSet</classname></listitem> |
172 |
+ <listitem><varname>live-rebuild</varname>: uses <classname>InheritSet</classname></listitem> |
173 |
+ <listitem><varname>module-rebuild</varname>: uses <classname>OwnerSet</classname></listitem> |
174 |
+ <listitem><varname>downgrade</varname>: uses <classname>DowngradeSet</classname></listitem> |
175 |
</itemizedlist> |
176 |
Additionally the default configuration includes a multi set section based on |
177 |
the <classname>StaticFileSet</classname> defaults that creates a set for each |
178 |
|
179 |
Modified: main/branches/prefix/pym/_emerge/__init__.py |
180 |
=================================================================== |
181 |
--- main/branches/prefix/pym/_emerge/__init__.py 2008-07-31 13:26:41 UTC (rev 11301) |
182 |
+++ main/branches/prefix/pym/_emerge/__init__.py 2008-07-31 13:30:22 UTC (rev 11302) |
183 |
@@ -1626,7 +1626,7 @@ |
184 |
""" |
185 |
|
186 |
__slots__ = ("background", "cancelled", "returncode") + \ |
187 |
- ("_exit_listeners", "_start_listeners") |
188 |
+ ("_exit_listeners", "_exit_listener_stack", "_start_listeners") |
189 |
|
190 |
def start(self): |
191 |
""" |
192 |
@@ -1692,6 +1692,8 @@ |
193 |
|
194 |
def removeExitListener(self, f): |
195 |
if self._exit_listeners is None: |
196 |
+ if self._exit_listener_stack is not None: |
197 |
+ self._exit_listener_stack.remove(f) |
198 |
return |
199 |
self._exit_listeners.remove(f) |
200 |
|
201 |
@@ -1707,12 +1709,22 @@ |
202 |
|
203 |
# This prevents recursion, in case one of the |
204 |
# exit handlers triggers this method again by |
205 |
- # calling wait(). |
206 |
- exit_listeners = self._exit_listeners |
207 |
+ # calling wait(). Use a stack that gives |
208 |
+ # removeExitListener() an opportunity to consume |
209 |
+ # listeners from the stack, before they can get |
210 |
+ # called below. This is necessary because a call |
211 |
+ # to one exit listener may result in a call to |
212 |
+ # removeExitListener() for another listener on |
213 |
+ # the stack. That listener needs to be removed |
214 |
+ # from the stack since it would be inconsistent |
215 |
+ # to call it after it has been been passed into |
216 |
+ # removeExitListener(). |
217 |
+ self._exit_listener_stack = self._exit_listeners |
218 |
self._exit_listeners = None |
219 |
|
220 |
- for f in exit_listeners: |
221 |
- f(self) |
222 |
+ self._exit_listener_stack.reverse() |
223 |
+ while self._exit_listener_stack: |
224 |
+ self._exit_listener_stack.pop()(self) |
225 |
|
226 |
class PipeReader(AsynchronousTask): |
227 |
|
228 |
|
229 |
Modified: main/branches/prefix/pym/_emerge/help.py |
230 |
=================================================================== |
231 |
--- main/branches/prefix/pym/_emerge/help.py 2008-07-31 13:26:41 UTC (rev 11301) |
232 |
+++ main/branches/prefix/pym/_emerge/help.py 2008-07-31 13:30:22 UTC (rev 11302) |
233 |
@@ -189,8 +189,8 @@ |
234 |
print " Updates packages to the best version available, which may not" |
235 |
print " always be the highest version number due to masking for testing" |
236 |
print " and development. This will also update direct dependencies which" |
237 |
- print " may not what you want. Package atoms specified on the command line" |
238 |
- print " are greedy, meaning that unspecific atoms may match multiple" |
239 |
+ print " may not be what you want. Package atoms specified on the command" |
240 |
+ print " line are greedy, meaning that unspecific atoms may match multiple" |
241 |
print " installed versions of slotted packages." |
242 |
print |
243 |
print " "+green("--version")+" ("+green("-V")+" short option)" |
244 |
|
245 |
Modified: main/branches/prefix/pym/portage/__init__.py |
246 |
=================================================================== |
247 |
--- main/branches/prefix/pym/portage/__init__.py 2008-07-31 13:26:41 UTC (rev 11301) |
248 |
+++ main/branches/prefix/pym/portage/__init__.py 2008-07-31 13:30:22 UTC (rev 11302) |
249 |
@@ -3167,6 +3167,84 @@ |
250 |
return retval >> 8 |
251 |
return retval |
252 |
|
253 |
+_userpriv_spawn_kwargs = ( |
254 |
+ ("uid", portage_uid), |
255 |
+ ("gid", portage_gid), |
256 |
+ ("groups", userpriv_groups), |
257 |
+ ("umask", 002), |
258 |
+) |
259 |
+ |
260 |
+def _spawn_fetch(settings, args, **kwargs): |
261 |
+ """ |
262 |
+ Spawn a process with appropriate settings for fetching, including |
263 |
+ userfetch and selinux support. |
264 |
+ """ |
265 |
+ |
266 |
+ global _userpriv_spawn_kwargs |
267 |
+ |
268 |
+ # Redirect all output to stdout since some fetchers like |
269 |
+ # wget pollute stderr (if portage detects a problem then it |
270 |
+ # can send it's own message to stderr). |
271 |
+ if "fd_pipes" not in kwargs: |
272 |
+ |
273 |
+ kwargs["fd_pipes"] = { |
274 |
+ 0 : sys.stdin.fileno(), |
275 |
+ 1 : sys.stdout.fileno(), |
276 |
+ 2 : sys.stdout.fileno(), |
277 |
+ } |
278 |
+ |
279 |
+ if "userfetch" in settings.features and \ |
280 |
+ os.getuid() == 0 and portage_gid and portage_uid: |
281 |
+ kwargs.update(_userpriv_spawn_kwargs) |
282 |
+ |
283 |
+ try: |
284 |
+ |
285 |
+ if settings.selinux_enabled(): |
286 |
+ con = selinux.getcontext() |
287 |
+ con = con.replace(settings["PORTAGE_T"], settings["PORTAGE_FETCH_T"]) |
288 |
+ selinux.setexec(con) |
289 |
+ # bash is an allowed entrypoint, while most binaries are not |
290 |
+ if args[0] != BASH_BINARY: |
291 |
+ args = [BASH_BINARY, "-c", "exec \"$@\"", args[0]] + args |
292 |
+ |
293 |
+ rval = portage.process.spawn(args, |
294 |
+ env=dict(settings.iteritems()), **kwargs) |
295 |
+ |
296 |
+ finally: |
297 |
+ if settings.selinux_enabled(): |
298 |
+ selinux.setexec(None) |
299 |
+ |
300 |
+ return rval |
301 |
+ |
302 |
+_userpriv_test_write_file_cache = {} |
303 |
+_userpriv_test_write_cmd_script = "> %(file_path)s ; rval=$? ; " + \ |
304 |
+ "rm -f %(file_path)s ; exit $rval" |
305 |
+ |
306 |
+def _userpriv_test_write_file(settings, file_path): |
307 |
+ """ |
308 |
+ Drop privileges and try to open a file for writing. The file may or |
309 |
+ may not exist, and the parent directory is assumed to exist. The file |
310 |
+ is removed before returning. |
311 |
+ |
312 |
+ @param settings: A config instance which is passed to _spawn_fetch() |
313 |
+ @param file_path: A file path to open and write. |
314 |
+ @return: True if write succeeds, False otherwise. |
315 |
+ """ |
316 |
+ |
317 |
+ global _userpriv_test_write_file_cache, _userpriv_test_write_cmd_script |
318 |
+ rval = _userpriv_test_write_file_cache.get(file_path) |
319 |
+ if rval is not None: |
320 |
+ return rval |
321 |
+ |
322 |
+ args = [BASH_BINARY, "-c", _userpriv_test_write_cmd_script % \ |
323 |
+ {"file_path" : _shell_quote(file_path)}] |
324 |
+ |
325 |
+ returncode = _spawn_fetch(settings, args) |
326 |
+ |
327 |
+ rval = returncode == os.EX_OK |
328 |
+ _userpriv_test_write_file_cache[file_path] = rval |
329 |
+ return rval |
330 |
+ |
331 |
def _checksum_failure_temp_file(distdir, basename): |
332 |
""" |
333 |
First try to find a duplicate temp file with the same checksum and return |
334 |
@@ -3274,6 +3352,11 @@ |
335 |
|
336 |
features = mysettings.features |
337 |
restrict = mysettings.get("PORTAGE_RESTRICT","").split() |
338 |
+ |
339 |
+ from portage.data import secpass |
340 |
+ userfetch = secpass >= 2 and "userfetch" in features |
341 |
+ userpriv = secpass >= 2 and "userpriv" in features |
342 |
+ |
343 |
# 'nomirror' is bad/negative logic. You Restrict mirroring, not no-mirroring. |
344 |
if "mirror" in restrict or \ |
345 |
"nomirror" in restrict: |
346 |
@@ -3473,7 +3556,8 @@ |
347 |
if not mysettings.get(var_name, None): |
348 |
can_fetch = False |
349 |
|
350 |
- if can_fetch: |
351 |
+ if can_fetch and not fetch_to_ro: |
352 |
+ global _userpriv_test_write_file_cache |
353 |
dirmode = 02070 |
354 |
filemode = 060 |
355 |
modemask = 02 |
356 |
@@ -3491,6 +3575,16 @@ |
357 |
|
358 |
for x in distdir_dirs: |
359 |
mydir = os.path.join(mysettings["DISTDIR"], x) |
360 |
+ write_test_file = os.path.join( |
361 |
+ mydir, ".__portage_test_write__") |
362 |
+ |
363 |
+ if os.path.isdir(mydir): |
364 |
+ if not (userfetch or userpriv): |
365 |
+ continue |
366 |
+ if _userpriv_test_write_file(mysettings, write_test_file): |
367 |
+ continue |
368 |
+ |
369 |
+ _userpriv_test_write_file_cache.pop(write_test_file, None) |
370 |
if portage.util.ensure_dirs(mydir, gid=dir_gid, mode=dirmode, mask=modemask): |
371 |
writemsg("Adjusting permissions recursively: '%s'\n" % mydir, |
372 |
noiselevel=-1) |
373 |
@@ -3840,39 +3934,11 @@ |
374 |
lexer = shlex.shlex(StringIO.StringIO(locfetch), posix=True) |
375 |
lexer.whitespace_split = True |
376 |
myfetch = [varexpand(x, mydict=variables) for x in lexer] |
377 |
- |
378 |
- spawn_keywords = {} |
379 |
- # Redirect all output to stdout since some fetchers like |
380 |
- # wget pollute stderr (if portage detects a problem then it |
381 |
- # can send it's own message to stderr). |
382 |
- spawn_keywords["fd_pipes"] = { |
383 |
- 0:sys.stdin.fileno(), |
384 |
- 1:sys.stdout.fileno(), |
385 |
- 2:sys.stdout.fileno() |
386 |
- } |
387 |
- if "userfetch" in mysettings.features and \ |
388 |
- os.getuid() == 0 and portage_gid and portage_uid: |
389 |
- spawn_keywords.update({ |
390 |
- "uid" : portage_uid, |
391 |
- "gid" : portage_gid, |
392 |
- "groups" : userpriv_groups, |
393 |
- "umask" : 002}) |
394 |
myret = -1 |
395 |
try: |
396 |
|
397 |
- if mysettings.selinux_enabled(): |
398 |
- con = selinux.getcontext() |
399 |
- con = con.replace(mysettings["PORTAGE_T"], mysettings["PORTAGE_FETCH_T"]) |
400 |
- selinux.setexec(con) |
401 |
- # bash is an allowed entrypoint, while most binaries are not |
402 |
- myfetch = ["bash", "-c", "exec \"$@\"", myfetch[0]] + myfetch |
403 |
+ myret = _spawn_fetch(mysettings, myfetch) |
404 |
|
405 |
- myret = portage.process.spawn(myfetch, |
406 |
- env=dict(mysettings.iteritems()), **spawn_keywords) |
407 |
- |
408 |
- if mysettings.selinux_enabled(): |
409 |
- selinux.setexec(None) |
410 |
- |
411 |
finally: |
412 |
try: |
413 |
apply_secpass_permissions(myfile_path, |
414 |
|
415 |
Modified: main/branches/prefix/pym/portage/sets/dbapi.py |
416 |
=================================================================== |
417 |
--- main/branches/prefix/pym/portage/sets/dbapi.py 2008-07-31 13:26:41 UTC (rev 11301) |
418 |
+++ main/branches/prefix/pym/portage/sets/dbapi.py 2008-07-31 13:30:22 UTC (rev 11302) |
419 |
@@ -2,11 +2,11 @@ |
420 |
# Distributed under the terms of the GNU General Public License v2 |
421 |
# $Id$ |
422 |
|
423 |
-from portage.versions import catsplit |
424 |
+from portage.versions import catpkgsplit, catsplit, pkgcmp |
425 |
from portage.sets.base import PackageSet |
426 |
from portage.sets import SetConfigError, get_boolean |
427 |
|
428 |
-__all__ = ["CategorySet", "EverythingSet"] |
429 |
+__all__ = ["CategorySet", "EverythingSet", "InheritSet"] |
430 |
|
431 |
class EverythingSet(PackageSet): |
432 |
_operations = ["merge", "unmerge"] |
433 |
@@ -32,6 +32,119 @@ |
434 |
return EverythingSet(trees["vartree"].dbapi) |
435 |
singleBuilder = classmethod(singleBuilder) |
436 |
|
437 |
+class OwnerSet(PackageSet): |
438 |
+ |
439 |
+ _operations = ["merge", "unmerge"] |
440 |
+ |
441 |
+ description = "Package set which contains all packages " + \ |
442 |
+ "that own one or more files." |
443 |
+ |
444 |
+ def __init__(self, vardb=None, files=None): |
445 |
+ super(OwnerSet, self).__init__() |
446 |
+ self._db = vardb |
447 |
+ self._files = files |
448 |
+ |
449 |
+ def mapPathsToAtoms(self, paths): |
450 |
+ rValue = set() |
451 |
+ vardb = self._db |
452 |
+ aux_get = vardb.aux_get |
453 |
+ aux_keys = ["SLOT"] |
454 |
+ for link, p in vardb._owners.iter_owners(paths): |
455 |
+ cat, pn = catpkgsplit(link.mycpv)[:2] |
456 |
+ slot, = aux_get(link.mycpv, aux_keys) |
457 |
+ rValue.add("%s/%s:%s" % (cat, pn, slot)) |
458 |
+ return rValue |
459 |
+ |
460 |
+ def load(self): |
461 |
+ self._setAtoms(self.mapPathsToAtoms(self._files)) |
462 |
+ |
463 |
+ def singleBuilder(cls, options, settings, trees): |
464 |
+ if not "files" in options: |
465 |
+ raise SetConfigError("no files given") |
466 |
+ |
467 |
+ import shlex |
468 |
+ return cls(vardb=trees["vartree"].dbapi, |
469 |
+ files=frozenset(shlex.split(options["files"]))) |
470 |
+ |
471 |
+ singleBuilder = classmethod(singleBuilder) |
472 |
+ |
473 |
+class InheritSet(PackageSet): |
474 |
+ |
475 |
+ _operations = ["merge", "unmerge"] |
476 |
+ |
477 |
+ description = "Package set which contains all packages " + \ |
478 |
+ "that inherit one or more specific eclasses." |
479 |
+ |
480 |
+ def __init__(self, vardb=None, inherits=None): |
481 |
+ super(InheritSet, self).__init__() |
482 |
+ self._db = vardb |
483 |
+ self._inherits = inherits |
484 |
+ |
485 |
+ def load(self): |
486 |
+ atoms = [] |
487 |
+ inherits = self._inherits |
488 |
+ cp_list = self._db.cp_list |
489 |
+ aux_get = self._db.aux_get |
490 |
+ aux_keys = ["INHERITED", "SLOT"] |
491 |
+ for cp in self._db.cp_all(): |
492 |
+ for cpv in cp_list(cp): |
493 |
+ inherited, slot = aux_get(cpv, aux_keys) |
494 |
+ inherited = inherited.split() |
495 |
+ if inherits.intersection(inherited): |
496 |
+ atoms.append("%s:%s" % (cp, slot)) |
497 |
+ |
498 |
+ self._setAtoms(atoms) |
499 |
+ |
500 |
+ def singleBuilder(cls, options, settings, trees): |
501 |
+ if not "inherits" in options: |
502 |
+ raise SetConfigError("no inherits given") |
503 |
+ |
504 |
+ inherits = options["inherits"] |
505 |
+ return cls(vardb=trees["vartree"].dbapi, |
506 |
+ inherits=frozenset(inherits.split())) |
507 |
+ |
508 |
+ singleBuilder = classmethod(singleBuilder) |
509 |
+ |
510 |
+class DowngradeSet(PackageSet): |
511 |
+ |
512 |
+ _operations = ["merge", "unmerge"] |
513 |
+ |
514 |
+ description = "Package set which contains all packages " + \ |
515 |
+ "for which the highest visible ebuild version is lower than " + \ |
516 |
+ "the currently installed version." |
517 |
+ |
518 |
+ def __init__(self, portdb=None, vardb=None): |
519 |
+ super(DowngradeSet, self).__init__() |
520 |
+ self._portdb = portdb |
521 |
+ self._vardb = vardb |
522 |
+ |
523 |
+ def load(self): |
524 |
+ atoms = [] |
525 |
+ xmatch = self._portdb.xmatch |
526 |
+ xmatch_level = "bestmatch-visible" |
527 |
+ cp_list = self._vardb.cp_list |
528 |
+ aux_get = self._vardb.aux_get |
529 |
+ aux_keys = ["SLOT"] |
530 |
+ for cp in self._vardb.cp_all(): |
531 |
+ for cpv in cp_list(cp): |
532 |
+ slot, = aux_get(cpv, aux_keys) |
533 |
+ slot_atom = "%s:%s" % (cp, slot) |
534 |
+ ebuild = xmatch(xmatch_level, slot_atom) |
535 |
+ if not ebuild: |
536 |
+ continue |
537 |
+ ebuild_split = catpkgsplit(ebuild)[1:] |
538 |
+ installed_split = catpkgsplit(cpv)[1:] |
539 |
+ if pkgcmp(installed_split, ebuild_split) > 0: |
540 |
+ atoms.append(slot_atom) |
541 |
+ |
542 |
+ self._setAtoms(atoms) |
543 |
+ |
544 |
+ def singleBuilder(cls, options, settings, trees): |
545 |
+ return cls(portdb=trees["porttree"].dbapi, |
546 |
+ vardb=trees["vartree"].dbapi) |
547 |
+ |
548 |
+ singleBuilder = classmethod(singleBuilder) |
549 |
+ |
550 |
class CategorySet(PackageSet): |
551 |
_operations = ["merge", "unmerge"] |