Gentoo Archives: gentoo-commits

From: "Fabian Groffen (grobian)" <grobian@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] portage r11302 - in main/branches/prefix: cnf doc/config pym/_emerge pym/portage pym/portage/sets
Date: Thu, 31 Jul 2008 13:30:27
Message-Id: E1KOYEZ-0006w1-TR@stork.gentoo.org
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"]