Gentoo Archives: gentoo-commits

From: Sam James <sam@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] proj/portage:master commit in: bin/
Date: Sat, 31 Dec 2022 13:33:13
Message-Id: 1672493364.7141d7f0033bc7bf5bdf825271a0002657d4fb83.sam@gentoo
1 commit: 7141d7f0033bc7bf5bdf825271a0002657d4fb83
2 Author: Mike Gilbert <floppym <AT> gentoo <DOT> org>
3 AuthorDate: Tue Dec 27 03:57:56 2022 +0000
4 Commit: Sam James <sam <AT> gentoo <DOT> org>
5 CommitDate: Sat Dec 31 13:29:24 2022 +0000
6 URL: https://gitweb.gentoo.org/proj/portage.git/commit/?id=7141d7f0
7
8 Rework signal handling in entry scripts
9
10 Introduce a new exception SignalInterrupt which inherits from
11 KeyboardInterrupt and adds a 'signum' member. When a signal is received,
12 raise SignalInterrupt.
13
14 At the end of the script, catch KeyboardInterrupt, and look for the
15 signum member. Reset the signal handler to SIG_DFL, and re-raise the
16 signal to kill the process.
17
18 This ensures that the invoking shell sees that we got killed by a signal
19 instead of calling exit.
20
21 Bug: https://bugs.gentoo.org/887817
22 Signed-off-by: Mike Gilbert <floppym <AT> gentoo.org>
23 Closes: https://github.com/gentoo/portage/pull/965
24 Signed-off-by: Sam James <sam <AT> gentoo.org>
25
26 bin/ebuild | 781 +++++++--------
27 bin/ebuild-ipc.py | 505 +++++-----
28 bin/egencache | 2473 +++++++++++++++++++++++-----------------------
29 bin/emaint | 86 +-
30 bin/emerge | 43 +-
31 bin/portageq | 2854 ++++++++++++++++++++++++++---------------------------
32 6 files changed, 3381 insertions(+), 3361 deletions(-)
33
34 diff --git a/bin/ebuild b/bin/ebuild
35 index 112e14e3d..8f73b8684 100755
36 --- a/bin/ebuild
37 +++ b/bin/ebuild
38 @@ -2,434 +2,441 @@
39 # Copyright 1999-2022 Gentoo Authors
40 # Distributed under the terms of the GNU General Public License v2
41
42 -import argparse
43 +import os
44 import signal
45 -import sys
46 -import textwrap
47
48 -# This block ensures that ^C interrupts are handled quietly.
49 -try:
50 +# For compatibility with Python < 3.8
51 +raise_signal = getattr(
52 + signal, "raise_signal", lambda signum: os.kill(os.getpid(), signum)
53 +)
54
55 - def exithandler(signum, _frame):
56 - signal.signal(signal.SIGINT, signal.SIG_IGN)
57 - signal.signal(signal.SIGTERM, signal.SIG_IGN)
58 - sys.exit(128 + signum)
59 +# Inherit from KeyboardInterrupt to avoid a traceback from asyncio.
60 +class SignalInterrupt(KeyboardInterrupt):
61 + def __init__(self, signum):
62 + self.signum = signum
63
64 - signal.signal(signal.SIGINT, exithandler)
65 - signal.signal(signal.SIGTERM, exithandler)
66 - # Prevent "[Errno 32] Broken pipe" exceptions when
67 - # writing to a pipe.
68 - signal.signal(signal.SIGPIPE, signal.SIG_DFL)
69
70 -except KeyboardInterrupt:
71 - sys.exit(128 + signal.SIGINT)
72 +try:
73
74 + def signal_interrupt(signum, _frame):
75 + raise SignalInterrupt(signum)
76
77 -def debug_signal(_signum, _frame):
78 - import pdb
79 + def debug_signal(_signum, _frame):
80 + import pdb
81
82 - pdb.set_trace()
83 + pdb.set_trace()
84
85 + # Prevent "[Errno 32] Broken pipe" exceptions when writing to a pipe.
86 + signal.signal(signal.SIGPIPE, signal.SIG_DFL)
87 + signal.signal(signal.SIGTERM, signal_interrupt)
88 + signal.signal(signal.SIGUSR1, debug_signal)
89
90 -signal.signal(signal.SIGUSR1, debug_signal)
91 + import argparse
92 + from os import path as osp
93 + import sys
94 + import textwrap
95
96 -import os
97 -from os import path as osp
98 + if osp.isfile(
99 + osp.join(
100 + osp.dirname(osp.dirname(osp.realpath(__file__))), ".portage_not_installed"
101 + )
102 + ):
103 + sys.path.insert(
104 + 0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "lib")
105 + )
106 + import portage
107 +
108 + portage._internal_caller = True
109 + from portage import os
110 + from portage import _encodings
111 + from portage import _shell_quote
112 + from portage import _unicode_encode
113 + from portage.const import VDB_PATH
114 + from portage.exception import (
115 + PermissionDenied,
116 + PortageKeyError,
117 + PortagePackageException,
118 + UnsupportedAPIException,
119 + )
120 + from portage.localization import _
121 + import portage.util
122 + from portage.util._eventloop.global_event_loop import global_event_loop
123 + from _emerge.actions import apply_priorities
124 + from _emerge.Package import Package
125 + from _emerge.RootConfig import RootConfig
126 +
127 + portage.process.sanitize_fds()
128 +
129 + description = "See the ebuild(1) man page for more info"
130 + usage = "Usage: ebuild <ebuild file> <command> [command] ..."
131 + parser = argparse.ArgumentParser(description=description, usage=usage)
132 +
133 + force_help = (
134 + "When used together with the digest or manifest "
135 + + "command, this option forces regeneration of digests for all "
136 + + "distfiles associated with the current ebuild. Any distfiles "
137 + + "that do not already exist in ${DISTDIR} will be automatically fetched."
138 + )
139
140 -if osp.isfile(
141 - osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), ".portage_not_installed")
142 -):
143 - sys.path.insert(
144 - 0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "lib")
145 + parser.add_argument("--force", help=force_help, action="store_true")
146 + parser.add_argument(
147 + "--color", help="enable or disable color output", choices=("y", "n")
148 + )
149 + parser.add_argument("--debug", help="show debug output", action="store_true")
150 + parser.add_argument("--version", help="show version and exit", action="store_true")
151 + parser.add_argument(
152 + "--ignore-default-opts",
153 + action="store_true",
154 + help="do not use the EBUILD_DEFAULT_OPTS environment variable",
155 + )
156 + parser.add_argument(
157 + "--skip-manifest", help="skip all manifest checks", action="store_true"
158 )
159 -import portage
160 -
161 -portage._internal_caller = True
162 -from portage import os
163 -from portage import _encodings
164 -from portage import _shell_quote
165 -from portage import _unicode_encode
166 -from portage.const import VDB_PATH
167 -from portage.exception import (
168 - PermissionDenied,
169 - PortageKeyError,
170 - PortagePackageException,
171 - UnsupportedAPIException,
172 -)
173 -from portage.localization import _
174 -import portage.util
175 -from portage.util._eventloop.global_event_loop import global_event_loop
176 -from _emerge.actions import apply_priorities
177 -from _emerge.Package import Package
178 -from _emerge.RootConfig import RootConfig
179 -
180 -portage.process.sanitize_fds()
181 -
182 -description = "See the ebuild(1) man page for more info"
183 -usage = "Usage: ebuild <ebuild file> <command> [command] ..."
184 -parser = argparse.ArgumentParser(description=description, usage=usage)
185 -
186 -force_help = (
187 - "When used together with the digest or manifest "
188 - + "command, this option forces regeneration of digests for all "
189 - + "distfiles associated with the current ebuild. Any distfiles "
190 - + "that do not already exist in ${DISTDIR} will be automatically fetched."
191 -)
192
193 -parser.add_argument("--force", help=force_help, action="store_true")
194 -parser.add_argument(
195 - "--color", help="enable or disable color output", choices=("y", "n")
196 -)
197 -parser.add_argument("--debug", help="show debug output", action="store_true")
198 -parser.add_argument("--version", help="show version and exit", action="store_true")
199 -parser.add_argument(
200 - "--ignore-default-opts",
201 - action="store_true",
202 - help="do not use the EBUILD_DEFAULT_OPTS environment variable",
203 -)
204 -parser.add_argument(
205 - "--skip-manifest", help="skip all manifest checks", action="store_true"
206 -)
207 + opts, pargs = parser.parse_known_args(args=sys.argv[1:])
208
209 -opts, pargs = parser.parse_known_args(args=sys.argv[1:])
210 + def err(txt):
211 + portage.writemsg("ebuild: {}\n".format(txt), noiselevel=-1)
212 + sys.exit(1)
213
214 + if opts.version:
215 + print("Portage", portage.VERSION)
216 + sys.exit(os.EX_OK)
217
218 -def err(txt):
219 - portage.writemsg("ebuild: {}\n".format(txt), noiselevel=-1)
220 - sys.exit(1)
221 + if len(pargs) < 2:
222 + parser.error("missing required args")
223
224 + if not opts.ignore_default_opts:
225 + default_opts = portage.util.shlex_split(
226 + portage.settings.get("EBUILD_DEFAULT_OPTS", "")
227 + )
228 + opts, pargs = parser.parse_known_args(default_opts + sys.argv[1:])
229 +
230 + debug = opts.debug
231 + force = opts.force
232 +
233 + if debug:
234 + # Ensure that all config instances have this setting,
235 + # including the one that's used by portdbapi for aux_get.
236 + os.environ["PORTAGE_DEBUG"] = "1"
237 + portage._reset_legacy_globals()
238 +
239 + # do this _after_ 'import portage' to prevent unnecessary tracing
240 + if debug and "python-trace" in portage.features:
241 + portage.debug.set_trace(True)
242 +
243 + if not opts.color == "y" and (
244 + opts.color == "n"
245 + or portage.settings.get("NOCOLOR") in ("yes", "true")
246 + or portage.settings.get("TERM") == "dumb"
247 + or not sys.stdout.isatty()
248 + ):
249 + portage.output.nocolor()
250 + portage.settings.unlock()
251 + portage.settings["NOCOLOR"] = "true"
252 + portage.settings.backup_changes("NOCOLOR")
253 + portage.settings.lock()
254 +
255 + apply_priorities(portage.settings)
256 +
257 + ebuild = pargs.pop(0)
258 +
259 + pf = None
260 + if ebuild.endswith(".ebuild"):
261 + pf = os.path.basename(ebuild)[:-7]
262 +
263 + if pf is None:
264 + err("{}: does not end with '.ebuild'".format(ebuild))
265 +
266 + if not os.path.isabs(ebuild):
267 + mycwd = os.getcwd()
268 + # Try to get the non-canonical path from the PWD evironment variable, since
269 + # the canonical path returned from os.getcwd() may may be unusable in
270 + # cases where the directory stucture is built from symlinks.
271 + pwd = os.environ.get("PWD", "")
272 + if pwd and pwd != mycwd and os.path.realpath(pwd) == mycwd:
273 + mycwd = portage.normalize_path(pwd)
274 + ebuild = os.path.join(mycwd, ebuild)
275 + ebuild = portage.normalize_path(ebuild)
276 + # portdbapi uses the canonical path for the base of the ebuild repository, but
277 + # subdirectories of the base can be built from symlinks (like crossdev does).
278 + ebuild_portdir = os.path.realpath(
279 + os.path.dirname(os.path.dirname(os.path.dirname(ebuild)))
280 + )
281 + ebuild = os.path.join(ebuild_portdir, *ebuild.split(os.path.sep)[-3:])
282 + vdb_path = os.path.realpath(os.path.join(portage.settings["EROOT"], VDB_PATH))
283 +
284 + # Make sure that portdb.findname() returns the correct ebuild.
285 + if ebuild_portdir != vdb_path and ebuild_portdir not in portage.portdb.porttrees:
286 + portdir_overlay = portage.settings.get("PORTDIR_OVERLAY", "")
287 + os.environ["PORTDIR_OVERLAY"] = (
288 + portdir_overlay + " " + _shell_quote(ebuild_portdir)
289 + )
290
291 -if opts.version:
292 - print("Portage", portage.VERSION)
293 - sys.exit(os.EX_OK)
294 + print("Appending %s to PORTDIR_OVERLAY..." % ebuild_portdir)
295 + portage._reset_legacy_globals()
296
297 -if len(pargs) < 2:
298 - parser.error("missing required args")
299 + myrepo = None
300 + if ebuild_portdir != vdb_path:
301 + myrepo = portage.portdb.getRepositoryName(ebuild_portdir)
302
303 -if not opts.ignore_default_opts:
304 - default_opts = portage.util.shlex_split(
305 - portage.settings.get("EBUILD_DEFAULT_OPTS", "")
306 - )
307 - opts, pargs = parser.parse_known_args(default_opts + sys.argv[1:])
308 -
309 -debug = opts.debug
310 -force = opts.force
311 -
312 -if debug:
313 - # Ensure that all config instances have this setting,
314 - # including the one that's used by portdbapi for aux_get.
315 - os.environ["PORTAGE_DEBUG"] = "1"
316 - portage._reset_legacy_globals()
317 -
318 -# do this _after_ 'import portage' to prevent unnecessary tracing
319 -if debug and "python-trace" in portage.features:
320 - portage.debug.set_trace(True)
321 -
322 -if not opts.color == "y" and (
323 - opts.color == "n"
324 - or portage.settings.get("NOCOLOR") in ("yes", "true")
325 - or portage.settings.get("TERM") == "dumb"
326 - or not sys.stdout.isatty()
327 -):
328 - portage.output.nocolor()
329 - portage.settings.unlock()
330 - portage.settings["NOCOLOR"] = "true"
331 - portage.settings.backup_changes("NOCOLOR")
332 - portage.settings.lock()
333 -
334 -apply_priorities(portage.settings)
335 -
336 -ebuild = pargs.pop(0)
337 -
338 -pf = None
339 -if ebuild.endswith(".ebuild"):
340 - pf = os.path.basename(ebuild)[:-7]
341 -
342 -if pf is None:
343 - err("{}: does not end with '.ebuild'".format(ebuild))
344 -
345 -if not os.path.isabs(ebuild):
346 - mycwd = os.getcwd()
347 - # Try to get the non-canonical path from the PWD evironment variable, since
348 - # the canonical path returned from os.getcwd() may may be unusable in
349 - # cases where the directory stucture is built from symlinks.
350 - pwd = os.environ.get("PWD", "")
351 - if pwd and pwd != mycwd and os.path.realpath(pwd) == mycwd:
352 - mycwd = portage.normalize_path(pwd)
353 - ebuild = os.path.join(mycwd, ebuild)
354 -ebuild = portage.normalize_path(ebuild)
355 -# portdbapi uses the canonical path for the base of the ebuild repository, but
356 -# subdirectories of the base can be built from symlinks (like crossdev does).
357 -ebuild_portdir = os.path.realpath(
358 - os.path.dirname(os.path.dirname(os.path.dirname(ebuild)))
359 -)
360 -ebuild = os.path.join(ebuild_portdir, *ebuild.split(os.path.sep)[-3:])
361 -vdb_path = os.path.realpath(os.path.join(portage.settings["EROOT"], VDB_PATH))
362 + if not os.path.exists(ebuild):
363 + err("{}: does not exist".format(ebuild))
364
365 -# Make sure that portdb.findname() returns the correct ebuild.
366 -if ebuild_portdir != vdb_path and ebuild_portdir not in portage.portdb.porttrees:
367 - portdir_overlay = portage.settings.get("PORTDIR_OVERLAY", "")
368 - os.environ["PORTDIR_OVERLAY"] = portdir_overlay + " " + _shell_quote(ebuild_portdir)
369 + ebuild_split = ebuild.split("/")
370 + cpv = "{}/{}".format(ebuild_split[-3], pf)
371
372 - print("Appending %s to PORTDIR_OVERLAY..." % ebuild_portdir)
373 - portage._reset_legacy_globals()
374 + with open(
375 + _unicode_encode(ebuild, encoding=_encodings["fs"], errors="strict"),
376 + encoding=_encodings["repo.content"],
377 + errors="replace",
378 + ) as f:
379 + eapi = portage._parse_eapi_ebuild_head(f)[0]
380 + if eapi is None:
381 + eapi = "0"
382 + if not portage.catpkgsplit(cpv, eapi=eapi):
383 + err("{}: {}: does not follow correct package syntax".format(ebuild, cpv))
384
385 -myrepo = None
386 -if ebuild_portdir != vdb_path:
387 - myrepo = portage.portdb.getRepositoryName(ebuild_portdir)
388 + if ebuild.startswith(vdb_path):
389 + mytree = "vartree"
390 + pkg_type = "installed"
391
392 -if not os.path.exists(ebuild):
393 - err("{}: does not exist".format(ebuild))
394 + portage_ebuild = portage.db[portage.root][mytree].dbapi.findname(
395 + cpv, myrepo=myrepo
396 + )
397
398 -ebuild_split = ebuild.split("/")
399 -cpv = "{}/{}".format(ebuild_split[-3], pf)
400 + if os.path.realpath(portage_ebuild) != ebuild:
401 + err("Portage seems to think that {} is at {}".format(cpv, portage_ebuild))
402 +
403 + else:
404 + mytree = "porttree"
405 + pkg_type = "ebuild"
406 +
407 + portage_ebuild = portage.portdb.findname(cpv, myrepo=myrepo)
408 +
409 + if not portage_ebuild or portage_ebuild != ebuild:
410 + err("{}: does not seem to have a valid PORTDIR structure".format(ebuild))
411 +
412 + if len(pargs) > 1 and "config" in pargs:
413 + other_phases = set(pargs)
414 + other_phases.difference_update(("clean", "config", "digest", "manifest"))
415 + if other_phases:
416 + err('"config" must not be called with any other phase')
417 +
418 + def discard_digests(myebuild, mysettings, mydbapi):
419 + """Discard all distfiles digests for the given ebuild. This is useful when
420 + upstream has changed the identity of the distfiles and the user would
421 + otherwise have to manually remove the Manifest and files/digest-* files in
422 + order to ensure correct results."""
423 + try:
424 + portage._doebuild_manifest_exempt_depend += 1
425 + pkgdir = os.path.dirname(myebuild)
426 + fetchlist_dict = portage.FetchlistDict(pkgdir, mysettings, mydbapi)
427 + mf = mysettings.repositories.get_repo_for_location(
428 + os.path.dirname(os.path.dirname(pkgdir))
429 + )
430 + mf = mf.load_manifest(
431 + pkgdir, mysettings["DISTDIR"], fetchlist_dict=fetchlist_dict
432 + )
433 + mf.create(
434 + requiredDistfiles=None,
435 + assumeDistHashesSometimes=True,
436 + assumeDistHashesAlways=True,
437 + )
438 + distfiles = fetchlist_dict[cpv]
439 + for myfile in distfiles:
440 + try:
441 + del mf.fhashdict["DIST"][myfile]
442 + except KeyError:
443 + pass
444 + mf.write()
445 + finally:
446 + portage._doebuild_manifest_exempt_depend -= 1
447 +
448 + portage.settings.validate() # generate warning messages if necessary
449 +
450 + build_dir_phases = {
451 + "setup",
452 + "unpack",
453 + "prepare",
454 + "configure",
455 + "compile",
456 + "test",
457 + "install",
458 + "package",
459 + "rpm",
460 + "merge",
461 + "qmerge",
462 + }
463 +
464 + # If the current metadata is invalid then force the ebuild to be
465 + # sourced again even if ${T}/environment already exists.
466 + ebuild_changed = False
467 + if mytree == "porttree" and build_dir_phases.intersection(pargs):
468 + ebuild_changed = (
469 + portage.portdb._pull_valid_cache(cpv, ebuild, ebuild_portdir)[0] is None
470 + )
471
472 -with open(
473 - _unicode_encode(ebuild, encoding=_encodings["fs"], errors="strict"),
474 - encoding=_encodings["repo.content"],
475 - errors="replace",
476 -) as f:
477 - eapi = portage._parse_eapi_ebuild_head(f)[0]
478 -if eapi is None:
479 - eapi = "0"
480 -if not portage.catpkgsplit(cpv, eapi=eapi):
481 - err("{}: {}: does not follow correct package syntax".format(ebuild, cpv))
482 + # Make configuration adjustments to portage.portdb.doebuild_settings,
483 + # in order to enforce consistency for EBUILD_FORCE_TEST support
484 + # (see bug 601466).
485 + tmpsettings = portage.portdb.doebuild_settings
486
487 -if ebuild.startswith(vdb_path):
488 - mytree = "vartree"
489 - pkg_type = "installed"
490 + tmpsettings["PORTAGE_VERBOSE"] = "1"
491 + tmpsettings.backup_changes("PORTAGE_VERBOSE")
492
493 - portage_ebuild = portage.db[portage.root][mytree].dbapi.findname(cpv, myrepo=myrepo)
494 + if opts.skip_manifest:
495 + tmpsettings["EBUILD_SKIP_MANIFEST"] = "1"
496 + tmpsettings.backup_changes("EBUILD_SKIP_MANIFEST")
497
498 - if os.path.realpath(portage_ebuild) != ebuild:
499 - err("Portage seems to think that {} is at {}".format(cpv, portage_ebuild))
500 + if (
501 + opts.skip_manifest
502 + or "digest" in tmpsettings.features
503 + or "digest" in pargs
504 + or "manifest" in pargs
505 + ):
506 + portage._doebuild_manifest_exempt_depend += 1
507
508 -else:
509 - mytree = "porttree"
510 - pkg_type = "ebuild"
511 + if "test" in pargs:
512 + # This variable is a signal to config.regenerate() to
513 + # indicate that the test phase should be enabled regardless
514 + # of problems such as masked "test" USE flag.
515 + tmpsettings["EBUILD_FORCE_TEST"] = "1"
516 + tmpsettings.backup_changes("EBUILD_FORCE_TEST")
517 + tmpsettings.features.add("test")
518 + portage.writemsg(_("Forcing test.\n"), noiselevel=-1)
519
520 - portage_ebuild = portage.portdb.findname(cpv, myrepo=myrepo)
521 + tmpsettings.features.discard("fail-clean")
522
523 - if not portage_ebuild or portage_ebuild != ebuild:
524 - err("{}: does not seem to have a valid PORTDIR structure".format(ebuild))
525 + if "merge" in pargs and "noauto" in tmpsettings.features:
526 + print("Disabling noauto in features... merge disables it. (qmerge doesn't)")
527 + tmpsettings.features.discard("noauto")
528
529 -if len(pargs) > 1 and "config" in pargs:
530 - other_phases = set(pargs)
531 - other_phases.difference_update(("clean", "config", "digest", "manifest"))
532 - if other_phases:
533 - err('"config" must not be called with any other phase')
534 + if "digest" in tmpsettings.features:
535 + if pargs and pargs[0] not in ("digest", "manifest"):
536 + pargs = ["digest"] + pargs
537 + # We only need to build digests on the first pass.
538 + tmpsettings.features.discard("digest")
539
540 + # Now that configuration adjustments are complete, create a clone of
541 + # tmpsettings. The current instance refers to portdb.doebuild_settings,
542 + # and we want to avoid the possibility of unintended side-effects.
543 + tmpsettings = portage.config(clone=tmpsettings)
544
545 -def discard_digests(myebuild, mysettings, mydbapi):
546 - """Discard all distfiles digests for the given ebuild. This is useful when
547 - upstream has changed the identity of the distfiles and the user would
548 - otherwise have to manually remove the Manifest and files/digest-* files in
549 - order to ensure correct results."""
550 try:
551 - portage._doebuild_manifest_exempt_depend += 1
552 - pkgdir = os.path.dirname(myebuild)
553 - fetchlist_dict = portage.FetchlistDict(pkgdir, mysettings, mydbapi)
554 - mf = mysettings.repositories.get_repo_for_location(
555 - os.path.dirname(os.path.dirname(pkgdir))
556 - )
557 - mf = mf.load_manifest(
558 - pkgdir, mysettings["DISTDIR"], fetchlist_dict=fetchlist_dict
559 + metadata = dict(
560 + zip(
561 + Package.metadata_keys,
562 + portage.db[portage.settings["EROOT"]][mytree].dbapi.aux_get(
563 + cpv, Package.metadata_keys, myrepo=myrepo
564 + ),
565 + )
566 )
567 - mf.create(
568 - requiredDistfiles=None,
569 - assumeDistHashesSometimes=True,
570 - assumeDistHashesAlways=True,
571 - )
572 - distfiles = fetchlist_dict[cpv]
573 - for myfile in distfiles:
574 - try:
575 - del mf.fhashdict["DIST"][myfile]
576 - except KeyError:
577 - pass
578 - mf.write()
579 - finally:
580 - portage._doebuild_manifest_exempt_depend -= 1
581 -
582 -
583 -portage.settings.validate() # generate warning messages if necessary
584 -
585 -build_dir_phases = {
586 - "setup",
587 - "unpack",
588 - "prepare",
589 - "configure",
590 - "compile",
591 - "test",
592 - "install",
593 - "package",
594 - "rpm",
595 - "merge",
596 - "qmerge",
597 -}
598 -
599 -# If the current metadata is invalid then force the ebuild to be
600 -# sourced again even if ${T}/environment already exists.
601 -ebuild_changed = False
602 -if mytree == "porttree" and build_dir_phases.intersection(pargs):
603 - ebuild_changed = (
604 - portage.portdb._pull_valid_cache(cpv, ebuild, ebuild_portdir)[0] is None
605 - )
606 -
607 -# Make configuration adjustments to portage.portdb.doebuild_settings,
608 -# in order to enforce consistency for EBUILD_FORCE_TEST support
609 -# (see bug 601466).
610 -tmpsettings = portage.portdb.doebuild_settings
611 -
612 -tmpsettings["PORTAGE_VERBOSE"] = "1"
613 -tmpsettings.backup_changes("PORTAGE_VERBOSE")
614 -
615 -if opts.skip_manifest:
616 - tmpsettings["EBUILD_SKIP_MANIFEST"] = "1"
617 - tmpsettings.backup_changes("EBUILD_SKIP_MANIFEST")
618 -
619 -if (
620 - opts.skip_manifest
621 - or "digest" in tmpsettings.features
622 - or "digest" in pargs
623 - or "manifest" in pargs
624 -):
625 - portage._doebuild_manifest_exempt_depend += 1
626 -
627 -if "test" in pargs:
628 - # This variable is a signal to config.regenerate() to
629 - # indicate that the test phase should be enabled regardless
630 - # of problems such as masked "test" USE flag.
631 - tmpsettings["EBUILD_FORCE_TEST"] = "1"
632 - tmpsettings.backup_changes("EBUILD_FORCE_TEST")
633 - tmpsettings.features.add("test")
634 - portage.writemsg(_("Forcing test.\n"), noiselevel=-1)
635 -
636 -tmpsettings.features.discard("fail-clean")
637 -
638 -if "merge" in pargs and "noauto" in tmpsettings.features:
639 - print("Disabling noauto in features... merge disables it. (qmerge doesn't)")
640 - tmpsettings.features.discard("noauto")
641 -
642 -if "digest" in tmpsettings.features:
643 - if pargs and pargs[0] not in ("digest", "manifest"):
644 - pargs = ["digest"] + pargs
645 - # We only need to build digests on the first pass.
646 - tmpsettings.features.discard("digest")
647 -
648 -# Now that configuration adjustments are complete, create a clone of
649 -# tmpsettings. The current instance refers to portdb.doebuild_settings,
650 -# and we want to avoid the possibility of unintended side-effects.
651 -tmpsettings = portage.config(clone=tmpsettings)
652 + except PortageKeyError:
653 + # aux_get failure, message should have been shown on stderr.
654 + sys.exit(1)
655
656 -try:
657 - metadata = dict(
658 - zip(
659 - Package.metadata_keys,
660 - portage.db[portage.settings["EROOT"]][mytree].dbapi.aux_get(
661 - cpv, Package.metadata_keys, myrepo=myrepo
662 - ),
663 - )
664 + root_config = RootConfig(
665 + portage.settings, portage.db[portage.settings["EROOT"]], None
666 )
667 -except PortageKeyError:
668 - # aux_get failure, message should have been shown on stderr.
669 - sys.exit(1)
670 -
671 -root_config = RootConfig(portage.settings, portage.db[portage.settings["EROOT"]], None)
672
673 -cpv = portage.versions._pkg_str(
674 - cpv,
675 - metadata=metadata,
676 - settings=portage.settings,
677 - db=portage.db[portage.settings["EROOT"]][mytree].dbapi,
678 -)
679 -
680 -pkg = Package(
681 - built=(pkg_type != "ebuild"),
682 - cpv=cpv,
683 - installed=(pkg_type == "installed"),
684 - metadata=metadata,
685 - root_config=root_config,
686 - type_name=pkg_type,
687 -)
688 -
689 -# Apply package.env and repo-level settings. This allows per-package
690 -# FEATURES and other variables (possibly PORTAGE_TMPDIR) to be
691 -# available as soon as possible. Also, note that the only way to ensure
692 -# that setcpv gets metadata from the correct repository is to pass in
693 -# a Package instance, as we do here (previously we had to modify
694 -# portdb.porttrees in order to accomplish this).
695 -tmpsettings.setcpv(pkg)
696 + cpv = portage.versions._pkg_str(
697 + cpv,
698 + metadata=metadata,
699 + settings=portage.settings,
700 + db=portage.db[portage.settings["EROOT"]][mytree].dbapi,
701 + )
702
703 + pkg = Package(
704 + built=(pkg_type != "ebuild"),
705 + cpv=cpv,
706 + installed=(pkg_type == "installed"),
707 + metadata=metadata,
708 + root_config=root_config,
709 + type_name=pkg_type,
710 + )
711
712 -def stale_env_warning():
713 - if (
714 - "clean" not in pargs
715 - and "noauto" not in tmpsettings.features
716 - and build_dir_phases.intersection(pargs)
717 - ):
718 - portage.doebuild_environment(
719 - ebuild, "setup", portage.root, tmpsettings, debug, 1, portage.portdb
720 - )
721 - env_filename = os.path.join(tmpsettings["T"], "environment")
722 - if os.path.exists(env_filename):
723 - msg = (
724 - "Existing ${T}/environment for '%s' will be sourced. "
725 - + "Run 'clean' to start with a fresh environment."
726 - ) % (tmpsettings["PF"],)
727 - msg = textwrap.wrap(msg, 70)
728 + # Apply package.env and repo-level settings. This allows per-package
729 + # FEATURES and other variables (possibly PORTAGE_TMPDIR) to be
730 + # available as soon as possible. Also, note that the only way to ensure
731 + # that setcpv gets metadata from the correct repository is to pass in
732 + # a Package instance, as we do here (previously we had to modify
733 + # portdb.porttrees in order to accomplish this).
734 + tmpsettings.setcpv(pkg)
735 +
736 + def stale_env_warning():
737 + if (
738 + "clean" not in pargs
739 + and "noauto" not in tmpsettings.features
740 + and build_dir_phases.intersection(pargs)
741 + ):
742 + portage.doebuild_environment(
743 + ebuild, "setup", portage.root, tmpsettings, debug, 1, portage.portdb
744 + )
745 + env_filename = os.path.join(tmpsettings["T"], "environment")
746 + if os.path.exists(env_filename):
747 + msg = (
748 + "Existing ${T}/environment for '%s' will be sourced. "
749 + + "Run 'clean' to start with a fresh environment."
750 + ) % (tmpsettings["PF"],)
751 + msg = textwrap.wrap(msg, 70)
752 + for x in msg:
753 + portage.writemsg(">>> %s\n" % x)
754 +
755 + if ebuild_changed:
756 + open(
757 + os.path.join(
758 + tmpsettings["PORTAGE_BUILDDIR"], ".ebuild_changed"
759 + ),
760 + "w",
761 + ).close()
762 +
763 + checked_for_stale_env = False
764 +
765 + for arg in pargs:
766 + try:
767 + if not checked_for_stale_env and arg not in ("digest", "manifest"):
768 + # This has to go after manifest generation since otherwise
769 + # aux_get() might fail due to invalid ebuild digests.
770 + stale_env_warning()
771 + checked_for_stale_env = True
772 +
773 + if arg in ("digest", "manifest") and force:
774 + discard_digests(ebuild, tmpsettings, portage.portdb)
775 + a = portage.doebuild(
776 + ebuild,
777 + arg,
778 + settings=tmpsettings,
779 + debug=debug,
780 + tree=mytree,
781 + vartree=portage.db[portage.root]["vartree"],
782 + )
783 + except PortageKeyError:
784 + # aux_get error
785 + a = 1
786 + except UnsupportedAPIException as e:
787 + msg = textwrap.wrap(str(e), 70)
788 + del e
789 for x in msg:
790 - portage.writemsg(">>> %s\n" % x)
791 -
792 - if ebuild_changed:
793 - open(
794 - os.path.join(tmpsettings["PORTAGE_BUILDDIR"], ".ebuild_changed"),
795 - "w",
796 - ).close()
797 -
798 -
799 -checked_for_stale_env = False
800 -
801 -for arg in pargs:
802 - try:
803 - if not checked_for_stale_env and arg not in ("digest", "manifest"):
804 - # This has to go after manifest generation since otherwise
805 - # aux_get() might fail due to invalid ebuild digests.
806 - stale_env_warning()
807 - checked_for_stale_env = True
808 -
809 - if arg in ("digest", "manifest") and force:
810 - discard_digests(ebuild, tmpsettings, portage.portdb)
811 - a = portage.doebuild(
812 - ebuild,
813 - arg,
814 - settings=tmpsettings,
815 - debug=debug,
816 - tree=mytree,
817 - vartree=portage.db[portage.root]["vartree"],
818 - )
819 - except KeyboardInterrupt:
820 - print("Interrupted.")
821 - a = 1
822 - except PortageKeyError:
823 - # aux_get error
824 - a = 1
825 - except UnsupportedAPIException as e:
826 - msg = textwrap.wrap(str(e), 70)
827 - del e
828 - for x in msg:
829 - portage.writemsg("!!! %s\n" % x, noiselevel=-1)
830 - a = 1
831 - except PortagePackageException as e:
832 - portage.writemsg("!!! {}\n".format(e), noiselevel=-1)
833 - a = 1
834 - except PermissionDenied as e:
835 - portage.writemsg("!!! Permission Denied: {}\n".format(e), noiselevel=-1)
836 - a = 1
837 - if a is None:
838 - print("Could not run the required binary?")
839 - a = 127
840 - if a:
841 - global_event_loop().close()
842 - sys.exit(a)
843 -
844 -global_event_loop().close()
845 + portage.writemsg("!!! %s\n" % x, noiselevel=-1)
846 + a = 1
847 + except PortagePackageException as e:
848 + portage.writemsg("!!! {}\n".format(e), noiselevel=-1)
849 + a = 1
850 + except PermissionDenied as e:
851 + portage.writemsg("!!! Permission Denied: {}\n".format(e), noiselevel=-1)
852 + a = 1
853 + if a is None:
854 + print("Could not run the required binary?")
855 + a = 127
856 + if a:
857 + global_event_loop().close()
858 + sys.exit(a)
859 +
860 + global_event_loop().close()
861 +
862 +except KeyboardInterrupt as e:
863 + # Prevent traceback on ^C
864 + signum = getattr(e, "signum", signal.SIGINT)
865 + signal.signal(signum, signal.SIG_DFL)
866 + raise_signal(signum)
867
868 diff --git a/bin/ebuild-ipc.py b/bin/ebuild-ipc.py
869 index d0d902aff..fc632e015 100755
870 --- a/bin/ebuild-ipc.py
871 +++ b/bin/ebuild-ipc.py
872 @@ -5,316 +5,323 @@
873 # This is a helper which ebuild processes can use
874 # to communicate with portage's main python process.
875
876 -# This block ensures that ^C interrupts are handled quietly.
877 -try:
878 - import os
879 - import signal
880 +import os
881 +import signal
882
883 - def exithandler(signum, _frame):
884 - signal.signal(signum, signal.SIG_DFL)
885 - os.kill(os.getpid(), signum)
886 +# For compatibility with Python < 3.8
887 +raise_signal = getattr(
888 + signal, "raise_signal", lambda signum: os.kill(os.getpid(), signum)
889 +)
890
891 - signal.signal(signal.SIGINT, exithandler)
892 - signal.signal(signal.SIGTERM, exithandler)
893 - signal.signal(signal.SIGPIPE, signal.SIG_DFL)
894 +# Inherit from KeyboardInterrupt to avoid a traceback from asyncio.
895 +class SignalInterrupt(KeyboardInterrupt):
896 + def __init__(self, signum):
897 + self.signum = signum
898
899 -except KeyboardInterrupt:
900 - raise SystemExit(130)
901
902 -import errno
903 -import logging
904 -import pickle
905 -import sys
906 -import time
907 +try:
908
909 + def signal_interrupt(signum, _frame):
910 + raise SignalInterrupt(signum)
911
912 -def debug_signal(signum, frame):
913 - import pdb
914 + def debug_signal(_signum, _frame):
915 + import pdb
916
917 - pdb.set_trace()
918 + pdb.set_trace()
919
920 + # Prevent "[Errno 32] Broken pipe" exceptions when writing to a pipe.
921 + signal.signal(signal.SIGPIPE, signal.SIG_DFL)
922 + signal.signal(signal.SIGTERM, signal_interrupt)
923 + signal.signal(signal.SIGUSR1, debug_signal)
924
925 -signal.signal(signal.SIGUSR1, debug_signal)
926 + import errno
927 + import logging
928 + import pickle
929 + import sys
930 + import time
931
932 -if os.path.isfile(
933 - os.path.join(
934 - os.path.dirname(os.path.dirname(os.path.realpath(__file__))),
935 - ".portage_not_installed",
936 - )
937 -):
938 - pym_paths = [
939 + if os.path.isfile(
940 os.path.join(
941 - os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "lib"
942 + os.path.dirname(os.path.dirname(os.path.realpath(__file__))),
943 + ".portage_not_installed",
944 )
945 - ]
946 - sys.path.insert(0, pym_paths[0])
947 -else:
948 - import sysconfig
949 -
950 - pym_paths = [
951 - os.path.join(sysconfig.get_path("purelib"), x) for x in ("_emerge", "portage")
952 - ]
953 -# Avoid sandbox violations after Python upgrade.
954 -if os.environ.get("SANDBOX_ON") == "1":
955 - sandbox_write = os.environ.get("SANDBOX_WRITE", "").split(":")
956 - for pym_path in pym_paths:
957 - if pym_path not in sandbox_write:
958 - sandbox_write.append(pym_path)
959 - os.environ["SANDBOX_WRITE"] = ":".join(filter(None, sandbox_write))
960 - del pym_path, sandbox_write
961 -del pym_paths
962 + ):
963 + pym_paths = [
964 + os.path.join(
965 + os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "lib"
966 + )
967 + ]
968 + sys.path.insert(0, pym_paths[0])
969 + else:
970 + import sysconfig
971
972 -import portage
973 + pym_paths = [
974 + os.path.join(sysconfig.get_path("purelib"), x)
975 + for x in ("_emerge", "portage")
976 + ]
977 + # Avoid sandbox violations after Python upgrade.
978 + if os.environ.get("SANDBOX_ON") == "1":
979 + sandbox_write = os.environ.get("SANDBOX_WRITE", "").split(":")
980 + for pym_path in pym_paths:
981 + if pym_path not in sandbox_write:
982 + sandbox_write.append(pym_path)
983 + os.environ["SANDBOX_WRITE"] = ":".join(filter(None, sandbox_write))
984 + del pym_path, sandbox_write
985 + del pym_paths
986
987 -portage._internal_caller = True
988 -portage._disable_legacy_globals()
989 + import portage
990
991 -from portage.util._eventloop.global_event_loop import global_event_loop
992 -from _emerge.AbstractPollTask import AbstractPollTask
993 -from _emerge.PipeReader import PipeReader
994 + portage._internal_caller = True
995 + portage._disable_legacy_globals()
996
997 -RETURNCODE_WRITE_FAILED = 2
998 + from portage.util._eventloop.global_event_loop import global_event_loop
999 + from _emerge.AbstractPollTask import AbstractPollTask
1000 + from _emerge.PipeReader import PipeReader
1001
1002 + RETURNCODE_WRITE_FAILED = 2
1003
1004 -class FifoWriter(AbstractPollTask):
1005 + class FifoWriter(AbstractPollTask):
1006
1007 - __slots__ = ("buf", "fifo", "_fd")
1008 + __slots__ = ("buf", "fifo", "_fd")
1009
1010 - def _start(self):
1011 - try:
1012 - self._fd = os.open(self.fifo, os.O_WRONLY | os.O_NONBLOCK)
1013 - except OSError as e:
1014 - if e.errno == errno.ENXIO:
1015 - # This happens if the daemon has been killed.
1016 - self.returncode = RETURNCODE_WRITE_FAILED
1017 - self._unregister()
1018 - self._async_wait()
1019 - return
1020 - else:
1021 - raise
1022 - self.scheduler.add_writer(self._fd, self._output_handler)
1023 - self._registered = True
1024 -
1025 - def _output_handler(self):
1026 - # The whole buf should be able to fit in the fifo with
1027 - # a single write call, so there's no valid reason for
1028 - # os.write to raise EAGAIN here.
1029 - fd = self._fd
1030 - buf = self.buf
1031 - while buf:
1032 + def _start(self):
1033 try:
1034 - buf = buf[os.write(fd, buf) :]
1035 - except OSError:
1036 - self.returncode = RETURNCODE_WRITE_FAILED
1037 - self._async_wait()
1038 - return
1039 -
1040 - self.returncode = os.EX_OK
1041 - self._async_wait()
1042 -
1043 - def _cancel(self):
1044 - self.returncode = self._cancelled_returncode
1045 - self._unregister()
1046 -
1047 - def _unregister(self):
1048 - self._registered = False
1049 - if self._fd is not None:
1050 - self.scheduler.remove_writer(self._fd)
1051 - os.close(self._fd)
1052 - self._fd = None
1053 -
1054 + self._fd = os.open(self.fifo, os.O_WRONLY | os.O_NONBLOCK)
1055 + except OSError as e:
1056 + if e.errno == errno.ENXIO:
1057 + # This happens if the daemon has been killed.
1058 + self.returncode = RETURNCODE_WRITE_FAILED
1059 + self._unregister()
1060 + self._async_wait()
1061 + return
1062 + else:
1063 + raise
1064 + self.scheduler.add_writer(self._fd, self._output_handler)
1065 + self._registered = True
1066 +
1067 + def _output_handler(self):
1068 + # The whole buf should be able to fit in the fifo with
1069 + # a single write call, so there's no valid reason for
1070 + # os.write to raise EAGAIN here.
1071 + fd = self._fd
1072 + buf = self.buf
1073 + while buf:
1074 + try:
1075 + buf = buf[os.write(fd, buf) :]
1076 + except OSError:
1077 + self.returncode = RETURNCODE_WRITE_FAILED
1078 + self._async_wait()
1079 + return
1080 +
1081 + self.returncode = os.EX_OK
1082 + self._async_wait()
1083 +
1084 + def _cancel(self):
1085 + self.returncode = self._cancelled_returncode
1086 + self._unregister()
1087 +
1088 + def _unregister(self):
1089 + self._registered = False
1090 + if self._fd is not None:
1091 + self.scheduler.remove_writer(self._fd)
1092 + os.close(self._fd)
1093 + self._fd = None
1094 +
1095 + class EbuildIpc:
1096 +
1097 + # Timeout for each individual communication attempt (we retry
1098 + # as long as the daemon process appears to be alive).
1099 + _COMMUNICATE_RETRY_TIMEOUT = 15 # seconds
1100 +
1101 + def __init__(self):
1102 + self.fifo_dir = os.environ["PORTAGE_BUILDDIR"]
1103 + self.ipc_in_fifo = os.path.join(self.fifo_dir, ".ipc", "in")
1104 + self.ipc_out_fifo = os.path.join(self.fifo_dir, ".ipc", "out")
1105 + self.ipc_lock_file = os.path.join(self.fifo_dir, ".ipc", "lock")
1106 +
1107 + def _daemon_is_alive(self):
1108 + try:
1109 + builddir_lock = portage.locks.lockfile(
1110 + self.fifo_dir, wantnewlockfile=True, flags=os.O_NONBLOCK
1111 + )
1112 + except portage.exception.TryAgain:
1113 + return True
1114 + else:
1115 + portage.locks.unlockfile(builddir_lock)
1116 + return False
1117
1118 -class EbuildIpc:
1119 + def communicate(self, args):
1120
1121 - # Timeout for each individual communication attempt (we retry
1122 - # as long as the daemon process appears to be alive).
1123 - _COMMUNICATE_RETRY_TIMEOUT = 15 # seconds
1124 + # Make locks quiet since unintended locking messages displayed on
1125 + # stdout could corrupt the intended output of this program.
1126 + portage.locks._quiet = True
1127 + lock_obj = portage.locks.lockfile(self.ipc_lock_file, unlinkfile=True)
1128
1129 - def __init__(self):
1130 - self.fifo_dir = os.environ["PORTAGE_BUILDDIR"]
1131 - self.ipc_in_fifo = os.path.join(self.fifo_dir, ".ipc", "in")
1132 - self.ipc_out_fifo = os.path.join(self.fifo_dir, ".ipc", "out")
1133 - self.ipc_lock_file = os.path.join(self.fifo_dir, ".ipc", "lock")
1134 + try:
1135 + return self._communicate(args)
1136 + finally:
1137 + portage.locks.unlockfile(lock_obj)
1138
1139 - def _daemon_is_alive(self):
1140 - try:
1141 - builddir_lock = portage.locks.lockfile(
1142 - self.fifo_dir, wantnewlockfile=True, flags=os.O_NONBLOCK
1143 + def _timeout_retry_msg(self, start_time, when):
1144 + time_elapsed = time.time() - start_time
1145 + portage.util.writemsg_level(
1146 + portage.localization._(
1147 + "ebuild-ipc timed out %s after %d seconds," + " retrying...\n"
1148 + )
1149 + % (when, time_elapsed),
1150 + level=logging.ERROR,
1151 + noiselevel=-1,
1152 )
1153 - except portage.exception.TryAgain:
1154 - return True
1155 - else:
1156 - portage.locks.unlockfile(builddir_lock)
1157 - return False
1158 -
1159 - def communicate(self, args):
1160 -
1161 - # Make locks quiet since unintended locking messages displayed on
1162 - # stdout could corrupt the intended output of this program.
1163 - portage.locks._quiet = True
1164 - lock_obj = portage.locks.lockfile(self.ipc_lock_file, unlinkfile=True)
1165 -
1166 - try:
1167 - return self._communicate(args)
1168 - finally:
1169 - portage.locks.unlockfile(lock_obj)
1170
1171 - def _timeout_retry_msg(self, start_time, when):
1172 - time_elapsed = time.time() - start_time
1173 - portage.util.writemsg_level(
1174 - portage.localization._(
1175 - "ebuild-ipc timed out %s after %d seconds," + " retrying...\n"
1176 + def _no_daemon_msg(self):
1177 + portage.util.writemsg_level(
1178 + portage.localization._("ebuild-ipc: daemon process not detected\n"),
1179 + level=logging.ERROR,
1180 + noiselevel=-1,
1181 )
1182 - % (when, time_elapsed),
1183 - level=logging.ERROR,
1184 - noiselevel=-1,
1185 - )
1186 -
1187 - def _no_daemon_msg(self):
1188 - portage.util.writemsg_level(
1189 - portage.localization._("ebuild-ipc: daemon process not detected\n"),
1190 - level=logging.ERROR,
1191 - noiselevel=-1,
1192 - )
1193 -
1194 - def _run_writer(self, fifo_writer, msg):
1195 - """
1196 - Wait on pid and return an appropriate exit code. This
1197 - may return unsuccessfully due to timeout if the daemon
1198 - process does not appear to be alive.
1199 - """
1200 -
1201 - start_time = time.time()
1202
1203 - fifo_writer.start()
1204 - eof = fifo_writer.poll() is not None
1205 + def _run_writer(self, fifo_writer, msg):
1206 + """
1207 + Wait on pid and return an appropriate exit code. This
1208 + may return unsuccessfully due to timeout if the daemon
1209 + process does not appear to be alive.
1210 + """
1211
1212 - while not eof:
1213 - fifo_writer._wait_loop(timeout=self._COMMUNICATE_RETRY_TIMEOUT)
1214 + start_time = time.time()
1215
1216 + fifo_writer.start()
1217 eof = fifo_writer.poll() is not None
1218 - if eof:
1219 - break
1220 - elif self._daemon_is_alive():
1221 - self._timeout_retry_msg(start_time, msg)
1222 - else:
1223 - fifo_writer.cancel()
1224 - self._no_daemon_msg()
1225 - fifo_writer.wait()
1226 - return 2
1227 -
1228 - return fifo_writer.wait()
1229 -
1230 - def _receive_reply(self, input_fd):
1231
1232 - start_time = time.time()
1233 + while not eof:
1234 + fifo_writer._wait_loop(timeout=self._COMMUNICATE_RETRY_TIMEOUT)
1235
1236 - pipe_reader = PipeReader(
1237 - input_files={"input_fd": input_fd}, scheduler=global_event_loop()
1238 - )
1239 - pipe_reader.start()
1240 -
1241 - eof = pipe_reader.poll() is not None
1242 -
1243 - while not eof:
1244 - pipe_reader._wait_loop(timeout=self._COMMUNICATE_RETRY_TIMEOUT)
1245 - eof = pipe_reader.poll() is not None
1246 - if not eof:
1247 - if self._daemon_is_alive():
1248 - self._timeout_retry_msg(
1249 - start_time, portage.localization._("during read")
1250 - )
1251 + eof = fifo_writer.poll() is not None
1252 + if eof:
1253 + break
1254 + elif self._daemon_is_alive():
1255 + self._timeout_retry_msg(start_time, msg)
1256 else:
1257 - pipe_reader.cancel()
1258 + fifo_writer.cancel()
1259 self._no_daemon_msg()
1260 + fifo_writer.wait()
1261 return 2
1262
1263 - buf = pipe_reader.getvalue()
1264 + return fifo_writer.wait()
1265
1266 - retval = 2
1267 + def _receive_reply(self, input_fd):
1268
1269 - if not buf:
1270 + start_time = time.time()
1271
1272 - portage.util.writemsg_level(
1273 - "ebuild-ipc: {}\n".format(portage.localization._("read failed")),
1274 - level=logging.ERROR,
1275 - noiselevel=-1,
1276 + pipe_reader = PipeReader(
1277 + input_files={"input_fd": input_fd}, scheduler=global_event_loop()
1278 )
1279 + pipe_reader.start()
1280
1281 - else:
1282 + eof = pipe_reader.poll() is not None
1283 +
1284 + while not eof:
1285 + pipe_reader._wait_loop(timeout=self._COMMUNICATE_RETRY_TIMEOUT)
1286 + eof = pipe_reader.poll() is not None
1287 + if not eof:
1288 + if self._daemon_is_alive():
1289 + self._timeout_retry_msg(
1290 + start_time, portage.localization._("during read")
1291 + )
1292 + else:
1293 + pipe_reader.cancel()
1294 + self._no_daemon_msg()
1295 + return 2
1296 +
1297 + buf = pipe_reader.getvalue()
1298 +
1299 + retval = 2
1300 +
1301 + if not buf:
1302
1303 - try:
1304 - reply = pickle.loads(buf)
1305 - except SystemExit:
1306 - raise
1307 - except Exception as e:
1308 - # The pickle module can raise practically
1309 - # any exception when given corrupt data.
1310 portage.util.writemsg_level(
1311 - "ebuild-ipc: {}\n".format(e), level=logging.ERROR, noiselevel=-1
1312 + "ebuild-ipc: {}\n".format(portage.localization._("read failed")),
1313 + level=logging.ERROR,
1314 + noiselevel=-1,
1315 )
1316
1317 else:
1318
1319 - (out, err, retval) = reply
1320 + try:
1321 + reply = pickle.loads(buf)
1322 + except SystemExit:
1323 + raise
1324 + except Exception as e:
1325 + # The pickle module can raise practically
1326 + # any exception when given corrupt data.
1327 + portage.util.writemsg_level(
1328 + "ebuild-ipc: {}\n".format(e), level=logging.ERROR, noiselevel=-1
1329 + )
1330
1331 - if out:
1332 - portage.util.writemsg_stdout(out, noiselevel=-1)
1333 + else:
1334
1335 - if err:
1336 - portage.util.writemsg(err, noiselevel=-1)
1337 + (out, err, retval) = reply
1338
1339 - return retval
1340 + if out:
1341 + portage.util.writemsg_stdout(out, noiselevel=-1)
1342
1343 - def _communicate(self, args):
1344 + if err:
1345 + portage.util.writemsg(err, noiselevel=-1)
1346
1347 - if not self._daemon_is_alive():
1348 - self._no_daemon_msg()
1349 - return 2
1350 + return retval
1351
1352 - # Open the input fifo before the output fifo, in order to make it
1353 - # possible for the daemon to send a reply without blocking. This
1354 - # improves performance, and also makes it possible for the daemon
1355 - # to do a non-blocking write without a race condition.
1356 - input_fd = os.open(self.ipc_out_fifo, os.O_RDONLY | os.O_NONBLOCK)
1357 + def _communicate(self, args):
1358
1359 - # Use forks so that the child process can handle blocking IO
1360 - # un-interrupted, while the parent handles all timeout
1361 - # considerations. This helps to avoid possible race conditions
1362 - # from interference between timeouts and blocking IO operations.
1363 - msg = portage.localization._("during write")
1364 - retval = self._run_writer(
1365 - FifoWriter(
1366 - buf=pickle.dumps(args),
1367 - fifo=self.ipc_in_fifo,
1368 - scheduler=global_event_loop(),
1369 - ),
1370 - msg,
1371 - )
1372 + if not self._daemon_is_alive():
1373 + self._no_daemon_msg()
1374 + return 2
1375
1376 - if retval != os.EX_OK:
1377 - portage.util.writemsg_level(
1378 - "ebuild-ipc: %s: %s\n"
1379 - % (msg, portage.localization._("subprocess failure: %s") % retval),
1380 - level=logging.ERROR,
1381 - noiselevel=-1,
1382 + # Open the input fifo before the output fifo, in order to make it
1383 + # possible for the daemon to send a reply without blocking. This
1384 + # improves performance, and also makes it possible for the daemon
1385 + # to do a non-blocking write without a race condition.
1386 + input_fd = os.open(self.ipc_out_fifo, os.O_RDONLY | os.O_NONBLOCK)
1387 +
1388 + # Use forks so that the child process can handle blocking IO
1389 + # un-interrupted, while the parent handles all timeout
1390 + # considerations. This helps to avoid possible race conditions
1391 + # from interference between timeouts and blocking IO operations.
1392 + msg = portage.localization._("during write")
1393 + retval = self._run_writer(
1394 + FifoWriter(
1395 + buf=pickle.dumps(args),
1396 + fifo=self.ipc_in_fifo,
1397 + scheduler=global_event_loop(),
1398 + ),
1399 + msg,
1400 )
1401 - return retval
1402
1403 - if not self._daemon_is_alive():
1404 - self._no_daemon_msg()
1405 - return 2
1406 + if retval != os.EX_OK:
1407 + portage.util.writemsg_level(
1408 + "ebuild-ipc: %s: %s\n"
1409 + % (msg, portage.localization._("subprocess failure: %s") % retval),
1410 + level=logging.ERROR,
1411 + noiselevel=-1,
1412 + )
1413 + return retval
1414
1415 - return self._receive_reply(input_fd)
1416 + if not self._daemon_is_alive():
1417 + self._no_daemon_msg()
1418 + return 2
1419
1420 + return self._receive_reply(input_fd)
1421
1422 -def ebuild_ipc_main(args):
1423 - ebuild_ipc = EbuildIpc()
1424 - return ebuild_ipc.communicate(args)
1425 + def ebuild_ipc_main(args):
1426 + ebuild_ipc = EbuildIpc()
1427 + return ebuild_ipc.communicate(args)
1428
1429 + if __name__ == "__main__":
1430 + try:
1431 + sys.exit(ebuild_ipc_main(sys.argv[1:]))
1432 + finally:
1433 + global_event_loop().close()
1434
1435 -if __name__ == "__main__":
1436 - try:
1437 - sys.exit(ebuild_ipc_main(sys.argv[1:]))
1438 - finally:
1439 - global_event_loop().close()
1440 +except KeyboardInterrupt as e:
1441 + # Prevent traceback on ^C
1442 + signum = getattr(e, "signum", signal.SIGINT)
1443 + signal.signal(signum, signal.SIG_DFL)
1444 + raise_signal(signum)
1445
1446 diff --git a/bin/egencache b/bin/egencache
1447 index 47c9dd340..5f5664131 100755
1448 --- a/bin/egencache
1449 +++ b/bin/egencache
1450 @@ -2,797 +2,807 @@
1451 # Copyright 2009-2022 Gentoo Authors
1452 # Distributed under the terms of the GNU General Public License v2
1453
1454 -import argparse
1455 +import os
1456 import signal
1457 -import stat
1458 -import sys
1459
1460 -# This block ensures that ^C interrupts are handled quietly.
1461 -try:
1462 -
1463 - def exithandler(signum, _frame):
1464 - signal.signal(signal.SIGINT, signal.SIG_IGN)
1465 - signal.signal(signal.SIGTERM, signal.SIG_IGN)
1466 - sys.exit(128 + signum)
1467 +# For compatibility with Python < 3.8
1468 +raise_signal = getattr(
1469 + signal, "raise_signal", lambda signum: os.kill(os.getpid(), signum)
1470 +)
1471
1472 - signal.signal(signal.SIGINT, exithandler)
1473 - signal.signal(signal.SIGTERM, exithandler)
1474 +# Inherit from KeyboardInterrupt to avoid a traceback from asyncio.
1475 +class SignalInterrupt(KeyboardInterrupt):
1476 + def __init__(self, signum):
1477 + self.signum = signum
1478
1479 -except KeyboardInterrupt:
1480 - sys.exit(128 + signal.SIGINT)
1481
1482 +try:
1483
1484 -def debug_signal(_signum, _frame):
1485 - import pdb
1486 + def signal_interrupt(signum, _frame):
1487 + raise SignalInterrupt(signum)
1488
1489 - pdb.set_trace()
1490 + def debug_signal(_signum, _frame):
1491 + import pdb
1492
1493 + pdb.set_trace()
1494
1495 -signal.signal(signal.SIGUSR1, debug_signal)
1496 + # Prevent "[Errno 32] Broken pipe" exceptions when writing to a pipe.
1497 + signal.signal(signal.SIGPIPE, signal.SIG_DFL)
1498 + signal.signal(signal.SIGTERM, signal_interrupt)
1499 + signal.signal(signal.SIGUSR1, debug_signal)
1500
1501 -import functools
1502 -import logging
1503 -import subprocess
1504 -import time
1505 -import textwrap
1506 -import re
1507 + import argparse
1508 + import stat
1509 + import sys
1510 + import functools
1511 + import logging
1512 + import subprocess
1513 + import time
1514 + import textwrap
1515 + import re
1516
1517 -from os import path as osp
1518 + from os import path as osp
1519
1520 -if osp.isfile(
1521 - osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), ".portage_not_installed")
1522 -):
1523 - sys.path.insert(
1524 - 0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "lib")
1525 + if osp.isfile(
1526 + osp.join(
1527 + osp.dirname(osp.dirname(osp.realpath(__file__))), ".portage_not_installed"
1528 + )
1529 + ):
1530 + sys.path.insert(
1531 + 0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "lib")
1532 + )
1533 + import portage
1534 +
1535 + portage._internal_caller = True
1536 + from portage import os, _encodings, _unicode_encode, _unicode_decode
1537 + from portage.cache.cache_errors import CacheError, StatCollision
1538 + from portage.cache.index.pkg_desc_index import (
1539 + pkg_desc_index_line_format,
1540 + pkg_desc_index_line_read,
1541 )
1542 -import portage
1543 -
1544 -portage._internal_caller = True
1545 -from portage import os, _encodings, _unicode_encode, _unicode_decode
1546 -from portage.cache.cache_errors import CacheError, StatCollision
1547 -from portage.cache.index.pkg_desc_index import (
1548 - pkg_desc_index_line_format,
1549 - pkg_desc_index_line_read,
1550 -)
1551 -from portage.const import TIMESTAMP_FORMAT
1552 -from portage.dep import _repo_separator
1553 -from portage.output import colorize, EOutput
1554 -from portage.package.ebuild._parallel_manifest.ManifestScheduler import (
1555 - ManifestScheduler,
1556 -)
1557 -from portage.util import cmp_sort_key, writemsg_level
1558 -from portage.util._async.AsyncFunction import AsyncFunction
1559 -from portage.util._async.run_main_scheduler import run_main_scheduler
1560 -from portage.util._async.TaskScheduler import TaskScheduler
1561 -from portage.util._eventloop.global_event_loop import global_event_loop
1562 -from portage.util.changelog import ChangeLogTypeSort
1563 -from portage import cpv_getkey
1564 -from portage.dep import Atom, isjustname
1565 -from portage.versions import vercmp
1566 -from _emerge.MetadataRegen import MetadataRegen
1567 + from portage.const import TIMESTAMP_FORMAT
1568 + from portage.dep import _repo_separator
1569 + from portage.output import colorize, EOutput
1570 + from portage.package.ebuild._parallel_manifest.ManifestScheduler import (
1571 + ManifestScheduler,
1572 + )
1573 + from portage.util import cmp_sort_key, writemsg_level
1574 + from portage.util._async.AsyncFunction import AsyncFunction
1575 + from portage.util._async.run_main_scheduler import run_main_scheduler
1576 + from portage.util._async.TaskScheduler import TaskScheduler
1577 + from portage.util._eventloop.global_event_loop import global_event_loop
1578 + from portage.util.changelog import ChangeLogTypeSort
1579 + from portage import cpv_getkey
1580 + from portage.dep import Atom, isjustname
1581 + from portage.versions import vercmp
1582 + from _emerge.MetadataRegen import MetadataRegen
1583
1584 -try:
1585 - from xml.etree import ElementTree
1586 -except ImportError:
1587 - pass
1588 -else:
1589 try:
1590 - from xml.parsers.expat import ExpatError
1591 + from xml.etree import ElementTree
1592 except ImportError:
1593 pass
1594 else:
1595 - from portage.xml.metadata import ( # pylint: disable=ungrouped-imports
1596 - parse_metadata_use,
1597 - )
1598 -
1599 -
1600 -def parse_args(args):
1601 - usage = "egencache [options] <action> ... [atom] ..."
1602 - parser = argparse.ArgumentParser(usage=usage)
1603 + try:
1604 + from xml.parsers.expat import ExpatError
1605 + except ImportError:
1606 + pass
1607 + else:
1608 + from portage.xml.metadata import ( # pylint: disable=ungrouped-imports
1609 + parse_metadata_use,
1610 + )
1611
1612 - actions = parser.add_argument_group("Actions")
1613 - actions.add_argument(
1614 - "--update",
1615 - action="store_true",
1616 - help="update metadata/md5-cache/ (generate as necessary)",
1617 - )
1618 - actions.add_argument(
1619 - "--update-use-local-desc",
1620 - action="store_true",
1621 - help="update the use.local.desc file from metadata.xml",
1622 - )
1623 - actions.add_argument(
1624 - "--update-changelogs",
1625 - action="store_true",
1626 - help="update the ChangeLog files from SCM logs",
1627 - )
1628 - actions.add_argument(
1629 - "--update-pkg-desc-index",
1630 - action="store_true",
1631 - help="update package description index",
1632 - )
1633 - actions.add_argument(
1634 - "--update-manifests", action="store_true", help="update manifests"
1635 - )
1636 + def parse_args(args):
1637 + usage = "egencache [options] <action> ... [atom] ..."
1638 + parser = argparse.ArgumentParser(usage=usage)
1639
1640 - common = parser.add_argument_group("Common options")
1641 - common.add_argument("--repo", action="store", help="name of repo to operate on")
1642 - common.add_argument(
1643 - "--config-root",
1644 - help="location of portage config files",
1645 - dest="portage_configroot",
1646 - )
1647 - common.add_argument(
1648 - "--external-cache-only",
1649 - action="store_true",
1650 - help="Output only to the external cache (not the repository itself)",
1651 - )
1652 - common.add_argument(
1653 - "--gpg-dir", help="override the PORTAGE_GPG_DIR variable", dest="gpg_dir"
1654 - )
1655 - common.add_argument(
1656 - "--gpg-key", help="override the PORTAGE_GPG_KEY variable", dest="gpg_key"
1657 - )
1658 - common.add_argument(
1659 - "--repositories-configuration",
1660 - help="override configuration of repositories (in format of repos.conf)",
1661 - dest="repositories_configuration",
1662 - )
1663 - common.add_argument(
1664 - "--sign-manifests",
1665 - choices=("y", "n"),
1666 - metavar="<y|n>",
1667 - help="manually override layout.conf sign-manifests setting",
1668 - )
1669 - common.add_argument(
1670 - "--strict-manifests",
1671 - choices=("y", "n"),
1672 - metavar="<y|n>",
1673 - help='manually override "strict" FEATURES setting',
1674 - )
1675 - common.add_argument(
1676 - "--thin-manifests",
1677 - choices=("y", "n"),
1678 - metavar="<y|n>",
1679 - help="manually override layout.conf thin-manifests setting",
1680 - )
1681 - common.add_argument(
1682 - "--tolerant",
1683 - action="store_true",
1684 - help="exit successfully if only minor errors occurred",
1685 - )
1686 - common.add_argument(
1687 - "--ignore-default-opts",
1688 - action="store_true",
1689 - help="do not use the EGENCACHE_DEFAULT_OPTS environment variable",
1690 - )
1691 - common.add_argument(
1692 - "-v", "--verbose", action="count", default=0, help="increase verbosity"
1693 - )
1694 - common.add_argument(
1695 - "--write-timestamp",
1696 - action="store_true",
1697 - help="write metadata/timestamp.chk as required for rsync repositories",
1698 - )
1699 + actions = parser.add_argument_group("Actions")
1700 + actions.add_argument(
1701 + "--update",
1702 + action="store_true",
1703 + help="update metadata/md5-cache/ (generate as necessary)",
1704 + )
1705 + actions.add_argument(
1706 + "--update-use-local-desc",
1707 + action="store_true",
1708 + help="update the use.local.desc file from metadata.xml",
1709 + )
1710 + actions.add_argument(
1711 + "--update-changelogs",
1712 + action="store_true",
1713 + help="update the ChangeLog files from SCM logs",
1714 + )
1715 + actions.add_argument(
1716 + "--update-pkg-desc-index",
1717 + action="store_true",
1718 + help="update package description index",
1719 + )
1720 + actions.add_argument(
1721 + "--update-manifests", action="store_true", help="update manifests"
1722 + )
1723
1724 - update = parser.add_argument_group("--update options")
1725 - update.add_argument(
1726 - "--cache-dir", help="location of the metadata cache", dest="cache_dir"
1727 - )
1728 - update.add_argument(
1729 - "-j", "--jobs", type=int, action="store", help="max ebuild processes to spawn"
1730 - )
1731 - update.add_argument(
1732 - "--load-average",
1733 - type=float,
1734 - action="store",
1735 - help="max load allowed when spawning multiple jobs",
1736 - dest="load_average",
1737 - )
1738 - update.add_argument(
1739 - "--rsync",
1740 - action="store_true",
1741 - help="enable rsync stat collision workaround "
1742 - + "for bug 139134 (use with --update)",
1743 - )
1744 + common = parser.add_argument_group("Common options")
1745 + common.add_argument("--repo", action="store", help="name of repo to operate on")
1746 + common.add_argument(
1747 + "--config-root",
1748 + help="location of portage config files",
1749 + dest="portage_configroot",
1750 + )
1751 + common.add_argument(
1752 + "--external-cache-only",
1753 + action="store_true",
1754 + help="Output only to the external cache (not the repository itself)",
1755 + )
1756 + common.add_argument(
1757 + "--gpg-dir", help="override the PORTAGE_GPG_DIR variable", dest="gpg_dir"
1758 + )
1759 + common.add_argument(
1760 + "--gpg-key", help="override the PORTAGE_GPG_KEY variable", dest="gpg_key"
1761 + )
1762 + common.add_argument(
1763 + "--repositories-configuration",
1764 + help="override configuration of repositories (in format of repos.conf)",
1765 + dest="repositories_configuration",
1766 + )
1767 + common.add_argument(
1768 + "--sign-manifests",
1769 + choices=("y", "n"),
1770 + metavar="<y|n>",
1771 + help="manually override layout.conf sign-manifests setting",
1772 + )
1773 + common.add_argument(
1774 + "--strict-manifests",
1775 + choices=("y", "n"),
1776 + metavar="<y|n>",
1777 + help='manually override "strict" FEATURES setting',
1778 + )
1779 + common.add_argument(
1780 + "--thin-manifests",
1781 + choices=("y", "n"),
1782 + metavar="<y|n>",
1783 + help="manually override layout.conf thin-manifests setting",
1784 + )
1785 + common.add_argument(
1786 + "--tolerant",
1787 + action="store_true",
1788 + help="exit successfully if only minor errors occurred",
1789 + )
1790 + common.add_argument(
1791 + "--ignore-default-opts",
1792 + action="store_true",
1793 + help="do not use the EGENCACHE_DEFAULT_OPTS environment variable",
1794 + )
1795 + common.add_argument(
1796 + "-v", "--verbose", action="count", default=0, help="increase verbosity"
1797 + )
1798 + common.add_argument(
1799 + "--write-timestamp",
1800 + action="store_true",
1801 + help="write metadata/timestamp.chk as required for rsync repositories",
1802 + )
1803
1804 - uld = parser.add_argument_group("--update-use-local-desc options")
1805 - uld.add_argument(
1806 - "--preserve-comments",
1807 - action="store_true",
1808 - help="preserve the comments from the existing use.local.desc file",
1809 - )
1810 - uld.add_argument(
1811 - "--use-local-desc-output",
1812 - help="output file for use.local.desc data (or '-' for stdout)",
1813 - dest="uld_output",
1814 - )
1815 + update = parser.add_argument_group("--update options")
1816 + update.add_argument(
1817 + "--cache-dir", help="location of the metadata cache", dest="cache_dir"
1818 + )
1819 + update.add_argument(
1820 + "-j",
1821 + "--jobs",
1822 + type=int,
1823 + action="store",
1824 + help="max ebuild processes to spawn",
1825 + )
1826 + update.add_argument(
1827 + "--load-average",
1828 + type=float,
1829 + action="store",
1830 + help="max load allowed when spawning multiple jobs",
1831 + dest="load_average",
1832 + )
1833 + update.add_argument(
1834 + "--rsync",
1835 + action="store_true",
1836 + help="enable rsync stat collision workaround "
1837 + + "for bug 139134 (use with --update)",
1838 + )
1839
1840 - uc = parser.add_argument_group("--update-changelogs options")
1841 - uc.add_argument(
1842 - "--changelog-reversed",
1843 - action="store_true",
1844 - help="log commits in reverse order (oldest first)",
1845 - )
1846 - uc.add_argument(
1847 - "--changelog-output",
1848 - help="output filename for change logs",
1849 - dest="changelog_output",
1850 - default="ChangeLog",
1851 - )
1852 + uld = parser.add_argument_group("--update-use-local-desc options")
1853 + uld.add_argument(
1854 + "--preserve-comments",
1855 + action="store_true",
1856 + help="preserve the comments from the existing use.local.desc file",
1857 + )
1858 + uld.add_argument(
1859 + "--use-local-desc-output",
1860 + help="output file for use.local.desc data (or '-' for stdout)",
1861 + dest="uld_output",
1862 + )
1863
1864 - options, args = parser.parse_known_args(args)
1865 + uc = parser.add_argument_group("--update-changelogs options")
1866 + uc.add_argument(
1867 + "--changelog-reversed",
1868 + action="store_true",
1869 + help="log commits in reverse order (oldest first)",
1870 + )
1871 + uc.add_argument(
1872 + "--changelog-output",
1873 + help="output filename for change logs",
1874 + dest="changelog_output",
1875 + default="ChangeLog",
1876 + )
1877
1878 - if options.jobs:
1879 - jobs = None
1880 - try:
1881 - jobs = int(options.jobs)
1882 - except ValueError:
1883 - jobs = -1
1884 + options, args = parser.parse_known_args(args)
1885
1886 - if jobs < 1:
1887 - parser.error("Invalid: --jobs='{}'".format(options.jobs))
1888 + if options.jobs:
1889 + jobs = None
1890 + try:
1891 + jobs = int(options.jobs)
1892 + except ValueError:
1893 + jobs = -1
1894
1895 - options.jobs = jobs
1896 + if jobs < 1:
1897 + parser.error("Invalid: --jobs='{}'".format(options.jobs))
1898
1899 - else:
1900 - options.jobs = None
1901 + options.jobs = jobs
1902
1903 - if options.load_average:
1904 - try:
1905 - load_average = float(options.load_average)
1906 - except ValueError:
1907 - load_average = 0.0
1908 + else:
1909 + options.jobs = None
1910
1911 - if load_average <= 0.0:
1912 - parser.error("Invalid: --load-average='{}'".format(options.load_average))
1913 + if options.load_average:
1914 + try:
1915 + load_average = float(options.load_average)
1916 + except ValueError:
1917 + load_average = 0.0
1918
1919 - options.load_average = load_average
1920 + if load_average <= 0.0:
1921 + parser.error(
1922 + "Invalid: --load-average='{}'".format(options.load_average)
1923 + )
1924
1925 - else:
1926 - options.load_average = None
1927 + options.load_average = load_average
1928
1929 - options.config_root = options.portage_configroot
1930 - if options.config_root is not None and not os.path.isdir(options.config_root):
1931 - parser.error("Not a directory: --config-root='{}'".format(options.config_root))
1932 + else:
1933 + options.load_average = None
1934
1935 - if options.cache_dir is not None:
1936 - if not os.path.isdir(options.cache_dir):
1937 - parser.error("Not a directory: --cache-dir='{}'".format(options.cache_dir))
1938 - if not os.access(options.cache_dir, os.W_OK):
1939 + options.config_root = options.portage_configroot
1940 + if options.config_root is not None and not os.path.isdir(options.config_root):
1941 parser.error(
1942 - "Write access denied: --cache-dir='{}'".format(options.cache_dir)
1943 + "Not a directory: --config-root='{}'".format(options.config_root)
1944 )
1945
1946 - for atom in args:
1947 - try:
1948 - atom = portage.dep.Atom(atom)
1949 - except portage.exception.InvalidAtom:
1950 - parser.error("Invalid atom: {}".format(atom))
1951 -
1952 - if not isjustname(atom):
1953 - parser.error("Atom is too specific: {}".format(atom))
1954 -
1955 - if options.update_use_local_desc:
1956 - try:
1957 - ElementTree
1958 - ExpatError
1959 - except NameError:
1960 - parser.error("--update-use-local-desc requires python with USE=xml!")
1961 -
1962 - if options.uld_output == "-" and options.preserve_comments:
1963 - parser.error("--preserve-comments can not be used when outputting to stdout")
1964 -
1965 - return parser, options, args
1966 -
1967 -
1968 -class GenCache:
1969 - def __init__(
1970 - self,
1971 - portdb,
1972 - cp_iter=None,
1973 - max_jobs=None,
1974 - max_load=None,
1975 - rsync=False,
1976 - external_cache_only=False,
1977 - ):
1978 - # The caller must set portdb.porttrees in order to constrain
1979 - # findname, cp_list, and cpv_list to the desired tree.
1980 - tree = portdb.porttrees[0]
1981 - self._portdb = portdb
1982 - self._eclass_db = portdb.repositories.get_repo_for_location(tree).eclass_db
1983 - self._auxdbkeys = portdb._known_keys
1984 - # We can globally cleanse stale cache only if we
1985 - # iterate over every single cp.
1986 - self._global_cleanse = cp_iter is None
1987 - if cp_iter is not None:
1988 - self._cp_set = set(cp_iter)
1989 - cp_iter = iter(self._cp_set)
1990 - self._cp_missing = self._cp_set.copy()
1991 - else:
1992 - self._cp_set = None
1993 - self._cp_missing = set()
1994 - write_auxdb = (
1995 - external_cache_only or "metadata-transfer" in portdb.settings.features
1996 - )
1997 - self._regen = MetadataRegen(
1998 - portdb,
1999 - cp_iter=cp_iter,
2000 - consumer=self._metadata_callback,
2001 - max_jobs=max_jobs,
2002 - max_load=max_load,
2003 - write_auxdb=write_auxdb,
2004 - main=True,
2005 - )
2006 - self.returncode = os.EX_OK
2007 - conf = portdb.repositories.get_repo_for_location(tree)
2008 - if external_cache_only:
2009 - self._trg_caches = ()
2010 - else:
2011 - self._trg_caches = tuple(
2012 - conf.iter_pregenerated_caches(
2013 - self._auxdbkeys, force=True, readonly=False
2014 + if options.cache_dir is not None:
2015 + if not os.path.isdir(options.cache_dir):
2016 + parser.error(
2017 + "Not a directory: --cache-dir='{}'".format(options.cache_dir)
2018 )
2019 - )
2020 - if not self._trg_caches:
2021 - raise Exception(
2022 - "cache formats '%s' aren't supported"
2023 - % (" ".join(conf.cache_formats),)
2024 + if not os.access(options.cache_dir, os.W_OK):
2025 + parser.error(
2026 + "Write access denied: --cache-dir='{}'".format(options.cache_dir)
2027 )
2028
2029 - if rsync:
2030 - for trg_cache in self._trg_caches:
2031 - if hasattr(trg_cache, "raise_stat_collision"):
2032 - trg_cache.raise_stat_collision = True
2033 - # Make _metadata_callback write this cache first, in case
2034 - # it raises a StatCollision and triggers mtime
2035 - # modification.
2036 - self._trg_caches = tuple(
2037 - [trg_cache]
2038 - + [x for x in self._trg_caches if x is not trg_cache]
2039 - )
2040 + for atom in args:
2041 + try:
2042 + atom = portage.dep.Atom(atom)
2043 + except portage.exception.InvalidAtom:
2044 + parser.error("Invalid atom: {}".format(atom))
2045
2046 - self._existing_nodes = set()
2047 + if not isjustname(atom):
2048 + parser.error("Atom is too specific: {}".format(atom))
2049
2050 - def _metadata_callback(self, cpv, repo_path, metadata, ebuild_hash, eapi_supported):
2051 - self._existing_nodes.add(cpv)
2052 - self._cp_missing.discard(cpv_getkey(cpv))
2053 + if options.update_use_local_desc:
2054 + try:
2055 + ElementTree
2056 + ExpatError
2057 + except NameError:
2058 + parser.error("--update-use-local-desc requires python with USE=xml!")
2059
2060 - # Since we're supposed to be able to efficiently obtain the
2061 - # EAPI from _parse_eapi_ebuild_head, we don't write cache
2062 - # entries for unsupported EAPIs.
2063 - if metadata is not None and eapi_supported:
2064 - for trg_cache in self._trg_caches:
2065 - self._write_cache(trg_cache, cpv, repo_path, metadata, ebuild_hash)
2066 + if options.uld_output == "-" and options.preserve_comments:
2067 + parser.error(
2068 + "--preserve-comments can not be used when outputting to stdout"
2069 + )
2070
2071 - def _write_cache(self, trg_cache, cpv, repo_path, metadata, ebuild_hash):
2072 + return parser, options, args
2073
2074 - if not hasattr(trg_cache, "raise_stat_collision"):
2075 - # This cache does not avoid redundant writes automatically,
2076 - # so check for an identical existing entry before writing.
2077 - # This prevents unnecessary disk writes and can also prevent
2078 - # unnecessary rsync transfers.
2079 - try:
2080 - dest = trg_cache[cpv]
2081 - except (KeyError, CacheError):
2082 - pass
2083 + class GenCache:
2084 + def __init__(
2085 + self,
2086 + portdb,
2087 + cp_iter=None,
2088 + max_jobs=None,
2089 + max_load=None,
2090 + rsync=False,
2091 + external_cache_only=False,
2092 + ):
2093 + # The caller must set portdb.porttrees in order to constrain
2094 + # findname, cp_list, and cpv_list to the desired tree.
2095 + tree = portdb.porttrees[0]
2096 + self._portdb = portdb
2097 + self._eclass_db = portdb.repositories.get_repo_for_location(tree).eclass_db
2098 + self._auxdbkeys = portdb._known_keys
2099 + # We can globally cleanse stale cache only if we
2100 + # iterate over every single cp.
2101 + self._global_cleanse = cp_iter is None
2102 + if cp_iter is not None:
2103 + self._cp_set = set(cp_iter)
2104 + cp_iter = iter(self._cp_set)
2105 + self._cp_missing = self._cp_set.copy()
2106 else:
2107 - if trg_cache.validate_entry(dest, ebuild_hash, self._eclass_db):
2108 - identical = True
2109 - for k in self._auxdbkeys:
2110 - if dest.get(k, "") != metadata.get(k, ""):
2111 - identical = False
2112 - break
2113 - if identical:
2114 - return
2115 -
2116 - try:
2117 - chf = trg_cache.validation_chf
2118 - metadata["_%s_" % chf] = getattr(ebuild_hash, chf)
2119 - try:
2120 - trg_cache[cpv] = metadata
2121 - except StatCollision as sc:
2122 - # If the content of a cache entry changes and neither the
2123 - # file mtime nor size changes, it will prevent rsync from
2124 - # detecting changes. Cache backends may raise this
2125 - # exception from _setitem() if they detect this type of stat
2126 - # collision. These exceptions are handled by bumping the
2127 - # mtime on the ebuild (and the corresponding cache entry).
2128 - # See bug #139134. It is convenient to include checks for
2129 - # redundant writes along with the internal StatCollision
2130 - # detection code, so for caches with the
2131 - # raise_stat_collision attribute, we do not need to
2132 - # explicitly check for redundant writes like we do for the
2133 - # other cache types above.
2134 - max_mtime = sc.mtime
2135 - for _ec, ec_hash in metadata["_eclasses_"].items():
2136 - if max_mtime < ec_hash.mtime:
2137 - max_mtime = ec_hash.mtime
2138 - if max_mtime == sc.mtime:
2139 - max_mtime += 1
2140 - max_mtime = int(max_mtime)
2141 - try:
2142 - os.utime(ebuild_hash.location, (max_mtime, max_mtime))
2143 - except OSError as e:
2144 - self.returncode |= 1
2145 - writemsg_level(
2146 - "{} writing target: {}\n".format(cpv, e),
2147 - level=logging.ERROR,
2148 - noiselevel=-1,
2149 - )
2150 - else:
2151 - ebuild_hash.mtime = max_mtime
2152 - metadata["_mtime_"] = max_mtime
2153 - trg_cache[cpv] = metadata
2154 - self._portdb.auxdb[repo_path][cpv] = metadata
2155 -
2156 - except CacheError as ce:
2157 - self.returncode |= 1
2158 - writemsg_level(
2159 - "{} writing target: {}\n".format(cpv, ce),
2160 - level=logging.ERROR,
2161 - noiselevel=-1,
2162 + self._cp_set = None
2163 + self._cp_missing = set()
2164 + write_auxdb = (
2165 + external_cache_only or "metadata-transfer" in portdb.settings.features
2166 + )
2167 + self._regen = MetadataRegen(
2168 + portdb,
2169 + cp_iter=cp_iter,
2170 + consumer=self._metadata_callback,
2171 + max_jobs=max_jobs,
2172 + max_load=max_load,
2173 + write_auxdb=write_auxdb,
2174 + main=True,
2175 )
2176 + self.returncode = os.EX_OK
2177 + conf = portdb.repositories.get_repo_for_location(tree)
2178 + if external_cache_only:
2179 + self._trg_caches = ()
2180 + else:
2181 + self._trg_caches = tuple(
2182 + conf.iter_pregenerated_caches(
2183 + self._auxdbkeys, force=True, readonly=False
2184 + )
2185 + )
2186 + if not self._trg_caches:
2187 + raise Exception(
2188 + "cache formats '%s' aren't supported"
2189 + % (" ".join(conf.cache_formats),)
2190 + )
2191
2192 - def run(self):
2193 - signum = run_main_scheduler(self._regen)
2194 - if signum is not None:
2195 - sys.exit(128 + signum)
2196 + if rsync:
2197 + for trg_cache in self._trg_caches:
2198 + if hasattr(trg_cache, "raise_stat_collision"):
2199 + trg_cache.raise_stat_collision = True
2200 + # Make _metadata_callback write this cache first, in case
2201 + # it raises a StatCollision and triggers mtime
2202 + # modification.
2203 + self._trg_caches = tuple(
2204 + [trg_cache]
2205 + + [x for x in self._trg_caches if x is not trg_cache]
2206 + )
2207
2208 - self.returncode |= self._regen.returncode
2209 + self._existing_nodes = set()
2210
2211 - for trg_cache in self._trg_caches:
2212 - self._cleanse_cache(trg_cache)
2213 + def _metadata_callback(
2214 + self, cpv, repo_path, metadata, ebuild_hash, eapi_supported
2215 + ):
2216 + self._existing_nodes.add(cpv)
2217 + self._cp_missing.discard(cpv_getkey(cpv))
2218 +
2219 + # Since we're supposed to be able to efficiently obtain the
2220 + # EAPI from _parse_eapi_ebuild_head, we don't write cache
2221 + # entries for unsupported EAPIs.
2222 + if metadata is not None and eapi_supported:
2223 + for trg_cache in self._trg_caches:
2224 + self._write_cache(trg_cache, cpv, repo_path, metadata, ebuild_hash)
2225 +
2226 + def _write_cache(self, trg_cache, cpv, repo_path, metadata, ebuild_hash):
2227 +
2228 + if not hasattr(trg_cache, "raise_stat_collision"):
2229 + # This cache does not avoid redundant writes automatically,
2230 + # so check for an identical existing entry before writing.
2231 + # This prevents unnecessary disk writes and can also prevent
2232 + # unnecessary rsync transfers.
2233 + try:
2234 + dest = trg_cache[cpv]
2235 + except (KeyError, CacheError):
2236 + pass
2237 + else:
2238 + if trg_cache.validate_entry(dest, ebuild_hash, self._eclass_db):
2239 + identical = True
2240 + for k in self._auxdbkeys:
2241 + if dest.get(k, "") != metadata.get(k, ""):
2242 + identical = False
2243 + break
2244 + if identical:
2245 + return
2246
2247 - def _cleanse_cache(self, trg_cache):
2248 - cp_missing = self._cp_missing
2249 - dead_nodes = set()
2250 - if self._global_cleanse:
2251 try:
2252 - for cpv in trg_cache:
2253 - cp = cpv_getkey(cpv)
2254 - if cp is None:
2255 + chf = trg_cache.validation_chf
2256 + metadata["_%s_" % chf] = getattr(ebuild_hash, chf)
2257 + try:
2258 + trg_cache[cpv] = metadata
2259 + except StatCollision as sc:
2260 + # If the content of a cache entry changes and neither the
2261 + # file mtime nor size changes, it will prevent rsync from
2262 + # detecting changes. Cache backends may raise this
2263 + # exception from _setitem() if they detect this type of stat
2264 + # collision. These exceptions are handled by bumping the
2265 + # mtime on the ebuild (and the corresponding cache entry).
2266 + # See bug #139134. It is convenient to include checks for
2267 + # redundant writes along with the internal StatCollision
2268 + # detection code, so for caches with the
2269 + # raise_stat_collision attribute, we do not need to
2270 + # explicitly check for redundant writes like we do for the
2271 + # other cache types above.
2272 + max_mtime = sc.mtime
2273 + for _ec, ec_hash in metadata["_eclasses_"].items():
2274 + if max_mtime < ec_hash.mtime:
2275 + max_mtime = ec_hash.mtime
2276 + if max_mtime == sc.mtime:
2277 + max_mtime += 1
2278 + max_mtime = int(max_mtime)
2279 + try:
2280 + os.utime(ebuild_hash.location, (max_mtime, max_mtime))
2281 + except OSError as e:
2282 self.returncode |= 1
2283 writemsg_level(
2284 - "Unable to parse cp for '{}'\n".format(cpv),
2285 + "{} writing target: {}\n".format(cpv, e),
2286 level=logging.ERROR,
2287 noiselevel=-1,
2288 )
2289 else:
2290 - dead_nodes.add(cpv)
2291 + ebuild_hash.mtime = max_mtime
2292 + metadata["_mtime_"] = max_mtime
2293 + trg_cache[cpv] = metadata
2294 + self._portdb.auxdb[repo_path][cpv] = metadata
2295 +
2296 except CacheError as ce:
2297 self.returncode |= 1
2298 writemsg_level(
2299 - "Error listing cache entries for "
2300 - + "'{}': {}, continuing...\n".format(trg_cache.location, ce),
2301 + "{} writing target: {}\n".format(cpv, ce),
2302 level=logging.ERROR,
2303 noiselevel=-1,
2304 )
2305
2306 - else:
2307 - cp_set = self._cp_set
2308 - try:
2309 - for cpv in trg_cache:
2310 - cp = cpv_getkey(cpv)
2311 - if cp is None:
2312 + def run(self):
2313 + signum = run_main_scheduler(self._regen)
2314 + if signum is not None:
2315 + sys.exit(128 + signum)
2316 +
2317 + self.returncode |= self._regen.returncode
2318 +
2319 + for trg_cache in self._trg_caches:
2320 + self._cleanse_cache(trg_cache)
2321 +
2322 + def _cleanse_cache(self, trg_cache):
2323 + cp_missing = self._cp_missing
2324 + dead_nodes = set()
2325 + if self._global_cleanse:
2326 + try:
2327 + for cpv in trg_cache:
2328 + cp = cpv_getkey(cpv)
2329 + if cp is None:
2330 + self.returncode |= 1
2331 + writemsg_level(
2332 + "Unable to parse cp for '{}'\n".format(cpv),
2333 + level=logging.ERROR,
2334 + noiselevel=-1,
2335 + )
2336 + else:
2337 + dead_nodes.add(cpv)
2338 + except CacheError as ce:
2339 + self.returncode |= 1
2340 + writemsg_level(
2341 + "Error listing cache entries for "
2342 + + "'{}': {}, continuing...\n".format(trg_cache.location, ce),
2343 + level=logging.ERROR,
2344 + noiselevel=-1,
2345 + )
2346 +
2347 + else:
2348 + cp_set = self._cp_set
2349 + try:
2350 + for cpv in trg_cache:
2351 + cp = cpv_getkey(cpv)
2352 + if cp is None:
2353 + self.returncode |= 1
2354 + writemsg_level(
2355 + "Unable to parse cp for '{}'\n".format(cpv),
2356 + level=logging.ERROR,
2357 + noiselevel=-1,
2358 + )
2359 + else:
2360 + cp_missing.discard(cp)
2361 + if cp in cp_set:
2362 + dead_nodes.add(cpv)
2363 + except CacheError as ce:
2364 + self.returncode |= 1
2365 + writemsg_level(
2366 + "Error listing cache entries for "
2367 + + "'{}': {}, continuing...\n".format(trg_cache.location, ce),
2368 + level=logging.ERROR,
2369 + noiselevel=-1,
2370 + )
2371 +
2372 + if cp_missing:
2373 + self.returncode |= 1
2374 + for cp in sorted(cp_missing):
2375 + writemsg_level(
2376 + "No ebuilds or cache entries found for '{}'\n".format(cp),
2377 + level=logging.ERROR,
2378 + noiselevel=-1,
2379 + )
2380 +
2381 + if dead_nodes:
2382 + dead_nodes.difference_update(self._existing_nodes)
2383 + for k in dead_nodes:
2384 + try:
2385 + del trg_cache[k]
2386 + except KeyError:
2387 + pass
2388 + except CacheError as ce:
2389 self.returncode |= 1
2390 writemsg_level(
2391 - "Unable to parse cp for '{}'\n".format(cpv),
2392 + "{} deleting stale cache: {}\n".format(k, ce),
2393 level=logging.ERROR,
2394 noiselevel=-1,
2395 )
2396 - else:
2397 - cp_missing.discard(cp)
2398 - if cp in cp_set:
2399 - dead_nodes.add(cpv)
2400 - except CacheError as ce:
2401 - self.returncode |= 1
2402 - writemsg_level(
2403 - "Error listing cache entries for "
2404 - + "'{}': {}, continuing...\n".format(trg_cache.location, ce),
2405 - level=logging.ERROR,
2406 - noiselevel=-1,
2407 - )
2408 -
2409 - if cp_missing:
2410 - self.returncode |= 1
2411 - for cp in sorted(cp_missing):
2412 - writemsg_level(
2413 - "No ebuilds or cache entries found for '{}'\n".format(cp),
2414 - level=logging.ERROR,
2415 - noiselevel=-1,
2416 - )
2417
2418 - if dead_nodes:
2419 - dead_nodes.difference_update(self._existing_nodes)
2420 - for k in dead_nodes:
2421 + if not trg_cache.autocommits:
2422 try:
2423 - del trg_cache[k]
2424 - except KeyError:
2425 - pass
2426 + trg_cache.commit()
2427 except CacheError as ce:
2428 self.returncode |= 1
2429 writemsg_level(
2430 - "{} deleting stale cache: {}\n".format(k, ce),
2431 + "committing target: {}\n".format(ce),
2432 level=logging.ERROR,
2433 noiselevel=-1,
2434 )
2435
2436 - if not trg_cache.autocommits:
2437 - try:
2438 - trg_cache.commit()
2439 - except CacheError as ce:
2440 - self.returncode |= 1
2441 - writemsg_level(
2442 - "committing target: {}\n".format(ce),
2443 - level=logging.ERROR,
2444 - noiselevel=-1,
2445 - )
2446 + if hasattr(trg_cache, "_prune_empty_dirs"):
2447 + trg_cache._prune_empty_dirs()
2448
2449 - if hasattr(trg_cache, "_prune_empty_dirs"):
2450 - trg_cache._prune_empty_dirs()
2451 + class GenPkgDescIndex:
2452 + def __init__(self, repo_config, portdb, output_file, verbose=False):
2453 + self.returncode = os.EX_OK
2454 + self._repo_config = repo_config
2455 + self._portdb = portdb
2456 + self._output_file = output_file
2457 + self._verbose = verbose
2458
2459 + def run(self):
2460
2461 -class GenPkgDescIndex:
2462 - def __init__(self, repo_config, portdb, output_file, verbose=False):
2463 - self.returncode = os.EX_OK
2464 - self._repo_config = repo_config
2465 - self._portdb = portdb
2466 - self._output_file = output_file
2467 - self._verbose = verbose
2468 + display_updates = self._verbose > 0
2469 + old = {}
2470 + new = {}
2471 + if display_updates:
2472 + try:
2473 + with open(
2474 + self._output_file, encoding=_encodings["repo.content"]
2475 + ) as f:
2476 + for line in f:
2477 + pkg_desc = pkg_desc_index_line_read(line)
2478 + old[pkg_desc.cp] = pkg_desc
2479 + except FileNotFoundError:
2480 + pass
2481
2482 - def run(self):
2483 + portage.util.ensure_dirs(os.path.dirname(self._output_file))
2484 + f = portage.util.atomic_ofstream(
2485 + self._output_file, encoding=_encodings["repo.content"]
2486 + )
2487
2488 - display_updates = self._verbose > 0
2489 - old = {}
2490 - new = {}
2491 - if display_updates:
2492 - try:
2493 - with open(self._output_file, encoding=_encodings["repo.content"]) as f:
2494 - for line in f:
2495 - pkg_desc = pkg_desc_index_line_read(line)
2496 - old[pkg_desc.cp] = pkg_desc
2497 - except FileNotFoundError:
2498 - pass
2499 + portdb = self._portdb
2500 + for cp in portdb.cp_all():
2501 + pkgs = portdb.cp_list(cp)
2502 + if not pkgs:
2503 + continue
2504 + (desc,) = portdb.aux_get(pkgs[-1], ["DESCRIPTION"])
2505
2506 - portage.util.ensure_dirs(os.path.dirname(self._output_file))
2507 - f = portage.util.atomic_ofstream(
2508 - self._output_file, encoding=_encodings["repo.content"]
2509 - )
2510 + line = pkg_desc_index_line_format(cp, pkgs, desc)
2511 + f.write(line)
2512 + if display_updates:
2513 + new[cp] = pkg_desc_index_line_read(line)
2514
2515 - portdb = self._portdb
2516 - for cp in portdb.cp_all():
2517 - pkgs = portdb.cp_list(cp)
2518 - if not pkgs:
2519 - continue
2520 - (desc,) = portdb.aux_get(pkgs[-1], ["DESCRIPTION"])
2521 + f.close()
2522
2523 - line = pkg_desc_index_line_format(cp, pkgs, desc)
2524 - f.write(line)
2525 if display_updates:
2526 - new[cp] = pkg_desc_index_line_read(line)
2527 -
2528 - f.close()
2529 -
2530 - if display_updates:
2531 - out = EOutput()
2532 - out.einfo("Searching for changes")
2533 - print("")
2534 - items = sorted(new.values(), key=lambda pkg_desc: pkg_desc.cp)
2535 - haspkgs = False
2536 - for pkg_desc in items:
2537 - masked = False
2538 - version = self._portdb.xmatch(
2539 - "bestmatch-visible",
2540 - Atom(
2541 - "{}{}{}".format(
2542 - pkg_desc.cp, _repo_separator, self._repo_config.name
2543 - )
2544 - ),
2545 - )
2546 - if not version:
2547 - version = pkg_desc.cpv_list[-1]
2548 - masked = True
2549 - old_versions = old.get(pkg_desc.cp)
2550 - if old_versions is None or version not in old_versions.cpv_list:
2551 - prefix0 = " "
2552 - prefix1 = " "
2553 -
2554 - if old_versions is None:
2555 - color = functools.partial(colorize, "darkgreen")
2556 - prefix1 = "N"
2557 - else:
2558 - color = functools.partial(colorize, "turquoise")
2559 - prefix1 = "U"
2560 -
2561 - if masked:
2562 - prefix0 = "M"
2563 -
2564 - print(
2565 - " [%s%s] %s (%s): %s"
2566 - % (
2567 - colorize("red", prefix0),
2568 - color(prefix1),
2569 - colorize("bold", pkg_desc.cp),
2570 - color(version[len(pkg_desc.cp) + 1 :]),
2571 - pkg_desc.desc,
2572 - )
2573 + out = EOutput()
2574 + out.einfo("Searching for changes")
2575 + print("")
2576 + items = sorted(new.values(), key=lambda pkg_desc: pkg_desc.cp)
2577 + haspkgs = False
2578 + for pkg_desc in items:
2579 + masked = False
2580 + version = self._portdb.xmatch(
2581 + "bestmatch-visible",
2582 + Atom(
2583 + "{}{}{}".format(
2584 + pkg_desc.cp, _repo_separator, self._repo_config.name
2585 + )
2586 + ),
2587 )
2588 - haspkgs = True
2589 -
2590 - if not haspkgs:
2591 - out.einfo("No updates found")
2592 -
2593 + if not version:
2594 + version = pkg_desc.cpv_list[-1]
2595 + masked = True
2596 + old_versions = old.get(pkg_desc.cp)
2597 + if old_versions is None or version not in old_versions.cpv_list:
2598 + prefix0 = " "
2599 + prefix1 = " "
2600 +
2601 + if old_versions is None:
2602 + color = functools.partial(colorize, "darkgreen")
2603 + prefix1 = "N"
2604 + else:
2605 + color = functools.partial(colorize, "turquoise")
2606 + prefix1 = "U"
2607
2608 -class GenUseLocalDesc:
2609 - def __init__(self, portdb, output=None, preserve_comments=False):
2610 - self.returncode = os.EX_OK
2611 - self._portdb = portdb
2612 - self._output = output
2613 - self._preserve_comments = preserve_comments
2614 + if masked:
2615 + prefix0 = "M"
2616
2617 - def run(self):
2618 - repo_path = self._portdb.porttrees[0]
2619 - ops = {"<": 0, "<=": 1, "=": 2, ">=": 3, ">": 4}
2620 - prev_mtime = None
2621 - prev_md5 = None
2622 + print(
2623 + " [%s%s] %s (%s): %s"
2624 + % (
2625 + colorize("red", prefix0),
2626 + color(prefix1),
2627 + colorize("bold", pkg_desc.cp),
2628 + color(version[len(pkg_desc.cp) + 1 :]),
2629 + pkg_desc.desc,
2630 + )
2631 + )
2632 + haspkgs = True
2633 +
2634 + if not haspkgs:
2635 + out.einfo("No updates found")
2636 +
2637 + class GenUseLocalDesc:
2638 + def __init__(self, portdb, output=None, preserve_comments=False):
2639 + self.returncode = os.EX_OK
2640 + self._portdb = portdb
2641 + self._output = output
2642 + self._preserve_comments = preserve_comments
2643 +
2644 + def run(self):
2645 + repo_path = self._portdb.porttrees[0]
2646 + ops = {"<": 0, "<=": 1, "=": 2, ">=": 3, ">": 4}
2647 + prev_mtime = None
2648 + prev_md5 = None
2649 +
2650 + if self._output is None or self._output != "-":
2651 + if self._output is None:
2652 + prof_path = os.path.join(repo_path, "profiles")
2653 + desc_path = os.path.join(prof_path, "use.local.desc")
2654 + try:
2655 + os.mkdir(prof_path)
2656 + except OSError:
2657 + pass
2658 + else:
2659 + desc_path = self._output
2660
2661 - if self._output is None or self._output != "-":
2662 - if self._output is None:
2663 - prof_path = os.path.join(repo_path, "profiles")
2664 - desc_path = os.path.join(prof_path, "use.local.desc")
2665 try:
2666 - os.mkdir(prof_path)
2667 - except OSError:
2668 + prev_md5 = portage.checksum.perform_md5(desc_path)
2669 + prev_mtime = os.stat(desc_path)[stat.ST_MTIME]
2670 + except (portage.exception.FileNotFound, OSError):
2671 pass
2672 - else:
2673 - desc_path = self._output
2674
2675 - try:
2676 - prev_md5 = portage.checksum.perform_md5(desc_path)
2677 - prev_mtime = os.stat(desc_path)[stat.ST_MTIME]
2678 - except (portage.exception.FileNotFound, OSError):
2679 - pass
2680 + try:
2681 + if self._preserve_comments:
2682 + # Probe in binary mode, in order to avoid
2683 + # potential character encoding issues.
2684 + output = open(
2685 + _unicode_encode(
2686 + desc_path, encoding=_encodings["fs"], errors="strict"
2687 + ),
2688 + "r+b",
2689 + )
2690 + else:
2691 + output = open(
2692 + _unicode_encode(
2693 + desc_path, encoding=_encodings["fs"], errors="strict"
2694 + ),
2695 + mode="w",
2696 + encoding=_encodings["repo.content"],
2697 + errors="backslashreplace",
2698 + )
2699 + except OSError as e:
2700 + if not self._preserve_comments or os.path.isfile(desc_path):
2701 + writemsg_level(
2702 + "ERROR: failed to open output file {}: {}\n".format(
2703 + desc_path, e
2704 + ),
2705 + level=logging.ERROR,
2706 + noiselevel=-1,
2707 + )
2708 + self.returncode |= 2
2709 + return
2710
2711 - try:
2712 - if self._preserve_comments:
2713 - # Probe in binary mode, in order to avoid
2714 - # potential character encoding issues.
2715 - output = open(
2716 - _unicode_encode(
2717 - desc_path, encoding=_encodings["fs"], errors="strict"
2718 - ),
2719 - "r+b",
2720 - )
2721 - else:
2722 - output = open(
2723 - _unicode_encode(
2724 - desc_path, encoding=_encodings["fs"], errors="strict"
2725 - ),
2726 - mode="w",
2727 - encoding=_encodings["repo.content"],
2728 - errors="backslashreplace",
2729 - )
2730 - except OSError as e:
2731 - if not self._preserve_comments or os.path.isfile(desc_path):
2732 + # Open in r+b mode failed because the file doesn't
2733 + # exist yet. We can probably recover if we disable
2734 + # preserve_comments mode now.
2735 writemsg_level(
2736 - "ERROR: failed to open output file {}: {}\n".format(
2737 - desc_path, e
2738 - ),
2739 - level=logging.ERROR,
2740 + "WARNING: --preserve-comments enabled, but "
2741 + + "output file not found: {}\n".format(desc_path),
2742 + level=logging.WARNING,
2743 noiselevel=-1,
2744 )
2745 - self.returncode |= 2
2746 - return
2747 -
2748 - # Open in r+b mode failed because the file doesn't
2749 - # exist yet. We can probably recover if we disable
2750 - # preserve_comments mode now.
2751 - writemsg_level(
2752 - "WARNING: --preserve-comments enabled, but "
2753 - + "output file not found: {}\n".format(desc_path),
2754 - level=logging.WARNING,
2755 - noiselevel=-1,
2756 + self._preserve_comments = False
2757 + try:
2758 + output = open(
2759 + _unicode_encode(
2760 + desc_path, encoding=_encodings["fs"], errors="strict"
2761 + ),
2762 + mode="w",
2763 + encoding=_encodings["repo.content"],
2764 + errors="backslashreplace",
2765 + )
2766 + except OSError as e:
2767 + writemsg_level(
2768 + "ERROR: failed to open output file {}: {}\n".format(
2769 + desc_path, e
2770 + ),
2771 + level=logging.ERROR,
2772 + noiselevel=-1,
2773 + )
2774 + self.returncode |= 2
2775 + return
2776 + else:
2777 + output = sys.stdout
2778 +
2779 + if self._preserve_comments:
2780 + while True:
2781 + pos = output.tell()
2782 + if not output.readline().startswith(b"#"):
2783 + break
2784 + output.seek(pos)
2785 + output.truncate()
2786 + output.close()
2787 +
2788 + # Finished probing comments in binary mode, now append
2789 + # in text mode.
2790 + output = open(
2791 + _unicode_encode(
2792 + desc_path, encoding=_encodings["fs"], errors="strict"
2793 + ),
2794 + mode="a",
2795 + encoding=_encodings["repo.content"],
2796 + errors="backslashreplace",
2797 )
2798 - self._preserve_comments = False
2799 - try:
2800 - output = open(
2801 - _unicode_encode(
2802 - desc_path, encoding=_encodings["fs"], errors="strict"
2803 - ),
2804 - mode="w",
2805 - encoding=_encodings["repo.content"],
2806 - errors="backslashreplace",
2807 - )
2808 - except OSError as e:
2809 - writemsg_level(
2810 - "ERROR: failed to open output file {}: {}\n".format(
2811 - desc_path, e
2812 - ),
2813 - level=logging.ERROR,
2814 - noiselevel=-1,
2815 + output.write("\n")
2816 + else:
2817 + output.write(
2818 + textwrap.dedent(
2819 + """\
2820 + # This file is deprecated as per GLEP 56 in favor of metadata.xml. Please add
2821 + # your descriptions to your package's metadata.xml ONLY.
2822 + # * generated automatically using egencache *
2823 +
2824 + """
2825 )
2826 - self.returncode |= 2
2827 - return
2828 - else:
2829 - output = sys.stdout
2830 -
2831 - if self._preserve_comments:
2832 - while True:
2833 - pos = output.tell()
2834 - if not output.readline().startswith(b"#"):
2835 - break
2836 - output.seek(pos)
2837 - output.truncate()
2838 - output.close()
2839 -
2840 - # Finished probing comments in binary mode, now append
2841 - # in text mode.
2842 - output = open(
2843 - _unicode_encode(desc_path, encoding=_encodings["fs"], errors="strict"),
2844 - mode="a",
2845 - encoding=_encodings["repo.content"],
2846 - errors="backslashreplace",
2847 - )
2848 - output.write("\n")
2849 - else:
2850 - output.write(
2851 - textwrap.dedent(
2852 - """\
2853 - # This file is deprecated as per GLEP 56 in favor of metadata.xml. Please add
2854 - # your descriptions to your package's metadata.xml ONLY.
2855 - # * generated automatically using egencache *
2856 -
2857 - """
2858 )
2859 - )
2860
2861 - # The cmp function no longer exists in python3, so we'll
2862 - # implement our own here under a slightly different name
2863 - # since we don't want any confusion given that we never
2864 - # want to rely on the builtin cmp function.
2865 - def cmp_func(a, b):
2866 - if a is None or b is None:
2867 - # None can't be compared with other types in python3.
2868 - if a is None and b is None:
2869 - return 0
2870 - elif a is None:
2871 - return -1
2872 - else:
2873 - return 1
2874 - return (a > b) - (a < b)
2875 + # The cmp function no longer exists in python3, so we'll
2876 + # implement our own here under a slightly different name
2877 + # since we don't want any confusion given that we never
2878 + # want to rely on the builtin cmp function.
2879 + def cmp_func(a, b):
2880 + if a is None or b is None:
2881 + # None can't be compared with other types in python3.
2882 + if a is None and b is None:
2883 + return 0
2884 + elif a is None:
2885 + return -1
2886 + else:
2887 + return 1
2888 + return (a > b) - (a < b)
2889
2890 - class _MetadataTreeBuilder(ElementTree.TreeBuilder):
2891 - """
2892 - Implements doctype() as required to avoid deprecation warnings
2893 - since Python >=2.7
2894 - """
2895 + class _MetadataTreeBuilder(ElementTree.TreeBuilder):
2896 + """
2897 + Implements doctype() as required to avoid deprecation warnings
2898 + since Python >=2.7
2899 + """
2900
2901 - def doctype(self, name, pubid, system):
2902 - pass
2903 + def doctype(self, name, pubid, system):
2904 + pass
2905
2906 - for cp in self._portdb.cp_all():
2907 - metadata_path = os.path.join(repo_path, cp, "metadata.xml")
2908 - try:
2909 - metadata = ElementTree.parse(
2910 - _unicode_encode(
2911 - metadata_path, encoding=_encodings["fs"], errors="strict"
2912 - ),
2913 - parser=ElementTree.XMLParser(target=_MetadataTreeBuilder()),
2914 - )
2915 - except OSError:
2916 - pass
2917 - except (ExpatError, OSError) as e:
2918 - writemsg_level(
2919 - "ERROR: failed parsing {}/metadata.xml: {}\n".format(cp, e),
2920 - level=logging.ERROR,
2921 - noiselevel=-1,
2922 - )
2923 - self.returncode |= 1
2924 - else:
2925 + for cp in self._portdb.cp_all():
2926 + metadata_path = os.path.join(repo_path, cp, "metadata.xml")
2927 try:
2928 - usedict = parse_metadata_use(metadata)
2929 - except portage.exception.ParseError as e:
2930 + metadata = ElementTree.parse(
2931 + _unicode_encode(
2932 + metadata_path, encoding=_encodings["fs"], errors="strict"
2933 + ),
2934 + parser=ElementTree.XMLParser(target=_MetadataTreeBuilder()),
2935 + )
2936 + except OSError:
2937 + pass
2938 + except (ExpatError, OSError) as e:
2939 writemsg_level(
2940 "ERROR: failed parsing {}/metadata.xml: {}\n".format(cp, e),
2941 level=logging.ERROR,
2942 @@ -800,610 +810,635 @@ class GenUseLocalDesc:
2943 )
2944 self.returncode |= 1
2945 else:
2946 - for flag in sorted(usedict):
2947 -
2948 - def atomcmp(atoma, atomb):
2949 - # None is better than an atom, that's why we reverse the args
2950 - if atoma is None or atomb is None:
2951 - return cmp_func(atomb, atoma)
2952 - # Same for plain PNs (.operator is None then)
2953 - elif atoma.operator is None or atomb.operator is None:
2954 - return cmp_func(atomb.operator, atoma.operator)
2955 - # Version matching
2956 - elif atoma.cpv != atomb.cpv:
2957 - return vercmp(atoma.version, atomb.version)
2958 - # Versions match, let's fallback to operator matching
2959 - else:
2960 - return cmp_func(
2961 - ops.get(atoma.operator, -1),
2962 - ops.get(atomb.operator, -1),
2963 - )
2964 -
2965 - def _Atom(key):
2966 - if key is not None:
2967 - return Atom(key)
2968 - return None
2969 -
2970 - resdict = usedict[flag]
2971 - if len(resdict) == 1:
2972 - resdesc = next(iter(resdict.items()))[1]
2973 - else:
2974 - try:
2975 - reskeys = {_Atom(k): k for k in resdict}
2976 - except portage.exception.InvalidAtom as e:
2977 - writemsg_level(
2978 - "ERROR: failed parsing %s/metadata.xml: %s\n"
2979 - % (cp, e),
2980 - level=logging.ERROR,
2981 - noiselevel=-1,
2982 - )
2983 - self.returncode |= 1
2984 + try:
2985 + usedict = parse_metadata_use(metadata)
2986 + except portage.exception.ParseError as e:
2987 + writemsg_level(
2988 + "ERROR: failed parsing {}/metadata.xml: {}\n".format(cp, e),
2989 + level=logging.ERROR,
2990 + noiselevel=-1,
2991 + )
2992 + self.returncode |= 1
2993 + else:
2994 + for flag in sorted(usedict):
2995 +
2996 + def atomcmp(atoma, atomb):
2997 + # None is better than an atom, that's why we reverse the args
2998 + if atoma is None or atomb is None:
2999 + return cmp_func(atomb, atoma)
3000 + # Same for plain PNs (.operator is None then)
3001 + elif atoma.operator is None or atomb.operator is None:
3002 + return cmp_func(atomb.operator, atoma.operator)
3003 + # Version matching
3004 + elif atoma.cpv != atomb.cpv:
3005 + return vercmp(atoma.version, atomb.version)
3006 + # Versions match, let's fallback to operator matching
3007 + else:
3008 + return cmp_func(
3009 + ops.get(atoma.operator, -1),
3010 + ops.get(atomb.operator, -1),
3011 + )
3012 +
3013 + def _Atom(key):
3014 + if key is not None:
3015 + return Atom(key)
3016 + return None
3017 +
3018 + resdict = usedict[flag]
3019 + if len(resdict) == 1:
3020 resdesc = next(iter(resdict.items()))[1]
3021 else:
3022 - resatoms = sorted(reskeys, key=cmp_sort_key(atomcmp))
3023 - resdesc = resdict[reskeys[resatoms[-1]]]
3024 + try:
3025 + reskeys = {_Atom(k): k for k in resdict}
3026 + except portage.exception.InvalidAtom as e:
3027 + writemsg_level(
3028 + "ERROR: failed parsing %s/metadata.xml: %s\n"
3029 + % (cp, e),
3030 + level=logging.ERROR,
3031 + noiselevel=-1,
3032 + )
3033 + self.returncode |= 1
3034 + resdesc = next(iter(resdict.items()))[1]
3035 + else:
3036 + resatoms = sorted(
3037 + reskeys, key=cmp_sort_key(atomcmp)
3038 + )
3039 + resdesc = resdict[reskeys[resatoms[-1]]]
3040 +
3041 + output.write("{}:{} - {}\n".format(cp, flag, resdesc))
3042
3043 - output.write("{}:{} - {}\n".format(cp, flag, resdesc))
3044 + output.close()
3045 + if prev_mtime is not None and prev_md5 == portage.checksum.perform_md5(
3046 + desc_path
3047 + ):
3048 + # Preserve mtime for rsync.
3049 + mtime = prev_mtime
3050 + else:
3051 + # For portability, and consistency with the mtime preservation
3052 + # code, set mtime to an exact integer value.
3053 + mtime = int(time.time())
3054
3055 - output.close()
3056 - if prev_mtime is not None and prev_md5 == portage.checksum.perform_md5(
3057 - desc_path
3058 - ):
3059 - # Preserve mtime for rsync.
3060 - mtime = prev_mtime
3061 - else:
3062 - # For portability, and consistency with the mtime preservation
3063 - # code, set mtime to an exact integer value.
3064 - mtime = int(time.time())
3065 + os.utime(desc_path, (mtime, mtime))
3066
3067 - os.utime(desc_path, (mtime, mtime))
3068 + class GenChangeLogs:
3069 + def __init__(
3070 + self,
3071 + portdb,
3072 + changelog_output,
3073 + changelog_reversed,
3074 + max_jobs=None,
3075 + max_load=None,
3076 + ):
3077 + self.returncode = os.EX_OK
3078 + self._portdb = portdb
3079 + self._wrapper = textwrap.TextWrapper(
3080 + width=78, initial_indent=" ", subsequent_indent=" "
3081 + )
3082 + self._changelog_output = changelog_output
3083 + self._changelog_reversed = changelog_reversed
3084 + self._max_jobs = max_jobs
3085 + self._max_load = max_load
3086 + self._repo_path = self._portdb.porttrees[0]
3087 + # --work-tree=... must be passed to Git if GIT_DIR is used
3088 + # and GIT_DIR is not a child of the root of the checkout
3089 + # eg:
3090 + # GIT_DIR=${parent}/work/.git/
3091 + # work-tree=${parent}/staging/
3092 + # If work-tree is not passed, Git tries to use the shared
3093 + # parent of the current directory and the ${GIT_DIR}, which can
3094 + # be outside the root of the checkout.
3095 + self._work_tree = "--work-tree=%s" % self._repo_path
3096 +
3097 + @staticmethod
3098 + def grab(cmd):
3099 + p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
3100 + return _unicode_decode(
3101 + p.communicate()[0], encoding=_encodings["stdio"], errors="strict"
3102 + )
3103
3104 + def generate_changelog(self, cp):
3105
3106 -class GenChangeLogs:
3107 - def __init__(
3108 - self, portdb, changelog_output, changelog_reversed, max_jobs=None, max_load=None
3109 - ):
3110 - self.returncode = os.EX_OK
3111 - self._portdb = portdb
3112 - self._wrapper = textwrap.TextWrapper(
3113 - width=78, initial_indent=" ", subsequent_indent=" "
3114 - )
3115 - self._changelog_output = changelog_output
3116 - self._changelog_reversed = changelog_reversed
3117 - self._max_jobs = max_jobs
3118 - self._max_load = max_load
3119 - self._repo_path = self._portdb.porttrees[0]
3120 - # --work-tree=... must be passed to Git if GIT_DIR is used
3121 - # and GIT_DIR is not a child of the root of the checkout
3122 - # eg:
3123 - # GIT_DIR=${parent}/work/.git/
3124 - # work-tree=${parent}/staging/
3125 - # If work-tree is not passed, Git tries to use the shared
3126 - # parent of the current directory and the ${GIT_DIR}, which can
3127 - # be outside the root of the checkout.
3128 - self._work_tree = "--work-tree=%s" % self._repo_path
3129 -
3130 - @staticmethod
3131 - def grab(cmd):
3132 - p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
3133 - return _unicode_decode(
3134 - p.communicate()[0], encoding=_encodings["stdio"], errors="strict"
3135 - )
3136 + os.chdir(os.path.join(self._repo_path, cp))
3137 + # Determine whether ChangeLog is up-to-date by comparing
3138 + # the newest commit timestamp with the ChangeLog timestamp.
3139 + lmod = self.grab(["git", self._work_tree, "log", "--format=%ct", "-1", "."])
3140 + if not lmod:
3141 + # This cp has not been added to the repo.
3142 + return
3143
3144 - def generate_changelog(self, cp):
3145 + lmod = int(lmod)
3146
3147 - os.chdir(os.path.join(self._repo_path, cp))
3148 - # Determine whether ChangeLog is up-to-date by comparing
3149 - # the newest commit timestamp with the ChangeLog timestamp.
3150 - lmod = self.grab(["git", self._work_tree, "log", "--format=%ct", "-1", "."])
3151 - if not lmod:
3152 - # This cp has not been added to the repo.
3153 - return
3154 + try:
3155 + cmod = os.stat("ChangeLog")[stat.ST_MTIME]
3156 + except OSError:
3157 + cmod = 0
3158
3159 - lmod = int(lmod)
3160 + # Use exact comparison, since commit times are
3161 + # not necessarily ordered.
3162 + if cmod == lmod:
3163 + return
3164
3165 - try:
3166 - cmod = os.stat("ChangeLog")[stat.ST_MTIME]
3167 - except OSError:
3168 - cmod = 0
3169 + try:
3170 + output = open(
3171 + self._changelog_output,
3172 + mode="w",
3173 + encoding=_encodings["repo.content"],
3174 + errors="backslashreplace",
3175 + )
3176 + except OSError as e:
3177 + writemsg_level(
3178 + "ERROR: failed to open ChangeLog for %s: %s\n"
3179 + % (
3180 + cp,
3181 + e,
3182 + ),
3183 + level=logging.ERROR,
3184 + noiselevel=-1,
3185 + )
3186 + self.returncode |= 2
3187 + return
3188
3189 - # Use exact comparison, since commit times are
3190 - # not necessarily ordered.
3191 - if cmod == lmod:
3192 - return
3193 + output.write(
3194 + textwrap.dedent(
3195 + """\
3196 + # ChangeLog for %s
3197 + # Copyright 1999-%s Gentoo Foundation; Distributed under the GPL v2
3198 + # (auto-generated from git log)
3199
3200 - try:
3201 - output = open(
3202 - self._changelog_output,
3203 - mode="w",
3204 - encoding=_encodings["repo.content"],
3205 - errors="backslashreplace",
3206 - )
3207 - except OSError as e:
3208 - writemsg_level(
3209 - "ERROR: failed to open ChangeLog for %s: %s\n"
3210 - % (
3211 - cp,
3212 - e,
3213 - ),
3214 - level=logging.ERROR,
3215 - noiselevel=-1,
3216 - )
3217 - self.returncode |= 2
3218 - return
3219 -
3220 - output.write(
3221 - textwrap.dedent(
3222 - """\
3223 - # ChangeLog for %s
3224 - # Copyright 1999-%s Gentoo Foundation; Distributed under the GPL v2
3225 - # (auto-generated from git log)
3226 -
3227 - """
3228 - % (cp, time.strftime("%Y"))
3229 + """
3230 + % (cp, time.strftime("%Y"))
3231 + )
3232 )
3233 - )
3234
3235 - # now grab all the commits
3236 - revlist_cmd = ["git", self._work_tree, "rev-list"]
3237 - if self._changelog_reversed:
3238 - revlist_cmd.append("--reverse")
3239 - revlist_cmd.extend(["HEAD", "--", "."])
3240 - commits = self.grab(revlist_cmd).split()
3241 -
3242 - for c in commits:
3243 - # Explaining the arguments:
3244 - # --name-status to get a list of added/removed files
3245 - # --no-renames to avoid getting more complex records on the list
3246 - # --format to get the timestamp, author and commit description
3247 - # --root to make it work fine even with the initial commit
3248 - # --relative=${cp} to get paths relative to ebuilddir
3249 - # -r (recursive) to get per-file changes
3250 - # then the commit-id and path.
3251 -
3252 - cinfo = (
3253 - self.grab(
3254 - [
3255 - "git",
3256 - self._work_tree,
3257 - "diff-tree",
3258 - "--name-status",
3259 - "--no-renames",
3260 - "--format=%ct %cN <%cE>%n%B",
3261 - "--root",
3262 - "--relative={}".format(cp),
3263 - "-r",
3264 - c,
3265 - "--",
3266 - ".",
3267 - ]
3268 + # now grab all the commits
3269 + revlist_cmd = ["git", self._work_tree, "rev-list"]
3270 + if self._changelog_reversed:
3271 + revlist_cmd.append("--reverse")
3272 + revlist_cmd.extend(["HEAD", "--", "."])
3273 + commits = self.grab(revlist_cmd).split()
3274 +
3275 + for c in commits:
3276 + # Explaining the arguments:
3277 + # --name-status to get a list of added/removed files
3278 + # --no-renames to avoid getting more complex records on the list
3279 + # --format to get the timestamp, author and commit description
3280 + # --root to make it work fine even with the initial commit
3281 + # --relative=${cp} to get paths relative to ebuilddir
3282 + # -r (recursive) to get per-file changes
3283 + # then the commit-id and path.
3284 +
3285 + cinfo = (
3286 + self.grab(
3287 + [
3288 + "git",
3289 + self._work_tree,
3290 + "diff-tree",
3291 + "--name-status",
3292 + "--no-renames",
3293 + "--format=%ct %cN <%cE>%n%B",
3294 + "--root",
3295 + "--relative={}".format(cp),
3296 + "-r",
3297 + c,
3298 + "--",
3299 + ".",
3300 + ]
3301 + )
3302 + .rstrip("\n")
3303 + .split("\n")
3304 )
3305 - .rstrip("\n")
3306 - .split("\n")
3307 - )
3308
3309 - # Expected output:
3310 - # timestamp Author Name <author@email>
3311 - # commit message l1
3312 - # ...
3313 - # commit message ln
3314 - #
3315 - # status1 filename1
3316 - # ...
3317 - # statusn filenamen
3318 -
3319 - changed = []
3320 - for n, l in enumerate(reversed(cinfo)):
3321 - if not l:
3322 - body = cinfo[1 : -n - 1]
3323 - break
3324 - else:
3325 - f = l.split()
3326 - if f[1] == "Manifest":
3327 - pass # XXX: remanifest commits?
3328 - elif f[1].startswith("ChangeLog"):
3329 - pass
3330 - elif f[0].startswith("A"):
3331 - changed.append(ChangeLogTypeSort("+", f[1]))
3332 - elif f[0].startswith("D"):
3333 - changed.append(ChangeLogTypeSort("-", f[1]))
3334 - elif f[0].startswith("M"):
3335 - changed.append(ChangeLogTypeSort("", f[1]))
3336 + # Expected output:
3337 + # timestamp Author Name <author@email>
3338 + # commit message l1
3339 + # ...
3340 + # commit message ln
3341 + #
3342 + # status1 filename1
3343 + # ...
3344 + # statusn filenamen
3345 +
3346 + changed = []
3347 + for n, l in enumerate(reversed(cinfo)):
3348 + if not l:
3349 + body = cinfo[1 : -n - 1]
3350 + break
3351 else:
3352 - writemsg_level(
3353 - "ERROR: unexpected git file status for %s: %s\n"
3354 - % (
3355 - cp,
3356 - f,
3357 - ),
3358 - level=logging.ERROR,
3359 - noiselevel=-1,
3360 - )
3361 - self.returncode |= 1
3362 -
3363 - if not changed:
3364 - continue
3365 -
3366 - (ts, author) = cinfo[0].split(" ", 1)
3367 - date = time.strftime("%d %b %Y", time.gmtime(float(ts)))
3368 -
3369 - changed = [str(x) for x in sorted(changed)]
3370 -
3371 - wroteheader = False
3372 - # Reverse the sort order for headers.
3373 - for c in reversed(changed):
3374 - if c.startswith("+") and c.endswith(".ebuild"):
3375 - output.write("*{} ({})\n".format(c[1:-7], date))
3376 - wroteheader = True
3377 - if wroteheader:
3378 - output.write("\n")
3379 -
3380 - # strip '<cp>: ', '[<cp>] ', and similar
3381 - body[0] = re.sub(r"^\W*" + re.escape(cp) + r"\W+", "", body[0])
3382 - # strip trailing newline
3383 - if not body[-1]:
3384 - body = body[:-1]
3385 - # strip git-svn id
3386 - if body[-1].startswith("git-svn-id:") and not body[-2]:
3387 - body = body[:-2]
3388 - # strip the repoman version/manifest note
3389 - if (
3390 - body[-1] == " (Signed Manifest commit)"
3391 - or body[-1] == " (Unsigned Manifest commit)"
3392 - ):
3393 - body = body[:-1]
3394 - if body[-1].startswith("(Portage version:") and body[-1].endswith(")"):
3395 - body = body[:-1]
3396 + f = l.split()
3397 + if f[1] == "Manifest":
3398 + pass # XXX: remanifest commits?
3399 + elif f[1].startswith("ChangeLog"):
3400 + pass
3401 + elif f[0].startswith("A"):
3402 + changed.append(ChangeLogTypeSort("+", f[1]))
3403 + elif f[0].startswith("D"):
3404 + changed.append(ChangeLogTypeSort("-", f[1]))
3405 + elif f[0].startswith("M"):
3406 + changed.append(ChangeLogTypeSort("", f[1]))
3407 + else:
3408 + writemsg_level(
3409 + "ERROR: unexpected git file status for %s: %s\n"
3410 + % (
3411 + cp,
3412 + f,
3413 + ),
3414 + level=logging.ERROR,
3415 + noiselevel=-1,
3416 + )
3417 + self.returncode |= 1
3418 +
3419 + if not changed:
3420 + continue
3421 +
3422 + (ts, author) = cinfo[0].split(" ", 1)
3423 + date = time.strftime("%d %b %Y", time.gmtime(float(ts)))
3424 +
3425 + changed = [str(x) for x in sorted(changed)]
3426 +
3427 + wroteheader = False
3428 + # Reverse the sort order for headers.
3429 + for c in reversed(changed):
3430 + if c.startswith("+") and c.endswith(".ebuild"):
3431 + output.write("*{} ({})\n".format(c[1:-7], date))
3432 + wroteheader = True
3433 + if wroteheader:
3434 + output.write("\n")
3435 +
3436 + # strip '<cp>: ', '[<cp>] ', and similar
3437 + body[0] = re.sub(r"^\W*" + re.escape(cp) + r"\W+", "", body[0])
3438 + # strip trailing newline
3439 if not body[-1]:
3440 body = body[:-1]
3441 -
3442 - # don't break filenames on hyphens
3443 - self._wrapper.break_on_hyphens = False
3444 - output.write(
3445 - self._wrapper.fill(
3446 - "{}; {} {}:".format(date, author, ", ".join(changed))
3447 + # strip git-svn id
3448 + if body[-1].startswith("git-svn-id:") and not body[-2]:
3449 + body = body[:-2]
3450 + # strip the repoman version/manifest note
3451 + if (
3452 + body[-1] == " (Signed Manifest commit)"
3453 + or body[-1] == " (Unsigned Manifest commit)"
3454 + ):
3455 + body = body[:-1]
3456 + if body[-1].startswith("(Portage version:") and body[-1].endswith(")"):
3457 + body = body[:-1]
3458 + if not body[-1]:
3459 + body = body[:-1]
3460 +
3461 + # don't break filenames on hyphens
3462 + self._wrapper.break_on_hyphens = False
3463 + output.write(
3464 + self._wrapper.fill(
3465 + "{}; {} {}:".format(date, author, ", ".join(changed))
3466 + )
3467 + )
3468 + # but feel free to break commit messages there
3469 + self._wrapper.break_on_hyphens = True
3470 + output.write(
3471 + "\n%s\n\n" % "\n".join(self._wrapper.fill(x) for x in body)
3472 )
3473 - )
3474 - # but feel free to break commit messages there
3475 - self._wrapper.break_on_hyphens = True
3476 - output.write("\n%s\n\n" % "\n".join(self._wrapper.fill(x) for x in body))
3477
3478 - output.close()
3479 - os.utime(self._changelog_output, (lmod, lmod))
3480 + output.close()
3481 + os.utime(self._changelog_output, (lmod, lmod))
3482
3483 - def _task_iter(self):
3484 - if not os.path.isdir(
3485 - os.environ.get("GIT_DIR", os.path.join(self._repo_path, ".git"))
3486 - ):
3487 - writemsg_level(
3488 - "ERROR: --update-changelogs supported only in git repos\n",
3489 - level=logging.ERROR,
3490 - noiselevel=-1,
3491 - )
3492 - self.returncode = 127
3493 - return
3494 -
3495 - for cp in self._portdb.cp_all():
3496 - yield AsyncFunction(target=self.generate_changelog, args=[cp])
3497 -
3498 - def run(self):
3499 - return run_main_scheduler(
3500 - TaskScheduler(
3501 - self._task_iter(),
3502 - event_loop=global_event_loop(),
3503 - max_jobs=self._max_jobs,
3504 - max_load=self._max_load,
3505 + def _task_iter(self):
3506 + if not os.path.isdir(
3507 + os.environ.get("GIT_DIR", os.path.join(self._repo_path, ".git"))
3508 + ):
3509 + writemsg_level(
3510 + "ERROR: --update-changelogs supported only in git repos\n",
3511 + level=logging.ERROR,
3512 + noiselevel=-1,
3513 + )
3514 + self.returncode = 127
3515 + return
3516 +
3517 + for cp in self._portdb.cp_all():
3518 + yield AsyncFunction(target=self.generate_changelog, args=[cp])
3519 +
3520 + def run(self):
3521 + return run_main_scheduler(
3522 + TaskScheduler(
3523 + self._task_iter(),
3524 + event_loop=global_event_loop(),
3525 + max_jobs=self._max_jobs,
3526 + max_load=self._max_load,
3527 + )
3528 )
3529 - )
3530 -
3531 -
3532 -def egencache_main(args):
3533 -
3534 - # The calling environment is ignored, so the program is
3535 - # completely controlled by commandline arguments.
3536 - env = {}
3537 -
3538 - if not sys.stdout.isatty() or os.environ.get("NOCOLOR", "").lower() in (
3539 - "yes",
3540 - "true",
3541 - ):
3542 - portage.output.nocolor()
3543 - env["NOCOLOR"] = "true"
3544
3545 - parser, options, atoms = parse_args(args)
3546 + def egencache_main(args):
3547
3548 - config_root = options.config_root
3549 + # The calling environment is ignored, so the program is
3550 + # completely controlled by commandline arguments.
3551 + env = {}
3552
3553 - if options.repositories_configuration is not None:
3554 - env["PORTAGE_REPOSITORIES"] = options.repositories_configuration
3555 -
3556 - if options.cache_dir is not None:
3557 - env["PORTAGE_DEPCACHEDIR"] = options.cache_dir
3558 + if not sys.stdout.isatty() or os.environ.get("NOCOLOR", "").lower() in (
3559 + "yes",
3560 + "true",
3561 + ):
3562 + portage.output.nocolor()
3563 + env["NOCOLOR"] = "true"
3564
3565 - settings = portage.config(config_root=config_root, local_config=False, env=env)
3566 + parser, options, atoms = parse_args(args)
3567
3568 - default_opts = None
3569 - if not options.ignore_default_opts:
3570 - default_opts = portage.util.shlex_split(
3571 - settings.get("EGENCACHE_DEFAULT_OPTS", "")
3572 - )
3573 + config_root = options.config_root
3574
3575 - if default_opts:
3576 - parser, options, args = parse_args(default_opts + args)
3577 + if options.repositories_configuration is not None:
3578 + env["PORTAGE_REPOSITORIES"] = options.repositories_configuration
3579
3580 if options.cache_dir is not None:
3581 env["PORTAGE_DEPCACHEDIR"] = options.cache_dir
3582
3583 settings = portage.config(config_root=config_root, local_config=False, env=env)
3584
3585 - if not (
3586 - options.update
3587 - or options.update_use_local_desc
3588 - or options.update_changelogs
3589 - or options.update_manifests
3590 - or options.update_pkg_desc_index
3591 - ):
3592 - parser.error("No action specified")
3593 - return 1
3594 -
3595 - if options.repo is None:
3596 - if len(settings.repositories.prepos) == 2:
3597 - for repo in settings.repositories:
3598 - if repo.name != "DEFAULT":
3599 - options.repo = repo.name
3600 - break
3601 + default_opts = None
3602 + if not options.ignore_default_opts:
3603 + default_opts = portage.util.shlex_split(
3604 + settings.get("EGENCACHE_DEFAULT_OPTS", "")
3605 + )
3606
3607 - if options.repo is None:
3608 - parser.error("--repo option is required")
3609 + if default_opts:
3610 + parser, options, args = parse_args(default_opts + args)
3611
3612 - repo_path = settings.repositories.treemap.get(options.repo)
3613 - if repo_path is None:
3614 - parser.error("Unable to locate repository named '{}'".format(options.repo))
3615 - return 1
3616 + if options.cache_dir is not None:
3617 + env["PORTAGE_DEPCACHEDIR"] = options.cache_dir
3618
3619 - repo_config = settings.repositories.get_repo_for_location(repo_path)
3620 + settings = portage.config(
3621 + config_root=config_root, local_config=False, env=env
3622 + )
3623
3624 - if options.strict_manifests is not None:
3625 - if options.strict_manifests == "y":
3626 - settings.features.add("strict")
3627 - else:
3628 - settings.features.discard("strict")
3629 + if not (
3630 + options.update
3631 + or options.update_use_local_desc
3632 + or options.update_changelogs
3633 + or options.update_manifests
3634 + or options.update_pkg_desc_index
3635 + ):
3636 + parser.error("No action specified")
3637 + return 1
3638
3639 - if options.update and "metadata-transfer" not in settings.features:
3640 - # Forcibly enable metadata-transfer if portdbapi has a pregenerated
3641 - # cache that does not support eclass validation.
3642 - cache = repo_config.get_pregenerated_cache(
3643 - portage.dbapi.dbapi._known_keys, readonly=True
3644 - )
3645 - if cache is not None and not cache.complete_eclass_entries:
3646 - settings.features.add("metadata-transfer")
3647 - cache = None
3648 + if options.repo is None:
3649 + if len(settings.repositories.prepos) == 2:
3650 + for repo in settings.repositories:
3651 + if repo.name != "DEFAULT":
3652 + options.repo = repo.name
3653 + break
3654
3655 - settings.lock()
3656 + if options.repo is None:
3657 + parser.error("--repo option is required")
3658
3659 - portdb = portage.portdbapi(mysettings=settings)
3660 + repo_path = settings.repositories.treemap.get(options.repo)
3661 + if repo_path is None:
3662 + parser.error("Unable to locate repository named '{}'".format(options.repo))
3663 + return 1
3664
3665 - # Limit ebuilds to the specified repo.
3666 - portdb.porttrees = [repo_path]
3667 + repo_config = settings.repositories.get_repo_for_location(repo_path)
3668
3669 - if options.update:
3670 - if options.cache_dir is not None:
3671 - # already validated earlier
3672 - pass
3673 - else:
3674 - # We check write access after the portdbapi constructor
3675 - # has had an opportunity to create it. This ensures that
3676 - # we don't use the cache in the "volatile" mode which is
3677 - # undesirable for egencache.
3678 - if not os.access(settings["PORTAGE_DEPCACHEDIR"], os.W_OK):
3679 - writemsg_level(
3680 - "ecachegen: error: "
3681 - + "write access denied: {}\n".format(
3682 - settings["PORTAGE_DEPCACHEDIR"]
3683 - ),
3684 - level=logging.ERROR,
3685 - noiselevel=-1,
3686 - )
3687 - return 1
3688 + if options.strict_manifests is not None:
3689 + if options.strict_manifests == "y":
3690 + settings.features.add("strict")
3691 + else:
3692 + settings.features.discard("strict")
3693
3694 - if options.sign_manifests is not None:
3695 - repo_config.sign_manifest = options.sign_manifests == "y"
3696 + if options.update and "metadata-transfer" not in settings.features:
3697 + # Forcibly enable metadata-transfer if portdbapi has a pregenerated
3698 + # cache that does not support eclass validation.
3699 + cache = repo_config.get_pregenerated_cache(
3700 + portage.dbapi.dbapi._known_keys, readonly=True
3701 + )
3702 + if cache is not None and not cache.complete_eclass_entries:
3703 + settings.features.add("metadata-transfer")
3704 + cache = None
3705
3706 - if options.thin_manifests is not None:
3707 - repo_config.thin_manifest = options.thin_manifests == "y"
3708 + settings.lock()
3709
3710 - gpg_cmd = None
3711 - gpg_vars = None
3712 - force_sign_key = None
3713 + portdb = portage.portdbapi(mysettings=settings)
3714
3715 - if options.update_manifests:
3716 - if repo_config.sign_manifest:
3717 + # Limit ebuilds to the specified repo.
3718 + portdb.porttrees = [repo_path]
3719
3720 - sign_problem = False
3721 - gpg_dir = None
3722 - gpg_cmd = settings.get("PORTAGE_GPG_SIGNING_COMMAND")
3723 - if gpg_cmd is None:
3724 - writemsg_level(
3725 - "egencache: error: "
3726 - "PORTAGE_GPG_SIGNING_COMMAND is unset! "
3727 - "Is make.globals missing?\n",
3728 - level=logging.ERROR,
3729 - noiselevel=-1,
3730 - )
3731 - sign_problem = True
3732 - elif (
3733 - "${PORTAGE_GPG_KEY}" in gpg_cmd
3734 - and options.gpg_key is None
3735 - and "PORTAGE_GPG_KEY" not in settings
3736 - ):
3737 - writemsg_level(
3738 - "egencache: error: " "PORTAGE_GPG_KEY is unset!\n",
3739 - level=logging.ERROR,
3740 - noiselevel=-1,
3741 - )
3742 - sign_problem = True
3743 - elif "${PORTAGE_GPG_DIR}" in gpg_cmd:
3744 - if options.gpg_dir is not None:
3745 - gpg_dir = options.gpg_dir
3746 - elif "PORTAGE_GPG_DIR" not in settings:
3747 - gpg_dir = os.path.expanduser("~/.gnupg")
3748 - else:
3749 - gpg_dir = os.path.expanduser(settings["PORTAGE_GPG_DIR"])
3750 - if not os.access(gpg_dir, os.X_OK):
3751 + if options.update:
3752 + if options.cache_dir is not None:
3753 + # already validated earlier
3754 + pass
3755 + else:
3756 + # We check write access after the portdbapi constructor
3757 + # has had an opportunity to create it. This ensures that
3758 + # we don't use the cache in the "volatile" mode which is
3759 + # undesirable for egencache.
3760 + if not os.access(settings["PORTAGE_DEPCACHEDIR"], os.W_OK):
3761 writemsg_level(
3762 - (
3763 - "egencache: error: "
3764 - "Unable to access directory: "
3765 - "PORTAGE_GPG_DIR='%s'\n"
3766 - )
3767 - % gpg_dir,
3768 + "ecachegen: error: "
3769 + + "write access denied: {}\n".format(
3770 + settings["PORTAGE_DEPCACHEDIR"]
3771 + ),
3772 level=logging.ERROR,
3773 noiselevel=-1,
3774 )
3775 - sign_problem = True
3776 -
3777 - if sign_problem:
3778 - writemsg_level(
3779 - "egencache: You may disable manifest "
3780 - "signatures with --sign-manifests=n or by setting "
3781 - '"sign-manifests = false" in metadata/layout.conf\n',
3782 - level=logging.ERROR,
3783 - noiselevel=-1,
3784 - )
3785 - return 1
3786 -
3787 - gpg_vars = {}
3788 - if gpg_dir is not None:
3789 - gpg_vars["PORTAGE_GPG_DIR"] = gpg_dir
3790 - gpg_var_names = []
3791 - if options.gpg_key is None:
3792 - gpg_var_names.append("PORTAGE_GPG_KEY")
3793 - else:
3794 - gpg_vars["PORTAGE_GPG_KEY"] = options.gpg_key
3795 + return 1
3796
3797 - for k in gpg_var_names:
3798 - v = settings.get(k)
3799 - if v is not None:
3800 - gpg_vars[k] = v
3801 + if options.sign_manifests is not None:
3802 + repo_config.sign_manifest = options.sign_manifests == "y"
3803
3804 - force_sign_key = gpg_vars.get("PORTAGE_GPG_KEY")
3805 + if options.thin_manifests is not None:
3806 + repo_config.thin_manifest = options.thin_manifests == "y"
3807
3808 - ret = [os.EX_OK]
3809 + gpg_cmd = None
3810 + gpg_vars = None
3811 + force_sign_key = None
3812
3813 - if options.update:
3814 - cp_iter = None
3815 - if atoms:
3816 - cp_iter = iter(atoms)
3817 + if options.update_manifests:
3818 + if repo_config.sign_manifest:
3819
3820 - gen_cache = GenCache(
3821 - portdb,
3822 - cp_iter=cp_iter,
3823 - max_jobs=options.jobs,
3824 - max_load=options.load_average,
3825 - rsync=options.rsync,
3826 - external_cache_only=options.external_cache_only,
3827 - )
3828 - gen_cache.run()
3829 - if options.tolerant:
3830 - ret.append(os.EX_OK)
3831 - else:
3832 - ret.append(gen_cache.returncode)
3833 + sign_problem = False
3834 + gpg_dir = None
3835 + gpg_cmd = settings.get("PORTAGE_GPG_SIGNING_COMMAND")
3836 + if gpg_cmd is None:
3837 + writemsg_level(
3838 + "egencache: error: "
3839 + "PORTAGE_GPG_SIGNING_COMMAND is unset! "
3840 + "Is make.globals missing?\n",
3841 + level=logging.ERROR,
3842 + noiselevel=-1,
3843 + )
3844 + sign_problem = True
3845 + elif (
3846 + "${PORTAGE_GPG_KEY}" in gpg_cmd
3847 + and options.gpg_key is None
3848 + and "PORTAGE_GPG_KEY" not in settings
3849 + ):
3850 + writemsg_level(
3851 + "egencache: error: " "PORTAGE_GPG_KEY is unset!\n",
3852 + level=logging.ERROR,
3853 + noiselevel=-1,
3854 + )
3855 + sign_problem = True
3856 + elif "${PORTAGE_GPG_DIR}" in gpg_cmd:
3857 + if options.gpg_dir is not None:
3858 + gpg_dir = options.gpg_dir
3859 + elif "PORTAGE_GPG_DIR" not in settings:
3860 + gpg_dir = os.path.expanduser("~/.gnupg")
3861 + else:
3862 + gpg_dir = os.path.expanduser(settings["PORTAGE_GPG_DIR"])
3863 + if not os.access(gpg_dir, os.X_OK):
3864 + writemsg_level(
3865 + (
3866 + "egencache: error: "
3867 + "Unable to access directory: "
3868 + "PORTAGE_GPG_DIR='%s'\n"
3869 + )
3870 + % gpg_dir,
3871 + level=logging.ERROR,
3872 + noiselevel=-1,
3873 + )
3874 + sign_problem = True
3875
3876 - if options.update_pkg_desc_index:
3877 - if not options.external_cache_only and repo_config.writable:
3878 - writable_location = repo_config.location
3879 - else:
3880 - writable_location = os.path.join(
3881 - portdb.depcachedir, repo_config.location.lstrip(os.sep)
3882 - )
3883 - if not options.external_cache_only:
3884 - msg = [
3885 - "WARNING: Repository is not writable: {}".format(
3886 - repo_config.location
3887 - ),
3888 - " Using cache directory instead: {}".format(
3889 - writable_location
3890 - ),
3891 - ]
3892 - msg = "".join(line + "\n" for line in msg)
3893 - writemsg_level(msg, level=logging.WARNING, noiselevel=-1)
3894 + if sign_problem:
3895 + writemsg_level(
3896 + "egencache: You may disable manifest "
3897 + "signatures with --sign-manifests=n or by setting "
3898 + '"sign-manifests = false" in metadata/layout.conf\n',
3899 + level=logging.ERROR,
3900 + noiselevel=-1,
3901 + )
3902 + return 1
3903
3904 - gen_index = GenPkgDescIndex(
3905 - repo_config,
3906 - portdb,
3907 - os.path.join(writable_location, "metadata", "pkg_desc_index"),
3908 - verbose=options.verbose,
3909 - )
3910 - gen_index.run()
3911 - ret.append(gen_index.returncode)
3912 + gpg_vars = {}
3913 + if gpg_dir is not None:
3914 + gpg_vars["PORTAGE_GPG_DIR"] = gpg_dir
3915 + gpg_var_names = []
3916 + if options.gpg_key is None:
3917 + gpg_var_names.append("PORTAGE_GPG_KEY")
3918 + else:
3919 + gpg_vars["PORTAGE_GPG_KEY"] = options.gpg_key
3920
3921 - if options.update_use_local_desc:
3922 - gen_desc = GenUseLocalDesc(
3923 - portdb,
3924 - output=options.uld_output,
3925 - preserve_comments=options.preserve_comments,
3926 - )
3927 - gen_desc.run()
3928 - ret.append(gen_desc.returncode)
3929 + for k in gpg_var_names:
3930 + v = settings.get(k)
3931 + if v is not None:
3932 + gpg_vars[k] = v
3933
3934 - if options.update_changelogs:
3935 - gen_clogs = GenChangeLogs(
3936 - portdb,
3937 - changelog_output=options.changelog_output,
3938 - changelog_reversed=options.changelog_reversed,
3939 - max_jobs=options.jobs,
3940 - max_load=options.load_average,
3941 - )
3942 - signum = gen_clogs.run()
3943 - if signum is not None:
3944 - sys.exit(128 + signum)
3945 - ret.append(gen_clogs.returncode)
3946 + force_sign_key = gpg_vars.get("PORTAGE_GPG_KEY")
3947
3948 - if options.update_manifests:
3949 + ret = [os.EX_OK]
3950
3951 - cp_iter = None
3952 - if atoms:
3953 - cp_iter = iter(atoms)
3954 + if options.update:
3955 + cp_iter = None
3956 + if atoms:
3957 + cp_iter = iter(atoms)
3958
3959 - event_loop = global_event_loop()
3960 - scheduler = ManifestScheduler(
3961 - portdb,
3962 - cp_iter=cp_iter,
3963 - gpg_cmd=gpg_cmd,
3964 - gpg_vars=gpg_vars,
3965 - force_sign_key=force_sign_key,
3966 - max_jobs=options.jobs,
3967 - max_load=options.load_average,
3968 - event_loop=event_loop,
3969 - )
3970 + gen_cache = GenCache(
3971 + portdb,
3972 + cp_iter=cp_iter,
3973 + max_jobs=options.jobs,
3974 + max_load=options.load_average,
3975 + rsync=options.rsync,
3976 + external_cache_only=options.external_cache_only,
3977 + )
3978 + gen_cache.run()
3979 + if options.tolerant:
3980 + ret.append(os.EX_OK)
3981 + else:
3982 + ret.append(gen_cache.returncode)
3983
3984 - signum = run_main_scheduler(scheduler)
3985 - if signum is not None:
3986 - sys.exit(128 + signum)
3987 + if options.update_pkg_desc_index:
3988 + if not options.external_cache_only and repo_config.writable:
3989 + writable_location = repo_config.location
3990 + else:
3991 + writable_location = os.path.join(
3992 + portdb.depcachedir, repo_config.location.lstrip(os.sep)
3993 + )
3994 + if not options.external_cache_only:
3995 + msg = [
3996 + "WARNING: Repository is not writable: {}".format(
3997 + repo_config.location
3998 + ),
3999 + " Using cache directory instead: {}".format(
4000 + writable_location
4001 + ),
4002 + ]
4003 + msg = "".join(line + "\n" for line in msg)
4004 + writemsg_level(msg, level=logging.WARNING, noiselevel=-1)
4005 +
4006 + gen_index = GenPkgDescIndex(
4007 + repo_config,
4008 + portdb,
4009 + os.path.join(writable_location, "metadata", "pkg_desc_index"),
4010 + verbose=options.verbose,
4011 + )
4012 + gen_index.run()
4013 + ret.append(gen_index.returncode)
4014 +
4015 + if options.update_use_local_desc:
4016 + gen_desc = GenUseLocalDesc(
4017 + portdb,
4018 + output=options.uld_output,
4019 + preserve_comments=options.preserve_comments,
4020 + )
4021 + gen_desc.run()
4022 + ret.append(gen_desc.returncode)
4023 +
4024 + if options.update_changelogs:
4025 + gen_clogs = GenChangeLogs(
4026 + portdb,
4027 + changelog_output=options.changelog_output,
4028 + changelog_reversed=options.changelog_reversed,
4029 + max_jobs=options.jobs,
4030 + max_load=options.load_average,
4031 + )
4032 + signum = gen_clogs.run()
4033 + if signum is not None:
4034 + sys.exit(128 + signum)
4035 + ret.append(gen_clogs.returncode)
4036 +
4037 + if options.update_manifests:
4038 +
4039 + cp_iter = None
4040 + if atoms:
4041 + cp_iter = iter(atoms)
4042 +
4043 + event_loop = global_event_loop()
4044 + scheduler = ManifestScheduler(
4045 + portdb,
4046 + cp_iter=cp_iter,
4047 + gpg_cmd=gpg_cmd,
4048 + gpg_vars=gpg_vars,
4049 + force_sign_key=force_sign_key,
4050 + max_jobs=options.jobs,
4051 + max_load=options.load_average,
4052 + event_loop=event_loop,
4053 + )
4054
4055 - if options.tolerant:
4056 - ret.append(os.EX_OK)
4057 - else:
4058 - ret.append(scheduler.returncode)
4059 + signum = run_main_scheduler(scheduler)
4060 + if signum is not None:
4061 + sys.exit(128 + signum)
4062
4063 - if options.write_timestamp:
4064 - timestamp_path = os.path.join(repo_path, "metadata", "timestamp.chk")
4065 - try:
4066 - portage.util.write_atomic(
4067 - timestamp_path, time.strftime("%s\n" % TIMESTAMP_FORMAT, time.gmtime())
4068 - )
4069 - except (OSError, portage.exception.PortageException):
4070 - ret.append(os.EX_IOERR)
4071 - else:
4072 - ret.append(os.EX_OK)
4073 + if options.tolerant:
4074 + ret.append(os.EX_OK)
4075 + else:
4076 + ret.append(scheduler.returncode)
4077
4078 - return max(ret)
4079 + if options.write_timestamp:
4080 + timestamp_path = os.path.join(repo_path, "metadata", "timestamp.chk")
4081 + try:
4082 + portage.util.write_atomic(
4083 + timestamp_path,
4084 + time.strftime("%s\n" % TIMESTAMP_FORMAT, time.gmtime()),
4085 + )
4086 + except (OSError, portage.exception.PortageException):
4087 + ret.append(os.EX_IOERR)
4088 + else:
4089 + ret.append(os.EX_OK)
4090
4091 + return max(ret)
4092
4093 -if __name__ == "__main__":
4094 - portage._disable_legacy_globals()
4095 - portage.util.noiselimit = -1
4096 - try:
4097 - sys.exit(egencache_main(sys.argv[1:]))
4098 - finally:
4099 - global_event_loop().close()
4100 + if __name__ == "__main__":
4101 + portage._disable_legacy_globals()
4102 + portage.util.noiselimit = -1
4103 + try:
4104 + sys.exit(egencache_main(sys.argv[1:]))
4105 + finally:
4106 + global_event_loop().close()
4107 +
4108 +except KeyboardInterrupt as e:
4109 + # Prevent traceback on ^C
4110 + signum = getattr(e, "signum", signal.SIGINT)
4111 + signal.signal(signum, signal.SIG_DFL)
4112 + raise_signal(signum)
4113
4114 diff --git a/bin/emaint b/bin/emaint
4115 index 103dc2571..7fb38f5e3 100755
4116 --- a/bin/emaint
4117 +++ b/bin/emaint
4118 @@ -5,46 +5,66 @@
4119 """System health checks and maintenance utilities.
4120 """
4121
4122 -import sys
4123 -import errno
4124 +import os
4125 +import signal
4126 +
4127 +# For compatibility with Python < 3.8
4128 +raise_signal = getattr(
4129 + signal, "raise_signal", lambda signum: os.kill(os.getpid(), signum)
4130 +)
4131 +
4132 +# Inherit from KeyboardInterrupt to avoid a traceback from asyncio.
4133 +class SignalInterrupt(KeyboardInterrupt):
4134 + def __init__(self, signum):
4135 + self.signum = signum
4136 +
4137
4138 -# This block ensures that ^C interrupts are handled quietly.
4139 try:
4140 - import signal
4141
4142 - def exithandler(signum, _frame):
4143 - signal.signal(signal.SIGINT, signal.SIG_IGN)
4144 - signal.signal(signal.SIGTERM, signal.SIG_IGN)
4145 - sys.exit(128 + signum)
4146 + def signal_interrupt(signum, _frame):
4147 + raise SignalInterrupt(signum)
4148
4149 - signal.signal(signal.SIGINT, exithandler)
4150 - signal.signal(signal.SIGTERM, exithandler)
4151 + def debug_signal(_signum, _frame):
4152 + import pdb
4153 +
4154 + pdb.set_trace()
4155 +
4156 + # Prevent "[Errno 32] Broken pipe" exceptions when writing to a pipe.
4157 signal.signal(signal.SIGPIPE, signal.SIG_DFL)
4158 + signal.signal(signal.SIGTERM, signal_interrupt)
4159 + signal.signal(signal.SIGUSR1, debug_signal)
4160
4161 -except KeyboardInterrupt:
4162 - sys.exit(1)
4163 + import sys
4164 + import errno
4165 + from os import path as osp
4166
4167 -from os import path as osp
4168 + if osp.isfile(
4169 + osp.join(
4170 + osp.dirname(osp.dirname(osp.realpath(__file__))), ".portage_not_installed"
4171 + )
4172 + ):
4173 + sys.path.insert(
4174 + 0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "lib")
4175 + )
4176 + import portage
4177
4178 -if osp.isfile(
4179 - osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), ".portage_not_installed")
4180 -):
4181 - sys.path.insert(
4182 - 0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "lib")
4183 - )
4184 -import portage
4185 + portage._internal_caller = True
4186 + from portage.emaint.main import emaint_main
4187 + from portage.util._eventloop.global_event_loop import global_event_loop
4188
4189 -portage._internal_caller = True
4190 -from portage.emaint.main import emaint_main
4191 -from portage.util._eventloop.global_event_loop import global_event_loop
4192 + try:
4193 + emaint_main(sys.argv[1:])
4194 + except OSError as e:
4195 + if e.errno == errno.EACCES:
4196 + print("\nemaint: Need superuser access")
4197 + sys.exit(1)
4198 + else:
4199 + raise
4200 + finally:
4201 + global_event_loop().close()
4202
4203 -try:
4204 - emaint_main(sys.argv[1:])
4205 -except OSError as e:
4206 - if e.errno == errno.EACCES:
4207 - print("\nemaint: Need superuser access")
4208 - sys.exit(1)
4209 - else:
4210 - raise
4211 -finally:
4212 - global_event_loop().close()
4213 +except KeyboardInterrupt as e:
4214 + # Prevent traceback on ^C
4215 + signum = getattr(e, "signum", signal.SIGINT)
4216 + signal.signal(signum, signal.SIG_DFL)
4217 + raise_signal(signum)
4218
4219 diff --git a/bin/emerge b/bin/emerge
4220 index d90a73c34..a16c5039a 100755
4221 --- a/bin/emerge
4222 +++ b/bin/emerge
4223 @@ -2,31 +2,35 @@
4224 # Copyright 2006-2022 Gentoo Authors
4225 # Distributed under the terms of the GNU General Public License v2
4226
4227 +import os
4228 import signal
4229 import sys
4230
4231 -# This block ensures that ^C interrupts are handled quietly. We handle
4232 -# KeyboardInterrupt instead of installing a SIGINT handler, since
4233 -# exiting from signal handlers intermittently causes python to ignore
4234 -# the SystemExit exception with a message like this:
4235 -# Exception SystemExit: 130 in <function remove at 0x7fd2146c1320> ignored
4236 +# For compatibility with Python < 3.8
4237 +raise_signal = getattr(
4238 + signal, "raise_signal", lambda signum: os.kill(os.getpid(), signum)
4239 +)
4240 +
4241 +# Inherit from KeyboardInterrupt to avoid a traceback from asyncio.
4242 +class SignalInterrupt(KeyboardInterrupt):
4243 + def __init__(self, signum):
4244 + self.signum = signum
4245 +
4246 +
4247 global_event_loop = None
4248 try:
4249
4250 - def exithandler(signum, _frame):
4251 - signal.signal(signal.SIGTERM, signal.SIG_IGN)
4252 - sys.exit(128 + signum)
4253 -
4254 - signal.signal(signal.SIGTERM, exithandler)
4255 - # Prevent "[Errno 32] Broken pipe" exceptions when
4256 - # writing to a pipe.
4257 - signal.signal(signal.SIGPIPE, signal.SIG_DFL)
4258 + def signal_interrupt(signum, _frame):
4259 + raise SignalInterrupt(signum)
4260
4261 def debug_signal(_signum, _frame):
4262 import pdb
4263
4264 pdb.set_trace()
4265
4266 + # Prevent "[Errno 32] Broken pipe" exceptions when writing to a pipe.
4267 + signal.signal(signal.SIGPIPE, signal.SIG_DFL)
4268 + signal.signal(signal.SIGTERM, signal_interrupt)
4269 signal.signal(signal.SIGUSR1, debug_signal)
4270
4271 from os import path as osp
4272 @@ -79,10 +83,17 @@ try:
4273 sys.exit(1)
4274 sys.exit(retval)
4275
4276 -except KeyboardInterrupt:
4277 - sys.stderr.write("\n\nExiting on signal {signal}\n".format(signal=signal.SIGINT))
4278 +except KeyboardInterrupt as e:
4279 + # This block ensures that ^C interrupts are handled quietly. We handle
4280 + # KeyboardInterrupt instead of installing a SIGINT handler, since
4281 + # exiting from signal handlers intermittently causes python to ignore
4282 + # the SystemExit exception with a message like this:
4283 + # Exception SystemExit: 130 in <function remove at 0x7fd2146c1320> ignored
4284 + signum = getattr(e, "signum", signal.SIGINT)
4285 + signal.signal(signum, signal.SIG_DFL)
4286 + sys.stderr.write(f"\n\nExiting on signal {signum}\n")
4287 sys.stderr.flush()
4288 - sys.exit(128 + signal.SIGINT)
4289 + raise_signal(signum)
4290 finally:
4291 if global_event_loop is not None:
4292 global_event_loop().close()
4293
4294 diff --git a/bin/portageq b/bin/portageq
4295 index dca249a7b..20a2f6646 100755
4296 --- a/bin/portageq
4297 +++ b/bin/portageq
4298 @@ -2,1644 +2,1584 @@
4299 # Copyright 1999-2021 Gentoo Authors
4300 # Distributed under the terms of the GNU General Public License v2
4301
4302 -import argparse
4303 +import os
4304 import signal
4305 -import sys
4306
4307 -# This block ensures that ^C interrupts are handled quietly.
4308 +# For compatibility with Python < 3.8
4309 +raise_signal = getattr(
4310 + signal, "raise_signal", lambda signum: os.kill(os.getpid(), signum)
4311 +)
4312 +
4313 +# Inherit from KeyboardInterrupt to avoid a traceback from asyncio.
4314 +class SignalInterrupt(KeyboardInterrupt):
4315 + def __init__(self, signum):
4316 + self.signum = signum
4317 +
4318 +
4319 try:
4320
4321 - def exithandler(signum, _frame):
4322 - signal.signal(signal.SIGINT, signal.SIG_IGN)
4323 - signal.signal(signal.SIGTERM, signal.SIG_IGN)
4324 - sys.exit(128 + signum)
4325 + def signal_interrupt(signum, _frame):
4326 + raise SignalInterrupt(signum)
4327
4328 - signal.signal(signal.SIGINT, exithandler)
4329 - signal.signal(signal.SIGTERM, exithandler)
4330 + def debug_signal(_signum, _frame):
4331 + import pdb
4332
4333 -except KeyboardInterrupt:
4334 - sys.exit(128 + signal.SIGINT)
4335 + pdb.set_trace()
4336
4337 -import os
4338 -import types
4339 + # Prevent "[Errno 32] Broken pipe" exceptions when writing to a pipe.
4340 + signal.signal(signal.SIGPIPE, signal.SIG_DFL)
4341 + signal.signal(signal.SIGTERM, signal_interrupt)
4342 + signal.signal(signal.SIGUSR1, debug_signal)
4343
4344 -if os.path.isfile(
4345 - os.path.join(
4346 - os.path.dirname(os.path.dirname(os.path.realpath(__file__))),
4347 - ".portage_not_installed",
4348 - )
4349 -):
4350 - pym_paths = [
4351 + import argparse
4352 + import sys
4353 + import types
4354 +
4355 + if os.path.isfile(
4356 os.path.join(
4357 - os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "lib"
4358 + os.path.dirname(os.path.dirname(os.path.realpath(__file__))),
4359 + ".portage_not_installed",
4360 )
4361 - ]
4362 - sys.path.insert(0, pym_paths[0])
4363 -else:
4364 - import sysconfig
4365 -
4366 - pym_paths = [
4367 - os.path.join(sysconfig.get_path("purelib"), x) for x in ("_emerge", "portage")
4368 - ]
4369 -# Avoid sandbox violations after Python upgrade.
4370 -if os.environ.get("SANDBOX_ON") == "1":
4371 - sandbox_write = os.environ.get("SANDBOX_WRITE", "").split(":")
4372 - for pym_path in pym_paths:
4373 - if pym_path not in sandbox_write:
4374 - sandbox_write.append(pym_path)
4375 - os.environ["SANDBOX_WRITE"] = ":".join(filter(None, sandbox_write))
4376 - del pym_path, sandbox_write
4377 -del pym_paths
4378 -
4379 -import portage
4380 -
4381 -portage._internal_caller = True
4382 -from portage import os
4383 -from portage.eapi import eapi_has_repo_deps
4384 -from portage.util import writemsg, writemsg_stdout
4385 -
4386 -portage.proxy.lazyimport.lazyimport(
4387 - globals(),
4388 - "re",
4389 - "subprocess",
4390 - "_emerge.Package:Package",
4391 - "_emerge.RootConfig:RootConfig",
4392 - "_emerge.is_valid_package_atom:insert_category_into_atom",
4393 - "portage.dbapi._expand_new_virt:expand_new_virt",
4394 - "portage._sets.base:InternalPackageSet",
4395 - "portage.util._eventloop.global_event_loop:global_event_loop",
4396 - "portage.xml.metadata:MetaDataXML",
4397 -)
4398 + ):
4399 + pym_paths = [
4400 + os.path.join(
4401 + os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "lib"
4402 + )
4403 + ]
4404 + sys.path.insert(0, pym_paths[0])
4405 + else:
4406 + import sysconfig
4407 +
4408 + pym_paths = [
4409 + os.path.join(sysconfig.get_path("purelib"), x)
4410 + for x in ("_emerge", "portage")
4411 + ]
4412 + # Avoid sandbox violations after Python upgrade.
4413 + if os.environ.get("SANDBOX_ON") == "1":
4414 + sandbox_write = os.environ.get("SANDBOX_WRITE", "").split(":")
4415 + for pym_path in pym_paths:
4416 + if pym_path not in sandbox_write:
4417 + sandbox_write.append(pym_path)
4418 + os.environ["SANDBOX_WRITE"] = ":".join(filter(None, sandbox_write))
4419 + del pym_path, sandbox_write
4420 + del pym_paths
4421 +
4422 + import portage
4423 +
4424 + portage._internal_caller = True
4425 + from portage import os
4426 + from portage.eapi import eapi_has_repo_deps
4427 + from portage.util import writemsg, writemsg_stdout
4428 +
4429 + portage.proxy.lazyimport.lazyimport(
4430 + globals(),
4431 + "re",
4432 + "subprocess",
4433 + "_emerge.Package:Package",
4434 + "_emerge.RootConfig:RootConfig",
4435 + "_emerge.is_valid_package_atom:insert_category_into_atom",
4436 + "portage.dbapi._expand_new_virt:expand_new_virt",
4437 + "portage._sets.base:InternalPackageSet",
4438 + "portage.util._eventloop.global_event_loop:global_event_loop",
4439 + "portage.xml.metadata:MetaDataXML",
4440 + )
4441
4442 + def eval_atom_use(atom):
4443 + if "USE" in os.environ:
4444 + use = frozenset(os.environ["USE"].split())
4445 + atom = atom.evaluate_conditionals(use)
4446 + return atom
4447
4448 -def eval_atom_use(atom):
4449 - if "USE" in os.environ:
4450 - use = frozenset(os.environ["USE"].split())
4451 - atom = atom.evaluate_conditionals(use)
4452 - return atom
4453 -
4454 -
4455 -def uses_configroot(function):
4456 - function.uses_configroot = True
4457 - return function
4458 -
4459 -
4460 -def uses_eroot(function):
4461 - function.uses_eroot = True
4462 - return function
4463 -
4464 -
4465 -# global to hold all function docstrings to be used for argparse help.
4466 -# Avoids python compilation level 2 optimization troubles.
4467 -docstrings = {}
4468 -
4469 -# -----------------------------------------------------------------------------
4470 -#
4471 -# To add functionality to this tool, add a function below.
4472 -#
4473 -# The format for functions is:
4474 -#
4475 -# def function(argv):
4476 -# <code>
4477 -#
4478 -# docstrings['function'] = """<list of options for this function>
4479 -# <description of the function>
4480 -# """
4481 -# function.__doc__ = docstrings['function']
4482 -#
4483 -# "argv" is an array of the command line parameters provided after the command.
4484 -#
4485 -# Make sure you document the function in the right format. The documentation
4486 -# is used to display help on the function.
4487 -#
4488 -# You do not need to add the function to any lists, this tool is introspective,
4489 -# and will automaticly add a command by the same name as the function!
4490 -#
4491 -
4492 -
4493 -@uses_eroot
4494 -def has_version(argv):
4495 - if len(argv) < 2:
4496 - print("ERROR: insufficient parameters!")
4497 - return 3
4498 -
4499 - warnings = []
4500 -
4501 - allow_repo = atom_validate_strict is False or eapi_has_repo_deps(eapi)
4502 - try:
4503 - atom = portage.dep.Atom(argv[1], allow_repo=allow_repo)
4504 - except portage.exception.InvalidAtom:
4505 - if atom_validate_strict:
4506 - portage.writemsg("ERROR: Invalid atom: '%s'\n" % argv[1], noiselevel=-1)
4507 - return 2
4508 - else:
4509 - atom = argv[1]
4510 - else:
4511 - if atom_validate_strict:
4512 - try:
4513 - atom = portage.dep.Atom(argv[1], allow_repo=allow_repo, eapi=eapi)
4514 - except portage.exception.InvalidAtom as e:
4515 - warnings.append("QA Notice: {}: {}".format("has_version", e))
4516 - atom = eval_atom_use(atom)
4517 + def uses_configroot(function):
4518 + function.uses_configroot = True
4519 + return function
4520
4521 - if warnings:
4522 - elog("eqawarn", warnings)
4523 + def uses_eroot(function):
4524 + function.uses_eroot = True
4525 + return function
4526
4527 - try:
4528 - mylist = portage.db[argv[0]]["vartree"].dbapi.match(atom)
4529 - if mylist:
4530 - return 0
4531 - else:
4532 - return 1
4533 - except KeyError:
4534 - return 1
4535 - except portage.exception.InvalidAtom:
4536 - portage.writemsg("ERROR: Invalid atom: '%s'\n" % argv[1], noiselevel=-1)
4537 - return 2
4538 + # global to hold all function docstrings to be used for argparse help.
4539 + # Avoids python compilation level 2 optimization troubles.
4540 + docstrings = {}
4541
4542 + # -----------------------------------------------------------------------------
4543 + #
4544 + # To add functionality to this tool, add a function below.
4545 + #
4546 + # The format for functions is:
4547 + #
4548 + # def function(argv):
4549 + # <code>
4550 + #
4551 + # docstrings['function'] = """<list of options for this function>
4552 + # <description of the function>
4553 + # """
4554 + # function.__doc__ = docstrings['function']
4555 + #
4556 + # "argv" is an array of the command line parameters provided after the command.
4557 + #
4558 + # Make sure you document the function in the right format. The documentation
4559 + # is used to display help on the function.
4560 + #
4561 + # You do not need to add the function to any lists, this tool is introspective,
4562 + # and will automaticly add a command by the same name as the function!
4563 + #
4564
4565 -docstrings[
4566 - "has_version"
4567 -] = """<eroot> <category/package>
4568 - Return code 0 if it's available, 1 otherwise.
4569 - """
4570 -has_version.__doc__ = docstrings["has_version"]
4571 + @uses_eroot
4572 + def has_version(argv):
4573 + if len(argv) < 2:
4574 + print("ERROR: insufficient parameters!")
4575 + return 3
4576
4577 + warnings = []
4578
4579 -@uses_eroot
4580 -def best_version(argv):
4581 - if len(argv) < 2:
4582 - print("ERROR: insufficient parameters!")
4583 - return 3
4584 + allow_repo = atom_validate_strict is False or eapi_has_repo_deps(eapi)
4585 + try:
4586 + atom = portage.dep.Atom(argv[1], allow_repo=allow_repo)
4587 + except portage.exception.InvalidAtom:
4588 + if atom_validate_strict:
4589 + portage.writemsg("ERROR: Invalid atom: '%s'\n" % argv[1], noiselevel=-1)
4590 + return 2
4591 + else:
4592 + atom = argv[1]
4593 + else:
4594 + if atom_validate_strict:
4595 + try:
4596 + atom = portage.dep.Atom(argv[1], allow_repo=allow_repo, eapi=eapi)
4597 + except portage.exception.InvalidAtom as e:
4598 + warnings.append("QA Notice: {}: {}".format("has_version", e))
4599 + atom = eval_atom_use(atom)
4600
4601 - warnings = []
4602 + if warnings:
4603 + elog("eqawarn", warnings)
4604
4605 - allow_repo = atom_validate_strict is False or eapi_has_repo_deps(eapi)
4606 - try:
4607 - atom = portage.dep.Atom(argv[1], allow_repo=allow_repo)
4608 - except portage.exception.InvalidAtom:
4609 - if atom_validate_strict:
4610 + try:
4611 + mylist = portage.db[argv[0]]["vartree"].dbapi.match(atom)
4612 + if mylist:
4613 + return 0
4614 + else:
4615 + return 1
4616 + except KeyError:
4617 + return 1
4618 + except portage.exception.InvalidAtom:
4619 portage.writemsg("ERROR: Invalid atom: '%s'\n" % argv[1], noiselevel=-1)
4620 return 2
4621 - else:
4622 - atom = argv[1]
4623 - else:
4624 - if atom_validate_strict:
4625 - try:
4626 - atom = portage.dep.Atom(argv[1], allow_repo=allow_repo, eapi=eapi)
4627 - except portage.exception.InvalidAtom as e:
4628 - warnings.append("QA Notice: {}: {}".format("best_version", e))
4629 - atom = eval_atom_use(atom)
4630 -
4631 - if warnings:
4632 - elog("eqawarn", warnings)
4633 -
4634 - try:
4635 - mylist = portage.db[argv[0]]["vartree"].dbapi.match(atom)
4636 - print(portage.best(mylist))
4637 - except KeyError:
4638 - return 1
4639
4640 + docstrings[
4641 + "has_version"
4642 + ] = """<eroot> <category/package>
4643 + Return code 0 if it's available, 1 otherwise.
4644 + """
4645 + has_version.__doc__ = docstrings["has_version"]
4646
4647 -docstrings[
4648 - "best_version"
4649 -] = """<eroot> <category/package>
4650 - Returns highest installed matching category/package-version (without .ebuild).
4651 - """
4652 -best_version.__doc__ = docstrings["best_version"]
4653 -
4654 -
4655 -@uses_eroot
4656 -def mass_best_version(argv):
4657 - if len(argv) < 2:
4658 - print("ERROR: insufficient parameters!")
4659 - return 2
4660 - try:
4661 - for pack in argv[1:]:
4662 - mylist = portage.db[argv[0]]["vartree"].dbapi.match(pack)
4663 - print("{}:{}".format(pack, portage.best(mylist)))
4664 - except KeyError:
4665 - return 1
4666 + @uses_eroot
4667 + def best_version(argv):
4668 + if len(argv) < 2:
4669 + print("ERROR: insufficient parameters!")
4670 + return 3
4671 +
4672 + warnings = []
4673
4674 + allow_repo = atom_validate_strict is False or eapi_has_repo_deps(eapi)
4675 + try:
4676 + atom = portage.dep.Atom(argv[1], allow_repo=allow_repo)
4677 + except portage.exception.InvalidAtom:
4678 + if atom_validate_strict:
4679 + portage.writemsg("ERROR: Invalid atom: '%s'\n" % argv[1], noiselevel=-1)
4680 + return 2
4681 + else:
4682 + atom = argv[1]
4683 + else:
4684 + if atom_validate_strict:
4685 + try:
4686 + atom = portage.dep.Atom(argv[1], allow_repo=allow_repo, eapi=eapi)
4687 + except portage.exception.InvalidAtom as e:
4688 + warnings.append("QA Notice: {}: {}".format("best_version", e))
4689 + atom = eval_atom_use(atom)
4690
4691 -docstrings[
4692 - "mass_best_version"
4693 -] = """<eroot> [<category/package>]+
4694 - Returns category/package-version (without .ebuild).
4695 - """
4696 -mass_best_version.__doc__ = docstrings["mass_best_version"]
4697 + if warnings:
4698 + elog("eqawarn", warnings)
4699
4700 + try:
4701 + mylist = portage.db[argv[0]]["vartree"].dbapi.match(atom)
4702 + print(portage.best(mylist))
4703 + except KeyError:
4704 + return 1
4705
4706 -@uses_eroot
4707 -def metadata(argv):
4708 - if len(argv) < 4:
4709 - print("ERROR: insufficient parameters!", file=sys.stderr)
4710 - return 2
4711 + docstrings[
4712 + "best_version"
4713 + ] = """<eroot> <category/package>
4714 + Returns highest installed matching category/package-version (without .ebuild).
4715 + """
4716 + best_version.__doc__ = docstrings["best_version"]
4717 +
4718 + @uses_eroot
4719 + def mass_best_version(argv):
4720 + if len(argv) < 2:
4721 + print("ERROR: insufficient parameters!")
4722 + return 2
4723 + try:
4724 + for pack in argv[1:]:
4725 + mylist = portage.db[argv[0]]["vartree"].dbapi.match(pack)
4726 + print("{}:{}".format(pack, portage.best(mylist)))
4727 + except KeyError:
4728 + return 1
4729
4730 - eroot, pkgtype, pkgspec = argv[0:3]
4731 - metakeys = argv[3:]
4732 - type_map = {"ebuild": "porttree", "binary": "bintree", "installed": "vartree"}
4733 - if pkgtype not in type_map:
4734 - print("Unrecognized package type: '%s'" % pkgtype, file=sys.stderr)
4735 - return 1
4736 - trees = portage.db
4737 - repo = portage.dep.dep_getrepo(pkgspec)
4738 - pkgspec = portage.dep.remove_slot(pkgspec)
4739 - try:
4740 - values = trees[eroot][type_map[pkgtype]].dbapi.aux_get(
4741 - pkgspec, metakeys, myrepo=repo
4742 - )
4743 - writemsg_stdout("".join("%s\n" % x for x in values), noiselevel=-1)
4744 - except KeyError:
4745 - print("Package not found: '%s'" % pkgspec, file=sys.stderr)
4746 - return 1
4747 + docstrings[
4748 + "mass_best_version"
4749 + ] = """<eroot> [<category/package>]+
4750 + Returns category/package-version (without .ebuild).
4751 + """
4752 + mass_best_version.__doc__ = docstrings["mass_best_version"]
4753 +
4754 + @uses_eroot
4755 + def metadata(argv):
4756 + if len(argv) < 4:
4757 + print("ERROR: insufficient parameters!", file=sys.stderr)
4758 + return 2
4759
4760 + eroot, pkgtype, pkgspec = argv[0:3]
4761 + metakeys = argv[3:]
4762 + type_map = {"ebuild": "porttree", "binary": "bintree", "installed": "vartree"}
4763 + if pkgtype not in type_map:
4764 + print("Unrecognized package type: '%s'" % pkgtype, file=sys.stderr)
4765 + return 1
4766 + trees = portage.db
4767 + repo = portage.dep.dep_getrepo(pkgspec)
4768 + pkgspec = portage.dep.remove_slot(pkgspec)
4769 + try:
4770 + values = trees[eroot][type_map[pkgtype]].dbapi.aux_get(
4771 + pkgspec, metakeys, myrepo=repo
4772 + )
4773 + writemsg_stdout("".join("%s\n" % x for x in values), noiselevel=-1)
4774 + except KeyError:
4775 + print("Package not found: '%s'" % pkgspec, file=sys.stderr)
4776 + return 1
4777
4778 -docstrings[
4779 - "metadata"
4780 -] = """
4781 -<eroot> <pkgtype> <category/package> [<key>]+
4782 -Returns metadata values for the specified package.
4783 -Available keys: %s
4784 -""" % ",".join(
4785 - sorted(x for x in portage.auxdbkeys)
4786 -)
4787 -metadata.__doc__ = docstrings["metadata"]
4788 + docstrings[
4789 + "metadata"
4790 + ] = """
4791 + <eroot> <pkgtype> <category/package> [<key>]+
4792 + Returns metadata values for the specified package.
4793 + Available keys: %s
4794 + """ % ",".join(
4795 + sorted(x for x in portage.auxdbkeys)
4796 + )
4797 + metadata.__doc__ = docstrings["metadata"]
4798
4799 + @uses_eroot
4800 + def contents(argv):
4801 + if len(argv) != 2:
4802 + print("ERROR: expected 2 parameters, got %d!" % len(argv))
4803 + return 2
4804
4805 -@uses_eroot
4806 -def contents(argv):
4807 - if len(argv) != 2:
4808 - print("ERROR: expected 2 parameters, got %d!" % len(argv))
4809 - return 2
4810 + root, cpv = argv
4811 + vartree = portage.db[root]["vartree"]
4812 + if not vartree.dbapi.cpv_exists(cpv):
4813 + sys.stderr.write("Package not found: '%s'\n" % cpv)
4814 + return 1
4815 + cat, pkg = portage.catsplit(cpv)
4816 + db = portage.dblink(
4817 + cat, pkg, root, vartree.settings, treetype="vartree", vartree=vartree
4818 + )
4819 + writemsg_stdout(
4820 + "".join("%s\n" % x for x in sorted(db.getcontents())), noiselevel=-1
4821 + )
4822
4823 - root, cpv = argv
4824 - vartree = portage.db[root]["vartree"]
4825 - if not vartree.dbapi.cpv_exists(cpv):
4826 - sys.stderr.write("Package not found: '%s'\n" % cpv)
4827 - return 1
4828 - cat, pkg = portage.catsplit(cpv)
4829 - db = portage.dblink(
4830 - cat, pkg, root, vartree.settings, treetype="vartree", vartree=vartree
4831 - )
4832 - writemsg_stdout(
4833 - "".join("%s\n" % x for x in sorted(db.getcontents())), noiselevel=-1
4834 - )
4835 + docstrings[
4836 + "contents"
4837 + ] = """<eroot> <category/package>
4838 + List the files that are installed for a given package, with
4839 + one file listed on each line. All file names will begin with
4840 + <eroot>.
4841 + """
4842 + contents.__doc__ = docstrings["contents"]
4843 +
4844 + @uses_eroot
4845 + def owners(argv):
4846 + if len(argv) < 2:
4847 + sys.stderr.write("ERROR: insufficient parameters!\n")
4848 + sys.stderr.flush()
4849 + return 2
4850
4851 + eroot = argv[0]
4852 + vardb = portage.db[eroot]["vartree"].dbapi
4853 + root = portage.settings["ROOT"]
4854
4855 -docstrings[
4856 - "contents"
4857 -] = """<eroot> <category/package>
4858 - List the files that are installed for a given package, with
4859 - one file listed on each line. All file names will begin with
4860 - <eroot>.
4861 - """
4862 -contents.__doc__ = docstrings["contents"]
4863 -
4864 -
4865 -@uses_eroot
4866 -def owners(argv):
4867 - if len(argv) < 2:
4868 - sys.stderr.write("ERROR: insufficient parameters!\n")
4869 - sys.stderr.flush()
4870 - return 2
4871 -
4872 - eroot = argv[0]
4873 - vardb = portage.db[eroot]["vartree"].dbapi
4874 - root = portage.settings["ROOT"]
4875 -
4876 - cwd = None
4877 - try:
4878 - cwd = os.getcwd()
4879 - except OSError:
4880 - pass
4881 -
4882 - files = []
4883 - orphan_abs_paths = set()
4884 - orphan_basenames = set()
4885 - for f in argv[1:]:
4886 - f = portage.normalize_path(f)
4887 - is_basename = os.sep not in f
4888 - if not is_basename and f[:1] != os.sep:
4889 - if cwd is None:
4890 - sys.stderr.write("ERROR: cwd does not exist!\n")
4891 + cwd = None
4892 + try:
4893 + cwd = os.getcwd()
4894 + except OSError:
4895 + pass
4896 +
4897 + files = []
4898 + orphan_abs_paths = set()
4899 + orphan_basenames = set()
4900 + for f in argv[1:]:
4901 + f = portage.normalize_path(f)
4902 + is_basename = os.sep not in f
4903 + if not is_basename and f[:1] != os.sep:
4904 + if cwd is None:
4905 + sys.stderr.write("ERROR: cwd does not exist!\n")
4906 + sys.stderr.flush()
4907 + return 2
4908 + f = os.path.join(cwd, f)
4909 + f = portage.normalize_path(f)
4910 + if not is_basename and not f.startswith(eroot):
4911 + sys.stderr.write("ERROR: file paths must begin with <eroot>!\n")
4912 sys.stderr.flush()
4913 return 2
4914 - f = os.path.join(cwd, f)
4915 - f = portage.normalize_path(f)
4916 - if not is_basename and not f.startswith(eroot):
4917 - sys.stderr.write("ERROR: file paths must begin with <eroot>!\n")
4918 - sys.stderr.flush()
4919 - return 2
4920 - if is_basename:
4921 - files.append(f)
4922 - orphan_basenames.add(f)
4923 - else:
4924 - files.append(f[len(root) - 1 :])
4925 - orphan_abs_paths.add(f)
4926 -
4927 - owners = vardb._owners.get_owners(files)
4928 -
4929 - msg = []
4930 - for pkg, owned_files in owners.items():
4931 - cpv = pkg.mycpv
4932 - msg.append("%s\n" % cpv)
4933 - for f in sorted(owned_files):
4934 - f_abs = os.path.join(root, f.lstrip(os.path.sep))
4935 - msg.append("\t{}\n".format(f_abs))
4936 - orphan_abs_paths.discard(f_abs)
4937 - if orphan_basenames:
4938 - orphan_basenames.discard(os.path.basename(f_abs))
4939 -
4940 - writemsg_stdout("".join(msg), noiselevel=-1)
4941 -
4942 - if orphan_abs_paths or orphan_basenames:
4943 - orphans = []
4944 - orphans.extend(orphan_abs_paths)
4945 - orphans.extend(orphan_basenames)
4946 - orphans.sort()
4947 + if is_basename:
4948 + files.append(f)
4949 + orphan_basenames.add(f)
4950 + else:
4951 + files.append(f[len(root) - 1 :])
4952 + orphan_abs_paths.add(f)
4953 +
4954 + owners = vardb._owners.get_owners(files)
4955 +
4956 msg = []
4957 - msg.append("None of the installed packages claim these files:\n")
4958 - for f in orphans:
4959 - msg.append("\t{}\n".format(f))
4960 - sys.stderr.write("".join(msg))
4961 - sys.stderr.flush()
4962 + for pkg, owned_files in owners.items():
4963 + cpv = pkg.mycpv
4964 + msg.append("%s\n" % cpv)
4965 + for f in sorted(owned_files):
4966 + f_abs = os.path.join(root, f.lstrip(os.path.sep))
4967 + msg.append("\t{}\n".format(f_abs))
4968 + orphan_abs_paths.discard(f_abs)
4969 + if orphan_basenames:
4970 + orphan_basenames.discard(os.path.basename(f_abs))
4971 +
4972 + writemsg_stdout("".join(msg), noiselevel=-1)
4973 +
4974 + if orphan_abs_paths or orphan_basenames:
4975 + orphans = []
4976 + orphans.extend(orphan_abs_paths)
4977 + orphans.extend(orphan_basenames)
4978 + orphans.sort()
4979 + msg = []
4980 + msg.append("None of the installed packages claim these files:\n")
4981 + for f in orphans:
4982 + msg.append("\t{}\n".format(f))
4983 + sys.stderr.write("".join(msg))
4984 + sys.stderr.flush()
4985
4986 - if owners:
4987 - return 0
4988 - return 1
4989 -
4990 -
4991 -docstrings[
4992 - "owners"
4993 -] = """<eroot> [<filename>]+
4994 - Given a list of files, print the packages that own the files and which
4995 - files belong to each package. Files owned by a package are listed on
4996 - the lines below it, indented by a single tab character (\\t). All file
4997 - paths must either start with <eroot> or be a basename alone.
4998 - Returns 1 if no owners could be found, and 0 otherwise.
4999 - """
5000 -owners.__doc__ = docstrings["owners"]
5001 -
5002 -
5003 -@uses_eroot
5004 -def is_protected(argv):
5005 - if len(argv) != 2:
5006 - sys.stderr.write("ERROR: expected 2 parameters, got %d!\n" % len(argv))
5007 - sys.stderr.flush()
5008 - return 2
5009 -
5010 - root, filename = argv
5011 -
5012 - err = sys.stderr
5013 - cwd = None
5014 - try:
5015 - cwd = os.getcwd()
5016 - except OSError:
5017 - pass
5018 -
5019 - f = portage.normalize_path(filename)
5020 - if not f.startswith(os.path.sep):
5021 - if cwd is None:
5022 - err.write("ERROR: cwd does not exist!\n")
5023 - err.flush()
5024 + if owners:
5025 + return 0
5026 + return 1
5027 +
5028 + docstrings[
5029 + "owners"
5030 + ] = """<eroot> [<filename>]+
5031 + Given a list of files, print the packages that own the files and which
5032 + files belong to each package. Files owned by a package are listed on
5033 + the lines below it, indented by a single tab character (\\t). All file
5034 + paths must either start with <eroot> or be a basename alone.
5035 + Returns 1 if no owners could be found, and 0 otherwise.
5036 + """
5037 + owners.__doc__ = docstrings["owners"]
5038 +
5039 + @uses_eroot
5040 + def is_protected(argv):
5041 + if len(argv) != 2:
5042 + sys.stderr.write("ERROR: expected 2 parameters, got %d!\n" % len(argv))
5043 + sys.stderr.flush()
5044 return 2
5045 - f = os.path.join(cwd, f)
5046 - f = portage.normalize_path(f)
5047 -
5048 - if not f.startswith(root):
5049 - err.write("ERROR: file paths must begin with <eroot>!\n")
5050 - err.flush()
5051 - return 2
5052 -
5053 - from portage.util import ConfigProtect
5054 -
5055 - settings = portage.settings
5056 - protect = portage.util.shlex_split(settings.get("CONFIG_PROTECT", ""))
5057 - protect_mask = portage.util.shlex_split(settings.get("CONFIG_PROTECT_MASK", ""))
5058 - protect_obj = ConfigProtect(
5059 - root,
5060 - protect,
5061 - protect_mask,
5062 - case_insensitive=("case-insensitive-fs" in settings.features),
5063 - )
5064 - if protect_obj.isprotected(f):
5065 - return 0
5066 - return 1
5067 -
5068 -
5069 -docstrings[
5070 - "is_protected"
5071 -] = """<eroot> <filename>
5072 - Given a single filename, return code 0 if it's protected, 1 otherwise.
5073 - The filename must begin with <eroot>.
5074 - """
5075 -is_protected.__doc__ = docstrings["is_protected"]
5076 -
5077 -
5078 -@uses_eroot
5079 -def filter_protected(argv):
5080 - if len(argv) != 1:
5081 - sys.stderr.write("ERROR: expected 1 parameter, got %d!\n" % len(argv))
5082 - sys.stderr.flush()
5083 - return 2
5084 -
5085 - (root,) = argv
5086 - out = sys.stdout
5087 - err = sys.stderr
5088 - cwd = None
5089 - try:
5090 - cwd = os.getcwd()
5091 - except OSError:
5092 - pass
5093 -
5094 - from portage.util import ConfigProtect
5095 -
5096 - settings = portage.settings
5097 - protect = portage.util.shlex_split(settings.get("CONFIG_PROTECT", ""))
5098 - protect_mask = portage.util.shlex_split(settings.get("CONFIG_PROTECT_MASK", ""))
5099 - protect_obj = ConfigProtect(
5100 - root,
5101 - protect,
5102 - protect_mask,
5103 - case_insensitive=("case-insensitive-fs" in settings.features),
5104 - )
5105
5106 - errors = 0
5107 + root, filename = argv
5108 +
5109 + err = sys.stderr
5110 + cwd = None
5111 + try:
5112 + cwd = os.getcwd()
5113 + except OSError:
5114 + pass
5115
5116 - for line in sys.stdin:
5117 - filename = line.rstrip("\n")
5118 f = portage.normalize_path(filename)
5119 if not f.startswith(os.path.sep):
5120 if cwd is None:
5121 err.write("ERROR: cwd does not exist!\n")
5122 err.flush()
5123 - errors += 1
5124 - continue
5125 + return 2
5126 f = os.path.join(cwd, f)
5127 f = portage.normalize_path(f)
5128
5129 if not f.startswith(root):
5130 err.write("ERROR: file paths must begin with <eroot>!\n")
5131 err.flush()
5132 - errors += 1
5133 - continue
5134 -
5135 - if protect_obj.isprotected(f):
5136 - out.write("%s\n" % filename)
5137 - out.flush()
5138 -
5139 - if errors:
5140 - return 2
5141 + return 2
5142
5143 - return 0
5144 + from portage.util import ConfigProtect
5145
5146 + settings = portage.settings
5147 + protect = portage.util.shlex_split(settings.get("CONFIG_PROTECT", ""))
5148 + protect_mask = portage.util.shlex_split(settings.get("CONFIG_PROTECT_MASK", ""))
5149 + protect_obj = ConfigProtect(
5150 + root,
5151 + protect,
5152 + protect_mask,
5153 + case_insensitive=("case-insensitive-fs" in settings.features),
5154 + )
5155 + if protect_obj.isprotected(f):
5156 + return 0
5157 + return 1
5158
5159 -docstrings[
5160 - "filter_protected"
5161 -] = """<eroot>
5162 - Read filenames from stdin and write them to stdout if they are protected.
5163 - All filenames are delimited by \\n and must begin with <eroot>.
5164 - """
5165 -filter_protected.__doc__ = docstrings["filter_protected"]
5166 + docstrings[
5167 + "is_protected"
5168 + ] = """<eroot> <filename>
5169 + Given a single filename, return code 0 if it's protected, 1 otherwise.
5170 + The filename must begin with <eroot>.
5171 + """
5172 + is_protected.__doc__ = docstrings["is_protected"]
5173 +
5174 + @uses_eroot
5175 + def filter_protected(argv):
5176 + if len(argv) != 1:
5177 + sys.stderr.write("ERROR: expected 1 parameter, got %d!\n" % len(argv))
5178 + sys.stderr.flush()
5179 + return 2
5180
5181 + (root,) = argv
5182 + out = sys.stdout
5183 + err = sys.stderr
5184 + cwd = None
5185 + try:
5186 + cwd = os.getcwd()
5187 + except OSError:
5188 + pass
5189 +
5190 + from portage.util import ConfigProtect
5191 +
5192 + settings = portage.settings
5193 + protect = portage.util.shlex_split(settings.get("CONFIG_PROTECT", ""))
5194 + protect_mask = portage.util.shlex_split(settings.get("CONFIG_PROTECT_MASK", ""))
5195 + protect_obj = ConfigProtect(
5196 + root,
5197 + protect,
5198 + protect_mask,
5199 + case_insensitive=("case-insensitive-fs" in settings.features),
5200 + )
5201
5202 -@uses_eroot
5203 -def best_visible(argv):
5204 - if len(argv) < 2:
5205 - writemsg("ERROR: insufficient parameters!\n", noiselevel=-1)
5206 - return 2
5207 + errors = 0
5208
5209 - pkgtype = "ebuild"
5210 - if len(argv) > 2:
5211 - pkgtype = argv[1]
5212 - atom = argv[2]
5213 - else:
5214 - atom = argv[1]
5215 + for line in sys.stdin:
5216 + filename = line.rstrip("\n")
5217 + f = portage.normalize_path(filename)
5218 + if not f.startswith(os.path.sep):
5219 + if cwd is None:
5220 + err.write("ERROR: cwd does not exist!\n")
5221 + err.flush()
5222 + errors += 1
5223 + continue
5224 + f = os.path.join(cwd, f)
5225 + f = portage.normalize_path(f)
5226
5227 - type_map = {"ebuild": "porttree", "binary": "bintree", "installed": "vartree"}
5228 + if not f.startswith(root):
5229 + err.write("ERROR: file paths must begin with <eroot>!\n")
5230 + err.flush()
5231 + errors += 1
5232 + continue
5233
5234 - if pkgtype not in type_map:
5235 - writemsg("Unrecognized package type: '%s'\n" % pkgtype, noiselevel=-1)
5236 - return 2
5237 + if protect_obj.isprotected(f):
5238 + out.write("%s\n" % filename)
5239 + out.flush()
5240
5241 - eroot = argv[0]
5242 - db = portage.db[eroot][type_map[pkgtype]].dbapi
5243 + if errors:
5244 + return 2
5245
5246 - try:
5247 - atom = portage.dep_expand(atom, mydb=db, settings=portage.settings)
5248 - except portage.exception.InvalidAtom:
5249 - writemsg("ERROR: Invalid atom: '%s'\n" % atom, noiselevel=-1)
5250 - return 2
5251 + return 0
5252
5253 - root_config = RootConfig(portage.settings, portage.db[eroot], None)
5254 + docstrings[
5255 + "filter_protected"
5256 + ] = """<eroot>
5257 + Read filenames from stdin and write them to stdout if they are protected.
5258 + All filenames are delimited by \\n and must begin with <eroot>.
5259 + """
5260 + filter_protected.__doc__ = docstrings["filter_protected"]
5261 +
5262 + @uses_eroot
5263 + def best_visible(argv):
5264 + if len(argv) < 2:
5265 + writemsg("ERROR: insufficient parameters!\n", noiselevel=-1)
5266 + return 2
5267
5268 - if hasattr(db, "xmatch"):
5269 - cpv_list = db.xmatch("match-all-cpv-only", atom)
5270 - else:
5271 - cpv_list = db.match(atom)
5272 -
5273 - if cpv_list:
5274 - # reversed, for descending order
5275 - cpv_list.reverse()
5276 - # verify match, since the atom may match the package
5277 - # for a given cpv from one repo but not another, and
5278 - # we can use match-all-cpv-only to avoid redundant
5279 - # metadata access.
5280 - atom_set = InternalPackageSet(initial_atoms=(atom,))
5281 -
5282 - if atom.repo is None and hasattr(db, "getRepositories"):
5283 - repo_list = db.getRepositories()
5284 + pkgtype = "ebuild"
5285 + if len(argv) > 2:
5286 + pkgtype = argv[1]
5287 + atom = argv[2]
5288 else:
5289 - repo_list = [atom.repo]
5290 -
5291 - for cpv in cpv_list:
5292 - for repo in repo_list:
5293 - try:
5294 - metadata = dict(
5295 - zip(
5296 - Package.metadata_keys,
5297 - db.aux_get(cpv, Package.metadata_keys, myrepo=repo),
5298 - )
5299 - )
5300 - except KeyError:
5301 - continue
5302 - pkg = Package(
5303 - built=(pkgtype != "ebuild"),
5304 - cpv=cpv,
5305 - installed=(pkgtype == "installed"),
5306 - metadata=metadata,
5307 - root_config=root_config,
5308 - type_name=pkgtype,
5309 - )
5310 - if not atom_set.findAtomForPackage(pkg):
5311 - continue
5312 -
5313 - if pkg.visible:
5314 - writemsg_stdout("{}\n".format(pkg.cpv), noiselevel=-1)
5315 - return os.EX_OK
5316 -
5317 - # No package found, write out an empty line.
5318 - writemsg_stdout("\n", noiselevel=-1)
5319 -
5320 - return 1
5321 -
5322 + atom = argv[1]
5323
5324 -docstrings[
5325 - "best_visible"
5326 -] = """<eroot> [pkgtype] <atom>
5327 - Returns category/package-version (without .ebuild).
5328 - The pkgtype argument defaults to "ebuild" if unspecified,
5329 - otherwise it must be one of ebuild, binary, or installed.
5330 - """
5331 -best_visible.__doc__ = docstrings["best_visible"]
5332 + type_map = {"ebuild": "porttree", "binary": "bintree", "installed": "vartree"}
5333
5334 + if pkgtype not in type_map:
5335 + writemsg("Unrecognized package type: '%s'\n" % pkgtype, noiselevel=-1)
5336 + return 2
5337
5338 -@uses_eroot
5339 -def mass_best_visible(argv):
5340 - type_map = {"ebuild": "porttree", "binary": "bintree", "installed": "vartree"}
5341 + eroot = argv[0]
5342 + db = portage.db[eroot][type_map[pkgtype]].dbapi
5343
5344 - if len(argv) < 2:
5345 - print("ERROR: insufficient parameters!")
5346 - return 2
5347 - try:
5348 - root = argv.pop(0)
5349 - pkgtype = "ebuild"
5350 - if argv[0] in type_map:
5351 - pkgtype = argv.pop(0)
5352 - for pack in argv:
5353 - writemsg_stdout("%s:" % pack, noiselevel=-1)
5354 - best_visible([root, pkgtype, pack])
5355 - except KeyError:
5356 - return 1
5357 + try:
5358 + atom = portage.dep_expand(atom, mydb=db, settings=portage.settings)
5359 + except portage.exception.InvalidAtom:
5360 + writemsg("ERROR: Invalid atom: '%s'\n" % atom, noiselevel=-1)
5361 + return 2
5362
5363 + root_config = RootConfig(portage.settings, portage.db[eroot], None)
5364
5365 -docstrings[
5366 - "mass_best_visible"
5367 -] = """<eroot> [<type>] [<category/package>]+
5368 - Returns category/package-version (without .ebuild).
5369 - The pkgtype argument defaults to "ebuild" if unspecified,
5370 - otherwise it must be one of ebuild, binary, or installed.
5371 - """
5372 -mass_best_visible.__doc__ = docstrings["mass_best_visible"]
5373 -
5374 -
5375 -@uses_eroot
5376 -def all_best_visible(argv):
5377 - if len(argv) < 1:
5378 - sys.stderr.write("ERROR: insufficient parameters!\n")
5379 - sys.stderr.flush()
5380 - return 2
5381 -
5382 - # print portage.db[argv[0]]["porttree"].dbapi.cp_all()
5383 - for pkg in portage.db[argv[0]]["porttree"].dbapi.cp_all():
5384 - mybest = portage.best(portage.db[argv[0]]["porttree"].dbapi.match(pkg))
5385 - if mybest:
5386 - print(mybest)
5387 -
5388 -
5389 -docstrings[
5390 - "all_best_visible"
5391 -] = """<eroot>
5392 - Returns all best_visible packages (without .ebuild).
5393 - """
5394 -all_best_visible.__doc__ = docstrings["all_best_visible"]
5395 -
5396 -
5397 -@uses_eroot
5398 -def match(argv):
5399 - if len(argv) != 2:
5400 - print("ERROR: expected 2 parameters, got %d!" % len(argv))
5401 - return 2
5402 - root, atom = argv
5403 - if not atom:
5404 - atom = "*/*"
5405 -
5406 - vardb = portage.db[root]["vartree"].dbapi
5407 - try:
5408 - atom = portage.dep.Atom(atom, allow_wildcard=True, allow_repo=True)
5409 - except portage.exception.InvalidAtom:
5410 - # maybe it's valid but missing category
5411 - atom = portage.dep_expand(atom, mydb=vardb, settings=vardb.settings)
5412 -
5413 - if atom.extended_syntax:
5414 - if atom == "*/*":
5415 - results = vardb.cpv_all()
5416 + if hasattr(db, "xmatch"):
5417 + cpv_list = db.xmatch("match-all-cpv-only", atom)
5418 else:
5419 - results = []
5420 - require_metadata = atom.slot or atom.repo
5421 - for cpv in vardb.cpv_all():
5422 -
5423 - if not portage.match_from_list(atom, [cpv]):
5424 - continue
5425 + cpv_list = db.match(atom)
5426 +
5427 + if cpv_list:
5428 + # reversed, for descending order
5429 + cpv_list.reverse()
5430 + # verify match, since the atom may match the package
5431 + # for a given cpv from one repo but not another, and
5432 + # we can use match-all-cpv-only to avoid redundant
5433 + # metadata access.
5434 + atom_set = InternalPackageSet(initial_atoms=(atom,))
5435 +
5436 + if atom.repo is None and hasattr(db, "getRepositories"):
5437 + repo_list = db.getRepositories()
5438 + else:
5439 + repo_list = [atom.repo]
5440
5441 - if require_metadata:
5442 + for cpv in cpv_list:
5443 + for repo in repo_list:
5444 try:
5445 - cpv = vardb._pkg_str(cpv, atom.repo)
5446 - except (KeyError, portage.exception.InvalidData):
5447 + metadata = dict(
5448 + zip(
5449 + Package.metadata_keys,
5450 + db.aux_get(cpv, Package.metadata_keys, myrepo=repo),
5451 + )
5452 + )
5453 + except KeyError:
5454 continue
5455 - if not portage.match_from_list(atom, [cpv]):
5456 + pkg = Package(
5457 + built=(pkgtype != "ebuild"),
5458 + cpv=cpv,
5459 + installed=(pkgtype == "installed"),
5460 + metadata=metadata,
5461 + root_config=root_config,
5462 + type_name=pkgtype,
5463 + )
5464 + if not atom_set.findAtomForPackage(pkg):
5465 continue
5466
5467 - results.append(cpv)
5468 -
5469 - results.sort()
5470 - else:
5471 - results = vardb.match(atom)
5472 - for cpv in results:
5473 - print(cpv)
5474 -
5475 -
5476 -docstrings[
5477 - "match"
5478 -] = """<eroot> <atom>
5479 - Returns a \\n separated list of category/package-version.
5480 - When given an empty string, all installed packages will
5481 - be listed.
5482 - """
5483 -match.__doc__ = docstrings["match"]
5484 -
5485 -
5486 -@uses_eroot
5487 -def expand_virtual(argv):
5488 - if len(argv) != 2:
5489 - writemsg("ERROR: expected 2 parameters, got %d!\n" % len(argv), noiselevel=-1)
5490 - return 2
5491 -
5492 - root, atom = argv
5493 -
5494 - try:
5495 - results = list(expand_new_virt(portage.db[root]["vartree"].dbapi, atom))
5496 - except portage.exception.InvalidAtom:
5497 - writemsg("ERROR: Invalid atom: '%s'\n" % atom, noiselevel=-1)
5498 - return 2
5499 -
5500 - results.sort()
5501 - for x in results:
5502 - if not x.blocker:
5503 - writemsg_stdout("{}\n".format(x))
5504 -
5505 - return os.EX_OK
5506 -
5507 -
5508 -docstrings[
5509 - "expand_virtual"
5510 -] = """<eroot> <atom>
5511 - Returns a \\n separated list of atoms expanded from a
5512 - given virtual atom (GLEP 37 virtuals only),
5513 - excluding blocker atoms. Satisfied
5514 - virtual atoms are not included in the output, since
5515 - they are expanded to real atoms which are displayed.
5516 - Unsatisfied virtual atoms are displayed without
5517 - any expansion. The "match" command can be used to
5518 - resolve the returned atoms to specific installed
5519 - packages.
5520 - """
5521 -expand_virtual.__doc__ = docstrings["expand_virtual"]
5522 -
5523 -
5524 -def vdb_path(_argv):
5525 - out = sys.stdout
5526 - out.write(os.path.join(portage.settings["EROOT"], portage.VDB_PATH) + "\n")
5527 - out.flush()
5528 - return os.EX_OK
5529 -
5530 -
5531 -docstrings[
5532 - "vdb_path"
5533 -] = """
5534 - Returns the path used for the var(installed) package database for the
5535 - set environment/configuration options.
5536 - """
5537 -vdb_path.__doc__ = docstrings["vdb_path"]
5538 -
5539 -
5540 -def gentoo_mirrors(_argv):
5541 - print(portage.settings["GENTOO_MIRRORS"])
5542 -
5543 -
5544 -docstrings[
5545 - "gentoo_mirrors"
5546 -] = """
5547 - Returns the mirrors set to use in the portage configuration.
5548 - """
5549 -gentoo_mirrors.__doc__ = docstrings["gentoo_mirrors"]
5550 -
5551 -
5552 -@uses_configroot
5553 -@uses_eroot
5554 -def repositories_configuration(argv):
5555 - if len(argv) < 1:
5556 - print("ERROR: insufficient parameters!", file=sys.stderr)
5557 - return 3
5558 - sys.stdout.write(
5559 - portage.db[argv[0]]["vartree"].settings.repositories.config_string()
5560 - )
5561 - sys.stdout.flush()
5562 -
5563 -
5564 -docstrings[
5565 - "repositories_configuration"
5566 -] = """<eroot>
5567 - Returns the configuration of repositories.
5568 - """
5569 -repositories_configuration.__doc__ = docstrings["repositories_configuration"]
5570 -
5571 -
5572 -@uses_configroot
5573 -@uses_eroot
5574 -def repos_config(argv):
5575 - return repositories_configuration(argv)
5576 -
5577 -
5578 -docstrings[
5579 - "repos_config"
5580 -] = """
5581 - <eroot>
5582 - This is an alias for the repositories_configuration command.
5583 - """
5584 -repos_config.__doc__ = docstrings["repos_config"]
5585 -
5586 -
5587 -def portdir(_argv):
5588 - print(
5589 - "WARNING: 'portageq portdir' is deprecated. Use the get_repo_path "
5590 - "command instead. eg: "
5591 - "'portageq get_repo_path / gentoo' instead.",
5592 - file=sys.stderr,
5593 - )
5594 - print(portage.settings["PORTDIR"])
5595 -
5596 + if pkg.visible:
5597 + writemsg_stdout("{}\n".format(pkg.cpv), noiselevel=-1)
5598 + return os.EX_OK
5599
5600 -docstrings[
5601 - "portdir"
5602 -] = """
5603 - Returns the PORTDIR path.
5604 - Deprecated in favor of get_repo_path command.
5605 - """
5606 -portdir.__doc__ = docstrings["portdir"]
5607 + # No package found, write out an empty line.
5608 + writemsg_stdout("\n", noiselevel=-1)
5609
5610 + return 1
5611
5612 -def config_protect(_argv):
5613 - print(portage.settings["CONFIG_PROTECT"])
5614 -
5615 -
5616 -docstrings[
5617 - "config_protect"
5618 -] = """
5619 - Returns the CONFIG_PROTECT paths.
5620 - """
5621 -config_protect.__doc__ = docstrings["config_protect"]
5622 -
5623 -
5624 -def config_protect_mask(_argv):
5625 - print(portage.settings["CONFIG_PROTECT_MASK"])
5626 -
5627 -
5628 -docstrings[
5629 - "config_protect_mask"
5630 -] = """
5631 - Returns the CONFIG_PROTECT_MASK paths.
5632 - """
5633 -config_protect_mask.__doc__ = docstrings["config_protect_mask"]
5634 -
5635 -
5636 -def portdir_overlay(_argv):
5637 - print(
5638 - "WARNING: 'portageq portdir_overlay' is deprecated. Use the get_repos"
5639 - " and get_repo_path commands or the repos_config command instead. eg: "
5640 - "'portageq repos_config /'",
5641 - file=sys.stderr,
5642 - )
5643 - print(portage.settings["PORTDIR_OVERLAY"])
5644 -
5645 -
5646 -docstrings[
5647 - "portdir_overlay"
5648 -] = """
5649 - Returns the PORTDIR_OVERLAY path.
5650 - Deprecated in favor of get_repos & get_repo_path or repos_config commands.
5651 - """
5652 -portdir_overlay.__doc__ = docstrings["portdir_overlay"]
5653 -
5654 -
5655 -def pkgdir(_argv):
5656 - print(portage.settings["PKGDIR"])
5657 -
5658 -
5659 -docstrings[
5660 - "pkgdir"
5661 -] = """
5662 - Returns the PKGDIR path.
5663 - """
5664 -pkgdir.__doc__ = docstrings["pkgdir"]
5665 -
5666 + docstrings[
5667 + "best_visible"
5668 + ] = """<eroot> [pkgtype] <atom>
5669 + Returns category/package-version (without .ebuild).
5670 + The pkgtype argument defaults to "ebuild" if unspecified,
5671 + otherwise it must be one of ebuild, binary, or installed.
5672 + """
5673 + best_visible.__doc__ = docstrings["best_visible"]
5674 +
5675 + @uses_eroot
5676 + def mass_best_visible(argv):
5677 + type_map = {"ebuild": "porttree", "binary": "bintree", "installed": "vartree"}
5678 +
5679 + if len(argv) < 2:
5680 + print("ERROR: insufficient parameters!")
5681 + return 2
5682 + try:
5683 + root = argv.pop(0)
5684 + pkgtype = "ebuild"
5685 + if argv[0] in type_map:
5686 + pkgtype = argv.pop(0)
5687 + for pack in argv:
5688 + writemsg_stdout("%s:" % pack, noiselevel=-1)
5689 + best_visible([root, pkgtype, pack])
5690 + except KeyError:
5691 + return 1
5692
5693 -def distdir(_argv):
5694 - print(portage.settings["DISTDIR"])
5695 + docstrings[
5696 + "mass_best_visible"
5697 + ] = """<eroot> [<type>] [<category/package>]+
5698 + Returns category/package-version (without .ebuild).
5699 + The pkgtype argument defaults to "ebuild" if unspecified,
5700 + otherwise it must be one of ebuild, binary, or installed.
5701 + """
5702 + mass_best_visible.__doc__ = docstrings["mass_best_visible"]
5703 +
5704 + @uses_eroot
5705 + def all_best_visible(argv):
5706 + if len(argv) < 1:
5707 + sys.stderr.write("ERROR: insufficient parameters!\n")
5708 + sys.stderr.flush()
5709 + return 2
5710
5711 + # print portage.db[argv[0]]["porttree"].dbapi.cp_all()
5712 + for pkg in portage.db[argv[0]]["porttree"].dbapi.cp_all():
5713 + mybest = portage.best(portage.db[argv[0]]["porttree"].dbapi.match(pkg))
5714 + if mybest:
5715 + print(mybest)
5716 +
5717 + docstrings[
5718 + "all_best_visible"
5719 + ] = """<eroot>
5720 + Returns all best_visible packages (without .ebuild).
5721 + """
5722 + all_best_visible.__doc__ = docstrings["all_best_visible"]
5723 +
5724 + @uses_eroot
5725 + def match(argv):
5726 + if len(argv) != 2:
5727 + print("ERROR: expected 2 parameters, got %d!" % len(argv))
5728 + return 2
5729 + root, atom = argv
5730 + if not atom:
5731 + atom = "*/*"
5732
5733 -docstrings[
5734 - "distdir"
5735 -] = """
5736 - Returns the DISTDIR path.
5737 - """
5738 -distdir.__doc__ = docstrings["distdir"]
5739 + vardb = portage.db[root]["vartree"].dbapi
5740 + try:
5741 + atom = portage.dep.Atom(atom, allow_wildcard=True, allow_repo=True)
5742 + except portage.exception.InvalidAtom:
5743 + # maybe it's valid but missing category
5744 + atom = portage.dep_expand(atom, mydb=vardb, settings=vardb.settings)
5745
5746 + if atom.extended_syntax:
5747 + if atom == "*/*":
5748 + results = vardb.cpv_all()
5749 + else:
5750 + results = []
5751 + require_metadata = atom.slot or atom.repo
5752 + for cpv in vardb.cpv_all():
5753
5754 -def colormap(_argv):
5755 - print(portage.output.colormap())
5756 + if not portage.match_from_list(atom, [cpv]):
5757 + continue
5758
5759 + if require_metadata:
5760 + try:
5761 + cpv = vardb._pkg_str(cpv, atom.repo)
5762 + except (KeyError, portage.exception.InvalidData):
5763 + continue
5764 + if not portage.match_from_list(atom, [cpv]):
5765 + continue
5766
5767 -docstrings[
5768 - "colormap"
5769 -] = """
5770 - Display the color.map as environment variables.
5771 - """
5772 -colormap.__doc__ = docstrings["colormap"]
5773 + results.append(cpv)
5774
5775 + results.sort()
5776 + else:
5777 + results = vardb.match(atom)
5778 + for cpv in results:
5779 + print(cpv)
5780 +
5781 + docstrings[
5782 + "match"
5783 + ] = """<eroot> <atom>
5784 + Returns a \\n separated list of category/package-version.
5785 + When given an empty string, all installed packages will
5786 + be listed.
5787 + """
5788 + match.__doc__ = docstrings["match"]
5789 +
5790 + @uses_eroot
5791 + def expand_virtual(argv):
5792 + if len(argv) != 2:
5793 + writemsg(
5794 + "ERROR: expected 2 parameters, got %d!\n" % len(argv), noiselevel=-1
5795 + )
5796 + return 2
5797
5798 -def envvar(argv):
5799 - verbose = "-v" in argv
5800 - if verbose:
5801 - argv.pop(argv.index("-v"))
5802 + root, atom = argv
5803
5804 - if len(argv) == 0:
5805 - print("ERROR: insufficient parameters!")
5806 - return 2
5807 + try:
5808 + results = list(expand_new_virt(portage.db[root]["vartree"].dbapi, atom))
5809 + except portage.exception.InvalidAtom:
5810 + writemsg("ERROR: Invalid atom: '%s'\n" % atom, noiselevel=-1)
5811 + return 2
5812
5813 - exit_status = 0
5814 + results.sort()
5815 + for x in results:
5816 + if not x.blocker:
5817 + writemsg_stdout("{}\n".format(x))
5818
5819 - for arg in argv:
5820 - if arg in ("PORTDIR", "PORTDIR_OVERLAY", "SYNC"):
5821 - print(
5822 - "WARNING: 'portageq envvar %s' is deprecated. Use any of "
5823 - "'get_repos, get_repo_path, repos_config' instead." % arg,
5824 - file=sys.stderr,
5825 - )
5826 + return os.EX_OK
5827
5828 - value = portage.settings.get(arg)
5829 - if value is None:
5830 - value = ""
5831 - exit_status = 1
5832 + docstrings[
5833 + "expand_virtual"
5834 + ] = """<eroot> <atom>
5835 + Returns a \\n separated list of atoms expanded from a
5836 + given virtual atom (GLEP 37 virtuals only),
5837 + excluding blocker atoms. Satisfied
5838 + virtual atoms are not included in the output, since
5839 + they are expanded to real atoms which are displayed.
5840 + Unsatisfied virtual atoms are displayed without
5841 + any expansion. The "match" command can be used to
5842 + resolve the returned atoms to specific installed
5843 + packages.
5844 + """
5845 + expand_virtual.__doc__ = docstrings["expand_virtual"]
5846 +
5847 + def vdb_path(_argv):
5848 + out = sys.stdout
5849 + out.write(os.path.join(portage.settings["EROOT"], portage.VDB_PATH) + "\n")
5850 + out.flush()
5851 + return os.EX_OK
5852
5853 + docstrings[
5854 + "vdb_path"
5855 + ] = """
5856 + Returns the path used for the var(installed) package database for the
5857 + set environment/configuration options.
5858 + """
5859 + vdb_path.__doc__ = docstrings["vdb_path"]
5860 +
5861 + def gentoo_mirrors(_argv):
5862 + print(portage.settings["GENTOO_MIRRORS"])
5863 +
5864 + docstrings[
5865 + "gentoo_mirrors"
5866 + ] = """
5867 + Returns the mirrors set to use in the portage configuration.
5868 + """
5869 + gentoo_mirrors.__doc__ = docstrings["gentoo_mirrors"]
5870 +
5871 + @uses_configroot
5872 + @uses_eroot
5873 + def repositories_configuration(argv):
5874 + if len(argv) < 1:
5875 + print("ERROR: insufficient parameters!", file=sys.stderr)
5876 + return 3
5877 + sys.stdout.write(
5878 + portage.db[argv[0]]["vartree"].settings.repositories.config_string()
5879 + )
5880 + sys.stdout.flush()
5881 +
5882 + docstrings[
5883 + "repositories_configuration"
5884 + ] = """<eroot>
5885 + Returns the configuration of repositories.
5886 + """
5887 + repositories_configuration.__doc__ = docstrings["repositories_configuration"]
5888 +
5889 + @uses_configroot
5890 + @uses_eroot
5891 + def repos_config(argv):
5892 + return repositories_configuration(argv)
5893 +
5894 + docstrings[
5895 + "repos_config"
5896 + ] = """
5897 + <eroot>
5898 + This is an alias for the repositories_configuration command.
5899 + """
5900 + repos_config.__doc__ = docstrings["repos_config"]
5901 +
5902 + def portdir(_argv):
5903 + print(
5904 + "WARNING: 'portageq portdir' is deprecated. Use the get_repo_path "
5905 + "command instead. eg: "
5906 + "'portageq get_repo_path / gentoo' instead.",
5907 + file=sys.stderr,
5908 + )
5909 + print(portage.settings["PORTDIR"])
5910 +
5911 + docstrings[
5912 + "portdir"
5913 + ] = """
5914 + Returns the PORTDIR path.
5915 + Deprecated in favor of get_repo_path command.
5916 + """
5917 + portdir.__doc__ = docstrings["portdir"]
5918 +
5919 + def config_protect(_argv):
5920 + print(portage.settings["CONFIG_PROTECT"])
5921 +
5922 + docstrings[
5923 + "config_protect"
5924 + ] = """
5925 + Returns the CONFIG_PROTECT paths.
5926 + """
5927 + config_protect.__doc__ = docstrings["config_protect"]
5928 +
5929 + def config_protect_mask(_argv):
5930 + print(portage.settings["CONFIG_PROTECT_MASK"])
5931 +
5932 + docstrings[
5933 + "config_protect_mask"
5934 + ] = """
5935 + Returns the CONFIG_PROTECT_MASK paths.
5936 + """
5937 + config_protect_mask.__doc__ = docstrings["config_protect_mask"]
5938 +
5939 + def portdir_overlay(_argv):
5940 + print(
5941 + "WARNING: 'portageq portdir_overlay' is deprecated. Use the get_repos"
5942 + " and get_repo_path commands or the repos_config command instead. eg: "
5943 + "'portageq repos_config /'",
5944 + file=sys.stderr,
5945 + )
5946 + print(portage.settings["PORTDIR_OVERLAY"])
5947 +
5948 + docstrings[
5949 + "portdir_overlay"
5950 + ] = """
5951 + Returns the PORTDIR_OVERLAY path.
5952 + Deprecated in favor of get_repos & get_repo_path or repos_config commands.
5953 + """
5954 + portdir_overlay.__doc__ = docstrings["portdir_overlay"]
5955 +
5956 + def pkgdir(_argv):
5957 + print(portage.settings["PKGDIR"])
5958 +
5959 + docstrings[
5960 + "pkgdir"
5961 + ] = """
5962 + Returns the PKGDIR path.
5963 + """
5964 + pkgdir.__doc__ = docstrings["pkgdir"]
5965 +
5966 + def distdir(_argv):
5967 + print(portage.settings["DISTDIR"])
5968 +
5969 + docstrings[
5970 + "distdir"
5971 + ] = """
5972 + Returns the DISTDIR path.
5973 + """
5974 + distdir.__doc__ = docstrings["distdir"]
5975 +
5976 + def colormap(_argv):
5977 + print(portage.output.colormap())
5978 +
5979 + docstrings[
5980 + "colormap"
5981 + ] = """
5982 + Display the color.map as environment variables.
5983 + """
5984 + colormap.__doc__ = docstrings["colormap"]
5985 +
5986 + def envvar(argv):
5987 + verbose = "-v" in argv
5988 if verbose:
5989 - print(arg + "=" + portage._shell_quote(value))
5990 - else:
5991 - print(value)
5992 + argv.pop(argv.index("-v"))
5993
5994 - return exit_status
5995 + if len(argv) == 0:
5996 + print("ERROR: insufficient parameters!")
5997 + return 2
5998
5999 + exit_status = 0
6000
6001 -docstrings[
6002 - "envvar"
6003 -] = """<variable>+
6004 - Returns a specific environment variable as exists prior to ebuild.sh.
6005 - Similar to: emerge --verbose --info | grep -E '^<variable>='
6006 - """
6007 -envvar.__doc__ = docstrings["envvar"]
6008 + for arg in argv:
6009 + if arg in ("PORTDIR", "PORTDIR_OVERLAY", "SYNC"):
6010 + print(
6011 + "WARNING: 'portageq envvar %s' is deprecated. Use any of "
6012 + "'get_repos, get_repo_path, repos_config' instead." % arg,
6013 + file=sys.stderr,
6014 + )
6015
6016 + value = portage.settings.get(arg)
6017 + if value is None:
6018 + value = ""
6019 + exit_status = 1
6020
6021 -@uses_configroot
6022 -@uses_eroot
6023 -def get_repos(argv):
6024 - if len(argv) < 1:
6025 - print("ERROR: insufficient parameters!")
6026 - return 2
6027 - print(
6028 - " ".join(
6029 - reversed(portage.db[argv[0]]["vartree"].settings.repositories.prepos_order)
6030 + if verbose:
6031 + print(arg + "=" + portage._shell_quote(value))
6032 + else:
6033 + print(value)
6034 +
6035 + return exit_status
6036 +
6037 + docstrings[
6038 + "envvar"
6039 + ] = """<variable>+
6040 + Returns a specific environment variable as exists prior to ebuild.sh.
6041 + Similar to: emerge --verbose --info | grep -E '^<variable>='
6042 + """
6043 + envvar.__doc__ = docstrings["envvar"]
6044 +
6045 + @uses_configroot
6046 + @uses_eroot
6047 + def get_repos(argv):
6048 + if len(argv) < 1:
6049 + print("ERROR: insufficient parameters!")
6050 + return 2
6051 + print(
6052 + " ".join(
6053 + reversed(
6054 + portage.db[argv[0]]["vartree"].settings.repositories.prepos_order
6055 + )
6056 + )
6057 )
6058 - )
6059
6060 -
6061 -docstrings[
6062 - "get_repos"
6063 -] = """<eroot>
6064 - Returns all repos with names (repo_name file) argv[0] = ${EROOT}
6065 - """
6066 -get_repos.__doc__ = docstrings["get_repos"]
6067 -
6068 -
6069 -@uses_configroot
6070 -@uses_eroot
6071 -def master_repositories(argv):
6072 - if len(argv) < 2:
6073 - print("ERROR: insufficient parameters!", file=sys.stderr)
6074 - return 3
6075 - for arg in argv[1:]:
6076 - if portage.dep._repo_name_re.match(arg) is None:
6077 - print("ERROR: invalid repository: %s" % arg, file=sys.stderr)
6078 + docstrings[
6079 + "get_repos"
6080 + ] = """<eroot>
6081 + Returns all repos with names (repo_name file) argv[0] = ${EROOT}
6082 + """
6083 + get_repos.__doc__ = docstrings["get_repos"]
6084 +
6085 + @uses_configroot
6086 + @uses_eroot
6087 + def master_repositories(argv):
6088 + if len(argv) < 2:
6089 + print("ERROR: insufficient parameters!", file=sys.stderr)
6090 + return 3
6091 + for arg in argv[1:]:
6092 + if portage.dep._repo_name_re.match(arg) is None:
6093 + print("ERROR: invalid repository: %s" % arg, file=sys.stderr)
6094 + return 2
6095 + try:
6096 + repo = portage.db[argv[0]]["vartree"].settings.repositories[arg]
6097 + except KeyError:
6098 + print("")
6099 + return 1
6100 + else:
6101 + print(" ".join(x.name for x in repo.masters))
6102 +
6103 + docstrings[
6104 + "master_repositories"
6105 + ] = """<eroot> <repo_id>+
6106 + Returns space-separated list of master repositories for specified repository.
6107 + """
6108 + master_repositories.__doc__ = docstrings["master_repositories"]
6109 +
6110 + @uses_configroot
6111 + @uses_eroot
6112 + def master_repos(argv):
6113 + return master_repositories(argv)
6114 +
6115 + docstrings[
6116 + "master_repos"
6117 + ] = """<eroot> <repo_id>+
6118 + This is an alias for the master_repositories command.
6119 + """
6120 + master_repos.__doc__ = docstrings["master_repos"]
6121 +
6122 + @uses_configroot
6123 + @uses_eroot
6124 + def get_repo_path(argv):
6125 +
6126 + if len(argv) < 2:
6127 + print("ERROR: insufficient parameters!", file=sys.stderr)
6128 + return 3
6129 + for arg in argv[1:]:
6130 + if portage.dep._repo_name_re.match(arg) is None:
6131 + print("ERROR: invalid repository: %s" % arg, file=sys.stderr)
6132 + return 2
6133 + path = portage.db[argv[0]]["vartree"].settings.repositories.treemap.get(arg)
6134 + if path is None:
6135 + print("")
6136 + return 1
6137 + print(path)
6138 +
6139 + docstrings[
6140 + "get_repo_path"
6141 + ] = """<eroot> <repo_id>+
6142 + Returns the path to the repo named argv[1], argv[0] = ${EROOT}
6143 + """
6144 + get_repo_path.__doc__ = docstrings["get_repo_path"]
6145 +
6146 + @uses_eroot
6147 + def available_eclasses(argv):
6148 + if len(argv) < 2:
6149 + print("ERROR: insufficient parameters!", file=sys.stderr)
6150 + return 3
6151 + for arg in argv[1:]:
6152 + if portage.dep._repo_name_re.match(arg) is None:
6153 + print("ERROR: invalid repository: %s" % arg, file=sys.stderr)
6154 + return 2
6155 + try:
6156 + repo = portage.db[argv[0]]["vartree"].settings.repositories[arg]
6157 + except KeyError:
6158 + print("")
6159 + return 1
6160 + else:
6161 + print(" ".join(sorted(repo.eclass_db.eclasses)))
6162 +
6163 + docstrings[
6164 + "available_eclasses"
6165 + ] = """<eroot> <repo_id>+
6166 + Returns space-separated list of available eclasses for specified repository.
6167 + """
6168 + available_eclasses.__doc__ = docstrings["available_eclasses"]
6169 +
6170 + @uses_eroot
6171 + def eclass_path(argv):
6172 + if len(argv) < 3:
6173 + print("ERROR: insufficient parameters!", file=sys.stderr)
6174 + return 3
6175 + if portage.dep._repo_name_re.match(argv[1]) is None:
6176 + print("ERROR: invalid repository: %s" % argv[1], file=sys.stderr)
6177 return 2
6178 try:
6179 - repo = portage.db[argv[0]]["vartree"].settings.repositories[arg]
6180 + repo = portage.db[argv[0]]["vartree"].settings.repositories[argv[1]]
6181 except KeyError:
6182 print("")
6183 return 1
6184 else:
6185 - print(" ".join(x.name for x in repo.masters))
6186 -
6187 -
6188 -docstrings[
6189 - "master_repositories"
6190 -] = """<eroot> <repo_id>+
6191 - Returns space-separated list of master repositories for specified repository.
6192 - """
6193 -master_repositories.__doc__ = docstrings["master_repositories"]
6194 -
6195 -
6196 -@uses_configroot
6197 -@uses_eroot
6198 -def master_repos(argv):
6199 - return master_repositories(argv)
6200 -
6201 -
6202 -docstrings[
6203 - "master_repos"
6204 -] = """<eroot> <repo_id>+
6205 - This is an alias for the master_repositories command.
6206 - """
6207 -master_repos.__doc__ = docstrings["master_repos"]
6208 -
6209 -
6210 -@uses_configroot
6211 -@uses_eroot
6212 -def get_repo_path(argv):
6213 -
6214 - if len(argv) < 2:
6215 - print("ERROR: insufficient parameters!", file=sys.stderr)
6216 - return 3
6217 - for arg in argv[1:]:
6218 - if portage.dep._repo_name_re.match(arg) is None:
6219 - print("ERROR: invalid repository: %s" % arg, file=sys.stderr)
6220 - return 2
6221 - path = portage.db[argv[0]]["vartree"].settings.repositories.treemap.get(arg)
6222 - if path is None:
6223 - print("")
6224 - return 1
6225 - print(path)
6226 -
6227 -
6228 -docstrings[
6229 - "get_repo_path"
6230 -] = """<eroot> <repo_id>+
6231 - Returns the path to the repo named argv[1], argv[0] = ${EROOT}
6232 - """
6233 -get_repo_path.__doc__ = docstrings["get_repo_path"]
6234 -
6235 -
6236 -@uses_eroot
6237 -def available_eclasses(argv):
6238 - if len(argv) < 2:
6239 - print("ERROR: insufficient parameters!", file=sys.stderr)
6240 - return 3
6241 - for arg in argv[1:]:
6242 - if portage.dep._repo_name_re.match(arg) is None:
6243 - print("ERROR: invalid repository: %s" % arg, file=sys.stderr)
6244 + retval = 0
6245 + for arg in argv[2:]:
6246 + try:
6247 + eclass = repo.eclass_db.eclasses[arg]
6248 + except KeyError:
6249 + print("")
6250 + retval = 1
6251 + else:
6252 + print(eclass.location)
6253 + return retval
6254 +
6255 + docstrings[
6256 + "eclass_path"
6257 + ] = """<eroot> <repo_id> <eclass>+
6258 + Returns the path to specified eclass for specified repository.
6259 + """
6260 + eclass_path.__doc__ = docstrings["eclass_path"]
6261 +
6262 + @uses_eroot
6263 + def license_path(argv):
6264 + if len(argv) < 3:
6265 + print("ERROR: insufficient parameters!", file=sys.stderr)
6266 + return 3
6267 + if portage.dep._repo_name_re.match(argv[1]) is None:
6268 + print("ERROR: invalid repository: %s" % argv[1], file=sys.stderr)
6269 return 2
6270 try:
6271 - repo = portage.db[argv[0]]["vartree"].settings.repositories[arg]
6272 + repo = portage.db[argv[0]]["vartree"].settings.repositories[argv[1]]
6273 except KeyError:
6274 print("")
6275 return 1
6276 else:
6277 - print(" ".join(sorted(repo.eclass_db.eclasses)))
6278 -
6279 -
6280 -docstrings[
6281 - "available_eclasses"
6282 -] = """<eroot> <repo_id>+
6283 - Returns space-separated list of available eclasses for specified repository.
6284 - """
6285 -available_eclasses.__doc__ = docstrings["available_eclasses"]
6286 -
6287 -
6288 -@uses_eroot
6289 -def eclass_path(argv):
6290 - if len(argv) < 3:
6291 - print("ERROR: insufficient parameters!", file=sys.stderr)
6292 - return 3
6293 - if portage.dep._repo_name_re.match(argv[1]) is None:
6294 - print("ERROR: invalid repository: %s" % argv[1], file=sys.stderr)
6295 - return 2
6296 - try:
6297 - repo = portage.db[argv[0]]["vartree"].settings.repositories[argv[1]]
6298 - except KeyError:
6299 - print("")
6300 - return 1
6301 - else:
6302 - retval = 0
6303 - for arg in argv[2:]:
6304 - try:
6305 - eclass = repo.eclass_db.eclasses[arg]
6306 - except KeyError:
6307 - print("")
6308 - retval = 1
6309 - else:
6310 - print(eclass.location)
6311 - return retval
6312 -
6313 -
6314 -docstrings[
6315 - "eclass_path"
6316 -] = """<eroot> <repo_id> <eclass>+
6317 - Returns the path to specified eclass for specified repository.
6318 - """
6319 -eclass_path.__doc__ = docstrings["eclass_path"]
6320 -
6321 -
6322 -@uses_eroot
6323 -def license_path(argv):
6324 - if len(argv) < 3:
6325 - print("ERROR: insufficient parameters!", file=sys.stderr)
6326 - return 3
6327 - if portage.dep._repo_name_re.match(argv[1]) is None:
6328 - print("ERROR: invalid repository: %s" % argv[1], file=sys.stderr)
6329 - return 2
6330 - try:
6331 - repo = portage.db[argv[0]]["vartree"].settings.repositories[argv[1]]
6332 - except KeyError:
6333 - print("")
6334 - return 1
6335 - else:
6336 - retval = 0
6337 - for arg in argv[2:]:
6338 - eclass_path = ""
6339 - paths = reversed(
6340 - [
6341 - os.path.join(x.location, "licenses", arg)
6342 - for x in list(repo.masters) + [repo]
6343 - ]
6344 - )
6345 - for path in paths:
6346 - if os.path.exists(path):
6347 - eclass_path = path
6348 + retval = 0
6349 + for arg in argv[2:]:
6350 + eclass_path = ""
6351 + paths = reversed(
6352 + [
6353 + os.path.join(x.location, "licenses", arg)
6354 + for x in list(repo.masters) + [repo]
6355 + ]
6356 + )
6357 + for path in paths:
6358 + if os.path.exists(path):
6359 + eclass_path = path
6360 + break
6361 + if eclass_path == "":
6362 + retval = 1
6363 + print(eclass_path)
6364 + return retval
6365 +
6366 + docstrings[
6367 + "license_path"
6368 + ] = """<eroot> <repo_id> <license>+
6369 + Returns the path to specified license for specified repository.
6370 + """
6371 + license_path.__doc__ = docstrings["license_path"]
6372 +
6373 + @uses_eroot
6374 + def list_preserved_libs(argv):
6375 + if len(argv) != 1:
6376 + print("ERROR: wrong number of arguments")
6377 + return 2
6378 + mylibs = portage.db[argv[0]]["vartree"].dbapi._plib_registry.getPreservedLibs()
6379 + rValue = 1
6380 + msg = []
6381 + for cpv in sorted(mylibs):
6382 + msg.append(cpv)
6383 + for path in mylibs[cpv]:
6384 + msg.append(" " + path)
6385 + rValue = 0
6386 + msg.append("\n")
6387 + writemsg_stdout("".join(msg), noiselevel=-1)
6388 + return rValue
6389 +
6390 + docstrings[
6391 + "list_preserved_libs"
6392 + ] = """<eroot>
6393 + Print a list of libraries preserved during a package update in the form
6394 + package: path. Returns 1 if no preserved libraries could be found,
6395 + 0 otherwise.
6396 + """
6397 + list_preserved_libs.__doc__ = docstrings["list_preserved_libs"]
6398 +
6399 + class MaintainerEmailMatcher:
6400 + def __init__(self, maintainer_emails):
6401 + self._re = re.compile("^(%s)$" % "|".join(maintainer_emails), re.I)
6402 +
6403 + def __call__(self, metadata_xml):
6404 + match = False
6405 + matcher = self._re.match
6406 + for x in metadata_xml.maintainers():
6407 + if x.email is not None and matcher(x.email) is not None:
6408 + match = True
6409 break
6410 - if eclass_path == "":
6411 - retval = 1
6412 - print(eclass_path)
6413 - return retval
6414 -
6415 -
6416 -docstrings[
6417 - "license_path"
6418 -] = """<eroot> <repo_id> <license>+
6419 - Returns the path to specified license for specified repository.
6420 - """
6421 -license_path.__doc__ = docstrings["license_path"]
6422 -
6423 -
6424 -@uses_eroot
6425 -def list_preserved_libs(argv):
6426 - if len(argv) != 1:
6427 - print("ERROR: wrong number of arguments")
6428 - return 2
6429 - mylibs = portage.db[argv[0]]["vartree"].dbapi._plib_registry.getPreservedLibs()
6430 - rValue = 1
6431 - msg = []
6432 - for cpv in sorted(mylibs):
6433 - msg.append(cpv)
6434 - for path in mylibs[cpv]:
6435 - msg.append(" " + path)
6436 - rValue = 0
6437 - msg.append("\n")
6438 - writemsg_stdout("".join(msg), noiselevel=-1)
6439 - return rValue
6440 -
6441 -
6442 -docstrings[
6443 - "list_preserved_libs"
6444 -] = """<eroot>
6445 - Print a list of libraries preserved during a package update in the form
6446 - package: path. Returns 1 if no preserved libraries could be found,
6447 - 0 otherwise.
6448 - """
6449 -list_preserved_libs.__doc__ = docstrings["list_preserved_libs"]
6450 -
6451 -
6452 -class MaintainerEmailMatcher:
6453 - def __init__(self, maintainer_emails):
6454 - self._re = re.compile("^(%s)$" % "|".join(maintainer_emails), re.I)
6455 -
6456 - def __call__(self, metadata_xml):
6457 - match = False
6458 - matcher = self._re.match
6459 - for x in metadata_xml.maintainers():
6460 - if x.email is not None and matcher(x.email) is not None:
6461 - match = True
6462 - break
6463 - return match
6464 -
6465 -
6466 -# Match if metadata.xml contains no maintainer (orphaned package)
6467 -def match_orphaned(metadata_xml):
6468 - if not metadata_xml.maintainers():
6469 - return True
6470 - else:
6471 - return False
6472 + return match
6473
6474 + # Match if metadata.xml contains no maintainer (orphaned package)
6475 + def match_orphaned(metadata_xml):
6476 + if not metadata_xml.maintainers():
6477 + return True
6478 + else:
6479 + return False
6480
6481 -def pquery(parser, opts, args):
6482 - portdb = portage.db[portage.root]["porttree"].dbapi
6483 - root_config = RootConfig(portdb.settings, portage.db[portage.root], None)
6484 + def pquery(parser, opts, args):
6485 + portdb = portage.db[portage.root]["porttree"].dbapi
6486 + root_config = RootConfig(portdb.settings, portage.db[portage.root], None)
6487
6488 - def _pkg(cpv, repo_name):
6489 - try:
6490 - metadata = dict(
6491 - zip(
6492 - Package.metadata_keys,
6493 - portdb.aux_get(cpv, Package.metadata_keys, myrepo=repo_name),
6494 + def _pkg(cpv, repo_name):
6495 + try:
6496 + metadata = dict(
6497 + zip(
6498 + Package.metadata_keys,
6499 + portdb.aux_get(cpv, Package.metadata_keys, myrepo=repo_name),
6500 + )
6501 )
6502 + except KeyError:
6503 + raise portage.exception.PackageNotFound(cpv)
6504 + return Package(
6505 + built=False,
6506 + cpv=cpv,
6507 + installed=False,
6508 + metadata=metadata,
6509 + root_config=root_config,
6510 + type_name="ebuild",
6511 )
6512 - except KeyError:
6513 - raise portage.exception.PackageNotFound(cpv)
6514 - return Package(
6515 - built=False,
6516 - cpv=cpv,
6517 - installed=False,
6518 - metadata=metadata,
6519 - root_config=root_config,
6520 - type_name="ebuild",
6521 - )
6522
6523 - need_metadata = False
6524 - atoms = []
6525 - for arg in args:
6526 - if "/" not in arg.split(":")[0]:
6527 - atom = insert_category_into_atom(arg, "*")
6528 - if atom is None:
6529 + need_metadata = False
6530 + atoms = []
6531 + for arg in args:
6532 + if "/" not in arg.split(":")[0]:
6533 + atom = insert_category_into_atom(arg, "*")
6534 + if atom is None:
6535 + writemsg("ERROR: Invalid atom: '%s'\n" % arg, noiselevel=-1)
6536 + return 2
6537 + else:
6538 + atom = arg
6539 +
6540 + try:
6541 + atom = portage.dep.Atom(atom, allow_wildcard=True, allow_repo=True)
6542 + except portage.exception.InvalidAtom:
6543 writemsg("ERROR: Invalid atom: '%s'\n" % arg, noiselevel=-1)
6544 return 2
6545 - else:
6546 - atom = arg
6547
6548 - try:
6549 - atom = portage.dep.Atom(atom, allow_wildcard=True, allow_repo=True)
6550 - except portage.exception.InvalidAtom:
6551 - writemsg("ERROR: Invalid atom: '%s'\n" % arg, noiselevel=-1)
6552 - return 2
6553 + if atom.slot is not None:
6554 + need_metadata = True
6555
6556 - if atom.slot is not None:
6557 - need_metadata = True
6558 + atoms.append(atom)
6559
6560 - atoms.append(atom)
6561 + if "*/*" in atoms:
6562 + del atoms[:]
6563 + need_metadata = False
6564
6565 - if "*/*" in atoms:
6566 - del atoms[:]
6567 - need_metadata = False
6568 -
6569 - if not opts.no_filters:
6570 - need_metadata = True
6571 -
6572 - xml_matchers = []
6573 - if opts.maintainer_email:
6574 - maintainer_emails = []
6575 - for x in opts.maintainer_email:
6576 - maintainer_emails.extend(x.split(","))
6577 - if opts.no_regex: # Escape regex-special characters for an exact match
6578 - maintainer_emails = [re.escape(x) for x in maintainer_emails]
6579 - xml_matchers.append(MaintainerEmailMatcher(maintainer_emails))
6580 - if opts.orphaned:
6581 - xml_matchers.append(match_orphaned)
6582 -
6583 - if opts.repo is not None:
6584 - repos = [portdb.repositories[opts.repo]]
6585 - else:
6586 - repos = list(portdb.repositories)
6587 + if not opts.no_filters:
6588 + need_metadata = True
6589
6590 - if not atoms:
6591 - names = None
6592 - categories = list(portdb.categories)
6593 - else:
6594 - category_wildcard = False
6595 - name_wildcard = False
6596 - categories = []
6597 - names = []
6598 - for atom in atoms:
6599 - category, name = portage.catsplit(atom.cp)
6600 - categories.append(category)
6601 - names.append(name)
6602 - if "*" in category:
6603 - category_wildcard = True
6604 - if "*" in name:
6605 - name_wildcard = True
6606 -
6607 - if category_wildcard:
6608 - categories = list(portdb.categories)
6609 + xml_matchers = []
6610 + if opts.maintainer_email:
6611 + maintainer_emails = []
6612 + for x in opts.maintainer_email:
6613 + maintainer_emails.extend(x.split(","))
6614 + if opts.no_regex: # Escape regex-special characters for an exact match
6615 + maintainer_emails = [re.escape(x) for x in maintainer_emails]
6616 + xml_matchers.append(MaintainerEmailMatcher(maintainer_emails))
6617 + if opts.orphaned:
6618 + xml_matchers.append(match_orphaned)
6619 +
6620 + if opts.repo is not None:
6621 + repos = [portdb.repositories[opts.repo]]
6622 else:
6623 - categories = list(set(categories))
6624 + repos = list(portdb.repositories)
6625
6626 - if name_wildcard:
6627 + if not atoms:
6628 names = None
6629 + categories = list(portdb.categories)
6630 else:
6631 - names = sorted(set(names))
6632 + category_wildcard = False
6633 + name_wildcard = False
6634 + categories = []
6635 + names = []
6636 + for atom in atoms:
6637 + category, name = portage.catsplit(atom.cp)
6638 + categories.append(category)
6639 + names.append(name)
6640 + if "*" in category:
6641 + category_wildcard = True
6642 + if "*" in name:
6643 + name_wildcard = True
6644 +
6645 + if category_wildcard:
6646 + categories = list(portdb.categories)
6647 + else:
6648 + categories = list(set(categories))
6649
6650 - no_version = opts.no_version
6651 - categories.sort()
6652 + if name_wildcard:
6653 + names = None
6654 + else:
6655 + names = sorted(set(names))
6656
6657 - for category in categories:
6658 - if names is None:
6659 - cp_list = portdb.cp_all(categories=(category,))
6660 - else:
6661 - cp_list = [category + "/" + name for name in names]
6662 - for cp in cp_list:
6663 - matches = []
6664 - for repo in repos:
6665 - match = True
6666 - if xml_matchers:
6667 - metadata_xml_path = os.path.join(repo.location, cp, "metadata.xml")
6668 - try:
6669 - metadata_xml = MetaDataXML(metadata_xml_path, None)
6670 - except (OSError, SyntaxError):
6671 - match = False
6672 - else:
6673 - for matcher in xml_matchers:
6674 - if not matcher(metadata_xml):
6675 - match = False
6676 - break
6677 - if not match:
6678 - continue
6679 - cpv_list = portdb.cp_list(cp, mytree=[repo.location])
6680 - if atoms:
6681 - for cpv in cpv_list:
6682 - pkg = None
6683 - for atom in atoms:
6684 - if atom.repo is not None and atom.repo != repo.name:
6685 - continue
6686 - if not portage.match_from_list(atom, [cpv]):
6687 - continue
6688 - if need_metadata:
6689 - if pkg is None:
6690 - try:
6691 - pkg = _pkg(cpv, repo.name)
6692 - except portage.exception.PackageNotFound:
6693 - continue
6694 + no_version = opts.no_version
6695 + categories.sort()
6696
6697 - if not (opts.no_filters or pkg.visible):
6698 - continue
6699 - if not portage.match_from_list(atom, [pkg]):
6700 - continue
6701 - matches.append(cpv)
6702 - break
6703 - if no_version and matches:
6704 - break
6705 - elif opts.no_filters:
6706 - matches.extend(cpv_list)
6707 - else:
6708 - for cpv in cpv_list:
6709 + for category in categories:
6710 + if names is None:
6711 + cp_list = portdb.cp_all(categories=(category,))
6712 + else:
6713 + cp_list = [category + "/" + name for name in names]
6714 + for cp in cp_list:
6715 + matches = []
6716 + for repo in repos:
6717 + match = True
6718 + if xml_matchers:
6719 + metadata_xml_path = os.path.join(
6720 + repo.location, cp, "metadata.xml"
6721 + )
6722 try:
6723 - pkg = _pkg(cpv, repo.name)
6724 - except portage.exception.PackageNotFound:
6725 - continue
6726 + metadata_xml = MetaDataXML(metadata_xml_path, None)
6727 + except (OSError, SyntaxError):
6728 + match = False
6729 else:
6730 - if pkg.visible:
6731 - matches.append(cpv)
6732 - if no_version:
6733 + for matcher in xml_matchers:
6734 + if not matcher(metadata_xml):
6735 + match = False
6736 break
6737 + if not match:
6738 + continue
6739 + cpv_list = portdb.cp_list(cp, mytree=[repo.location])
6740 + if atoms:
6741 + for cpv in cpv_list:
6742 + pkg = None
6743 + for atom in atoms:
6744 + if atom.repo is not None and atom.repo != repo.name:
6745 + continue
6746 + if not portage.match_from_list(atom, [cpv]):
6747 + continue
6748 + if need_metadata:
6749 + if pkg is None:
6750 + try:
6751 + pkg = _pkg(cpv, repo.name)
6752 + except portage.exception.PackageNotFound:
6753 + continue
6754 +
6755 + if not (opts.no_filters or pkg.visible):
6756 + continue
6757 + if not portage.match_from_list(atom, [pkg]):
6758 + continue
6759 + matches.append(cpv)
6760 + break
6761 + if no_version and matches:
6762 + break
6763 + elif opts.no_filters:
6764 + matches.extend(cpv_list)
6765 + else:
6766 + for cpv in cpv_list:
6767 + try:
6768 + pkg = _pkg(cpv, repo.name)
6769 + except portage.exception.PackageNotFound:
6770 + continue
6771 + else:
6772 + if pkg.visible:
6773 + matches.append(cpv)
6774 + if no_version:
6775 + break
6776
6777 - if no_version and matches:
6778 - break
6779 + if no_version and matches:
6780 + break
6781
6782 - if not matches:
6783 - continue
6784 + if not matches:
6785 + continue
6786
6787 - if no_version:
6788 - writemsg_stdout("{}\n".format(cp), noiselevel=-1)
6789 - else:
6790 - matches = list(set(matches))
6791 - portdb._cpv_sort_ascending(matches)
6792 - for cpv in matches:
6793 - writemsg_stdout("{}\n".format(cpv), noiselevel=-1)
6794 -
6795 - return os.EX_OK
6796 -
6797 -
6798 -docstrings[
6799 - "pquery"
6800 -] = """[options] [atom]+
6801 - Emulates a subset of Pkgcore's pquery tool.
6802 - """
6803 -pquery.__doc__ = docstrings["pquery"]
6804 -
6805 -
6806 -# -----------------------------------------------------------------------------
6807 -#
6808 -# DO NOT CHANGE CODE BEYOND THIS POINT - IT'S NOT NEEDED!
6809 -#
6810 -
6811 -non_commands = frozenset(
6812 - [
6813 - "elog",
6814 - "eval_atom_use",
6815 - "exithandler",
6816 - "match_orphaned",
6817 - "main",
6818 - "usage",
6819 - "uses_eroot",
6820 - ]
6821 -)
6822 -commands = sorted(
6823 - k
6824 - for k, v in globals().items()
6825 - if k not in non_commands
6826 - and isinstance(v, types.FunctionType)
6827 - and v.__module__ == "__main__"
6828 -)
6829 + if no_version:
6830 + writemsg_stdout("{}\n".format(cp), noiselevel=-1)
6831 + else:
6832 + matches = list(set(matches))
6833 + portdb._cpv_sort_ascending(matches)
6834 + for cpv in matches:
6835 + writemsg_stdout("{}\n".format(cpv), noiselevel=-1)
6836 +
6837 + return os.EX_OK
6838
6839 + docstrings[
6840 + "pquery"
6841 + ] = """[options] [atom]+
6842 + Emulates a subset of Pkgcore's pquery tool.
6843 + """
6844 + pquery.__doc__ = docstrings["pquery"]
6845 +
6846 + non_commands = frozenset(
6847 + [
6848 + "elog",
6849 + "eval_atom_use",
6850 + "exithandler",
6851 + "match_orphaned",
6852 + "main",
6853 + "usage",
6854 + "uses_eroot",
6855 + ]
6856 + )
6857 + commands = sorted(
6858 + k
6859 + for k, v in globals().items()
6860 + if k not in non_commands
6861 + and isinstance(v, types.FunctionType)
6862 + and v.__module__ == "__main__"
6863 + )
6864
6865 -def add_pquery_arguments(parser):
6866 - pquery_option_groups = (
6867 - (
6868 - "Repository matching options",
6869 + def add_pquery_arguments(parser):
6870 + pquery_option_groups = (
6871 (
6872 - {
6873 - "longopt": "--no-filters",
6874 - "action": "store_true",
6875 - "help": "no visibility filters (ACCEPT_KEYWORDS, package masking, etc)",
6876 - },
6877 - {
6878 - "longopt": "--repo",
6879 - "help": "repository to use (all repositories are used by default)",
6880 - },
6881 + "Repository matching options",
6882 + (
6883 + {
6884 + "longopt": "--no-filters",
6885 + "action": "store_true",
6886 + "help": "no visibility filters (ACCEPT_KEYWORDS, package masking, etc)",
6887 + },
6888 + {
6889 + "longopt": "--repo",
6890 + "help": "repository to use (all repositories are used by default)",
6891 + },
6892 + ),
6893 ),
6894 - ),
6895 - (
6896 - "Package matching options",
6897 (
6898 - {
6899 - "longopt": "--maintainer-email",
6900 - "action": "append",
6901 - "help": "comma-separated list of maintainer email regexes to search for",
6902 - },
6903 - {
6904 - "longopt": "--no-regex",
6905 - "action": "store_true",
6906 - "help": "Use exact matching instead of regex matching for --maintainer-email",
6907 - },
6908 - {
6909 - "longopt": "--orphaned",
6910 - "action": "store_true",
6911 - "help": "match only orphaned (maintainer-needed) packages",
6912 - },
6913 + "Package matching options",
6914 + (
6915 + {
6916 + "longopt": "--maintainer-email",
6917 + "action": "append",
6918 + "help": "comma-separated list of maintainer email regexes to search for",
6919 + },
6920 + {
6921 + "longopt": "--no-regex",
6922 + "action": "store_true",
6923 + "help": "Use exact matching instead of regex matching for --maintainer-email",
6924 + },
6925 + {
6926 + "longopt": "--orphaned",
6927 + "action": "store_true",
6928 + "help": "match only orphaned (maintainer-needed) packages",
6929 + },
6930 + ),
6931 ),
6932 - ),
6933 - (
6934 - "Output formatting",
6935 (
6936 - {
6937 - "shortopt": "-n",
6938 - "longopt": "--no-version",
6939 - "action": "store_true",
6940 - "help": "collapse multiple matching versions together",
6941 - },
6942 + "Output formatting",
6943 + (
6944 + {
6945 + "shortopt": "-n",
6946 + "longopt": "--no-version",
6947 + "action": "store_true",
6948 + "help": "collapse multiple matching versions together",
6949 + },
6950 + ),
6951 ),
6952 - ),
6953 - )
6954 -
6955 - for group_title, opt_data in pquery_option_groups:
6956 - arg_group = parser.add_argument_group(group_title)
6957 - for opt_info in opt_data:
6958 - pargs = []
6959 - try:
6960 - pargs.append(opt_info["shortopt"])
6961 - except KeyError:
6962 - pass
6963 - try:
6964 - pargs.append(opt_info["longopt"])
6965 - except KeyError:
6966 - pass
6967 -
6968 - kwargs = {}
6969 - try:
6970 - kwargs["action"] = opt_info["action"]
6971 - except KeyError:
6972 - pass
6973 - try:
6974 - kwargs["help"] = opt_info["help"]
6975 - except KeyError:
6976 - pass
6977 - arg_group.add_argument(*pargs, **kwargs)
6978 -
6979 -
6980 -def usage(argv):
6981 - print(">>> Portage information query tool")
6982 - print(">>> %s" % portage.VERSION)
6983 - print(">>> Usage: portageq <command> [<option> ...]")
6984 - print("")
6985 - print("Available commands:")
6986 + )
6987
6988 - #
6989 - # Show our commands -- we do this by scanning the functions in this
6990 - # file, and formatting each functions documentation.
6991 - #
6992 - help_mode = "--help" in argv
6993 - for name in commands:
6994 - doc = docstrings.get(name)
6995 - if doc is None:
6996 - print(" " + name)
6997 - print(" MISSING DOCUMENTATION!")
6998 - print("")
6999 - continue
7000 -
7001 - lines = doc.lstrip("\n").split("\n")
7002 - print(" " + name + " " + lines[0].strip())
7003 - if len(argv) > 1:
7004 - if not help_mode:
7005 - lines = lines[:-1]
7006 - for line in lines[1:]:
7007 - print(" " + line.strip())
7008 -
7009 - print()
7010 - print("Pkgcore pquery compatible options:")
7011 - print()
7012 - parser = argparse.ArgumentParser(
7013 - add_help=False, usage="portageq pquery [options] [atom ...]"
7014 - )
7015 - add_pquery_arguments(parser)
7016 - parser.print_help()
7017 + for group_title, opt_data in pquery_option_groups:
7018 + arg_group = parser.add_argument_group(group_title)
7019 + for opt_info in opt_data:
7020 + pargs = []
7021 + try:
7022 + pargs.append(opt_info["shortopt"])
7023 + except KeyError:
7024 + pass
7025 + try:
7026 + pargs.append(opt_info["longopt"])
7027 + except KeyError:
7028 + pass
7029
7030 - if len(argv) == 1:
7031 - print("\nRun portageq with --help for info")
7032 + kwargs = {}
7033 + try:
7034 + kwargs["action"] = opt_info["action"]
7035 + except KeyError:
7036 + pass
7037 + try:
7038 + kwargs["help"] = opt_info["help"]
7039 + except KeyError:
7040 + pass
7041 + arg_group.add_argument(*pargs, **kwargs)
7042
7043 + def usage(argv):
7044 + print(">>> Portage information query tool")
7045 + print(">>> %s" % portage.VERSION)
7046 + print(">>> Usage: portageq <command> [<option> ...]")
7047 + print("")
7048 + print("Available commands:")
7049 +
7050 + #
7051 + # Show our commands -- we do this by scanning the functions in this
7052 + # file, and formatting each functions documentation.
7053 + #
7054 + help_mode = "--help" in argv
7055 + for name in commands:
7056 + doc = docstrings.get(name)
7057 + if doc is None:
7058 + print(" " + name)
7059 + print(" MISSING DOCUMENTATION!")
7060 + print("")
7061 + continue
7062
7063 -atom_validate_strict = "EBUILD_PHASE" in os.environ
7064 -eapi = None
7065 -if atom_validate_strict:
7066 - eapi = os.environ.get("EAPI")
7067 + lines = doc.lstrip("\n").split("\n")
7068 + print(" " + name + " " + lines[0].strip())
7069 + if len(argv) > 1:
7070 + if not help_mode:
7071 + lines = lines[:-1]
7072 + for line in lines[1:]:
7073 + print(" " + line.strip())
7074 +
7075 + print()
7076 + print("Pkgcore pquery compatible options:")
7077 + print()
7078 + parser = argparse.ArgumentParser(
7079 + add_help=False, usage="portageq pquery [options] [atom ...]"
7080 + )
7081 + add_pquery_arguments(parser)
7082 + parser.print_help()
7083
7084 - def elog(elog_funcname, lines):
7085 - cmd = "source '%s/isolated-functions.sh' ; " % os.environ["PORTAGE_BIN_PATH"]
7086 - for line in lines:
7087 - cmd += "{} {} ; ".format(elog_funcname, portage._shell_quote(line))
7088 - subprocess.call([portage.const.BASH_BINARY, "-c", cmd])
7089 + if len(argv) == 1:
7090 + print("\nRun portageq with --help for info")
7091
7092 -else:
7093 + atom_validate_strict = "EBUILD_PHASE" in os.environ
7094 + eapi = None
7095 + if atom_validate_strict:
7096 + eapi = os.environ.get("EAPI")
7097
7098 - def elog(elog_funcname, lines):
7099 - pass
7100 + def elog(elog_funcname, lines):
7101 + cmd = (
7102 + "source '%s/isolated-functions.sh' ; " % os.environ["PORTAGE_BIN_PATH"]
7103 + )
7104 + for line in lines:
7105 + cmd += "{} {} ; ".format(elog_funcname, portage._shell_quote(line))
7106 + subprocess.call([portage.const.BASH_BINARY, "-c", cmd])
7107
7108 + else:
7109
7110 -def main(argv):
7111 + def elog(elog_funcname, lines):
7112 + pass
7113
7114 - argv = portage._decode_argv(argv)
7115 + def main(argv):
7116
7117 - nocolor = os.environ.get("NOCOLOR")
7118 - if nocolor in ("yes", "true"):
7119 - portage.output.nocolor()
7120 + argv = portage._decode_argv(argv)
7121
7122 - parser = argparse.ArgumentParser(add_help=False)
7123 + nocolor = os.environ.get("NOCOLOR")
7124 + if nocolor in ("yes", "true"):
7125 + portage.output.nocolor()
7126
7127 - # used by envvar
7128 - parser.add_argument("-v", dest="verbose", action="store_true")
7129 + parser = argparse.ArgumentParser(add_help=False)
7130
7131 - actions = parser.add_argument_group("Actions")
7132 - actions.add_argument("-h", "--help", action="store_true")
7133 - actions.add_argument("--version", action="store_true")
7134 + # used by envvar
7135 + parser.add_argument("-v", dest="verbose", action="store_true")
7136
7137 - add_pquery_arguments(parser)
7138 + actions = parser.add_argument_group("Actions")
7139 + actions.add_argument("-h", "--help", action="store_true")
7140 + actions.add_argument("--version", action="store_true")
7141
7142 - opts, args = parser.parse_known_args(argv[1:])
7143 + add_pquery_arguments(parser)
7144
7145 - if opts.help:
7146 - usage(argv)
7147 - return os.EX_OK
7148 - elif opts.version:
7149 - print("Portage", portage.VERSION)
7150 - return os.EX_OK
7151 + opts, args = parser.parse_known_args(argv[1:])
7152
7153 - cmd = None
7154 - if args and args[0] in commands:
7155 - cmd = args[0]
7156 + if opts.help:
7157 + usage(argv)
7158 + return os.EX_OK
7159 + elif opts.version:
7160 + print("Portage", portage.VERSION)
7161 + return os.EX_OK
7162
7163 - if cmd == "pquery":
7164 cmd = None
7165 - args = args[1:]
7166 + if args and args[0] in commands:
7167 + cmd = args[0]
7168
7169 - if cmd is None:
7170 - return pquery(parser, opts, args)
7171 + if cmd == "pquery":
7172 + cmd = None
7173 + args = args[1:]
7174
7175 - if opts.verbose:
7176 - # used by envvar
7177 - args.append("-v")
7178 + if cmd is None:
7179 + return pquery(parser, opts, args)
7180
7181 - argv = argv[:1] + args
7182 + if opts.verbose:
7183 + # used by envvar
7184 + args.append("-v")
7185
7186 - if len(argv) < 2:
7187 - usage(argv)
7188 - sys.exit(os.EX_USAGE)
7189 + argv = argv[:1] + args
7190
7191 - function = globals()[cmd]
7192 - uses_eroot = getattr(function, "uses_eroot", False) and len(argv) > 2
7193 - if uses_eroot:
7194 - if not os.path.isdir(argv[2]):
7195 - sys.stderr.write("Not a directory: '%s'\n" % argv[2])
7196 - sys.stderr.write("Run portageq with --help for info\n")
7197 - sys.stderr.flush()
7198 + if len(argv) < 2:
7199 + usage(argv)
7200 sys.exit(os.EX_USAGE)
7201 - # Calculate EPREFIX and ROOT that will be used to construct
7202 - # portage.settings later. It's tempting to use
7203 - # portage.settings["EPREFIX"] here, but that would force
7204 - # instantiation of portage.settings, which we don't want to do
7205 - # until after we've calculated ROOT (see bug #529200).
7206 - eprefix = portage.data._target_eprefix()
7207 - eroot = portage.util.normalize_path(argv[2])
7208 -
7209 - if eprefix:
7210 - if not eroot.endswith(eprefix):
7211 - sys.stderr.write(
7212 - "ERROR: This version of portageq"
7213 - " only supports <eroot>s ending in"
7214 - " '%s'. The provided <eroot>, '%s',"
7215 - " doesn't.\n" % (eprefix, eroot)
7216 - )
7217 +
7218 + function = globals()[cmd]
7219 + uses_eroot = getattr(function, "uses_eroot", False) and len(argv) > 2
7220 + if uses_eroot:
7221 + if not os.path.isdir(argv[2]):
7222 + sys.stderr.write("Not a directory: '%s'\n" % argv[2])
7223 + sys.stderr.write("Run portageq with --help for info\n")
7224 sys.stderr.flush()
7225 sys.exit(os.EX_USAGE)
7226 - root = eroot[: 1 - len(eprefix)]
7227 - else:
7228 - root = eroot
7229 + # Calculate EPREFIX and ROOT that will be used to construct
7230 + # portage.settings later. It's tempting to use
7231 + # portage.settings["EPREFIX"] here, but that would force
7232 + # instantiation of portage.settings, which we don't want to do
7233 + # until after we've calculated ROOT (see bug #529200).
7234 + eprefix = portage.data._target_eprefix()
7235 + eroot = portage.util.normalize_path(argv[2])
7236 +
7237 + if eprefix:
7238 + if not eroot.endswith(eprefix):
7239 + sys.stderr.write(
7240 + "ERROR: This version of portageq"
7241 + " only supports <eroot>s ending in"
7242 + " '%s'. The provided <eroot>, '%s',"
7243 + " doesn't.\n" % (eprefix, eroot)
7244 + )
7245 + sys.stderr.flush()
7246 + sys.exit(os.EX_USAGE)
7247 + root = eroot[: 1 - len(eprefix)]
7248 + else:
7249 + root = eroot
7250
7251 - os.environ["ROOT"] = root
7252 + os.environ["ROOT"] = root
7253
7254 - if getattr(function, "uses_configroot", False):
7255 - os.environ["PORTAGE_CONFIGROOT"] = eroot
7256 - # Disable RepoConfigLoader location validation, allowing raw
7257 - # configuration to pass through, since repo locations are not
7258 - # necessarily expected to exist if the configuration comes
7259 - # from a chroot.
7260 - portage._sync_mode = True
7261 + if getattr(function, "uses_configroot", False):
7262 + os.environ["PORTAGE_CONFIGROOT"] = eroot
7263 + # Disable RepoConfigLoader location validation, allowing raw
7264 + # configuration to pass through, since repo locations are not
7265 + # necessarily expected to exist if the configuration comes
7266 + # from a chroot.
7267 + portage._sync_mode = True
7268
7269 - args = argv[2:]
7270 + args = argv[2:]
7271
7272 - try:
7273 - if uses_eroot:
7274 - args[0] = portage.settings["EROOT"]
7275 - retval = function(args)
7276 - if retval:
7277 - sys.exit(retval)
7278 - except portage.exception.PermissionDenied as e:
7279 - sys.stderr.write("Permission denied: '%s'\n" % str(e))
7280 - sys.exit(e.errno)
7281 - except portage.exception.ParseError as e:
7282 - sys.stderr.write("%s\n" % str(e))
7283 - sys.exit(1)
7284 - except portage.exception.AmbiguousPackageName as e:
7285 - # Multiple matches thrown from cpv_expand
7286 - pkgs = e.args[0]
7287 - # An error has occurred so we writemsg to stderr and exit nonzero.
7288 - portage.writemsg(
7289 - "You specified an unqualified atom that matched multiple packages:\n",
7290 - noiselevel=-1,
7291 - )
7292 - for pkg in pkgs:
7293 - portage.writemsg("* %s\n" % pkg, noiselevel=-1)
7294 - portage.writemsg("\nPlease use a more specific atom.\n", noiselevel=-1)
7295 - sys.exit(1)
7296 -
7297 -
7298 -if __name__ == "__main__":
7299 - try:
7300 - sys.exit(main(sys.argv))
7301 - finally:
7302 - global_event_loop().close()
7303 + try:
7304 + if uses_eroot:
7305 + args[0] = portage.settings["EROOT"]
7306 + retval = function(args)
7307 + if retval:
7308 + sys.exit(retval)
7309 + except portage.exception.PermissionDenied as e:
7310 + sys.stderr.write("Permission denied: '%s'\n" % str(e))
7311 + sys.exit(e.errno)
7312 + except portage.exception.ParseError as e:
7313 + sys.stderr.write("%s\n" % str(e))
7314 + sys.exit(1)
7315 + except portage.exception.AmbiguousPackageName as e:
7316 + # Multiple matches thrown from cpv_expand
7317 + pkgs = e.args[0]
7318 + # An error has occurred so we writemsg to stderr and exit nonzero.
7319 + portage.writemsg(
7320 + "You specified an unqualified atom that matched multiple packages:\n",
7321 + noiselevel=-1,
7322 + )
7323 + for pkg in pkgs:
7324 + portage.writemsg("* %s\n" % pkg, noiselevel=-1)
7325 + portage.writemsg("\nPlease use a more specific atom.\n", noiselevel=-1)
7326 + sys.exit(1)
7327
7328 -# -----------------------------------------------------------------------------
7329 + if __name__ == "__main__":
7330 + try:
7331 + sys.exit(main(sys.argv))
7332 + finally:
7333 + global_event_loop().close()
7334 +
7335 +except KeyboardInterrupt as e:
7336 + # Prevent traceback on ^C
7337 + signum = getattr(e, "signum", signal.SIGINT)
7338 + signal.signal(signum, signal.SIG_DFL)
7339 + raise_signal(signum)