Gentoo Archives: gentoo-commits

From: Sam James <sam@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] proj/portage:master commit in: repoman/, bin/, repoman/bin/, /
Date: Mon, 21 Feb 2022 03:51:56
Message-Id: 1645415450.9fe091668c8a1d988c02c849ac1bece6eb764d0b.sam@gentoo
1 commit: 9fe091668c8a1d988c02c849ac1bece6eb764d0b
2 Author: John Helmert III <ajak <AT> gentoo <DOT> org>
3 AuthorDate: Wed Feb 9 20:52:08 2022 +0000
4 Commit: Sam James <sam <AT> gentoo <DOT> org>
5 CommitDate: Mon Feb 21 03:50:50 2022 +0000
6 URL: https://gitweb.gentoo.org/proj/portage.git/commit/?id=9fe09166
7
8 Blacken previously missed Python files
9
10 Signed-off-by: John Helmert III <ajak <AT> gentoo.org>
11 Signed-off-by: Sam James <sam <AT> gentoo.org>
12
13 bin/archive-conf | 44 +-
14 bin/binhost-snapshot | 262 +++---
15 bin/clean_locks | 56 +-
16 bin/dispatch-conf | 345 ++++---
17 bin/ebuild | 512 ++++++-----
18 bin/egencache | 2435 ++++++++++++++++++++++++++-----------------------
19 bin/emaint | 43 +-
20 bin/emerge | 128 +--
21 bin/emirrordist | 18 +-
22 bin/env-update | 44 +-
23 bin/fixpackages | 40 +-
24 bin/glsa-check | 703 +++++++++------
25 bin/pid-ns-init | 42 +-
26 bin/portageq | 2447 +++++++++++++++++++++++++++-----------------------
27 bin/quickpkg | 734 ++++++++-------
28 bin/regenworld | 207 +++--
29 bin/shelve-utils | 38 +-
30 repoman/bin/repoman | 6 +-
31 repoman/runtests | 113 +--
32 runtests | 110 +--
33 20 files changed, 4568 insertions(+), 3759 deletions(-)
34
35 diff --git a/bin/archive-conf b/bin/archive-conf
36 index 3b31ebe1a..beb4fcd23 100755
37 --- a/bin/archive-conf
38 +++ b/bin/archive-conf
39 @@ -12,18 +12,25 @@
40 import sys
41
42 from os import path as osp
43 -if osp.isfile(osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), ".portage_not_installed")):
44 - sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "lib"))
45 +
46 +if osp.isfile(
47 + osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), ".portage_not_installed")
48 +):
49 + sys.path.insert(
50 + 0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "lib")
51 + )
52 import portage
53 +
54 portage._internal_caller = True
55
56 import portage.dispatch_conf
57 from portage import os
58 from portage.checksum import perform_md5
59
60 -FIND_EXTANT_CONTENTS = "find %s -name CONTENTS"
61 +FIND_EXTANT_CONTENTS = "find %s -name CONTENTS"
62 +
63 +MANDATORY_OPTS = ["archive-dir"]
64
65 -MANDATORY_OPTS = [ 'archive-dir' ]
66
67 def archive_conf():
68 args = []
69 @@ -35,12 +42,15 @@ def archive_conf():
70 for conf in sys.argv[1:]:
71 if not os.path.isabs(conf):
72 conf = os.path.abspath(conf)
73 - args += [ conf ]
74 - md5_match_hash[conf] = ''
75 + args += [conf]
76 + md5_match_hash[conf] = ""
77
78 # Find all the CONTENT files in VDB_PATH.
79 - with os.popen(FIND_EXTANT_CONTENTS % (os.path.join(portage.settings['EROOT'], portage.VDB_PATH))) as f:
80 - content_files += f.readlines()
81 + with os.popen(
82 + FIND_EXTANT_CONTENTS
83 + % (os.path.join(portage.settings["EROOT"], portage.VDB_PATH))
84 + ) as f:
85 + content_files += f.readlines()
86
87 # Search for the saved md5 checksum of all the specified config files
88 # and see if the current file is unmodified or not.
89 @@ -51,12 +61,15 @@ def archive_conf():
90 try:
91 contents = open(filename, "r")
92 except IOError as e:
93 - print('archive-conf: Unable to open %s: %s' % (filename, e), file=sys.stderr)
94 + print(
95 + "archive-conf: Unable to open %s: %s" % (filename, e),
96 + file=sys.stderr,
97 + )
98 sys.exit(1)
99 lines = contents.readlines()
100 for line in lines:
101 items = line.split()
102 - if items[0] == 'obj':
103 + if items[0] == "obj":
104 for conf in args:
105 if items[1] == conf:
106 stored = items[2].lower()
107 @@ -70,18 +83,19 @@ def archive_conf():
108 pass
109
110 for conf in args:
111 - archive = os.path.join(options['archive-dir'], conf.lstrip('/'))
112 - if options['use-rcs'] == 'yes':
113 - portage.dispatch_conf.rcs_archive(archive, conf, md5_match_hash[conf], '')
114 + archive = os.path.join(options["archive-dir"], conf.lstrip("/"))
115 + if options["use-rcs"] == "yes":
116 + portage.dispatch_conf.rcs_archive(archive, conf, md5_match_hash[conf], "")
117 if md5_match_hash[conf]:
118 portage.dispatch_conf.rcs_archive_post_process(archive)
119 else:
120 - portage.dispatch_conf.file_archive(archive, conf, md5_match_hash[conf], '')
121 + portage.dispatch_conf.file_archive(archive, conf, md5_match_hash[conf], "")
122 if md5_match_hash[conf]:
123 portage.dispatch_conf.file_archive_post_process(archive)
124
125 +
126 # run
127 if len(sys.argv) > 1:
128 archive_conf()
129 else:
130 - print('Usage: archive-conf /CONFIG/FILE [/CONFIG/FILE...]', file=sys.stderr)
131 + print("Usage: archive-conf /CONFIG/FILE [/CONFIG/FILE...]", file=sys.stderr)
132
133 diff --git a/bin/binhost-snapshot b/bin/binhost-snapshot
134 index 2201781d6..3461a301c 100755
135 --- a/bin/binhost-snapshot
136 +++ b/bin/binhost-snapshot
137 @@ -11,128 +11,156 @@ import textwrap
138 from urllib.parse import urlparse
139
140 from os import path as osp
141 -if osp.isfile(osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), ".portage_not_installed")):
142 - sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "lib"))
143 +
144 +if osp.isfile(
145 + osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), ".portage_not_installed")
146 +):
147 + sys.path.insert(
148 + 0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "lib")
149 + )
150 import portage
151 +
152 portage._internal_caller = True
153
154 +
155 def parse_args(argv):
156 - prog_name = os.path.basename(argv[0])
157 - usage = prog_name + ' [options] ' + \
158 - '<src_pkg_dir> <snapshot_dir> <snapshot_uri> <binhost_dir>'
159 -
160 - prog_desc = "This program will copy src_pkg_dir to snapshot_dir " + \
161 - "and inside binhost_dir it will create a Packages index file " + \
162 - "which refers to snapshot_uri. This is intended to solve race " + \
163 - "conditions on binhosts as described at http://crosbug.com/3225."
164 -
165 - usage += "\n\n"
166 - for line in textwrap.wrap(prog_desc, 70):
167 - usage += line + "\n"
168 -
169 - usage += "\n"
170 - usage += "Required Arguments:\n\n"
171 - usage += " src_pkg_dir - the source $PKGDIR\n"
172 - usage += " snapshot_dir - destination snapshot " + \
173 - "directory (must not exist)\n"
174 - usage += " snapshot_uri - URI which refers to " + \
175 - "snapshot_dir from the\n" + \
176 - " client side\n"
177 - usage += " binhost_dir - directory in which to " + \
178 - "write Packages index with\n" + \
179 - " snapshot_uri"
180 -
181 - parser = argparse.ArgumentParser(usage=usage)
182 - parser.add_argument('--hardlinks',
183 - help='create hardlinks (y or n, default is y)',
184 - choices=('y', 'n'),
185 - default='y')
186 - options, args = parser.parse_known_args(argv[1:])
187 -
188 - if len(args) != 4:
189 - parser.error("Required 4 arguments, got %d" % (len(args),))
190 -
191 - return parser, options, args
192 + prog_name = os.path.basename(argv[0])
193 + usage = (
194 + prog_name
195 + + " [options] "
196 + + "<src_pkg_dir> <snapshot_dir> <snapshot_uri> <binhost_dir>"
197 + )
198 +
199 + prog_desc = (
200 + "This program will copy src_pkg_dir to snapshot_dir "
201 + + "and inside binhost_dir it will create a Packages index file "
202 + + "which refers to snapshot_uri. This is intended to solve race "
203 + + "conditions on binhosts as described at http://crosbug.com/3225."
204 + )
205 +
206 + usage += "\n\n"
207 + for line in textwrap.wrap(prog_desc, 70):
208 + usage += line + "\n"
209 +
210 + usage += "\n"
211 + usage += "Required Arguments:\n\n"
212 + usage += " src_pkg_dir - the source $PKGDIR\n"
213 + usage += " snapshot_dir - destination snapshot " + "directory (must not exist)\n"
214 + usage += (
215 + " snapshot_uri - URI which refers to "
216 + + "snapshot_dir from the\n"
217 + + " client side\n"
218 + )
219 + usage += (
220 + " binhost_dir - directory in which to "
221 + + "write Packages index with\n"
222 + + " snapshot_uri"
223 + )
224 +
225 + parser = argparse.ArgumentParser(usage=usage)
226 + parser.add_argument(
227 + "--hardlinks",
228 + help="create hardlinks (y or n, default is y)",
229 + choices=("y", "n"),
230 + default="y",
231 + )
232 + options, args = parser.parse_known_args(argv[1:])
233 +
234 + if len(args) != 4:
235 + parser.error("Required 4 arguments, got %d" % (len(args),))
236 +
237 + return parser, options, args
238 +
239
240 def main(argv):
241 - parser, options, args = parse_args(argv)
242 -
243 - src_pkg_dir, snapshot_dir, snapshot_uri, binhost_dir = args
244 - src_pkgs_index = os.path.join(src_pkg_dir, 'Packages')
245 -
246 - if not os.path.isdir(src_pkg_dir):
247 - parser.error("src_pkg_dir is not a directory: '%s'" % (src_pkg_dir,))
248 -
249 - if not os.path.isfile(src_pkgs_index):
250 - parser.error("src_pkg_dir does not contain a " + \
251 - "'Packages' index: '%s'" % (src_pkg_dir,))
252 -
253 - parse_result = urlparse(snapshot_uri)
254 - if not (parse_result.scheme and parse_result.netloc and parse_result.path):
255 - parser.error("snapshot_uri is not a valid URI: '%s'" % (snapshot_uri,))
256 -
257 - if os.path.isdir(snapshot_dir):
258 - parser.error("snapshot_dir already exists: '%s'" % snapshot_dir)
259 -
260 - try:
261 - os.makedirs(os.path.dirname(snapshot_dir))
262 - except OSError:
263 - pass
264 - if not os.path.isdir(os.path.dirname(snapshot_dir)):
265 - parser.error("snapshot_dir parent could not be created: '%s'" % \
266 - os.path.dirname(snapshot_dir))
267 -
268 - try:
269 - os.makedirs(binhost_dir)
270 - except OSError:
271 - pass
272 - if not os.path.isdir(binhost_dir):
273 - parser.error("binhost_dir could not be created: '%s'" % binhost_dir)
274 -
275 - cp_opts = 'RP'
276 - if options.hardlinks == 'n':
277 - cp_opts += 'p'
278 - else:
279 - cp_opts += 'l'
280 -
281 - cp_cmd = 'cp -%s %s %s' % (
282 - cp_opts,
283 - portage._shell_quote(src_pkg_dir),
284 - portage._shell_quote(snapshot_dir)
285 - )
286 -
287 - ret = os.system(cp_cmd)
288 - if not (os.WIFEXITED(ret) and os.WEXITSTATUS(ret) == os.EX_OK):
289 - return 1
290 -
291 - infile = io.open(portage._unicode_encode(src_pkgs_index,
292 - encoding=portage._encodings['fs'], errors='strict'),
293 - mode='r', encoding=portage._encodings['repo.content'],
294 - errors='strict')
295 -
296 - outfile = portage.util.atomic_ofstream(
297 - os.path.join(binhost_dir, "Packages"),
298 - encoding=portage._encodings['repo.content'],
299 - errors='strict')
300 -
301 - for line in infile:
302 - if line[:4] == 'URI:':
303 - # skip existing URI line
304 - pass
305 - else:
306 - if not line.strip():
307 - # end of header
308 - outfile.write("URI: %s\n\n" % snapshot_uri)
309 - break
310 - outfile.write(line)
311 -
312 - for line in infile:
313 - outfile.write(line)
314 -
315 - infile.close()
316 - outfile.close()
317 -
318 - return os.EX_OK
319 + parser, options, args = parse_args(argv)
320 +
321 + src_pkg_dir, snapshot_dir, snapshot_uri, binhost_dir = args
322 + src_pkgs_index = os.path.join(src_pkg_dir, "Packages")
323 +
324 + if not os.path.isdir(src_pkg_dir):
325 + parser.error("src_pkg_dir is not a directory: '%s'" % (src_pkg_dir,))
326 +
327 + if not os.path.isfile(src_pkgs_index):
328 + parser.error(
329 + "src_pkg_dir does not contain a "
330 + + "'Packages' index: '%s'" % (src_pkg_dir,)
331 + )
332 +
333 + parse_result = urlparse(snapshot_uri)
334 + if not (parse_result.scheme and parse_result.netloc and parse_result.path):
335 + parser.error("snapshot_uri is not a valid URI: '%s'" % (snapshot_uri,))
336 +
337 + if os.path.isdir(snapshot_dir):
338 + parser.error("snapshot_dir already exists: '%s'" % snapshot_dir)
339 +
340 + try:
341 + os.makedirs(os.path.dirname(snapshot_dir))
342 + except OSError:
343 + pass
344 + if not os.path.isdir(os.path.dirname(snapshot_dir)):
345 + parser.error(
346 + "snapshot_dir parent could not be created: '%s'"
347 + % os.path.dirname(snapshot_dir)
348 + )
349 +
350 + try:
351 + os.makedirs(binhost_dir)
352 + except OSError:
353 + pass
354 + if not os.path.isdir(binhost_dir):
355 + parser.error("binhost_dir could not be created: '%s'" % binhost_dir)
356 +
357 + cp_opts = "RP"
358 + if options.hardlinks == "n":
359 + cp_opts += "p"
360 + else:
361 + cp_opts += "l"
362 +
363 + cp_cmd = "cp -%s %s %s" % (
364 + cp_opts,
365 + portage._shell_quote(src_pkg_dir),
366 + portage._shell_quote(snapshot_dir),
367 + )
368 +
369 + ret = os.system(cp_cmd)
370 + if not (os.WIFEXITED(ret) and os.WEXITSTATUS(ret) == os.EX_OK):
371 + return 1
372 +
373 + infile = io.open(
374 + portage._unicode_encode(
375 + src_pkgs_index, encoding=portage._encodings["fs"], errors="strict"
376 + ),
377 + mode="r",
378 + encoding=portage._encodings["repo.content"],
379 + errors="strict",
380 + )
381 +
382 + outfile = portage.util.atomic_ofstream(
383 + os.path.join(binhost_dir, "Packages"),
384 + encoding=portage._encodings["repo.content"],
385 + errors="strict",
386 + )
387 +
388 + for line in infile:
389 + if line[:4] == "URI:":
390 + # skip existing URI line
391 + pass
392 + else:
393 + if not line.strip():
394 + # end of header
395 + outfile.write("URI: %s\n\n" % snapshot_uri)
396 + break
397 + outfile.write(line)
398 +
399 + for line in infile:
400 + outfile.write(line)
401 +
402 + infile.close()
403 + outfile.close()
404 +
405 + return os.EX_OK
406 +
407
408 if __name__ == "__main__":
409 - sys.exit(main(sys.argv))
410 + sys.exit(main(sys.argv))
411
412 diff --git a/bin/clean_locks b/bin/clean_locks
413 index 6618f58da..88e1b3325 100755
414 --- a/bin/clean_locks
415 +++ b/bin/clean_locks
416 @@ -5,38 +5,44 @@
417 import errno
418 import sys
419 from os import path as osp
420 -if osp.isfile(osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), ".portage_not_installed")):
421 - sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "lib"))
422 +
423 +if osp.isfile(
424 + osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), ".portage_not_installed")
425 +):
426 + sys.path.insert(
427 + 0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "lib")
428 + )
429 import portage
430 +
431 portage._internal_caller = True
432
433 if not sys.argv[1:] or "--help" in sys.argv or "-h" in sys.argv:
434 - print()
435 - print("You must specify directories with hardlink-locks to clean.")
436 - print("You may optionally specify --force, which will remove all")
437 - print("of the locks, even if we can't establish if they are in use.")
438 - print("Please attempt cleaning without force first.")
439 - print()
440 - print("%s %s/.locks" % (sys.argv[0], portage.settings["DISTDIR"]))
441 - print("%s --force %s/.locks" % (sys.argv[0], portage.settings["DISTDIR"]))
442 - print()
443 - sys.exit(1)
444 + print()
445 + print("You must specify directories with hardlink-locks to clean.")
446 + print("You may optionally specify --force, which will remove all")
447 + print("of the locks, even if we can't establish if they are in use.")
448 + print("Please attempt cleaning without force first.")
449 + print()
450 + print("%s %s/.locks" % (sys.argv[0], portage.settings["DISTDIR"]))
451 + print("%s --force %s/.locks" % (sys.argv[0], portage.settings["DISTDIR"]))
452 + print()
453 + sys.exit(1)
454
455 force = False
456 if "--force" in sys.argv[1:]:
457 - force=True
458 + force = True
459
460 for x in sys.argv[1:]:
461 - if x == "--force":
462 - continue
463 - try:
464 - for y in portage.locks.hardlock_cleanup(x, remove_all_locks=force):
465 - print(y)
466 - print()
467 + if x == "--force":
468 + continue
469 + try:
470 + for y in portage.locks.hardlock_cleanup(x, remove_all_locks=force):
471 + print(y)
472 + print()
473
474 - except OSError as e:
475 - if e.errno in (errno.ENOENT, errno.ENOTDIR):
476 - print("!!! %s is not a directory or does not exist" % x)
477 - else:
478 - raise
479 - sys.exit(e.errno)
480 + except OSError as e:
481 + if e.errno in (errno.ENOENT, errno.ENOTDIR):
482 + print("!!! %s is not a directory or does not exist" % x)
483 + else:
484 + raise
485 + sys.exit(e.errno)
486
487 diff --git a/bin/dispatch-conf b/bin/dispatch-conf
488 index a4ca80ba9..c0e7ffc1e 100755
489 --- a/bin/dispatch-conf
490 +++ b/bin/dispatch-conf
491 @@ -23,28 +23,39 @@ from stat import ST_GID, ST_MODE, ST_UID
492 from random import random
493
494 try:
495 - import curses
496 + import curses
497 except ImportError:
498 - curses = None
499 + curses = None
500
501 from os import path as osp
502 -if osp.isfile(osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), ".portage_not_installed")):
503 - sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "lib"))
504 +
505 +if osp.isfile(
506 + osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), ".portage_not_installed")
507 +):
508 + sys.path.insert(
509 + 0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "lib")
510 + )
511 import portage
512 +
513 portage._internal_caller = True
514 from portage import os, shutil
515 from portage import _encodings, _unicode_decode
516 -from portage.dispatch_conf import (diffstatusoutput, diff_mixed_wrapper,
517 - perform_conf_update_hooks, perform_conf_update_session_hooks)
518 +from portage.dispatch_conf import (
519 + diffstatusoutput,
520 + diff_mixed_wrapper,
521 + perform_conf_update_hooks,
522 + perform_conf_update_session_hooks,
523 +)
524 from portage.process import find_binary, spawn
525 from portage.util import writemsg, writemsg_stdout
526
527 -FIND_EXTANT_CONFIGS = "find '%s' %s -name '._cfg????_%s' ! -name '.*~' ! -iname '.*.bak' -print"
528 -DIFF_CONTENTS = "diff -Nu '%s' '%s'"
529 +FIND_EXTANT_CONFIGS = (
530 + "find '%s' %s -name '._cfg????_%s' ! -name '.*~' ! -iname '.*.bak' -print"
531 +)
532 +DIFF_CONTENTS = "diff -Nu '%s' '%s'"
533
534 if "case-insensitive-fs" in portage.settings.features:
535 - FIND_EXTANT_CONFIGS = FIND_EXTANT_CONFIGS.replace(
536 - "-name '._cfg", "-iname '._cfg")
537 + FIND_EXTANT_CONFIGS = FIND_EXTANT_CONFIGS.replace("-name '._cfg", "-iname '._cfg")
538
539 # We need a secure scratch dir and python does silly verbose errors on the use of tempnam
540 oldmask = os.umask(0o077)
541 @@ -52,13 +63,13 @@ SCRATCH_DIR = None
542 while SCRATCH_DIR is None:
543 try:
544 mydir = "/tmp/dispatch-conf."
545 - for x in range(0,8):
546 + for x in range(0, 8):
547 if int(random() * 3) == 0:
548 - mydir += chr(int(65+random()*26.0))
549 + mydir += chr(int(65 + random() * 26.0))
550 elif int(random() * 2) == 0:
551 - mydir += chr(int(97+random()*26.0))
552 + mydir += chr(int(97 + random() * 26.0))
553 else:
554 - mydir += chr(int(48+random()*10.0))
555 + mydir += chr(int(48 + random() * 10.0))
556 if os.path.exists(mydir):
557 continue
558 os.mkdir(mydir)
559 @@ -71,9 +82,12 @@ os.umask(oldmask)
560 # Ensure the scratch dir is deleted
561 def cleanup(mydir=SCRATCH_DIR):
562 shutil.rmtree(mydir)
563 +
564 +
565 atexit.register(cleanup)
566
567 -MANDATORY_OPTS = [ 'archive-dir', 'diff', 'replace-cvs', 'replace-wscomments', 'merge' ]
568 +MANDATORY_OPTS = ["archive-dir", "diff", "replace-cvs", "replace-wscomments", "merge"]
569 +
570
571 def cmd_var_is_valid(cmd):
572 """
573 @@ -89,12 +103,14 @@ def cmd_var_is_valid(cmd):
574
575 return find_binary(cmd[0]) is not None
576
577 +
578 diff = diff_mixed_wrapper(diffstatusoutput, DIFF_CONTENTS)
579
580 +
581 class dispatch:
582 options = {}
583
584 - def grind (self, config_paths):
585 + def grind(self, config_paths):
586 confs = []
587 count = 0
588
589 @@ -105,10 +121,11 @@ class dispatch:
590
591 if "log-file" in self.options:
592 if os.path.isfile(self.options["log-file"]):
593 - shutil.copy(self.options["log-file"], self.options["log-file"] + '.old')
594 - if os.path.isfile(self.options["log-file"]) \
595 - or not os.path.exists(self.options["log-file"]):
596 - open(self.options["log-file"], 'w').close() # Truncate it
597 + shutil.copy(self.options["log-file"], self.options["log-file"] + ".old")
598 + if os.path.isfile(self.options["log-file"]) or not os.path.exists(
599 + self.options["log-file"]
600 + ):
601 + open(self.options["log-file"], "w").close() # Truncate it
602 os.chmod(self.options["log-file"], 0o600)
603
604 pager = self.options.get("pager")
605 @@ -134,7 +151,8 @@ class dispatch:
606
607 for path in config_paths:
608 path = portage.normalize_path(
609 - os.path.join(config_root, path.lstrip(os.sep)))
610 + os.path.join(config_root, path.lstrip(os.sep))
611 + )
612
613 # Protect files that don't exist (bug #523684). If the
614 # parent directory doesn't exist, we can safely skip it.
615 @@ -148,32 +166,38 @@ class dispatch:
616 find_opts = "-maxdepth 1"
617
618 try:
619 - path_list = _unicode_decode(subprocess.check_output(
620 - portage.util.shlex_split(FIND_EXTANT_CONFIGS %
621 - (path, find_opts, basename))),
622 - errors='strict').splitlines()
623 + path_list = _unicode_decode(
624 + subprocess.check_output(
625 + portage.util.shlex_split(
626 + FIND_EXTANT_CONFIGS % (path, find_opts, basename)
627 + )
628 + ),
629 + errors="strict",
630 + ).splitlines()
631 except subprocess.CalledProcessError:
632 pass
633 else:
634 confs.extend(self.massage(path_list))
635
636 - if self.options['use-rcs'] == 'yes':
637 + if self.options["use-rcs"] == "yes":
638 for rcs_util in ("rcs", "ci", "co", "rcsmerge"):
639 if not find_binary(rcs_util):
640 - print('dispatch-conf: Error finding all RCS utils and " + \
641 - "use-rcs=yes in config; fatal', file=sys.stderr)
642 + print(
643 + 'dispatch-conf: Error finding all RCS utils and " + \
644 + "use-rcs=yes in config; fatal',
645 + file=sys.stderr,
646 + )
647 return False
648
649 -
650 # config file freezing support
651 frozen_files = set(self.options.get("frozen-files", "").split())
652 auto_zapped = []
653 protect_obj = portage.util.ConfigProtect(
654 - config_root, config_paths,
655 - portage.util.shlex_split(
656 - portage.settings.get('CONFIG_PROTECT_MASK', '')),
657 - case_insensitive=("case-insensitive-fs"
658 - in portage.settings.features))
659 + config_root,
660 + config_paths,
661 + portage.util.shlex_split(portage.settings.get("CONFIG_PROTECT_MASK", "")),
662 + case_insensitive=("case-insensitive-fs" in portage.settings.features),
663 + )
664
665 #
666 # Remove new configs identical to current
667 @@ -183,36 +207,44 @@ class dispatch:
668 # or c) in paths now unprotected by CONFIG_PROTECT_MASK,
669 #
670
671 - def f (conf):
672 - mrgconf = re.sub(r'\._cfg', '._mrg', conf['new'])
673 - archive = os.path.join(self.options['archive-dir'], conf['current'].lstrip('/'))
674 - if self.options['use-rcs'] == 'yes':
675 - mrgfail = portage.dispatch_conf.rcs_archive(archive, conf['current'], conf['new'], mrgconf)
676 + def f(conf):
677 + mrgconf = re.sub(r"\._cfg", "._mrg", conf["new"])
678 + archive = os.path.join(
679 + self.options["archive-dir"], conf["current"].lstrip("/")
680 + )
681 + if self.options["use-rcs"] == "yes":
682 + mrgfail = portage.dispatch_conf.rcs_archive(
683 + archive, conf["current"], conf["new"], mrgconf
684 + )
685 else:
686 - mrgfail = portage.dispatch_conf.file_archive(archive, conf['current'], conf['new'], mrgconf)
687 - if os.path.lexists(archive + '.dist'):
688 - unmodified = len(diff(conf['current'], archive + '.dist')[1]) == 0
689 + mrgfail = portage.dispatch_conf.file_archive(
690 + archive, conf["current"], conf["new"], mrgconf
691 + )
692 + if os.path.lexists(archive + ".dist"):
693 + unmodified = len(diff(conf["current"], archive + ".dist")[1]) == 0
694 else:
695 unmodified = 0
696 if os.path.exists(mrgconf):
697 - if mrgfail or len(diff(conf['new'], mrgconf)[1]) == 0:
698 + if mrgfail or len(diff(conf["new"], mrgconf)[1]) == 0:
699 os.unlink(mrgconf)
700 - newconf = conf['new']
701 + newconf = conf["new"]
702 else:
703 newconf = mrgconf
704 else:
705 - newconf = conf['new']
706 -
707 - if newconf == mrgconf and \
708 - self.options.get('ignore-previously-merged') != 'yes' and \
709 - os.path.lexists(archive+'.dist') and \
710 - len(diff(archive+'.dist', conf['new'])[1]) == 0:
711 + newconf = conf["new"]
712 +
713 + if (
714 + newconf == mrgconf
715 + and self.options.get("ignore-previously-merged") != "yes"
716 + and os.path.lexists(archive + ".dist")
717 + and len(diff(archive + ".dist", conf["new"])[1]) == 0
718 + ):
719 # The current update is identical to the archived .dist
720 # version that has previously been merged.
721 os.unlink(mrgconf)
722 - newconf = conf['new']
723 + newconf = conf["new"]
724
725 - mystatus, myoutput = diff(conf['current'], newconf)
726 + mystatus, myoutput = diff(conf["current"], newconf)
727 myoutput_len = len(myoutput)
728 same_file = 0 == myoutput_len
729 if mystatus >> 8 == 2:
730 @@ -221,49 +253,53 @@ class dispatch:
731 same_wsc = False
732 else:
733 # Extract all the normal diff lines (ignore the headers).
734 - mylines = re.findall('^[+-][^\n+-].*$', myoutput, re.MULTILINE)
735 + mylines = re.findall("^[+-][^\n+-].*$", myoutput, re.MULTILINE)
736
737 # Filter out all the cvs headers
738 - cvs_header = re.compile('# [$]Header:')
739 + cvs_header = re.compile("# [$]Header:")
740 cvs_lines = list(filter(cvs_header.search, mylines))
741 same_cvs = len(mylines) == len(cvs_lines)
742
743 # Filter out comments and whitespace-only changes.
744 # Note: be nice to also ignore lines that only differ in whitespace...
745 wsc_lines = []
746 - for x in [r'^[-+]\s*#', r'^[-+]\s*$']:
747 - wsc_lines += list(filter(re.compile(x).match, mylines))
748 + for x in [r"^[-+]\s*#", r"^[-+]\s*$"]:
749 + wsc_lines += list(filter(re.compile(x).match, mylines))
750 same_wsc = len(mylines) == len(wsc_lines)
751
752 # Do options permit?
753 - same_cvs = same_cvs and self.options['replace-cvs'] == 'yes'
754 - same_wsc = same_wsc and self.options['replace-wscomments'] == 'yes'
755 - unmodified = unmodified and self.options['replace-unmodified'] == 'yes'
756 + same_cvs = same_cvs and self.options["replace-cvs"] == "yes"
757 + same_wsc = same_wsc and self.options["replace-wscomments"] == "yes"
758 + unmodified = unmodified and self.options["replace-unmodified"] == "yes"
759
760 if same_file:
761 - os.unlink (conf ['new'])
762 - self.post_process(conf['current'])
763 + os.unlink(conf["new"])
764 + self.post_process(conf["current"])
765 if os.path.exists(mrgconf):
766 os.unlink(mrgconf)
767 return False
768 - elif conf['current'] in frozen_files:
769 + elif conf["current"] in frozen_files:
770 """Frozen files are automatically zapped. The new config has
771 already been archived with a .new suffix. When zapped, it is
772 left with the .new suffix (post_process is skipped), since it
773 hasn't been merged into the current config."""
774 - auto_zapped.append(conf['current'])
775 - os.unlink(conf['new'])
776 + auto_zapped.append(conf["current"])
777 + os.unlink(conf["new"])
778 try:
779 os.unlink(mrgconf)
780 except OSError:
781 pass
782 return False
783 - elif unmodified or same_cvs or same_wsc or \
784 - not protect_obj.isprotected(conf['current']):
785 - self.replace(newconf, conf['current'])
786 - self.post_process(conf['current'])
787 + elif (
788 + unmodified
789 + or same_cvs
790 + or same_wsc
791 + or not protect_obj.isprotected(conf["current"])
792 + ):
793 + self.replace(newconf, conf["current"])
794 + self.post_process(conf["current"])
795 if newconf == mrgconf:
796 - os.unlink(conf['new'])
797 + os.unlink(conf["new"])
798 elif os.path.exists(mrgconf):
799 os.unlink(mrgconf)
800 return False
801 @@ -279,7 +315,7 @@ class dispatch:
802 valid_input = "qhtnmlezu"
803
804 def diff_pager(file1, file2):
805 - cmd = self.options['diff'] % (file1, file2)
806 + cmd = self.options["diff"] % (file1, file2)
807 cmd += pager
808 spawn_shell(cmd)
809
810 @@ -288,8 +324,8 @@ class dispatch:
811 for conf in confs:
812 count = count + 1
813
814 - newconf = conf['new']
815 - mrgconf = re.sub(r'\._cfg', '._mrg', newconf)
816 + newconf = conf["new"]
817 + mrgconf = re.sub(r"\._cfg", "._mrg", newconf)
818 if os.path.exists(mrgconf):
819 newconf = mrgconf
820 show_new_diff = 0
821 @@ -297,14 +333,20 @@ class dispatch:
822 while 1:
823 clear_screen()
824 if show_new_diff:
825 - diff_pager(conf['new'], mrgconf)
826 + diff_pager(conf["new"], mrgconf)
827 show_new_diff = 0
828 else:
829 - diff_pager(conf['current'], newconf)
830 + diff_pager(conf["current"], newconf)
831
832 print()
833 - writemsg_stdout('>> (%i of %i) -- %s\n' % (count, len(confs), conf['current']), noiselevel=-1)
834 - print('>> q quit, h help, n next, e edit-new, z zap-new, u use-new\n m merge, t toggle-merge, l look-merge: ', end=' ')
835 + writemsg_stdout(
836 + ">> (%i of %i) -- %s\n" % (count, len(confs), conf["current"]),
837 + noiselevel=-1,
838 + )
839 + print(
840 + ">> q quit, h help, n next, e edit-new, z zap-new, u use-new\n m merge, t toggle-merge, l look-merge: ",
841 + end=" ",
842 + )
843
844 # In some cases getch() will return some spurious characters
845 # that do not represent valid input. If we don't validate the
846 @@ -315,28 +357,30 @@ class dispatch:
847 while True:
848 c = getch()
849 if c in valid_input:
850 - sys.stdout.write('\n')
851 + sys.stdout.write("\n")
852 sys.stdout.flush()
853 break
854
855 - if c == 'q':
856 + if c == "q":
857 perform_conf_update_session_hooks("post-session")
858 - sys.exit (0)
859 - if c == 'h':
860 - self.do_help ()
861 + sys.exit(0)
862 + if c == "h":
863 + self.do_help()
864 continue
865 - elif c == 't':
866 + elif c == "t":
867 if newconf == mrgconf:
868 - newconf = conf['new']
869 + newconf = conf["new"]
870 elif os.path.exists(mrgconf):
871 newconf = mrgconf
872 continue
873 - elif c == 'n':
874 + elif c == "n":
875 break
876 - elif c == 'm':
877 - merged = SCRATCH_DIR+"/"+os.path.basename(conf['current'])
878 + elif c == "m":
879 + merged = SCRATCH_DIR + "/" + os.path.basename(conf["current"])
880 print()
881 - ret = os.system (self.options['merge'] % (merged, conf ['current'], newconf))
882 + ret = os.system(
883 + self.options["merge"] % (merged, conf["current"], newconf)
884 + )
885 ret = os.WEXITSTATUS(ret)
886 if ret < 2:
887 ret = 0
888 @@ -345,29 +389,29 @@ class dispatch:
889 continue
890 shutil.copyfile(merged, mrgconf)
891 os.remove(merged)
892 - mystat = os.lstat(conf['new'])
893 + mystat = os.lstat(conf["new"])
894 os.chmod(mrgconf, mystat[ST_MODE])
895 os.chown(mrgconf, mystat[ST_UID], mystat[ST_GID])
896 newconf = mrgconf
897 continue
898 - elif c == 'l':
899 + elif c == "l":
900 show_new_diff = 1
901 continue
902 - elif c == 'e':
903 - if 'EDITOR' not in os.environ:
904 - os.environ['EDITOR']='nano'
905 - os.system(os.environ['EDITOR'] + ' ' + newconf)
906 + elif c == "e":
907 + if "EDITOR" not in os.environ:
908 + os.environ["EDITOR"] = "nano"
909 + os.system(os.environ["EDITOR"] + " " + newconf)
910 continue
911 - elif c == 'z':
912 - os.unlink(conf['new'])
913 + elif c == "z":
914 + os.unlink(conf["new"])
915 if os.path.exists(mrgconf):
916 os.unlink(mrgconf)
917 break
918 - elif c == 'u':
919 - self.replace(newconf, conf ['current'])
920 - self.post_process(conf['current'])
921 + elif c == "u":
922 + self.replace(newconf, conf["current"])
923 + self.post_process(conf["current"])
924 if newconf == mrgconf:
925 - os.unlink(conf['new'])
926 + os.unlink(conf["new"])
927 elif os.path.exists(mrgconf):
928 os.unlink(mrgconf)
929 break
930 @@ -384,13 +428,14 @@ class dispatch:
931
932 perform_conf_update_session_hooks("post-session")
933
934 - def replace (self, newconf, curconf):
935 + def replace(self, newconf, curconf):
936 """Replace current config with the new/merged version. Also logs
937 the diff of what changed into the configured log file."""
938 if "log-file" in self.options:
939 status, output = diff(curconf, newconf)
940 - with io.open(self.options["log-file"], mode="a",
941 - encoding=_encodings["stdio"]) as f:
942 + with io.open(
943 + self.options["log-file"], mode="a", encoding=_encodings["stdio"]
944 + ) as f:
945 f.write(output + "\n")
946
947 perform_conf_update_hooks("pre-update", curconf)
948 @@ -398,22 +443,23 @@ class dispatch:
949 try:
950 os.rename(newconf, curconf)
951 except (IOError, os.error) as why:
952 - writemsg('dispatch-conf: Error renaming %s to %s: %s; fatal\n' % \
953 - (newconf, curconf, str(why)), noiselevel=-1)
954 + writemsg(
955 + "dispatch-conf: Error renaming %s to %s: %s; fatal\n"
956 + % (newconf, curconf, str(why)),
957 + noiselevel=-1,
958 + )
959 return
960
961 perform_conf_update_hooks("post-update", curconf)
962
963 -
964 def post_process(self, curconf):
965 - archive = os.path.join(self.options['archive-dir'], curconf.lstrip('/'))
966 - if self.options['use-rcs'] == 'yes':
967 + archive = os.path.join(self.options["archive-dir"], curconf.lstrip("/"))
968 + if self.options["use-rcs"] == "yes":
969 portage.dispatch_conf.rcs_archive_post_process(archive)
970 else:
971 portage.dispatch_conf.file_archive_post_process(archive)
972
973 -
974 - def massage (self, newconfigs):
975 + def massage(self, newconfigs):
976 """Sort, rstrip, remove old versions, break into triad hash.
977
978 Triad is dictionary of current (/etc/make.conf), new (/etc/._cfg0003_make.conf)
979 @@ -423,25 +469,25 @@ class dispatch:
980 """
981 h = {}
982 configs = []
983 - newconfigs.sort ()
984 + newconfigs.sort()
985
986 for nconf in newconfigs:
987 # Use strict mode here, because we want to know if it fails,
988 # and portage only merges files with valid UTF-8 encoding.
989 - nconf = _unicode_decode(nconf, errors='strict').rstrip()
990 - conf = re.sub (r'\._cfg\d+_', '', nconf)
991 - dirname = os.path.dirname(nconf)
992 - conf_map = {
993 - 'current' : conf,
994 - 'dir' : dirname,
995 - 'new' : nconf,
996 + nconf = _unicode_decode(nconf, errors="strict").rstrip()
997 + conf = re.sub(r"\._cfg\d+_", "", nconf)
998 + dirname = os.path.dirname(nconf)
999 + conf_map = {
1000 + "current": conf,
1001 + "dir": dirname,
1002 + "new": nconf,
1003 }
1004
1005 if conf in h:
1006 - mrgconf = re.sub(r'\._cfg', '._mrg', h[conf]['new'])
1007 + mrgconf = re.sub(r"\._cfg", "._mrg", h[conf]["new"])
1008 if os.path.exists(mrgconf):
1009 os.unlink(mrgconf)
1010 - os.unlink(h[conf]['new'])
1011 + os.unlink(h[conf]["new"])
1012 h[conf].update(conf_map)
1013 else:
1014 h[conf] = conf_map
1015 @@ -449,27 +495,27 @@ class dispatch:
1016
1017 return configs
1018
1019 -
1020 - def do_help (self):
1021 + def do_help(self):
1022 print()
1023 print()
1024
1025 - print(' u -- update current config with new config and continue')
1026 - print(' z -- zap (delete) new config and continue')
1027 - print(' n -- skip to next config, leave all intact')
1028 - print(' e -- edit new config')
1029 - print(' m -- interactively merge current and new configs')
1030 - print(' l -- look at diff between pre-merged and merged configs')
1031 - print(' t -- toggle new config between merged and pre-merged state')
1032 - print(' h -- this screen')
1033 - print(' q -- quit')
1034 + print(" u -- update current config with new config and continue")
1035 + print(" z -- zap (delete) new config and continue")
1036 + print(" n -- skip to next config, leave all intact")
1037 + print(" e -- edit new config")
1038 + print(" m -- interactively merge current and new configs")
1039 + print(" l -- look at diff between pre-merged and merged configs")
1040 + print(" t -- toggle new config between merged and pre-merged state")
1041 + print(" h -- this screen")
1042 + print(" q -- quit")
1043
1044 - print(); print('press any key to return to diff...', end=' ')
1045 + print()
1046 + print("press any key to return to diff...", end=" ")
1047
1048 - getch ()
1049 + getch()
1050
1051
1052 -def getch ():
1053 +def getch():
1054 # from ASPN - Danny Yoo
1055 #
1056
1057 @@ -482,6 +528,7 @@ def getch ():
1058 termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
1059 return ch
1060
1061 +
1062 def clear_screen():
1063 if curses is not None:
1064 try:
1065 @@ -493,40 +540,48 @@ def clear_screen():
1066 pass
1067 os.system("clear 2>/dev/null")
1068
1069 +
1070 shell = os.environ.get("SHELL")
1071 if not shell or not os.access(shell, os.EX_OK):
1072 shell = find_binary("sh")
1073
1074 +
1075 def spawn_shell(cmd):
1076 if shell:
1077 sys.__stdout__.flush()
1078 sys.__stderr__.flush()
1079 - spawn([shell, "-c", cmd], env=os.environ,
1080 - fd_pipes = { 0 : portage._get_stdin().fileno(),
1081 - 1 : sys.__stdout__.fileno(),
1082 - 2 : sys.__stderr__.fileno()})
1083 + spawn(
1084 + [shell, "-c", cmd],
1085 + env=os.environ,
1086 + fd_pipes={
1087 + 0: portage._get_stdin().fileno(),
1088 + 1: sys.__stdout__.fileno(),
1089 + 2: sys.__stderr__.fileno(),
1090 + },
1091 + )
1092 else:
1093 os.system(cmd)
1094
1095 +
1096 def usage(argv):
1097 - print('dispatch-conf: sane configuration file update\n')
1098 - print('Usage: dispatch-conf [config dirs]\n')
1099 - print('See the dispatch-conf(1) man page for more details')
1100 + print("dispatch-conf: sane configuration file update\n")
1101 + print("Usage: dispatch-conf [config dirs]\n")
1102 + print("See the dispatch-conf(1) man page for more details")
1103 sys.exit(os.EX_OK)
1104
1105 +
1106 for x in sys.argv:
1107 - if x in ('-h', '--help'):
1108 + if x in ("-h", "--help"):
1109 usage(sys.argv)
1110 - elif x in ('--version',):
1111 + elif x in ("--version",):
1112 print("Portage", portage.VERSION)
1113 sys.exit(os.EX_OK)
1114
1115 # run
1116 -d = dispatch ()
1117 +d = dispatch()
1118
1119 if len(sys.argv) > 1:
1120 # for testing
1121 d.grind(sys.argv[1:])
1122 else:
1123 - d.grind(portage.util.shlex_split(
1124 - portage.settings.get('CONFIG_PROTECT', '')))
1125 + d.grind(portage.util.shlex_split(portage.settings.get("CONFIG_PROTECT", "")))
1126
1127 diff --git a/bin/ebuild b/bin/ebuild
1128 index 3ad589008..bdedab9cb 100755
1129 --- a/bin/ebuild
1130 +++ b/bin/ebuild
1131 @@ -11,45 +11,58 @@ import textwrap
1132 # This block ensures that ^C interrupts are handled quietly.
1133 try:
1134
1135 - def exithandler(signum, _frame):
1136 - signal.signal(signal.SIGINT, signal.SIG_IGN)
1137 - signal.signal(signal.SIGTERM, signal.SIG_IGN)
1138 - sys.exit(128 + signum)
1139 + def exithandler(signum, _frame):
1140 + signal.signal(signal.SIGINT, signal.SIG_IGN)
1141 + signal.signal(signal.SIGTERM, signal.SIG_IGN)
1142 + sys.exit(128 + signum)
1143
1144 - signal.signal(signal.SIGINT, exithandler)
1145 - signal.signal(signal.SIGTERM, exithandler)
1146 - # Prevent "[Errno 32] Broken pipe" exceptions when
1147 - # writing to a pipe.
1148 - signal.signal(signal.SIGPIPE, signal.SIG_DFL)
1149 + signal.signal(signal.SIGINT, exithandler)
1150 + signal.signal(signal.SIGTERM, exithandler)
1151 + # Prevent "[Errno 32] Broken pipe" exceptions when
1152 + # writing to a pipe.
1153 + signal.signal(signal.SIGPIPE, signal.SIG_DFL)
1154
1155 except KeyboardInterrupt:
1156 - sys.exit(128 + signal.SIGINT)
1157 + sys.exit(128 + signal.SIGINT)
1158 +
1159
1160 def debug_signal(_signum, _frame):
1161 - import pdb
1162 - pdb.set_trace()
1163 + import pdb
1164 +
1165 + pdb.set_trace()
1166
1167 -if platform.python_implementation() == 'Jython':
1168 - debug_signum = signal.SIGUSR2 # bug #424259
1169 +
1170 +if platform.python_implementation() == "Jython":
1171 + debug_signum = signal.SIGUSR2 # bug #424259
1172 else:
1173 - debug_signum = signal.SIGUSR1
1174 + debug_signum = signal.SIGUSR1
1175
1176 signal.signal(debug_signum, debug_signal)
1177
1178 import io
1179 import os
1180 from os import path as osp
1181 -if osp.isfile(osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), ".portage_not_installed")):
1182 - sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "lib"))
1183 +
1184 +if osp.isfile(
1185 + osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), ".portage_not_installed")
1186 +):
1187 + sys.path.insert(
1188 + 0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "lib")
1189 + )
1190 import portage
1191 +
1192 portage._internal_caller = True
1193 from portage import os
1194 from portage import _encodings
1195 from portage import _shell_quote
1196 from portage import _unicode_encode
1197 from portage.const import VDB_PATH
1198 -from portage.exception import PermissionDenied, PortageKeyError, \
1199 - PortagePackageException, UnsupportedAPIException
1200 +from portage.exception import (
1201 + PermissionDenied,
1202 + PortageKeyError,
1203 + PortagePackageException,
1204 + UnsupportedAPIException,
1205 +)
1206 from portage.localization import _
1207 import portage.util
1208 from portage.util._eventloop.global_event_loop import global_event_loop
1209 @@ -63,65 +76,73 @@ description = "See the ebuild(1) man page for more info"
1210 usage = "Usage: ebuild <ebuild file> <command> [command] ..."
1211 parser = argparse.ArgumentParser(description=description, usage=usage)
1212
1213 -force_help = "When used together with the digest or manifest " + \
1214 - "command, this option forces regeneration of digests for all " + \
1215 - "distfiles associated with the current ebuild. Any distfiles " + \
1216 - "that do not already exist in ${DISTDIR} will be automatically fetched."
1217 +force_help = (
1218 + "When used together with the digest or manifest "
1219 + + "command, this option forces regeneration of digests for all "
1220 + + "distfiles associated with the current ebuild. Any distfiles "
1221 + + "that do not already exist in ${DISTDIR} will be automatically fetched."
1222 +)
1223
1224 parser.add_argument("--force", help=force_help, action="store_true")
1225 -parser.add_argument("--color", help="enable or disable color output",
1226 - choices=("y", "n"))
1227 -parser.add_argument("--debug", help="show debug output",
1228 - action="store_true")
1229 -parser.add_argument("--version", help="show version and exit",
1230 - action="store_true")
1231 -parser.add_argument("--ignore-default-opts",
1232 - action="store_true",
1233 - help="do not use the EBUILD_DEFAULT_OPTS environment variable")
1234 -parser.add_argument("--skip-manifest", help="skip all manifest checks",
1235 - action="store_true")
1236 +parser.add_argument(
1237 + "--color", help="enable or disable color output", choices=("y", "n")
1238 +)
1239 +parser.add_argument("--debug", help="show debug output", action="store_true")
1240 +parser.add_argument("--version", help="show version and exit", action="store_true")
1241 +parser.add_argument(
1242 + "--ignore-default-opts",
1243 + action="store_true",
1244 + help="do not use the EBUILD_DEFAULT_OPTS environment variable",
1245 +)
1246 +parser.add_argument(
1247 + "--skip-manifest", help="skip all manifest checks", action="store_true"
1248 +)
1249
1250 opts, pargs = parser.parse_known_args(args=sys.argv[1:])
1251
1252 +
1253 def err(txt):
1254 - portage.writemsg('ebuild: %s\n' % (txt,), noiselevel=-1)
1255 - sys.exit(1)
1256 + portage.writemsg("ebuild: %s\n" % (txt,), noiselevel=-1)
1257 + sys.exit(1)
1258 +
1259
1260 if opts.version:
1261 - print("Portage", portage.VERSION)
1262 - sys.exit(os.EX_OK)
1263 + print("Portage", portage.VERSION)
1264 + sys.exit(os.EX_OK)
1265
1266 if len(pargs) < 2:
1267 - parser.error("missing required args")
1268 + parser.error("missing required args")
1269
1270 if not opts.ignore_default_opts:
1271 - default_opts = portage.util.shlex_split(
1272 - portage.settings.get("EBUILD_DEFAULT_OPTS", ""))
1273 - opts, pargs = parser.parse_known_args(default_opts + sys.argv[1:])
1274 + default_opts = portage.util.shlex_split(
1275 + portage.settings.get("EBUILD_DEFAULT_OPTS", "")
1276 + )
1277 + opts, pargs = parser.parse_known_args(default_opts + sys.argv[1:])
1278
1279 debug = opts.debug
1280 force = opts.force
1281
1282 if debug:
1283 - # Ensure that all config instances have this setting,
1284 - # including the one that's used by portdbapi for aux_get.
1285 - os.environ['PORTAGE_DEBUG'] = '1'
1286 - portage._reset_legacy_globals()
1287 + # Ensure that all config instances have this setting,
1288 + # including the one that's used by portdbapi for aux_get.
1289 + os.environ["PORTAGE_DEBUG"] = "1"
1290 + portage._reset_legacy_globals()
1291
1292 # do this _after_ 'import portage' to prevent unnecessary tracing
1293 if debug and "python-trace" in portage.features:
1294 - portage.debug.set_trace(True)
1295 -
1296 -if not opts.color == 'y' and \
1297 - (opts.color == 'n' or \
1298 - portage.settings.get('NOCOLOR') in ('yes', 'true') or \
1299 - portage.settings.get('TERM') == 'dumb' or \
1300 - not sys.stdout.isatty()):
1301 - portage.output.nocolor()
1302 - portage.settings.unlock()
1303 - portage.settings['NOCOLOR'] = 'true'
1304 - portage.settings.backup_changes('NOCOLOR')
1305 - portage.settings.lock()
1306 + portage.debug.set_trace(True)
1307 +
1308 +if not opts.color == "y" and (
1309 + opts.color == "n"
1310 + or portage.settings.get("NOCOLOR") in ("yes", "true")
1311 + or portage.settings.get("TERM") == "dumb"
1312 + or not sys.stdout.isatty()
1313 +):
1314 + portage.output.nocolor()
1315 + portage.settings.unlock()
1316 + portage.settings["NOCOLOR"] = "true"
1317 + portage.settings.backup_changes("NOCOLOR")
1318 + portage.settings.lock()
1319
1320 apply_priorities(portage.settings)
1321
1322 @@ -129,118 +150,140 @@ ebuild = pargs.pop(0)
1323
1324 pf = None
1325 if ebuild.endswith(".ebuild"):
1326 - pf = os.path.basename(ebuild)[:-7]
1327 + pf = os.path.basename(ebuild)[:-7]
1328
1329 if pf is None:
1330 - err("%s: does not end with '.ebuild'" % (ebuild,))
1331 + err("%s: does not end with '.ebuild'" % (ebuild,))
1332
1333 if not os.path.isabs(ebuild):
1334 - mycwd = os.getcwd()
1335 - # Try to get the non-canonical path from the PWD evironment variable, since
1336 - # the canonical path returned from os.getcwd() may may be unusable in
1337 - # cases where the directory stucture is built from symlinks.
1338 - pwd = os.environ.get('PWD', '')
1339 - if pwd and pwd != mycwd and \
1340 - os.path.realpath(pwd) == mycwd:
1341 - mycwd = portage.normalize_path(pwd)
1342 - ebuild = os.path.join(mycwd, ebuild)
1343 + mycwd = os.getcwd()
1344 + # Try to get the non-canonical path from the PWD evironment variable, since
1345 + # the canonical path returned from os.getcwd() may may be unusable in
1346 + # cases where the directory stucture is built from symlinks.
1347 + pwd = os.environ.get("PWD", "")
1348 + if pwd and pwd != mycwd and os.path.realpath(pwd) == mycwd:
1349 + mycwd = portage.normalize_path(pwd)
1350 + ebuild = os.path.join(mycwd, ebuild)
1351 ebuild = portage.normalize_path(ebuild)
1352 # portdbapi uses the canonical path for the base of the ebuild repository, but
1353 # subdirectories of the base can be built from symlinks (like crossdev does).
1354 ebuild_portdir = os.path.realpath(
1355 - os.path.dirname(os.path.dirname(os.path.dirname(ebuild))))
1356 + os.path.dirname(os.path.dirname(os.path.dirname(ebuild)))
1357 +)
1358 ebuild = os.path.join(ebuild_portdir, *ebuild.split(os.path.sep)[-3:])
1359 -vdb_path = os.path.realpath(os.path.join(portage.settings['EROOT'], VDB_PATH))
1360 +vdb_path = os.path.realpath(os.path.join(portage.settings["EROOT"], VDB_PATH))
1361
1362 # Make sure that portdb.findname() returns the correct ebuild.
1363 -if ebuild_portdir != vdb_path and \
1364 - ebuild_portdir not in portage.portdb.porttrees:
1365 - portdir_overlay = portage.settings.get("PORTDIR_OVERLAY", "")
1366 - os.environ["PORTDIR_OVERLAY"] = (
1367 - portdir_overlay + " " + _shell_quote(ebuild_portdir))
1368 +if ebuild_portdir != vdb_path and ebuild_portdir not in portage.portdb.porttrees:
1369 + portdir_overlay = portage.settings.get("PORTDIR_OVERLAY", "")
1370 + os.environ["PORTDIR_OVERLAY"] = portdir_overlay + " " + _shell_quote(ebuild_portdir)
1371
1372 - print("Appending %s to PORTDIR_OVERLAY..." % ebuild_portdir)
1373 - portage._reset_legacy_globals()
1374 + print("Appending %s to PORTDIR_OVERLAY..." % ebuild_portdir)
1375 + portage._reset_legacy_globals()
1376
1377 myrepo = None
1378 if ebuild_portdir != vdb_path:
1379 - myrepo = portage.portdb.getRepositoryName(ebuild_portdir)
1380 + myrepo = portage.portdb.getRepositoryName(ebuild_portdir)
1381
1382 if not os.path.exists(ebuild):
1383 - err('%s: does not exist' % (ebuild,))
1384 + err("%s: does not exist" % (ebuild,))
1385
1386 ebuild_split = ebuild.split("/")
1387 cpv = "%s/%s" % (ebuild_split[-3], pf)
1388
1389 -with io.open(_unicode_encode(ebuild, encoding=_encodings['fs'], errors='strict'),
1390 - mode='r', encoding=_encodings['repo.content'], errors='replace') as f:
1391 - eapi = portage._parse_eapi_ebuild_head(f)[0]
1392 +with io.open(
1393 + _unicode_encode(ebuild, encoding=_encodings["fs"], errors="strict"),
1394 + mode="r",
1395 + encoding=_encodings["repo.content"],
1396 + errors="replace",
1397 +) as f:
1398 + eapi = portage._parse_eapi_ebuild_head(f)[0]
1399 if eapi is None:
1400 - eapi = "0"
1401 + eapi = "0"
1402 if not portage.catpkgsplit(cpv, eapi=eapi):
1403 - err('%s: %s: does not follow correct package syntax' % (ebuild, cpv))
1404 + err("%s: %s: does not follow correct package syntax" % (ebuild, cpv))
1405
1406 if ebuild.startswith(vdb_path):
1407 - mytree = "vartree"
1408 - pkg_type = "installed"
1409 + mytree = "vartree"
1410 + pkg_type = "installed"
1411
1412 - portage_ebuild = portage.db[portage.root][mytree].dbapi.findname(cpv, myrepo=myrepo)
1413 + portage_ebuild = portage.db[portage.root][mytree].dbapi.findname(cpv, myrepo=myrepo)
1414
1415 - if os.path.realpath(portage_ebuild) != ebuild:
1416 - err('Portage seems to think that %s is at %s' % (cpv, portage_ebuild))
1417 + if os.path.realpath(portage_ebuild) != ebuild:
1418 + err("Portage seems to think that %s is at %s" % (cpv, portage_ebuild))
1419
1420 else:
1421 - mytree = "porttree"
1422 - pkg_type = "ebuild"
1423 + mytree = "porttree"
1424 + pkg_type = "ebuild"
1425
1426 - portage_ebuild = portage.portdb.findname(cpv, myrepo=myrepo)
1427 + portage_ebuild = portage.portdb.findname(cpv, myrepo=myrepo)
1428
1429 - if not portage_ebuild or portage_ebuild != ebuild:
1430 - err('%s: does not seem to have a valid PORTDIR structure' % (ebuild,))
1431 + if not portage_ebuild or portage_ebuild != ebuild:
1432 + err("%s: does not seem to have a valid PORTDIR structure" % (ebuild,))
1433
1434 if len(pargs) > 1 and "config" in pargs:
1435 - other_phases = set(pargs)
1436 - other_phases.difference_update(
1437 - ("clean", "config", "digest", "manifest"))
1438 - if other_phases:
1439 - err('"config" must not be called with any other phase')
1440 + other_phases = set(pargs)
1441 + other_phases.difference_update(("clean", "config", "digest", "manifest"))
1442 + if other_phases:
1443 + err('"config" must not be called with any other phase')
1444 +
1445
1446 def discard_digests(myebuild, mysettings, mydbapi):
1447 - """Discard all distfiles digests for the given ebuild. This is useful when
1448 - upstream has changed the identity of the distfiles and the user would
1449 - otherwise have to manually remove the Manifest and files/digest-* files in
1450 - order to ensure correct results."""
1451 - try:
1452 - portage._doebuild_manifest_exempt_depend += 1
1453 - pkgdir = os.path.dirname(myebuild)
1454 - fetchlist_dict = portage.FetchlistDict(pkgdir, mysettings, mydbapi)
1455 - mf = mysettings.repositories.get_repo_for_location(
1456 - os.path.dirname(os.path.dirname(pkgdir)))
1457 - mf = mf.load_manifest(pkgdir, mysettings["DISTDIR"],
1458 - fetchlist_dict=fetchlist_dict)
1459 - mf.create(requiredDistfiles=None,
1460 - assumeDistHashesSometimes=True, assumeDistHashesAlways=True)
1461 - distfiles = fetchlist_dict[cpv]
1462 - for myfile in distfiles:
1463 - try:
1464 - del mf.fhashdict["DIST"][myfile]
1465 - except KeyError:
1466 - pass
1467 - mf.write()
1468 - finally:
1469 - portage._doebuild_manifest_exempt_depend -= 1
1470 -
1471 -portage.settings.validate() # generate warning messages if necessary
1472 -
1473 -build_dir_phases = set(["setup", "unpack", "prepare", "configure", "compile",
1474 - "test", "install", "package", "rpm", "merge", "qmerge"])
1475 + """Discard all distfiles digests for the given ebuild. This is useful when
1476 + upstream has changed the identity of the distfiles and the user would
1477 + otherwise have to manually remove the Manifest and files/digest-* files in
1478 + order to ensure correct results."""
1479 + try:
1480 + portage._doebuild_manifest_exempt_depend += 1
1481 + pkgdir = os.path.dirname(myebuild)
1482 + fetchlist_dict = portage.FetchlistDict(pkgdir, mysettings, mydbapi)
1483 + mf = mysettings.repositories.get_repo_for_location(
1484 + os.path.dirname(os.path.dirname(pkgdir))
1485 + )
1486 + mf = mf.load_manifest(
1487 + pkgdir, mysettings["DISTDIR"], fetchlist_dict=fetchlist_dict
1488 + )
1489 + mf.create(
1490 + requiredDistfiles=None,
1491 + assumeDistHashesSometimes=True,
1492 + assumeDistHashesAlways=True,
1493 + )
1494 + distfiles = fetchlist_dict[cpv]
1495 + for myfile in distfiles:
1496 + try:
1497 + del mf.fhashdict["DIST"][myfile]
1498 + except KeyError:
1499 + pass
1500 + mf.write()
1501 + finally:
1502 + portage._doebuild_manifest_exempt_depend -= 1
1503 +
1504 +
1505 +portage.settings.validate() # generate warning messages if necessary
1506 +
1507 +build_dir_phases = set(
1508 + [
1509 + "setup",
1510 + "unpack",
1511 + "prepare",
1512 + "configure",
1513 + "compile",
1514 + "test",
1515 + "install",
1516 + "package",
1517 + "rpm",
1518 + "merge",
1519 + "qmerge",
1520 + ]
1521 +)
1522
1523 # If the current metadata is invalid then force the ebuild to be
1524 # sourced again even if $T/environment already exists.
1525 ebuild_changed = False
1526 if mytree == "porttree" and build_dir_phases.intersection(pargs):
1527 - ebuild_changed = \
1528 - portage.portdb._pull_valid_cache(cpv, ebuild, ebuild_portdir)[0] is None
1529 + ebuild_changed = (
1530 + portage.portdb._pull_valid_cache(cpv, ebuild, ebuild_portdir)[0] is None
1531 + )
1532
1533 # Make configuration adjustments to portage.portdb.doebuild_settings,
1534 # in order to enforce consistency for EBUILD_FORCE_TEST support
1535 @@ -251,35 +294,37 @@ tmpsettings["PORTAGE_VERBOSE"] = "1"
1536 tmpsettings.backup_changes("PORTAGE_VERBOSE")
1537
1538 if opts.skip_manifest:
1539 - tmpsettings["EBUILD_SKIP_MANIFEST"] = "1"
1540 - tmpsettings.backup_changes("EBUILD_SKIP_MANIFEST")
1541 + tmpsettings["EBUILD_SKIP_MANIFEST"] = "1"
1542 + tmpsettings.backup_changes("EBUILD_SKIP_MANIFEST")
1543
1544 -if opts.skip_manifest or \
1545 - "digest" in tmpsettings.features or \
1546 - "digest" in pargs or \
1547 - "manifest" in pargs:
1548 - portage._doebuild_manifest_exempt_depend += 1
1549 +if (
1550 + opts.skip_manifest
1551 + or "digest" in tmpsettings.features
1552 + or "digest" in pargs
1553 + or "manifest" in pargs
1554 +):
1555 + portage._doebuild_manifest_exempt_depend += 1
1556
1557 if "test" in pargs:
1558 - # This variable is a signal to config.regenerate() to
1559 - # indicate that the test phase should be enabled regardless
1560 - # of problems such as masked "test" USE flag.
1561 - tmpsettings["EBUILD_FORCE_TEST"] = "1"
1562 - tmpsettings.backup_changes("EBUILD_FORCE_TEST")
1563 - tmpsettings.features.add("test")
1564 - portage.writemsg(_("Forcing test.\n"), noiselevel=-1)
1565 + # This variable is a signal to config.regenerate() to
1566 + # indicate that the test phase should be enabled regardless
1567 + # of problems such as masked "test" USE flag.
1568 + tmpsettings["EBUILD_FORCE_TEST"] = "1"
1569 + tmpsettings.backup_changes("EBUILD_FORCE_TEST")
1570 + tmpsettings.features.add("test")
1571 + portage.writemsg(_("Forcing test.\n"), noiselevel=-1)
1572
1573 tmpsettings.features.discard("fail-clean")
1574
1575 if "merge" in pargs and "noauto" in tmpsettings.features:
1576 - print("Disabling noauto in features... merge disables it. (qmerge doesn't)")
1577 - tmpsettings.features.discard("noauto")
1578 + print("Disabling noauto in features... merge disables it. (qmerge doesn't)")
1579 + tmpsettings.features.discard("noauto")
1580
1581 -if 'digest' in tmpsettings.features:
1582 - if pargs and pargs[0] not in ("digest", "manifest"):
1583 - pargs = ['digest'] + pargs
1584 - # We only need to build digests on the first pass.
1585 - tmpsettings.features.discard('digest')
1586 +if "digest" in tmpsettings.features:
1587 + if pargs and pargs[0] not in ("digest", "manifest"):
1588 + pargs = ["digest"] + pargs
1589 + # We only need to build digests on the first pass.
1590 + tmpsettings.features.discard("digest")
1591
1592 # Now that configuration adjustments are complete, create a clone of
1593 # tmpsettings. The current instance refers to portdb.doebuild_settings,
1594 @@ -287,25 +332,35 @@ if 'digest' in tmpsettings.features:
1595 tmpsettings = portage.config(clone=tmpsettings)
1596
1597 try:
1598 - metadata = dict(zip(Package.metadata_keys,
1599 - portage.db[portage.settings['EROOT']][mytree].dbapi.aux_get(
1600 - cpv, Package.metadata_keys, myrepo=myrepo)))
1601 + metadata = dict(
1602 + zip(
1603 + Package.metadata_keys,
1604 + portage.db[portage.settings["EROOT"]][mytree].dbapi.aux_get(
1605 + cpv, Package.metadata_keys, myrepo=myrepo
1606 + ),
1607 + )
1608 + )
1609 except PortageKeyError:
1610 - # aux_get failure, message should have been shown on stderr.
1611 - sys.exit(1)
1612 -
1613 -root_config = RootConfig(portage.settings,
1614 - portage.db[portage.settings['EROOT']], None)
1615 -
1616 -cpv = portage.versions._pkg_str(cpv,
1617 - metadata=metadata,
1618 - settings=portage.settings,
1619 - db=portage.db[portage.settings['EROOT']][mytree].dbapi)
1620 -
1621 -pkg = Package(built=(pkg_type != "ebuild"), cpv=cpv,
1622 - installed=(pkg_type=="installed"),
1623 - metadata=metadata, root_config=root_config,
1624 - type_name=pkg_type)
1625 + # aux_get failure, message should have been shown on stderr.
1626 + sys.exit(1)
1627 +
1628 +root_config = RootConfig(portage.settings, portage.db[portage.settings["EROOT"]], None)
1629 +
1630 +cpv = portage.versions._pkg_str(
1631 + cpv,
1632 + metadata=metadata,
1633 + settings=portage.settings,
1634 + db=portage.db[portage.settings["EROOT"]][mytree].dbapi,
1635 +)
1636 +
1637 +pkg = Package(
1638 + built=(pkg_type != "ebuild"),
1639 + cpv=cpv,
1640 + installed=(pkg_type == "installed"),
1641 + metadata=metadata,
1642 + root_config=root_config,
1643 + type_name=pkg_type,
1644 +)
1645
1646 # Apply package.env and repo-level settings. This allows per-package
1647 # FEATURES and other variables (possibly PORTAGE_TMPDIR) to be
1648 @@ -315,63 +370,76 @@ pkg = Package(built=(pkg_type != "ebuild"), cpv=cpv,
1649 # portdb.porttrees in order to accomplish this).
1650 tmpsettings.setcpv(pkg)
1651
1652 +
1653 def stale_env_warning():
1654 - if "clean" not in pargs and \
1655 - "noauto" not in tmpsettings.features and \
1656 - build_dir_phases.intersection(pargs):
1657 - portage.doebuild_environment(ebuild, "setup", portage.root,
1658 - tmpsettings, debug, 1, portage.portdb)
1659 - env_filename = os.path.join(tmpsettings["T"], "environment")
1660 - if os.path.exists(env_filename):
1661 - msg = ("Existing ${T}/environment for '%s' will be sourced. " + \
1662 - "Run 'clean' to start with a fresh environment.") % \
1663 - (tmpsettings["PF"], )
1664 - msg = textwrap.wrap(msg, 70)
1665 - for x in msg:
1666 - portage.writemsg(">>> %s\n" % x)
1667 -
1668 - if ebuild_changed:
1669 - open(os.path.join(tmpsettings['PORTAGE_BUILDDIR'],
1670 - '.ebuild_changed'), 'w').close()
1671 + if (
1672 + "clean" not in pargs
1673 + and "noauto" not in tmpsettings.features
1674 + and build_dir_phases.intersection(pargs)
1675 + ):
1676 + portage.doebuild_environment(
1677 + ebuild, "setup", portage.root, tmpsettings, debug, 1, portage.portdb
1678 + )
1679 + env_filename = os.path.join(tmpsettings["T"], "environment")
1680 + if os.path.exists(env_filename):
1681 + msg = (
1682 + "Existing ${T}/environment for '%s' will be sourced. "
1683 + + "Run 'clean' to start with a fresh environment."
1684 + ) % (tmpsettings["PF"],)
1685 + msg = textwrap.wrap(msg, 70)
1686 + for x in msg:
1687 + portage.writemsg(">>> %s\n" % x)
1688 +
1689 + if ebuild_changed:
1690 + open(
1691 + os.path.join(tmpsettings["PORTAGE_BUILDDIR"], ".ebuild_changed"),
1692 + "w",
1693 + ).close()
1694 +
1695
1696 checked_for_stale_env = False
1697
1698 for arg in pargs:
1699 - try:
1700 - if not checked_for_stale_env and arg not in ("digest","manifest"):
1701 - # This has to go after manifest generation since otherwise
1702 - # aux_get() might fail due to invalid ebuild digests.
1703 - stale_env_warning()
1704 - checked_for_stale_env = True
1705 -
1706 - if arg in ("digest", "manifest") and force:
1707 - discard_digests(ebuild, tmpsettings, portage.portdb)
1708 - a = portage.doebuild(ebuild, arg, settings=tmpsettings,
1709 - debug=debug, tree=mytree,
1710 - vartree=portage.db[portage.root]['vartree'])
1711 - except KeyboardInterrupt:
1712 - print("Interrupted.")
1713 - a = 1
1714 - except PortageKeyError:
1715 - # aux_get error
1716 - a = 1
1717 - except UnsupportedAPIException as e:
1718 - msg = textwrap.wrap(str(e), 70)
1719 - del e
1720 - for x in msg:
1721 - portage.writemsg("!!! %s\n" % x, noiselevel=-1)
1722 - a = 1
1723 - except PortagePackageException as e:
1724 - portage.writemsg("!!! %s\n" % (e,), noiselevel=-1)
1725 - a = 1
1726 - except PermissionDenied as e:
1727 - portage.writemsg("!!! Permission Denied: %s\n" % (e,), noiselevel=-1)
1728 - a = 1
1729 - if a == None:
1730 - print("Could not run the required binary?")
1731 - a = 127
1732 - if a:
1733 - global_event_loop().close()
1734 - sys.exit(a)
1735 + try:
1736 + if not checked_for_stale_env and arg not in ("digest", "manifest"):
1737 + # This has to go after manifest generation since otherwise
1738 + # aux_get() might fail due to invalid ebuild digests.
1739 + stale_env_warning()
1740 + checked_for_stale_env = True
1741 +
1742 + if arg in ("digest", "manifest") and force:
1743 + discard_digests(ebuild, tmpsettings, portage.portdb)
1744 + a = portage.doebuild(
1745 + ebuild,
1746 + arg,
1747 + settings=tmpsettings,
1748 + debug=debug,
1749 + tree=mytree,
1750 + vartree=portage.db[portage.root]["vartree"],
1751 + )
1752 + except KeyboardInterrupt:
1753 + print("Interrupted.")
1754 + a = 1
1755 + except PortageKeyError:
1756 + # aux_get error
1757 + a = 1
1758 + except UnsupportedAPIException as e:
1759 + msg = textwrap.wrap(str(e), 70)
1760 + del e
1761 + for x in msg:
1762 + portage.writemsg("!!! %s\n" % x, noiselevel=-1)
1763 + a = 1
1764 + except PortagePackageException as e:
1765 + portage.writemsg("!!! %s\n" % (e,), noiselevel=-1)
1766 + a = 1
1767 + except PermissionDenied as e:
1768 + portage.writemsg("!!! Permission Denied: %s\n" % (e,), noiselevel=-1)
1769 + a = 1
1770 + if a == None:
1771 + print("Could not run the required binary?")
1772 + a = 127
1773 + if a:
1774 + global_event_loop().close()
1775 + sys.exit(a)
1776
1777 global_event_loop().close()
1778
1779 diff --git a/bin/egencache b/bin/egencache
1780 index b590a5529..2b523c7b3 100755
1781 --- a/bin/egencache
1782 +++ b/bin/egencache
1783 @@ -11,25 +11,28 @@ import sys
1784 # This block ensures that ^C interrupts are handled quietly.
1785 try:
1786
1787 - def exithandler(signum, _frame):
1788 - signal.signal(signal.SIGINT, signal.SIG_IGN)
1789 - signal.signal(signal.SIGTERM, signal.SIG_IGN)
1790 - sys.exit(128 + signum)
1791 + def exithandler(signum, _frame):
1792 + signal.signal(signal.SIGINT, signal.SIG_IGN)
1793 + signal.signal(signal.SIGTERM, signal.SIG_IGN)
1794 + sys.exit(128 + signum)
1795
1796 - signal.signal(signal.SIGINT, exithandler)
1797 - signal.signal(signal.SIGTERM, exithandler)
1798 + signal.signal(signal.SIGINT, exithandler)
1799 + signal.signal(signal.SIGTERM, exithandler)
1800
1801 except KeyboardInterrupt:
1802 - sys.exit(128 + signal.SIGINT)
1803 + sys.exit(128 + signal.SIGINT)
1804 +
1805
1806 def debug_signal(_signum, _frame):
1807 - import pdb
1808 - pdb.set_trace()
1809 + import pdb
1810 +
1811 + pdb.set_trace()
1812 +
1813
1814 -if platform.python_implementation() == 'Jython':
1815 - debug_signum = signal.SIGUSR2 # bug #424259
1816 +if platform.python_implementation() == "Jython":
1817 + debug_signum = signal.SIGUSR2 # bug #424259
1818 else:
1819 - debug_signum = signal.SIGUSR1
1820 + debug_signum = signal.SIGUSR1
1821
1822 signal.signal(debug_signum, debug_signal)
1823
1824 @@ -42,17 +45,28 @@ import textwrap
1825 import re
1826
1827 from os import path as osp
1828 -if osp.isfile(osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), ".portage_not_installed")):
1829 - sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "lib"))
1830 +
1831 +if osp.isfile(
1832 + osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), ".portage_not_installed")
1833 +):
1834 + sys.path.insert(
1835 + 0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "lib")
1836 + )
1837 import portage
1838 +
1839 portage._internal_caller = True
1840 from portage import os, _encodings, _unicode_encode, _unicode_decode
1841 from portage.cache.cache_errors import CacheError, StatCollision
1842 -from portage.cache.index.pkg_desc_index import pkg_desc_index_line_format, pkg_desc_index_line_read
1843 +from portage.cache.index.pkg_desc_index import (
1844 + pkg_desc_index_line_format,
1845 + pkg_desc_index_line_read,
1846 +)
1847 from portage.const import TIMESTAMP_FORMAT
1848 from portage.dep import _repo_separator
1849 from portage.output import colorize, EOutput
1850 -from portage.package.ebuild._parallel_manifest.ManifestScheduler import ManifestScheduler
1851 +from portage.package.ebuild._parallel_manifest.ManifestScheduler import (
1852 + ManifestScheduler,
1853 +)
1854 from portage.util import cmp_sort_key, writemsg_level
1855 from portage.util._async.AsyncFunction import AsyncFunction
1856 from portage.util._async.run_main_scheduler import run_main_scheduler
1857 @@ -65,1125 +79,1326 @@ from portage.versions import vercmp
1858 from _emerge.MetadataRegen import MetadataRegen
1859
1860 try:
1861 - from xml.etree import ElementTree
1862 + from xml.etree import ElementTree
1863 except ImportError:
1864 - pass
1865 + pass
1866 else:
1867 - try:
1868 - from xml.parsers.expat import ExpatError
1869 - except ImportError:
1870 - pass
1871 - else:
1872 - from portage.xml.metadata import parse_metadata_use # pylint: disable=ungrouped-imports
1873 + try:
1874 + from xml.parsers.expat import ExpatError
1875 + except ImportError:
1876 + pass
1877 + else:
1878 + from portage.xml.metadata import ( # pylint: disable=ungrouped-imports
1879 + parse_metadata_use,
1880 + )
1881
1882
1883 def parse_args(args):
1884 - usage = "egencache [options] <action> ... [atom] ..."
1885 - parser = argparse.ArgumentParser(usage=usage)
1886 -
1887 - actions = parser.add_argument_group('Actions')
1888 - actions.add_argument("--update",
1889 - action="store_true",
1890 - help="update metadata/md5-cache/ (generate as necessary)")
1891 - actions.add_argument("--update-use-local-desc",
1892 - action="store_true",
1893 - help="update the use.local.desc file from metadata.xml")
1894 - actions.add_argument("--update-changelogs",
1895 - action="store_true",
1896 - help="update the ChangeLog files from SCM logs")
1897 - actions.add_argument("--update-pkg-desc-index",
1898 - action="store_true",
1899 - help="update package description index")
1900 - actions.add_argument("--update-manifests",
1901 - action="store_true",
1902 - help="update manifests")
1903 -
1904 - common = parser.add_argument_group('Common options')
1905 - common.add_argument("--repo",
1906 - action="store",
1907 - help="name of repo to operate on")
1908 - common.add_argument("--config-root",
1909 - help="location of portage config files",
1910 - dest="portage_configroot")
1911 - common.add_argument("--external-cache-only",
1912 - action="store_true",
1913 - help="Output only to the external cache (not the repository itself)")
1914 - common.add_argument("--gpg-dir",
1915 - help="override the PORTAGE_GPG_DIR variable",
1916 - dest="gpg_dir")
1917 - common.add_argument("--gpg-key",
1918 - help="override the PORTAGE_GPG_KEY variable",
1919 - dest="gpg_key")
1920 - common.add_argument("--repositories-configuration",
1921 - help="override configuration of repositories (in format of repos.conf)",
1922 - dest="repositories_configuration")
1923 - common.add_argument("--sign-manifests",
1924 - choices=('y', 'n'),
1925 - metavar="<y|n>",
1926 - help="manually override layout.conf sign-manifests setting")
1927 - common.add_argument("--strict-manifests",
1928 - choices=('y', 'n'),
1929 - metavar="<y|n>",
1930 - help="manually override \"strict\" FEATURES setting")
1931 - common.add_argument("--thin-manifests",
1932 - choices=('y', 'n'),
1933 - metavar="<y|n>",
1934 - help="manually override layout.conf thin-manifests setting")
1935 - common.add_argument("--tolerant",
1936 - action="store_true",
1937 - help="exit successfully if only minor errors occurred")
1938 - common.add_argument("--ignore-default-opts",
1939 - action="store_true",
1940 - help="do not use the EGENCACHE_DEFAULT_OPTS environment variable")
1941 - common.add_argument("-v", "--verbose",
1942 - action="count", default=0,
1943 - help="increase verbosity")
1944 - common.add_argument("--write-timestamp",
1945 - action="store_true",
1946 - help="write metadata/timestamp.chk as required for rsync repositories")
1947 -
1948 - update = parser.add_argument_group('--update options')
1949 - update.add_argument("--cache-dir",
1950 - help="location of the metadata cache",
1951 - dest="cache_dir")
1952 - update.add_argument("-j", "--jobs",
1953 - type=int,
1954 - action="store",
1955 - help="max ebuild processes to spawn")
1956 - update.add_argument("--load-average",
1957 - type=float,
1958 - action="store",
1959 - help="max load allowed when spawning multiple jobs",
1960 - dest="load_average")
1961 - update.add_argument("--rsync",
1962 - action="store_true",
1963 - help="enable rsync stat collision workaround " + \
1964 - "for bug 139134 (use with --update)")
1965 -
1966 - uld = parser.add_argument_group('--update-use-local-desc options')
1967 - uld.add_argument("--preserve-comments",
1968 - action="store_true",
1969 - help="preserve the comments from the existing use.local.desc file")
1970 - uld.add_argument("--use-local-desc-output",
1971 - help="output file for use.local.desc data (or '-' for stdout)",
1972 - dest="uld_output")
1973 -
1974 - uc = parser.add_argument_group('--update-changelogs options')
1975 - uc.add_argument("--changelog-reversed",
1976 - action="store_true",
1977 - help="log commits in reverse order (oldest first)")
1978 - uc.add_argument("--changelog-output",
1979 - help="output filename for change logs",
1980 - dest="changelog_output",
1981 - default="ChangeLog")
1982 -
1983 - options, args = parser.parse_known_args(args)
1984 -
1985 - if options.jobs:
1986 - jobs = None
1987 - try:
1988 - jobs = int(options.jobs)
1989 - except ValueError:
1990 - jobs = -1
1991 -
1992 - if jobs < 1:
1993 - parser.error("Invalid: --jobs='%s'" % \
1994 - (options.jobs,))
1995 -
1996 - options.jobs = jobs
1997 -
1998 - else:
1999 - options.jobs = None
2000 -
2001 - if options.load_average:
2002 - try:
2003 - load_average = float(options.load_average)
2004 - except ValueError:
2005 - load_average = 0.0
2006 -
2007 - if load_average <= 0.0:
2008 - parser.error("Invalid: --load-average='%s'" % \
2009 - (options.load_average,))
2010 -
2011 - options.load_average = load_average
2012 -
2013 - else:
2014 - options.load_average = None
2015 -
2016 - options.config_root = options.portage_configroot
2017 - if options.config_root is not None and \
2018 - not os.path.isdir(options.config_root):
2019 - parser.error("Not a directory: --config-root='%s'" % \
2020 - (options.config_root,))
2021 -
2022 - if options.cache_dir is not None:
2023 - if not os.path.isdir(options.cache_dir):
2024 - parser.error("Not a directory: --cache-dir='%s'" % \
2025 - (options.cache_dir,))
2026 - if not os.access(options.cache_dir, os.W_OK):
2027 - parser.error("Write access denied: --cache-dir='%s'" % \
2028 - (options.cache_dir,))
2029 -
2030 - for atom in args:
2031 - try:
2032 - atom = portage.dep.Atom(atom)
2033 - except portage.exception.InvalidAtom:
2034 - parser.error('Invalid atom: %s' % (atom,))
2035 -
2036 - if not isjustname(atom):
2037 - parser.error('Atom is too specific: %s' % (atom,))
2038 -
2039 - if options.update_use_local_desc:
2040 - try:
2041 - ElementTree
2042 - ExpatError
2043 - except NameError:
2044 - parser.error('--update-use-local-desc requires python with USE=xml!')
2045 -
2046 - if options.uld_output == '-' and options.preserve_comments:
2047 - parser.error('--preserve-comments can not be used when outputting to stdout')
2048 -
2049 - return parser, options, args
2050 + usage = "egencache [options] <action> ... [atom] ..."
2051 + parser = argparse.ArgumentParser(usage=usage)
2052 +
2053 + actions = parser.add_argument_group("Actions")
2054 + actions.add_argument(
2055 + "--update",
2056 + action="store_true",
2057 + help="update metadata/md5-cache/ (generate as necessary)",
2058 + )
2059 + actions.add_argument(
2060 + "--update-use-local-desc",
2061 + action="store_true",
2062 + help="update the use.local.desc file from metadata.xml",
2063 + )
2064 + actions.add_argument(
2065 + "--update-changelogs",
2066 + action="store_true",
2067 + help="update the ChangeLog files from SCM logs",
2068 + )
2069 + actions.add_argument(
2070 + "--update-pkg-desc-index",
2071 + action="store_true",
2072 + help="update package description index",
2073 + )
2074 + actions.add_argument(
2075 + "--update-manifests", action="store_true", help="update manifests"
2076 + )
2077 +
2078 + common = parser.add_argument_group("Common options")
2079 + common.add_argument("--repo", action="store", help="name of repo to operate on")
2080 + common.add_argument(
2081 + "--config-root",
2082 + help="location of portage config files",
2083 + dest="portage_configroot",
2084 + )
2085 + common.add_argument(
2086 + "--external-cache-only",
2087 + action="store_true",
2088 + help="Output only to the external cache (not the repository itself)",
2089 + )
2090 + common.add_argument(
2091 + "--gpg-dir", help="override the PORTAGE_GPG_DIR variable", dest="gpg_dir"
2092 + )
2093 + common.add_argument(
2094 + "--gpg-key", help="override the PORTAGE_GPG_KEY variable", dest="gpg_key"
2095 + )
2096 + common.add_argument(
2097 + "--repositories-configuration",
2098 + help="override configuration of repositories (in format of repos.conf)",
2099 + dest="repositories_configuration",
2100 + )
2101 + common.add_argument(
2102 + "--sign-manifests",
2103 + choices=("y", "n"),
2104 + metavar="<y|n>",
2105 + help="manually override layout.conf sign-manifests setting",
2106 + )
2107 + common.add_argument(
2108 + "--strict-manifests",
2109 + choices=("y", "n"),
2110 + metavar="<y|n>",
2111 + help='manually override "strict" FEATURES setting',
2112 + )
2113 + common.add_argument(
2114 + "--thin-manifests",
2115 + choices=("y", "n"),
2116 + metavar="<y|n>",
2117 + help="manually override layout.conf thin-manifests setting",
2118 + )
2119 + common.add_argument(
2120 + "--tolerant",
2121 + action="store_true",
2122 + help="exit successfully if only minor errors occurred",
2123 + )
2124 + common.add_argument(
2125 + "--ignore-default-opts",
2126 + action="store_true",
2127 + help="do not use the EGENCACHE_DEFAULT_OPTS environment variable",
2128 + )
2129 + common.add_argument(
2130 + "-v", "--verbose", action="count", default=0, help="increase verbosity"
2131 + )
2132 + common.add_argument(
2133 + "--write-timestamp",
2134 + action="store_true",
2135 + help="write metadata/timestamp.chk as required for rsync repositories",
2136 + )
2137 +
2138 + update = parser.add_argument_group("--update options")
2139 + update.add_argument(
2140 + "--cache-dir", help="location of the metadata cache", dest="cache_dir"
2141 + )
2142 + update.add_argument(
2143 + "-j", "--jobs", type=int, action="store", help="max ebuild processes to spawn"
2144 + )
2145 + update.add_argument(
2146 + "--load-average",
2147 + type=float,
2148 + action="store",
2149 + help="max load allowed when spawning multiple jobs",
2150 + dest="load_average",
2151 + )
2152 + update.add_argument(
2153 + "--rsync",
2154 + action="store_true",
2155 + help="enable rsync stat collision workaround "
2156 + + "for bug 139134 (use with --update)",
2157 + )
2158 +
2159 + uld = parser.add_argument_group("--update-use-local-desc options")
2160 + uld.add_argument(
2161 + "--preserve-comments",
2162 + action="store_true",
2163 + help="preserve the comments from the existing use.local.desc file",
2164 + )
2165 + uld.add_argument(
2166 + "--use-local-desc-output",
2167 + help="output file for use.local.desc data (or '-' for stdout)",
2168 + dest="uld_output",
2169 + )
2170 +
2171 + uc = parser.add_argument_group("--update-changelogs options")
2172 + uc.add_argument(
2173 + "--changelog-reversed",
2174 + action="store_true",
2175 + help="log commits in reverse order (oldest first)",
2176 + )
2177 + uc.add_argument(
2178 + "--changelog-output",
2179 + help="output filename for change logs",
2180 + dest="changelog_output",
2181 + default="ChangeLog",
2182 + )
2183 +
2184 + options, args = parser.parse_known_args(args)
2185 +
2186 + if options.jobs:
2187 + jobs = None
2188 + try:
2189 + jobs = int(options.jobs)
2190 + except ValueError:
2191 + jobs = -1
2192 +
2193 + if jobs < 1:
2194 + parser.error("Invalid: --jobs='%s'" % (options.jobs,))
2195 +
2196 + options.jobs = jobs
2197 +
2198 + else:
2199 + options.jobs = None
2200 +
2201 + if options.load_average:
2202 + try:
2203 + load_average = float(options.load_average)
2204 + except ValueError:
2205 + load_average = 0.0
2206 +
2207 + if load_average <= 0.0:
2208 + parser.error("Invalid: --load-average='%s'" % (options.load_average,))
2209 +
2210 + options.load_average = load_average
2211 +
2212 + else:
2213 + options.load_average = None
2214 +
2215 + options.config_root = options.portage_configroot
2216 + if options.config_root is not None and not os.path.isdir(options.config_root):
2217 + parser.error("Not a directory: --config-root='%s'" % (options.config_root,))
2218 +
2219 + if options.cache_dir is not None:
2220 + if not os.path.isdir(options.cache_dir):
2221 + parser.error("Not a directory: --cache-dir='%s'" % (options.cache_dir,))
2222 + if not os.access(options.cache_dir, os.W_OK):
2223 + parser.error("Write access denied: --cache-dir='%s'" % (options.cache_dir,))
2224 +
2225 + for atom in args:
2226 + try:
2227 + atom = portage.dep.Atom(atom)
2228 + except portage.exception.InvalidAtom:
2229 + parser.error("Invalid atom: %s" % (atom,))
2230 +
2231 + if not isjustname(atom):
2232 + parser.error("Atom is too specific: %s" % (atom,))
2233 +
2234 + if options.update_use_local_desc:
2235 + try:
2236 + ElementTree
2237 + ExpatError
2238 + except NameError:
2239 + parser.error("--update-use-local-desc requires python with USE=xml!")
2240 +
2241 + if options.uld_output == "-" and options.preserve_comments:
2242 + parser.error("--preserve-comments can not be used when outputting to stdout")
2243 +
2244 + return parser, options, args
2245 +
2246
2247 class GenCache:
2248 - def __init__(self, portdb, cp_iter=None, max_jobs=None, max_load=None,
2249 - rsync=False, external_cache_only=False):
2250 - # The caller must set portdb.porttrees in order to constrain
2251 - # findname, cp_list, and cpv_list to the desired tree.
2252 - tree = portdb.porttrees[0]
2253 - self._portdb = portdb
2254 - self._eclass_db = portdb.repositories.get_repo_for_location(tree).eclass_db
2255 - self._auxdbkeys = portdb._known_keys
2256 - # We can globally cleanse stale cache only if we
2257 - # iterate over every single cp.
2258 - self._global_cleanse = cp_iter is None
2259 - if cp_iter is not None:
2260 - self._cp_set = set(cp_iter)
2261 - cp_iter = iter(self._cp_set)
2262 - self._cp_missing = self._cp_set.copy()
2263 - else:
2264 - self._cp_set = None
2265 - self._cp_missing = set()
2266 - write_auxdb = external_cache_only or "metadata-transfer" in portdb.settings.features
2267 - self._regen = MetadataRegen(portdb, cp_iter=cp_iter,
2268 - consumer=self._metadata_callback,
2269 - max_jobs=max_jobs, max_load=max_load,
2270 - write_auxdb=write_auxdb, main=True)
2271 - self.returncode = os.EX_OK
2272 - conf = portdb.repositories.get_repo_for_location(tree)
2273 - if external_cache_only:
2274 - self._trg_caches = ()
2275 - else:
2276 - self._trg_caches = tuple(conf.iter_pregenerated_caches(
2277 - self._auxdbkeys, force=True, readonly=False))
2278 - if not self._trg_caches:
2279 - raise Exception("cache formats '%s' aren't supported" %
2280 - (" ".join(conf.cache_formats),))
2281 -
2282 - if rsync:
2283 - for trg_cache in self._trg_caches:
2284 - if hasattr(trg_cache, 'raise_stat_collision'):
2285 - trg_cache.raise_stat_collision = True
2286 - # Make _metadata_callback write this cache first, in case
2287 - # it raises a StatCollision and triggers mtime
2288 - # modification.
2289 - self._trg_caches = tuple([trg_cache] +
2290 - [x for x in self._trg_caches if x is not trg_cache])
2291 -
2292 - self._existing_nodes = set()
2293 -
2294 - def _metadata_callback(self, cpv, repo_path, metadata,
2295 - ebuild_hash, eapi_supported):
2296 - self._existing_nodes.add(cpv)
2297 - self._cp_missing.discard(cpv_getkey(cpv))
2298 -
2299 - # Since we're supposed to be able to efficiently obtain the
2300 - # EAPI from _parse_eapi_ebuild_head, we don't write cache
2301 - # entries for unsupported EAPIs.
2302 - if metadata is not None and eapi_supported:
2303 - for trg_cache in self._trg_caches:
2304 - self._write_cache(trg_cache,
2305 - cpv, repo_path, metadata, ebuild_hash)
2306 -
2307 - def _write_cache(self, trg_cache, cpv, repo_path, metadata, ebuild_hash):
2308 -
2309 - if not hasattr(trg_cache, 'raise_stat_collision'):
2310 - # This cache does not avoid redundant writes automatically,
2311 - # so check for an identical existing entry before writing.
2312 - # This prevents unnecessary disk writes and can also prevent
2313 - # unnecessary rsync transfers.
2314 - try:
2315 - dest = trg_cache[cpv]
2316 - except (KeyError, CacheError):
2317 - pass
2318 - else:
2319 - if trg_cache.validate_entry(dest,
2320 - ebuild_hash, self._eclass_db):
2321 - identical = True
2322 - for k in self._auxdbkeys:
2323 - if dest.get(k, '') != metadata.get(k, ''):
2324 - identical = False
2325 - break
2326 - if identical:
2327 - return
2328 -
2329 - try:
2330 - chf = trg_cache.validation_chf
2331 - metadata['_%s_' % chf] = getattr(ebuild_hash, chf)
2332 - try:
2333 - trg_cache[cpv] = metadata
2334 - except StatCollision as sc:
2335 - # If the content of a cache entry changes and neither the
2336 - # file mtime nor size changes, it will prevent rsync from
2337 - # detecting changes. Cache backends may raise this
2338 - # exception from _setitem() if they detect this type of stat
2339 - # collision. These exceptions are handled by bumping the
2340 - # mtime on the ebuild (and the corresponding cache entry).
2341 - # See bug #139134. It is convenient to include checks for
2342 - # redundant writes along with the internal StatCollision
2343 - # detection code, so for caches with the
2344 - # raise_stat_collision attribute, we do not need to
2345 - # explicitly check for redundant writes like we do for the
2346 - # other cache types above.
2347 - max_mtime = sc.mtime
2348 - for _ec, ec_hash in metadata['_eclasses_'].items():
2349 - if max_mtime < ec_hash.mtime:
2350 - max_mtime = ec_hash.mtime
2351 - if max_mtime == sc.mtime:
2352 - max_mtime += 1
2353 - max_mtime = int(max_mtime)
2354 - try:
2355 - os.utime(ebuild_hash.location, (max_mtime, max_mtime))
2356 - except OSError as e:
2357 - self.returncode |= 1
2358 - writemsg_level(
2359 - "%s writing target: %s\n" % (cpv, e),
2360 - level=logging.ERROR, noiselevel=-1)
2361 - else:
2362 - ebuild_hash.mtime = max_mtime
2363 - metadata['_mtime_'] = max_mtime
2364 - trg_cache[cpv] = metadata
2365 - self._portdb.auxdb[repo_path][cpv] = metadata
2366 -
2367 - except CacheError as ce:
2368 - self.returncode |= 1
2369 - writemsg_level(
2370 - "%s writing target: %s\n" % (cpv, ce),
2371 - level=logging.ERROR, noiselevel=-1)
2372 -
2373 - def run(self):
2374 - signum = run_main_scheduler(self._regen)
2375 - if signum is not None:
2376 - sys.exit(128 + signum)
2377 -
2378 - self.returncode |= self._regen.returncode
2379 -
2380 - for trg_cache in self._trg_caches:
2381 - self._cleanse_cache(trg_cache)
2382 -
2383 - def _cleanse_cache(self, trg_cache):
2384 - cp_missing = self._cp_missing
2385 - dead_nodes = set()
2386 - if self._global_cleanse:
2387 - try:
2388 - for cpv in trg_cache:
2389 - cp = cpv_getkey(cpv)
2390 - if cp is None:
2391 - self.returncode |= 1
2392 - writemsg_level(
2393 - "Unable to parse cp for '%s'\n" % (cpv,),
2394 - level=logging.ERROR, noiselevel=-1)
2395 - else:
2396 - dead_nodes.add(cpv)
2397 - except CacheError as ce:
2398 - self.returncode |= 1
2399 - writemsg_level(
2400 - "Error listing cache entries for " + \
2401 - "'%s': %s, continuing...\n" % \
2402 - (trg_cache.location, ce),
2403 - level=logging.ERROR, noiselevel=-1)
2404 -
2405 - else:
2406 - cp_set = self._cp_set
2407 - try:
2408 - for cpv in trg_cache:
2409 - cp = cpv_getkey(cpv)
2410 - if cp is None:
2411 - self.returncode |= 1
2412 - writemsg_level(
2413 - "Unable to parse cp for '%s'\n" % (cpv,),
2414 - level=logging.ERROR, noiselevel=-1)
2415 - else:
2416 - cp_missing.discard(cp)
2417 - if cp in cp_set:
2418 - dead_nodes.add(cpv)
2419 - except CacheError as ce:
2420 - self.returncode |= 1
2421 - writemsg_level(
2422 - "Error listing cache entries for " + \
2423 - "'%s': %s, continuing...\n" % \
2424 - (trg_cache.location, ce),
2425 - level=logging.ERROR, noiselevel=-1)
2426 -
2427 - if cp_missing:
2428 - self.returncode |= 1
2429 - for cp in sorted(cp_missing):
2430 - writemsg_level(
2431 - "No ebuilds or cache entries found for '%s'\n" % (cp,),
2432 - level=logging.ERROR, noiselevel=-1)
2433 -
2434 - if dead_nodes:
2435 - dead_nodes.difference_update(self._existing_nodes)
2436 - for k in dead_nodes:
2437 - try:
2438 - del trg_cache[k]
2439 - except KeyError:
2440 - pass
2441 - except CacheError as ce:
2442 - self.returncode |= 1
2443 - writemsg_level(
2444 - "%s deleting stale cache: %s\n" % (k, ce),
2445 - level=logging.ERROR, noiselevel=-1)
2446 -
2447 - if not trg_cache.autocommits:
2448 - try:
2449 - trg_cache.commit()
2450 - except CacheError as ce:
2451 - self.returncode |= 1
2452 - writemsg_level(
2453 - "committing target: %s\n" % (ce,),
2454 - level=logging.ERROR, noiselevel=-1)
2455 -
2456 - if hasattr(trg_cache, '_prune_empty_dirs'):
2457 - trg_cache._prune_empty_dirs()
2458 + def __init__(
2459 + self,
2460 + portdb,
2461 + cp_iter=None,
2462 + max_jobs=None,
2463 + max_load=None,
2464 + rsync=False,
2465 + external_cache_only=False,
2466 + ):
2467 + # The caller must set portdb.porttrees in order to constrain
2468 + # findname, cp_list, and cpv_list to the desired tree.
2469 + tree = portdb.porttrees[0]
2470 + self._portdb = portdb
2471 + self._eclass_db = portdb.repositories.get_repo_for_location(tree).eclass_db
2472 + self._auxdbkeys = portdb._known_keys
2473 + # We can globally cleanse stale cache only if we
2474 + # iterate over every single cp.
2475 + self._global_cleanse = cp_iter is None
2476 + if cp_iter is not None:
2477 + self._cp_set = set(cp_iter)
2478 + cp_iter = iter(self._cp_set)
2479 + self._cp_missing = self._cp_set.copy()
2480 + else:
2481 + self._cp_set = None
2482 + self._cp_missing = set()
2483 + write_auxdb = (
2484 + external_cache_only or "metadata-transfer" in portdb.settings.features
2485 + )
2486 + self._regen = MetadataRegen(
2487 + portdb,
2488 + cp_iter=cp_iter,
2489 + consumer=self._metadata_callback,
2490 + max_jobs=max_jobs,
2491 + max_load=max_load,
2492 + write_auxdb=write_auxdb,
2493 + main=True,
2494 + )
2495 + self.returncode = os.EX_OK
2496 + conf = portdb.repositories.get_repo_for_location(tree)
2497 + if external_cache_only:
2498 + self._trg_caches = ()
2499 + else:
2500 + self._trg_caches = tuple(
2501 + conf.iter_pregenerated_caches(
2502 + self._auxdbkeys, force=True, readonly=False
2503 + )
2504 + )
2505 + if not self._trg_caches:
2506 + raise Exception(
2507 + "cache formats '%s' aren't supported"
2508 + % (" ".join(conf.cache_formats),)
2509 + )
2510 +
2511 + if rsync:
2512 + for trg_cache in self._trg_caches:
2513 + if hasattr(trg_cache, "raise_stat_collision"):
2514 + trg_cache.raise_stat_collision = True
2515 + # Make _metadata_callback write this cache first, in case
2516 + # it raises a StatCollision and triggers mtime
2517 + # modification.
2518 + self._trg_caches = tuple(
2519 + [trg_cache]
2520 + + [x for x in self._trg_caches if x is not trg_cache]
2521 + )
2522 +
2523 + self._existing_nodes = set()
2524 +
2525 + def _metadata_callback(self, cpv, repo_path, metadata, ebuild_hash, eapi_supported):
2526 + self._existing_nodes.add(cpv)
2527 + self._cp_missing.discard(cpv_getkey(cpv))
2528 +
2529 + # Since we're supposed to be able to efficiently obtain the
2530 + # EAPI from _parse_eapi_ebuild_head, we don't write cache
2531 + # entries for unsupported EAPIs.
2532 + if metadata is not None and eapi_supported:
2533 + for trg_cache in self._trg_caches:
2534 + self._write_cache(trg_cache, cpv, repo_path, metadata, ebuild_hash)
2535 +
2536 + def _write_cache(self, trg_cache, cpv, repo_path, metadata, ebuild_hash):
2537 +
2538 + if not hasattr(trg_cache, "raise_stat_collision"):
2539 + # This cache does not avoid redundant writes automatically,
2540 + # so check for an identical existing entry before writing.
2541 + # This prevents unnecessary disk writes and can also prevent
2542 + # unnecessary rsync transfers.
2543 + try:
2544 + dest = trg_cache[cpv]
2545 + except (KeyError, CacheError):
2546 + pass
2547 + else:
2548 + if trg_cache.validate_entry(dest, ebuild_hash, self._eclass_db):
2549 + identical = True
2550 + for k in self._auxdbkeys:
2551 + if dest.get(k, "") != metadata.get(k, ""):
2552 + identical = False
2553 + break
2554 + if identical:
2555 + return
2556 +
2557 + try:
2558 + chf = trg_cache.validation_chf
2559 + metadata["_%s_" % chf] = getattr(ebuild_hash, chf)
2560 + try:
2561 + trg_cache[cpv] = metadata
2562 + except StatCollision as sc:
2563 + # If the content of a cache entry changes and neither the
2564 + # file mtime nor size changes, it will prevent rsync from
2565 + # detecting changes. Cache backends may raise this
2566 + # exception from _setitem() if they detect this type of stat
2567 + # collision. These exceptions are handled by bumping the
2568 + # mtime on the ebuild (and the corresponding cache entry).
2569 + # See bug #139134. It is convenient to include checks for
2570 + # redundant writes along with the internal StatCollision
2571 + # detection code, so for caches with the
2572 + # raise_stat_collision attribute, we do not need to
2573 + # explicitly check for redundant writes like we do for the
2574 + # other cache types above.
2575 + max_mtime = sc.mtime
2576 + for _ec, ec_hash in metadata["_eclasses_"].items():
2577 + if max_mtime < ec_hash.mtime:
2578 + max_mtime = ec_hash.mtime
2579 + if max_mtime == sc.mtime:
2580 + max_mtime += 1
2581 + max_mtime = int(max_mtime)
2582 + try:
2583 + os.utime(ebuild_hash.location, (max_mtime, max_mtime))
2584 + except OSError as e:
2585 + self.returncode |= 1
2586 + writemsg_level(
2587 + "%s writing target: %s\n" % (cpv, e),
2588 + level=logging.ERROR,
2589 + noiselevel=-1,
2590 + )
2591 + else:
2592 + ebuild_hash.mtime = max_mtime
2593 + metadata["_mtime_"] = max_mtime
2594 + trg_cache[cpv] = metadata
2595 + self._portdb.auxdb[repo_path][cpv] = metadata
2596 +
2597 + except CacheError as ce:
2598 + self.returncode |= 1
2599 + writemsg_level(
2600 + "%s writing target: %s\n" % (cpv, ce),
2601 + level=logging.ERROR,
2602 + noiselevel=-1,
2603 + )
2604 +
2605 + def run(self):
2606 + signum = run_main_scheduler(self._regen)
2607 + if signum is not None:
2608 + sys.exit(128 + signum)
2609 +
2610 + self.returncode |= self._regen.returncode
2611 +
2612 + for trg_cache in self._trg_caches:
2613 + self._cleanse_cache(trg_cache)
2614 +
2615 + def _cleanse_cache(self, trg_cache):
2616 + cp_missing = self._cp_missing
2617 + dead_nodes = set()
2618 + if self._global_cleanse:
2619 + try:
2620 + for cpv in trg_cache:
2621 + cp = cpv_getkey(cpv)
2622 + if cp is None:
2623 + self.returncode |= 1
2624 + writemsg_level(
2625 + "Unable to parse cp for '%s'\n" % (cpv,),
2626 + level=logging.ERROR,
2627 + noiselevel=-1,
2628 + )
2629 + else:
2630 + dead_nodes.add(cpv)
2631 + except CacheError as ce:
2632 + self.returncode |= 1
2633 + writemsg_level(
2634 + "Error listing cache entries for "
2635 + + "'%s': %s, continuing...\n" % (trg_cache.location, ce),
2636 + level=logging.ERROR,
2637 + noiselevel=-1,
2638 + )
2639 +
2640 + else:
2641 + cp_set = self._cp_set
2642 + try:
2643 + for cpv in trg_cache:
2644 + cp = cpv_getkey(cpv)
2645 + if cp is None:
2646 + self.returncode |= 1
2647 + writemsg_level(
2648 + "Unable to parse cp for '%s'\n" % (cpv,),
2649 + level=logging.ERROR,
2650 + noiselevel=-1,
2651 + )
2652 + else:
2653 + cp_missing.discard(cp)
2654 + if cp in cp_set:
2655 + dead_nodes.add(cpv)
2656 + except CacheError as ce:
2657 + self.returncode |= 1
2658 + writemsg_level(
2659 + "Error listing cache entries for "
2660 + + "'%s': %s, continuing...\n" % (trg_cache.location, ce),
2661 + level=logging.ERROR,
2662 + noiselevel=-1,
2663 + )
2664 +
2665 + if cp_missing:
2666 + self.returncode |= 1
2667 + for cp in sorted(cp_missing):
2668 + writemsg_level(
2669 + "No ebuilds or cache entries found for '%s'\n" % (cp,),
2670 + level=logging.ERROR,
2671 + noiselevel=-1,
2672 + )
2673 +
2674 + if dead_nodes:
2675 + dead_nodes.difference_update(self._existing_nodes)
2676 + for k in dead_nodes:
2677 + try:
2678 + del trg_cache[k]
2679 + except KeyError:
2680 + pass
2681 + except CacheError as ce:
2682 + self.returncode |= 1
2683 + writemsg_level(
2684 + "%s deleting stale cache: %s\n" % (k, ce),
2685 + level=logging.ERROR,
2686 + noiselevel=-1,
2687 + )
2688 +
2689 + if not trg_cache.autocommits:
2690 + try:
2691 + trg_cache.commit()
2692 + except CacheError as ce:
2693 + self.returncode |= 1
2694 + writemsg_level(
2695 + "committing target: %s\n" % (ce,),
2696 + level=logging.ERROR,
2697 + noiselevel=-1,
2698 + )
2699 +
2700 + if hasattr(trg_cache, "_prune_empty_dirs"):
2701 + trg_cache._prune_empty_dirs()
2702 +
2703
2704 class GenPkgDescIndex:
2705 - def __init__(self, repo_config, portdb, output_file, verbose=False):
2706 - self.returncode = os.EX_OK
2707 - self._repo_config = repo_config
2708 - self._portdb = portdb
2709 - self._output_file = output_file
2710 - self._verbose = verbose
2711 -
2712 - def run(self):
2713 -
2714 - display_updates = self._verbose > 0
2715 - old = {}
2716 - new = {}
2717 - if display_updates:
2718 - try:
2719 - with open(self._output_file, 'rt', encoding=_encodings["repo.content"]) as f:
2720 - for line in f:
2721 - pkg_desc = pkg_desc_index_line_read(line)
2722 - old[pkg_desc.cp] = pkg_desc
2723 - except FileNotFoundError:
2724 - pass
2725 -
2726 - portage.util.ensure_dirs(os.path.dirname(self._output_file))
2727 - f = portage.util.atomic_ofstream(self._output_file,
2728 - encoding=_encodings["repo.content"])
2729 -
2730 - portdb = self._portdb
2731 - for cp in portdb.cp_all():
2732 - pkgs = portdb.cp_list(cp)
2733 - if not pkgs:
2734 - continue
2735 - desc, = portdb.aux_get(pkgs[-1], ["DESCRIPTION"])
2736 -
2737 - line = pkg_desc_index_line_format(cp, pkgs, desc)
2738 - f.write(line)
2739 - if display_updates:
2740 - new[cp] = pkg_desc_index_line_read(line)
2741 -
2742 - f.close()
2743 -
2744 - if display_updates:
2745 - out = EOutput()
2746 - out.einfo("Searching for changes")
2747 - print("")
2748 - items = sorted(new.values(), key=lambda pkg_desc: pkg_desc.cp)
2749 - haspkgs = False
2750 - for pkg_desc in items:
2751 - masked = False
2752 - version = self._portdb.xmatch("bestmatch-visible",
2753 - Atom("{}{}{}".format(pkg_desc.cp, _repo_separator, self._repo_config.name)))
2754 - if not version:
2755 - version = pkg_desc.cpv_list[-1]
2756 - masked = True
2757 - old_versions = old.get(pkg_desc.cp)
2758 - if old_versions is None or version not in old_versions.cpv_list:
2759 - prefix0 = " "
2760 - prefix1 = " "
2761 -
2762 - if old_versions is None:
2763 - color = functools.partial(colorize, "darkgreen")
2764 - prefix1 = "N"
2765 - else:
2766 - color = functools.partial(colorize, "turquoise")
2767 - prefix1 = "U"
2768 -
2769 - if masked:
2770 - prefix0 = "M"
2771 -
2772 - print(" [%s%s] %s (%s): %s" % (
2773 - colorize("red", prefix0),
2774 - color(prefix1),
2775 - colorize("bold", pkg_desc.cp),
2776 - color(version[len(pkg_desc.cp)+1:]),
2777 - pkg_desc.desc))
2778 - haspkgs = True
2779 -
2780 - if not haspkgs:
2781 - out.einfo("No updates found")
2782 + def __init__(self, repo_config, portdb, output_file, verbose=False):
2783 + self.returncode = os.EX_OK
2784 + self._repo_config = repo_config
2785 + self._portdb = portdb
2786 + self._output_file = output_file
2787 + self._verbose = verbose
2788 +
2789 + def run(self):
2790 +
2791 + display_updates = self._verbose > 0
2792 + old = {}
2793 + new = {}
2794 + if display_updates:
2795 + try:
2796 + with open(
2797 + self._output_file, "rt", encoding=_encodings["repo.content"]
2798 + ) as f:
2799 + for line in f:
2800 + pkg_desc = pkg_desc_index_line_read(line)
2801 + old[pkg_desc.cp] = pkg_desc
2802 + except FileNotFoundError:
2803 + pass
2804 +
2805 + portage.util.ensure_dirs(os.path.dirname(self._output_file))
2806 + f = portage.util.atomic_ofstream(
2807 + self._output_file, encoding=_encodings["repo.content"]
2808 + )
2809 +
2810 + portdb = self._portdb
2811 + for cp in portdb.cp_all():
2812 + pkgs = portdb.cp_list(cp)
2813 + if not pkgs:
2814 + continue
2815 + (desc,) = portdb.aux_get(pkgs[-1], ["DESCRIPTION"])
2816 +
2817 + line = pkg_desc_index_line_format(cp, pkgs, desc)
2818 + f.write(line)
2819 + if display_updates:
2820 + new[cp] = pkg_desc_index_line_read(line)
2821 +
2822 + f.close()
2823 +
2824 + if display_updates:
2825 + out = EOutput()
2826 + out.einfo("Searching for changes")
2827 + print("")
2828 + items = sorted(new.values(), key=lambda pkg_desc: pkg_desc.cp)
2829 + haspkgs = False
2830 + for pkg_desc in items:
2831 + masked = False
2832 + version = self._portdb.xmatch(
2833 + "bestmatch-visible",
2834 + Atom(
2835 + "{}{}{}".format(
2836 + pkg_desc.cp, _repo_separator, self._repo_config.name
2837 + )
2838 + ),
2839 + )
2840 + if not version:
2841 + version = pkg_desc.cpv_list[-1]
2842 + masked = True
2843 + old_versions = old.get(pkg_desc.cp)
2844 + if old_versions is None or version not in old_versions.cpv_list:
2845 + prefix0 = " "
2846 + prefix1 = " "
2847 +
2848 + if old_versions is None:
2849 + color = functools.partial(colorize, "darkgreen")
2850 + prefix1 = "N"
2851 + else:
2852 + color = functools.partial(colorize, "turquoise")
2853 + prefix1 = "U"
2854 +
2855 + if masked:
2856 + prefix0 = "M"
2857 +
2858 + print(
2859 + " [%s%s] %s (%s): %s"
2860 + % (
2861 + colorize("red", prefix0),
2862 + color(prefix1),
2863 + colorize("bold", pkg_desc.cp),
2864 + color(version[len(pkg_desc.cp) + 1 :]),
2865 + pkg_desc.desc,
2866 + )
2867 + )
2868 + haspkgs = True
2869 +
2870 + if not haspkgs:
2871 + out.einfo("No updates found")
2872 +
2873
2874 class GenUseLocalDesc:
2875 - def __init__(self, portdb, output=None,
2876 - preserve_comments=False):
2877 - self.returncode = os.EX_OK
2878 - self._portdb = portdb
2879 - self._output = output
2880 - self._preserve_comments = preserve_comments
2881 -
2882 - def run(self):
2883 - repo_path = self._portdb.porttrees[0]
2884 - ops = {'<':0, '<=':1, '=':2, '>=':3, '>':4}
2885 - prev_mtime = None
2886 - prev_md5 = None
2887 -
2888 - if self._output is None or self._output != '-':
2889 - if self._output is None:
2890 - prof_path = os.path.join(repo_path, 'profiles')
2891 - desc_path = os.path.join(prof_path, 'use.local.desc')
2892 - try:
2893 - os.mkdir(prof_path)
2894 - except OSError:
2895 - pass
2896 - else:
2897 - desc_path = self._output
2898 -
2899 - try:
2900 - prev_md5 = portage.checksum.perform_md5(desc_path)
2901 - prev_mtime = os.stat(desc_path)[stat.ST_MTIME]
2902 - except (portage.exception.FileNotFound, OSError):
2903 - pass
2904 -
2905 - try:
2906 - if self._preserve_comments:
2907 - # Probe in binary mode, in order to avoid
2908 - # potential character encoding issues.
2909 - output = open(_unicode_encode(desc_path,
2910 - encoding=_encodings['fs'], errors='strict'), 'r+b')
2911 - else:
2912 - output = io.open(_unicode_encode(desc_path,
2913 - encoding=_encodings['fs'], errors='strict'),
2914 - mode='w', encoding=_encodings['repo.content'],
2915 - errors='backslashreplace')
2916 - except IOError as e:
2917 - if not self._preserve_comments or \
2918 - os.path.isfile(desc_path):
2919 - writemsg_level(
2920 - "ERROR: failed to open output file %s: %s\n" \
2921 - % (desc_path, e), level=logging.ERROR, noiselevel=-1)
2922 - self.returncode |= 2
2923 - return
2924 -
2925 - # Open in r+b mode failed because the file doesn't
2926 - # exist yet. We can probably recover if we disable
2927 - # preserve_comments mode now.
2928 - writemsg_level(
2929 - "WARNING: --preserve-comments enabled, but " + \
2930 - "output file not found: %s\n" % (desc_path,),
2931 - level=logging.WARNING, noiselevel=-1)
2932 - self._preserve_comments = False
2933 - try:
2934 - output = io.open(_unicode_encode(desc_path,
2935 - encoding=_encodings['fs'], errors='strict'),
2936 - mode='w', encoding=_encodings['repo.content'],
2937 - errors='backslashreplace')
2938 - except IOError as e:
2939 - writemsg_level(
2940 - "ERROR: failed to open output file %s: %s\n" \
2941 - % (desc_path, e), level=logging.ERROR, noiselevel=-1)
2942 - self.returncode |= 2
2943 - return
2944 - else:
2945 - output = sys.stdout
2946 -
2947 - if self._preserve_comments:
2948 - while True:
2949 - pos = output.tell()
2950 - if not output.readline().startswith(b'#'):
2951 - break
2952 - output.seek(pos)
2953 - output.truncate()
2954 - output.close()
2955 -
2956 - # Finished probing comments in binary mode, now append
2957 - # in text mode.
2958 - output = io.open(_unicode_encode(desc_path,
2959 - encoding=_encodings['fs'], errors='strict'),
2960 - mode='a', encoding=_encodings['repo.content'],
2961 - errors='backslashreplace')
2962 - output.write('\n')
2963 - else:
2964 - output.write(textwrap.dedent('''\
2965 + def __init__(self, portdb, output=None, preserve_comments=False):
2966 + self.returncode = os.EX_OK
2967 + self._portdb = portdb
2968 + self._output = output
2969 + self._preserve_comments = preserve_comments
2970 +
2971 + def run(self):
2972 + repo_path = self._portdb.porttrees[0]
2973 + ops = {"<": 0, "<=": 1, "=": 2, ">=": 3, ">": 4}
2974 + prev_mtime = None
2975 + prev_md5 = None
2976 +
2977 + if self._output is None or self._output != "-":
2978 + if self._output is None:
2979 + prof_path = os.path.join(repo_path, "profiles")
2980 + desc_path = os.path.join(prof_path, "use.local.desc")
2981 + try:
2982 + os.mkdir(prof_path)
2983 + except OSError:
2984 + pass
2985 + else:
2986 + desc_path = self._output
2987 +
2988 + try:
2989 + prev_md5 = portage.checksum.perform_md5(desc_path)
2990 + prev_mtime = os.stat(desc_path)[stat.ST_MTIME]
2991 + except (portage.exception.FileNotFound, OSError):
2992 + pass
2993 +
2994 + try:
2995 + if self._preserve_comments:
2996 + # Probe in binary mode, in order to avoid
2997 + # potential character encoding issues.
2998 + output = open(
2999 + _unicode_encode(
3000 + desc_path, encoding=_encodings["fs"], errors="strict"
3001 + ),
3002 + "r+b",
3003 + )
3004 + else:
3005 + output = io.open(
3006 + _unicode_encode(
3007 + desc_path, encoding=_encodings["fs"], errors="strict"
3008 + ),
3009 + mode="w",
3010 + encoding=_encodings["repo.content"],
3011 + errors="backslashreplace",
3012 + )
3013 + except IOError as e:
3014 + if not self._preserve_comments or os.path.isfile(desc_path):
3015 + writemsg_level(
3016 + "ERROR: failed to open output file %s: %s\n" % (desc_path, e),
3017 + level=logging.ERROR,
3018 + noiselevel=-1,
3019 + )
3020 + self.returncode |= 2
3021 + return
3022 +
3023 + # Open in r+b mode failed because the file doesn't
3024 + # exist yet. We can probably recover if we disable
3025 + # preserve_comments mode now.
3026 + writemsg_level(
3027 + "WARNING: --preserve-comments enabled, but "
3028 + + "output file not found: %s\n" % (desc_path,),
3029 + level=logging.WARNING,
3030 + noiselevel=-1,
3031 + )
3032 + self._preserve_comments = False
3033 + try:
3034 + output = io.open(
3035 + _unicode_encode(
3036 + desc_path, encoding=_encodings["fs"], errors="strict"
3037 + ),
3038 + mode="w",
3039 + encoding=_encodings["repo.content"],
3040 + errors="backslashreplace",
3041 + )
3042 + except IOError as e:
3043 + writemsg_level(
3044 + "ERROR: failed to open output file %s: %s\n" % (desc_path, e),
3045 + level=logging.ERROR,
3046 + noiselevel=-1,
3047 + )
3048 + self.returncode |= 2
3049 + return
3050 + else:
3051 + output = sys.stdout
3052 +
3053 + if self._preserve_comments:
3054 + while True:
3055 + pos = output.tell()
3056 + if not output.readline().startswith(b"#"):
3057 + break
3058 + output.seek(pos)
3059 + output.truncate()
3060 + output.close()
3061 +
3062 + # Finished probing comments in binary mode, now append
3063 + # in text mode.
3064 + output = io.open(
3065 + _unicode_encode(desc_path, encoding=_encodings["fs"], errors="strict"),
3066 + mode="a",
3067 + encoding=_encodings["repo.content"],
3068 + errors="backslashreplace",
3069 + )
3070 + output.write("\n")
3071 + else:
3072 + output.write(
3073 + textwrap.dedent(
3074 + """\
3075 # This file is deprecated as per GLEP 56 in favor of metadata.xml. Please add
3076 # your descriptions to your package's metadata.xml ONLY.
3077 # * generated automatically using egencache *
3078
3079 - '''))
3080 -
3081 - # The cmp function no longer exists in python3, so we'll
3082 - # implement our own here under a slightly different name
3083 - # since we don't want any confusion given that we never
3084 - # want to rely on the builtin cmp function.
3085 - def cmp_func(a, b):
3086 - if a is None or b is None:
3087 - # None can't be compared with other types in python3.
3088 - if a is None and b is None:
3089 - return 0
3090 - elif a is None:
3091 - return -1
3092 - else:
3093 - return 1
3094 - return (a > b) - (a < b)
3095 -
3096 - class _MetadataTreeBuilder(ElementTree.TreeBuilder):
3097 - """
3098 - Implements doctype() as required to avoid deprecation warnings
3099 - since Python >=2.7
3100 - """
3101 - def doctype(self, name, pubid, system):
3102 - pass
3103 -
3104 - for cp in self._portdb.cp_all():
3105 - metadata_path = os.path.join(repo_path, cp, 'metadata.xml')
3106 - try:
3107 - metadata = ElementTree.parse(_unicode_encode(metadata_path,
3108 - encoding=_encodings['fs'], errors='strict'),
3109 - parser=ElementTree.XMLParser(
3110 - target=_MetadataTreeBuilder()))
3111 - except IOError:
3112 - pass
3113 - except (ExpatError, EnvironmentError) as e:
3114 - writemsg_level(
3115 - "ERROR: failed parsing %s/metadata.xml: %s\n" % (cp, e),
3116 - level=logging.ERROR, noiselevel=-1)
3117 - self.returncode |= 1
3118 - else:
3119 - try:
3120 - usedict = parse_metadata_use(metadata)
3121 - except portage.exception.ParseError as e:
3122 - writemsg_level(
3123 - "ERROR: failed parsing %s/metadata.xml: %s\n" % (cp, e),
3124 - level=logging.ERROR, noiselevel=-1)
3125 - self.returncode |= 1
3126 - else:
3127 - for flag in sorted(usedict):
3128 - def atomcmp(atoma, atomb):
3129 - # None is better than an atom, that's why we reverse the args
3130 - if atoma is None or atomb is None:
3131 - return cmp_func(atomb, atoma)
3132 - # Same for plain PNs (.operator is None then)
3133 - elif atoma.operator is None or atomb.operator is None:
3134 - return cmp_func(atomb.operator, atoma.operator)
3135 - # Version matching
3136 - elif atoma.cpv != atomb.cpv:
3137 - return vercmp(atoma.version, atomb.version)
3138 - # Versions match, let's fallback to operator matching
3139 - else:
3140 - return cmp_func(ops.get(atoma.operator, -1),
3141 - ops.get(atomb.operator, -1))
3142 -
3143 - def _Atom(key):
3144 - if key is not None:
3145 - return Atom(key)
3146 - return None
3147 -
3148 - resdict = usedict[flag]
3149 - if len(resdict) == 1:
3150 - resdesc = next(iter(resdict.items()))[1]
3151 - else:
3152 - try:
3153 - reskeys = dict((_Atom(k), k) for k in resdict)
3154 - except portage.exception.InvalidAtom as e:
3155 - writemsg_level(
3156 - "ERROR: failed parsing %s/metadata.xml: %s\n" % (cp, e),
3157 - level=logging.ERROR, noiselevel=-1)
3158 - self.returncode |= 1
3159 - resdesc = next(iter(resdict.items()))[1]
3160 - else:
3161 - resatoms = sorted(reskeys, key=cmp_sort_key(atomcmp))
3162 - resdesc = resdict[reskeys[resatoms[-1]]]
3163 -
3164 - output.write('%s:%s - %s\n' % (cp, flag, resdesc))
3165 -
3166 - output.close()
3167 - if (prev_mtime is not None and
3168 - prev_md5 == portage.checksum.perform_md5(desc_path)):
3169 - # Preserve mtime for rsync.
3170 - mtime = prev_mtime
3171 - else:
3172 - # For portability, and consistency with the mtime preservation
3173 - # code, set mtime to an exact integer value.
3174 - mtime = int(time.time())
3175 -
3176 - os.utime(desc_path, (mtime, mtime))
3177 + """
3178 + )
3179 + )
3180 +
3181 + # The cmp function no longer exists in python3, so we'll
3182 + # implement our own here under a slightly different name
3183 + # since we don't want any confusion given that we never
3184 + # want to rely on the builtin cmp function.
3185 + def cmp_func(a, b):
3186 + if a is None or b is None:
3187 + # None can't be compared with other types in python3.
3188 + if a is None and b is None:
3189 + return 0
3190 + elif a is None:
3191 + return -1
3192 + else:
3193 + return 1
3194 + return (a > b) - (a < b)
3195 +
3196 + class _MetadataTreeBuilder(ElementTree.TreeBuilder):
3197 + """
3198 + Implements doctype() as required to avoid deprecation warnings
3199 + since Python >=2.7
3200 + """
3201 +
3202 + def doctype(self, name, pubid, system):
3203 + pass
3204 +
3205 + for cp in self._portdb.cp_all():
3206 + metadata_path = os.path.join(repo_path, cp, "metadata.xml")
3207 + try:
3208 + metadata = ElementTree.parse(
3209 + _unicode_encode(
3210 + metadata_path, encoding=_encodings["fs"], errors="strict"
3211 + ),
3212 + parser=ElementTree.XMLParser(target=_MetadataTreeBuilder()),
3213 + )
3214 + except IOError:
3215 + pass
3216 + except (ExpatError, EnvironmentError) as e:
3217 + writemsg_level(
3218 + "ERROR: failed parsing %s/metadata.xml: %s\n" % (cp, e),
3219 + level=logging.ERROR,
3220 + noiselevel=-1,
3221 + )
3222 + self.returncode |= 1
3223 + else:
3224 + try:
3225 + usedict = parse_metadata_use(metadata)
3226 + except portage.exception.ParseError as e:
3227 + writemsg_level(
3228 + "ERROR: failed parsing %s/metadata.xml: %s\n" % (cp, e),
3229 + level=logging.ERROR,
3230 + noiselevel=-1,
3231 + )
3232 + self.returncode |= 1
3233 + else:
3234 + for flag in sorted(usedict):
3235 +
3236 + def atomcmp(atoma, atomb):
3237 + # None is better than an atom, that's why we reverse the args
3238 + if atoma is None or atomb is None:
3239 + return cmp_func(atomb, atoma)
3240 + # Same for plain PNs (.operator is None then)
3241 + elif atoma.operator is None or atomb.operator is None:
3242 + return cmp_func(atomb.operator, atoma.operator)
3243 + # Version matching
3244 + elif atoma.cpv != atomb.cpv:
3245 + return vercmp(atoma.version, atomb.version)
3246 + # Versions match, let's fallback to operator matching
3247 + else:
3248 + return cmp_func(
3249 + ops.get(atoma.operator, -1),
3250 + ops.get(atomb.operator, -1),
3251 + )
3252 +
3253 + def _Atom(key):
3254 + if key is not None:
3255 + return Atom(key)
3256 + return None
3257 +
3258 + resdict = usedict[flag]
3259 + if len(resdict) == 1:
3260 + resdesc = next(iter(resdict.items()))[1]
3261 + else:
3262 + try:
3263 + reskeys = dict((_Atom(k), k) for k in resdict)
3264 + except portage.exception.InvalidAtom as e:
3265 + writemsg_level(
3266 + "ERROR: failed parsing %s/metadata.xml: %s\n"
3267 + % (cp, e),
3268 + level=logging.ERROR,
3269 + noiselevel=-1,
3270 + )
3271 + self.returncode |= 1
3272 + resdesc = next(iter(resdict.items()))[1]
3273 + else:
3274 + resatoms = sorted(reskeys, key=cmp_sort_key(atomcmp))
3275 + resdesc = resdict[reskeys[resatoms[-1]]]
3276 +
3277 + output.write("%s:%s - %s\n" % (cp, flag, resdesc))
3278 +
3279 + output.close()
3280 + if prev_mtime is not None and prev_md5 == portage.checksum.perform_md5(
3281 + desc_path
3282 + ):
3283 + # Preserve mtime for rsync.
3284 + mtime = prev_mtime
3285 + else:
3286 + # For portability, and consistency with the mtime preservation
3287 + # code, set mtime to an exact integer value.
3288 + mtime = int(time.time())
3289 +
3290 + os.utime(desc_path, (mtime, mtime))
3291
3292
3293 class GenChangeLogs:
3294 - def __init__(self, portdb, changelog_output, changelog_reversed,
3295 - max_jobs=None, max_load=None):
3296 - self.returncode = os.EX_OK
3297 - self._portdb = portdb
3298 - self._wrapper = textwrap.TextWrapper(
3299 - width = 78,
3300 - initial_indent = ' ',
3301 - subsequent_indent = ' '
3302 - )
3303 - self._changelog_output = changelog_output
3304 - self._changelog_reversed = changelog_reversed
3305 - self._max_jobs = max_jobs
3306 - self._max_load = max_load
3307 - self._repo_path = self._portdb.porttrees[0]
3308 - # --work-tree=... must be passed to Git if GIT_DIR is used
3309 - # and GIT_DIR is not a child of the root of the checkout
3310 - # eg:
3311 - # GIT_DIR=$parent/work/.git/
3312 - # work-tree=$parent/staging/
3313 - # If work-tree is not passed, Git tries to use the shared
3314 - # parent of the current directory and the $GIT_DIR, which can
3315 - # be outside the root of the checkout.
3316 - self._work_tree = '--work-tree=%s' % self._repo_path
3317 -
3318 - @staticmethod
3319 - def grab(cmd):
3320 - p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
3321 - return _unicode_decode(p.communicate()[0],
3322 - encoding=_encodings['stdio'], errors='strict')
3323 -
3324 - def generate_changelog(self, cp):
3325 -
3326 - os.chdir(os.path.join(self._repo_path, cp))
3327 - # Determine whether ChangeLog is up-to-date by comparing
3328 - # the newest commit timestamp with the ChangeLog timestamp.
3329 - lmod = self.grab(['git', self._work_tree, 'log', '--format=%ct', '-1', '.'])
3330 - if not lmod:
3331 - # This cp has not been added to the repo.
3332 - return
3333 -
3334 - lmod = int(lmod)
3335 -
3336 - try:
3337 - cmod = os.stat('ChangeLog')[stat.ST_MTIME]
3338 - except OSError:
3339 - cmod = 0
3340 -
3341 - # Use exact comparison, since commit times are
3342 - # not necessarily ordered.
3343 - if cmod == lmod:
3344 - return
3345 -
3346 - try:
3347 - output = io.open(self._changelog_output,
3348 - mode='w', encoding=_encodings['repo.content'],
3349 - errors='backslashreplace')
3350 - except IOError as e:
3351 - writemsg_level(
3352 - "ERROR: failed to open ChangeLog for %s: %s\n" % (cp,e,),
3353 - level=logging.ERROR, noiselevel=-1)
3354 - self.returncode |= 2
3355 - return
3356 -
3357 - output.write(textwrap.dedent('''\
3358 + def __init__(
3359 + self, portdb, changelog_output, changelog_reversed, max_jobs=None, max_load=None
3360 + ):
3361 + self.returncode = os.EX_OK
3362 + self._portdb = portdb
3363 + self._wrapper = textwrap.TextWrapper(
3364 + width=78, initial_indent=" ", subsequent_indent=" "
3365 + )
3366 + self._changelog_output = changelog_output
3367 + self._changelog_reversed = changelog_reversed
3368 + self._max_jobs = max_jobs
3369 + self._max_load = max_load
3370 + self._repo_path = self._portdb.porttrees[0]
3371 + # --work-tree=... must be passed to Git if GIT_DIR is used
3372 + # and GIT_DIR is not a child of the root of the checkout
3373 + # eg:
3374 + # GIT_DIR=$parent/work/.git/
3375 + # work-tree=$parent/staging/
3376 + # If work-tree is not passed, Git tries to use the shared
3377 + # parent of the current directory and the $GIT_DIR, which can
3378 + # be outside the root of the checkout.
3379 + self._work_tree = "--work-tree=%s" % self._repo_path
3380 +
3381 + @staticmethod
3382 + def grab(cmd):
3383 + p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
3384 + return _unicode_decode(
3385 + p.communicate()[0], encoding=_encodings["stdio"], errors="strict"
3386 + )
3387 +
3388 + def generate_changelog(self, cp):
3389 +
3390 + os.chdir(os.path.join(self._repo_path, cp))
3391 + # Determine whether ChangeLog is up-to-date by comparing
3392 + # the newest commit timestamp with the ChangeLog timestamp.
3393 + lmod = self.grab(["git", self._work_tree, "log", "--format=%ct", "-1", "."])
3394 + if not lmod:
3395 + # This cp has not been added to the repo.
3396 + return
3397 +
3398 + lmod = int(lmod)
3399 +
3400 + try:
3401 + cmod = os.stat("ChangeLog")[stat.ST_MTIME]
3402 + except OSError:
3403 + cmod = 0
3404 +
3405 + # Use exact comparison, since commit times are
3406 + # not necessarily ordered.
3407 + if cmod == lmod:
3408 + return
3409 +
3410 + try:
3411 + output = io.open(
3412 + self._changelog_output,
3413 + mode="w",
3414 + encoding=_encodings["repo.content"],
3415 + errors="backslashreplace",
3416 + )
3417 + except IOError as e:
3418 + writemsg_level(
3419 + "ERROR: failed to open ChangeLog for %s: %s\n"
3420 + % (
3421 + cp,
3422 + e,
3423 + ),
3424 + level=logging.ERROR,
3425 + noiselevel=-1,
3426 + )
3427 + self.returncode |= 2
3428 + return
3429 +
3430 + output.write(
3431 + textwrap.dedent(
3432 + """\
3433 # ChangeLog for %s
3434 # Copyright 1999-%s Gentoo Foundation; Distributed under the GPL v2
3435 # (auto-generated from git log)
3436
3437 - ''' % (cp, time.strftime('%Y'))))
3438 -
3439 - # now grab all the commits
3440 - revlist_cmd = ['git', self._work_tree, 'rev-list']
3441 - if self._changelog_reversed:
3442 - revlist_cmd.append('--reverse')
3443 - revlist_cmd.extend(['HEAD', '--', '.'])
3444 - commits = self.grab(revlist_cmd).split()
3445 -
3446 - for c in commits:
3447 - # Explaining the arguments:
3448 - # --name-status to get a list of added/removed files
3449 - # --no-renames to avoid getting more complex records on the list
3450 - # --format to get the timestamp, author and commit description
3451 - # --root to make it work fine even with the initial commit
3452 - # --relative=$cp to get paths relative to ebuilddir
3453 - # -r (recursive) to get per-file changes
3454 - # then the commit-id and path.
3455 -
3456 - cinfo = self.grab(['git', self._work_tree, 'diff-tree',
3457 - '--name-status',
3458 - '--no-renames',
3459 - '--format=%ct %cN <%cE>%n%B',
3460 - '--root',
3461 - '--relative=%s' % (cp, ),
3462 - '-r',
3463 - c, '--', '.']).rstrip('\n').split('\n')
3464 -
3465 - # Expected output:
3466 - # timestamp Author Name <author@email>
3467 - # commit message l1
3468 - # ...
3469 - # commit message ln
3470 - #
3471 - # status1 filename1
3472 - # ...
3473 - # statusn filenamen
3474 -
3475 - changed = []
3476 - for n, l in enumerate(reversed(cinfo)):
3477 - if not l:
3478 - body = cinfo[1:-n-1]
3479 - break
3480 - else:
3481 - f = l.split()
3482 - if f[1] == 'Manifest':
3483 - pass # XXX: remanifest commits?
3484 - elif f[1].startswith('ChangeLog'):
3485 - pass
3486 - elif f[0].startswith('A'):
3487 - changed.append(ChangeLogTypeSort("+", f[1]))
3488 - elif f[0].startswith('D'):
3489 - changed.append(ChangeLogTypeSort("-", f[1]))
3490 - elif f[0].startswith('M'):
3491 - changed.append(ChangeLogTypeSort("", f[1]))
3492 - else:
3493 - writemsg_level(
3494 - "ERROR: unexpected git file status for %s: %s\n" % (cp,f,),
3495 - level=logging.ERROR, noiselevel=-1)
3496 - self.returncode |= 1
3497 -
3498 - if not changed:
3499 - continue
3500 -
3501 - (ts, author) = cinfo[0].split(' ', 1)
3502 - date = time.strftime('%d %b %Y', time.gmtime(float(ts)))
3503 -
3504 - changed = [str(x) for x in sorted(changed)]
3505 -
3506 - wroteheader = False
3507 - # Reverse the sort order for headers.
3508 - for c in reversed(changed):
3509 - if c.startswith('+') and c.endswith('.ebuild'):
3510 - output.write('*%s (%s)\n' % (c[1:-7], date))
3511 - wroteheader = True
3512 - if wroteheader:
3513 - output.write('\n')
3514 -
3515 - # strip '<cp>: ', '[<cp>] ', and similar
3516 - body[0] = re.sub(r'^\W*' + re.escape(cp) + r'\W+', '', body[0])
3517 - # strip trailing newline
3518 - if not body[-1]:
3519 - body = body[:-1]
3520 - # strip git-svn id
3521 - if body[-1].startswith('git-svn-id:') and not body[-2]:
3522 - body = body[:-2]
3523 - # strip the repoman version/manifest note
3524 - if body[-1] == ' (Signed Manifest commit)' or body[-1] == ' (Unsigned Manifest commit)':
3525 - body = body[:-1]
3526 - if body[-1].startswith('(Portage version:') and body[-1].endswith(')'):
3527 - body = body[:-1]
3528 - if not body[-1]:
3529 - body = body[:-1]
3530 -
3531 - # don't break filenames on hyphens
3532 - self._wrapper.break_on_hyphens = False
3533 - output.write(self._wrapper.fill(
3534 - '%s; %s %s:' % (date, author, ', '.join(changed))))
3535 - # but feel free to break commit messages there
3536 - self._wrapper.break_on_hyphens = True
3537 - output.write(
3538 - '\n%s\n\n' % '\n'.join(self._wrapper.fill(x) for x in body))
3539 -
3540 - output.close()
3541 - os.utime(self._changelog_output, (lmod, lmod))
3542 -
3543 - def _task_iter(self):
3544 - if not os.path.isdir(os.environ.get('GIT_DIR', os.path.join(self._repo_path, '.git'))):
3545 - writemsg_level(
3546 - "ERROR: --update-changelogs supported only in git repos\n",
3547 - level=logging.ERROR, noiselevel=-1)
3548 - self.returncode = 127
3549 - return
3550 -
3551 - for cp in self._portdb.cp_all():
3552 - yield AsyncFunction(target=self.generate_changelog, args=[cp])
3553 -
3554 - def run(self):
3555 - return run_main_scheduler(
3556 - TaskScheduler(self._task_iter(), event_loop=global_event_loop(),
3557 - max_jobs=self._max_jobs, max_load=self._max_load))
3558 + """
3559 + % (cp, time.strftime("%Y"))
3560 + )
3561 + )
3562 +
3563 + # now grab all the commits
3564 + revlist_cmd = ["git", self._work_tree, "rev-list"]
3565 + if self._changelog_reversed:
3566 + revlist_cmd.append("--reverse")
3567 + revlist_cmd.extend(["HEAD", "--", "."])
3568 + commits = self.grab(revlist_cmd).split()
3569 +
3570 + for c in commits:
3571 + # Explaining the arguments:
3572 + # --name-status to get a list of added/removed files
3573 + # --no-renames to avoid getting more complex records on the list
3574 + # --format to get the timestamp, author and commit description
3575 + # --root to make it work fine even with the initial commit
3576 + # --relative=$cp to get paths relative to ebuilddir
3577 + # -r (recursive) to get per-file changes
3578 + # then the commit-id and path.
3579 +
3580 + cinfo = (
3581 + self.grab(
3582 + [
3583 + "git",
3584 + self._work_tree,
3585 + "diff-tree",
3586 + "--name-status",
3587 + "--no-renames",
3588 + "--format=%ct %cN <%cE>%n%B",
3589 + "--root",
3590 + "--relative=%s" % (cp,),
3591 + "-r",
3592 + c,
3593 + "--",
3594 + ".",
3595 + ]
3596 + )
3597 + .rstrip("\n")
3598 + .split("\n")
3599 + )
3600 +
3601 + # Expected output:
3602 + # timestamp Author Name <author@email>
3603 + # commit message l1
3604 + # ...
3605 + # commit message ln
3606 + #
3607 + # status1 filename1
3608 + # ...
3609 + # statusn filenamen
3610 +
3611 + changed = []
3612 + for n, l in enumerate(reversed(cinfo)):
3613 + if not l:
3614 + body = cinfo[1 : -n - 1]
3615 + break
3616 + else:
3617 + f = l.split()
3618 + if f[1] == "Manifest":
3619 + pass # XXX: remanifest commits?
3620 + elif f[1].startswith("ChangeLog"):
3621 + pass
3622 + elif f[0].startswith("A"):
3623 + changed.append(ChangeLogTypeSort("+", f[1]))
3624 + elif f[0].startswith("D"):
3625 + changed.append(ChangeLogTypeSort("-", f[1]))
3626 + elif f[0].startswith("M"):
3627 + changed.append(ChangeLogTypeSort("", f[1]))
3628 + else:
3629 + writemsg_level(
3630 + "ERROR: unexpected git file status for %s: %s\n"
3631 + % (
3632 + cp,
3633 + f,
3634 + ),
3635 + level=logging.ERROR,
3636 + noiselevel=-1,
3637 + )
3638 + self.returncode |= 1
3639 +
3640 + if not changed:
3641 + continue
3642 +
3643 + (ts, author) = cinfo[0].split(" ", 1)
3644 + date = time.strftime("%d %b %Y", time.gmtime(float(ts)))
3645 +
3646 + changed = [str(x) for x in sorted(changed)]
3647 +
3648 + wroteheader = False
3649 + # Reverse the sort order for headers.
3650 + for c in reversed(changed):
3651 + if c.startswith("+") and c.endswith(".ebuild"):
3652 + output.write("*%s (%s)\n" % (c[1:-7], date))
3653 + wroteheader = True
3654 + if wroteheader:
3655 + output.write("\n")
3656 +
3657 + # strip '<cp>: ', '[<cp>] ', and similar
3658 + body[0] = re.sub(r"^\W*" + re.escape(cp) + r"\W+", "", body[0])
3659 + # strip trailing newline
3660 + if not body[-1]:
3661 + body = body[:-1]
3662 + # strip git-svn id
3663 + if body[-1].startswith("git-svn-id:") and not body[-2]:
3664 + body = body[:-2]
3665 + # strip the repoman version/manifest note
3666 + if (
3667 + body[-1] == " (Signed Manifest commit)"
3668 + or body[-1] == " (Unsigned Manifest commit)"
3669 + ):
3670 + body = body[:-1]
3671 + if body[-1].startswith("(Portage version:") and body[-1].endswith(")"):
3672 + body = body[:-1]
3673 + if not body[-1]:
3674 + body = body[:-1]
3675 +
3676 + # don't break filenames on hyphens
3677 + self._wrapper.break_on_hyphens = False
3678 + output.write(
3679 + self._wrapper.fill("%s; %s %s:" % (date, author, ", ".join(changed)))
3680 + )
3681 + # but feel free to break commit messages there
3682 + self._wrapper.break_on_hyphens = True
3683 + output.write("\n%s\n\n" % "\n".join(self._wrapper.fill(x) for x in body))
3684 +
3685 + output.close()
3686 + os.utime(self._changelog_output, (lmod, lmod))
3687 +
3688 + def _task_iter(self):
3689 + if not os.path.isdir(
3690 + os.environ.get("GIT_DIR", os.path.join(self._repo_path, ".git"))
3691 + ):
3692 + writemsg_level(
3693 + "ERROR: --update-changelogs supported only in git repos\n",
3694 + level=logging.ERROR,
3695 + noiselevel=-1,
3696 + )
3697 + self.returncode = 127
3698 + return
3699 +
3700 + for cp in self._portdb.cp_all():
3701 + yield AsyncFunction(target=self.generate_changelog, args=[cp])
3702 +
3703 + def run(self):
3704 + return run_main_scheduler(
3705 + TaskScheduler(
3706 + self._task_iter(),
3707 + event_loop=global_event_loop(),
3708 + max_jobs=self._max_jobs,
3709 + max_load=self._max_load,
3710 + )
3711 + )
3712 +
3713
3714 def egencache_main(args):
3715
3716 - # The calling environment is ignored, so the program is
3717 - # completely controlled by commandline arguments.
3718 - env = {}
3719 -
3720 - if (not sys.stdout.isatty() or
3721 - os.environ.get('NOCOLOR', '').lower() in ('yes', 'true')):
3722 - portage.output.nocolor()
3723 - env['NOCOLOR'] = 'true'
3724 + # The calling environment is ignored, so the program is
3725 + # completely controlled by commandline arguments.
3726 + env = {}
3727 +
3728 + if not sys.stdout.isatty() or os.environ.get("NOCOLOR", "").lower() in (
3729 + "yes",
3730 + "true",
3731 + ):
3732 + portage.output.nocolor()
3733 + env["NOCOLOR"] = "true"
3734 +
3735 + parser, options, atoms = parse_args(args)
3736 +
3737 + config_root = options.config_root
3738 +
3739 + if options.repositories_configuration is not None:
3740 + env["PORTAGE_REPOSITORIES"] = options.repositories_configuration
3741 +
3742 + if options.cache_dir is not None:
3743 + env["PORTAGE_DEPCACHEDIR"] = options.cache_dir
3744 +
3745 + settings = portage.config(config_root=config_root, local_config=False, env=env)
3746 +
3747 + default_opts = None
3748 + if not options.ignore_default_opts:
3749 + default_opts = portage.util.shlex_split(
3750 + settings.get("EGENCACHE_DEFAULT_OPTS", "")
3751 + )
3752 +
3753 + if default_opts:
3754 + parser, options, args = parse_args(default_opts + args)
3755 +
3756 + if options.cache_dir is not None:
3757 + env["PORTAGE_DEPCACHEDIR"] = options.cache_dir
3758 +
3759 + settings = portage.config(config_root=config_root, local_config=False, env=env)
3760 +
3761 + if not (
3762 + options.update
3763 + or options.update_use_local_desc
3764 + or options.update_changelogs
3765 + or options.update_manifests
3766 + or options.update_pkg_desc_index
3767 + ):
3768 + parser.error("No action specified")
3769 + return 1
3770 +
3771 + if options.repo is None:
3772 + if len(settings.repositories.prepos) == 2:
3773 + for repo in settings.repositories:
3774 + if repo.name != "DEFAULT":
3775 + options.repo = repo.name
3776 + break
3777 +
3778 + if options.repo is None:
3779 + parser.error("--repo option is required")
3780 +
3781 + repo_path = settings.repositories.treemap.get(options.repo)
3782 + if repo_path is None:
3783 + parser.error("Unable to locate repository named '%s'" % (options.repo,))
3784 + return 1
3785 +
3786 + repo_config = settings.repositories.get_repo_for_location(repo_path)
3787 +
3788 + if options.strict_manifests is not None:
3789 + if options.strict_manifests == "y":
3790 + settings.features.add("strict")
3791 + else:
3792 + settings.features.discard("strict")
3793 +
3794 + if options.update and "metadata-transfer" not in settings.features:
3795 + # Forcibly enable metadata-transfer if portdbapi has a pregenerated
3796 + # cache that does not support eclass validation.
3797 + cache = repo_config.get_pregenerated_cache(
3798 + portage.dbapi.dbapi._known_keys, readonly=True
3799 + )
3800 + if cache is not None and not cache.complete_eclass_entries:
3801 + settings.features.add("metadata-transfer")
3802 + cache = None
3803 +
3804 + settings.lock()
3805 +
3806 + portdb = portage.portdbapi(mysettings=settings)
3807 +
3808 + # Limit ebuilds to the specified repo.
3809 + portdb.porttrees = [repo_path]
3810 +
3811 + if options.update:
3812 + if options.cache_dir is not None:
3813 + # already validated earlier
3814 + pass
3815 + else:
3816 + # We check write access after the portdbapi constructor
3817 + # has had an opportunity to create it. This ensures that
3818 + # we don't use the cache in the "volatile" mode which is
3819 + # undesirable for egencache.
3820 + if not os.access(settings["PORTAGE_DEPCACHEDIR"], os.W_OK):
3821 + writemsg_level(
3822 + "ecachegen: error: "
3823 + + "write access denied: %s\n" % (settings["PORTAGE_DEPCACHEDIR"],),
3824 + level=logging.ERROR,
3825 + noiselevel=-1,
3826 + )
3827 + return 1
3828 +
3829 + if options.sign_manifests is not None:
3830 + repo_config.sign_manifest = options.sign_manifests == "y"
3831 +
3832 + if options.thin_manifests is not None:
3833 + repo_config.thin_manifest = options.thin_manifests == "y"
3834 +
3835 + gpg_cmd = None
3836 + gpg_vars = None
3837 + force_sign_key = None
3838 +
3839 + if options.update_manifests:
3840 + if repo_config.sign_manifest:
3841 +
3842 + sign_problem = False
3843 + gpg_dir = None
3844 + gpg_cmd = settings.get("PORTAGE_GPG_SIGNING_COMMAND")
3845 + if gpg_cmd is None:
3846 + writemsg_level(
3847 + "egencache: error: "
3848 + "PORTAGE_GPG_SIGNING_COMMAND is unset! "
3849 + "Is make.globals missing?\n",
3850 + level=logging.ERROR,
3851 + noiselevel=-1,
3852 + )
3853 + sign_problem = True
3854 + elif (
3855 + "${PORTAGE_GPG_KEY}" in gpg_cmd
3856 + and options.gpg_key is None
3857 + and "PORTAGE_GPG_KEY" not in settings
3858 + ):
3859 + writemsg_level(
3860 + "egencache: error: " "PORTAGE_GPG_KEY is unset!\n",
3861 + level=logging.ERROR,
3862 + noiselevel=-1,
3863 + )
3864 + sign_problem = True
3865 + elif "${PORTAGE_GPG_DIR}" in gpg_cmd:
3866 + if options.gpg_dir is not None:
3867 + gpg_dir = options.gpg_dir
3868 + elif "PORTAGE_GPG_DIR" not in settings:
3869 + gpg_dir = os.path.expanduser("~/.gnupg")
3870 + else:
3871 + gpg_dir = os.path.expanduser(settings["PORTAGE_GPG_DIR"])
3872 + if not os.access(gpg_dir, os.X_OK):
3873 + writemsg_level(
3874 + (
3875 + "egencache: error: "
3876 + "Unable to access directory: "
3877 + "PORTAGE_GPG_DIR='%s'\n"
3878 + )
3879 + % gpg_dir,
3880 + level=logging.ERROR,
3881 + noiselevel=-1,
3882 + )
3883 + sign_problem = True
3884 +
3885 + if sign_problem:
3886 + writemsg_level(
3887 + "egencache: You may disable manifest "
3888 + "signatures with --sign-manifests=n or by setting "
3889 + '"sign-manifests = false" in metadata/layout.conf\n',
3890 + level=logging.ERROR,
3891 + noiselevel=-1,
3892 + )
3893 + return 1
3894 +
3895 + gpg_vars = {}
3896 + if gpg_dir is not None:
3897 + gpg_vars["PORTAGE_GPG_DIR"] = gpg_dir
3898 + gpg_var_names = []
3899 + if options.gpg_key is None:
3900 + gpg_var_names.append("PORTAGE_GPG_KEY")
3901 + else:
3902 + gpg_vars["PORTAGE_GPG_KEY"] = options.gpg_key
3903 +
3904 + for k in gpg_var_names:
3905 + v = settings.get(k)
3906 + if v is not None:
3907 + gpg_vars[k] = v
3908 +
3909 + force_sign_key = gpg_vars.get("PORTAGE_GPG_KEY")
3910 +
3911 + ret = [os.EX_OK]
3912 +
3913 + if options.update:
3914 + cp_iter = None
3915 + if atoms:
3916 + cp_iter = iter(atoms)
3917 +
3918 + gen_cache = GenCache(
3919 + portdb,
3920 + cp_iter=cp_iter,
3921 + max_jobs=options.jobs,
3922 + max_load=options.load_average,
3923 + rsync=options.rsync,
3924 + external_cache_only=options.external_cache_only,
3925 + )
3926 + gen_cache.run()
3927 + if options.tolerant:
3928 + ret.append(os.EX_OK)
3929 + else:
3930 + ret.append(gen_cache.returncode)
3931 +
3932 + if options.update_pkg_desc_index:
3933 + if not options.external_cache_only and repo_config.writable:
3934 + writable_location = repo_config.location
3935 + else:
3936 + writable_location = os.path.join(
3937 + portdb.depcachedir, repo_config.location.lstrip(os.sep)
3938 + )
3939 + if not options.external_cache_only:
3940 + msg = [
3941 + "WARNING: Repository is not writable: %s" % (repo_config.location,),
3942 + " Using cache directory instead: %s" % (writable_location,),
3943 + ]
3944 + msg = "".join(line + "\n" for line in msg)
3945 + writemsg_level(msg, level=logging.WARNING, noiselevel=-1)
3946 +
3947 + gen_index = GenPkgDescIndex(
3948 + repo_config,
3949 + portdb,
3950 + os.path.join(writable_location, "metadata", "pkg_desc_index"),
3951 + verbose=options.verbose,
3952 + )
3953 + gen_index.run()
3954 + ret.append(gen_index.returncode)
3955 +
3956 + if options.update_use_local_desc:
3957 + gen_desc = GenUseLocalDesc(
3958 + portdb,
3959 + output=options.uld_output,
3960 + preserve_comments=options.preserve_comments,
3961 + )
3962 + gen_desc.run()
3963 + ret.append(gen_desc.returncode)
3964 +
3965 + if options.update_changelogs:
3966 + gen_clogs = GenChangeLogs(
3967 + portdb,
3968 + changelog_output=options.changelog_output,
3969 + changelog_reversed=options.changelog_reversed,
3970 + max_jobs=options.jobs,
3971 + max_load=options.load_average,
3972 + )
3973 + signum = gen_clogs.run()
3974 + if signum is not None:
3975 + sys.exit(128 + signum)
3976 + ret.append(gen_clogs.returncode)
3977 +
3978 + if options.update_manifests:
3979 +
3980 + cp_iter = None
3981 + if atoms:
3982 + cp_iter = iter(atoms)
3983 +
3984 + event_loop = global_event_loop()
3985 + scheduler = ManifestScheduler(
3986 + portdb,
3987 + cp_iter=cp_iter,
3988 + gpg_cmd=gpg_cmd,
3989 + gpg_vars=gpg_vars,
3990 + force_sign_key=force_sign_key,
3991 + max_jobs=options.jobs,
3992 + max_load=options.load_average,
3993 + event_loop=event_loop,
3994 + )
3995 +
3996 + signum = run_main_scheduler(scheduler)
3997 + if signum is not None:
3998 + sys.exit(128 + signum)
3999 +
4000 + if options.tolerant:
4001 + ret.append(os.EX_OK)
4002 + else:
4003 + ret.append(scheduler.returncode)
4004 +
4005 + if options.write_timestamp:
4006 + timestamp_path = os.path.join(repo_path, "metadata", "timestamp.chk")
4007 + try:
4008 + portage.util.write_atomic(
4009 + timestamp_path, time.strftime("%s\n" % TIMESTAMP_FORMAT, time.gmtime())
4010 + )
4011 + except (EnvironmentError, portage.exception.PortageException):
4012 + ret.append(os.EX_IOERR)
4013 + else:
4014 + ret.append(os.EX_OK)
4015 +
4016 + return max(ret)
4017
4018 - parser, options, atoms = parse_args(args)
4019 -
4020 - config_root = options.config_root
4021 -
4022 - if options.repositories_configuration is not None:
4023 - env['PORTAGE_REPOSITORIES'] = options.repositories_configuration
4024 -
4025 - if options.cache_dir is not None:
4026 - env['PORTAGE_DEPCACHEDIR'] = options.cache_dir
4027 -
4028 - settings = portage.config(config_root=config_root,
4029 - local_config=False, env=env)
4030 -
4031 - default_opts = None
4032 - if not options.ignore_default_opts:
4033 - default_opts = portage.util.shlex_split(
4034 - settings.get('EGENCACHE_DEFAULT_OPTS', ''))
4035 -
4036 - if default_opts:
4037 - parser, options, args = parse_args(default_opts + args)
4038 -
4039 - if options.cache_dir is not None:
4040 - env['PORTAGE_DEPCACHEDIR'] = options.cache_dir
4041 -
4042 - settings = portage.config(config_root=config_root,
4043 - local_config=False, env=env)
4044 -
4045 - if not (options.update or options.update_use_local_desc or
4046 - options.update_changelogs or options.update_manifests or
4047 - options.update_pkg_desc_index):
4048 - parser.error('No action specified')
4049 - return 1
4050 -
4051 - if options.repo is None:
4052 - if len(settings.repositories.prepos) == 2:
4053 - for repo in settings.repositories:
4054 - if repo.name != "DEFAULT":
4055 - options.repo = repo.name
4056 - break
4057 -
4058 - if options.repo is None:
4059 - parser.error("--repo option is required")
4060 -
4061 - repo_path = settings.repositories.treemap.get(options.repo)
4062 - if repo_path is None:
4063 - parser.error("Unable to locate repository named '%s'" % (options.repo,))
4064 - return 1
4065 -
4066 - repo_config = settings.repositories.get_repo_for_location(repo_path)
4067 -
4068 - if options.strict_manifests is not None:
4069 - if options.strict_manifests == "y":
4070 - settings.features.add("strict")
4071 - else:
4072 - settings.features.discard("strict")
4073 -
4074 - if options.update and 'metadata-transfer' not in settings.features:
4075 - # Forcibly enable metadata-transfer if portdbapi has a pregenerated
4076 - # cache that does not support eclass validation.
4077 - cache = repo_config.get_pregenerated_cache(
4078 - portage.dbapi.dbapi._known_keys, readonly=True)
4079 - if cache is not None and not cache.complete_eclass_entries:
4080 - settings.features.add('metadata-transfer')
4081 - cache = None
4082 -
4083 - settings.lock()
4084 -
4085 - portdb = portage.portdbapi(mysettings=settings)
4086 -
4087 - # Limit ebuilds to the specified repo.
4088 - portdb.porttrees = [repo_path]
4089 -
4090 - if options.update:
4091 - if options.cache_dir is not None:
4092 - # already validated earlier
4093 - pass
4094 - else:
4095 - # We check write access after the portdbapi constructor
4096 - # has had an opportunity to create it. This ensures that
4097 - # we don't use the cache in the "volatile" mode which is
4098 - # undesirable for egencache.
4099 - if not os.access(settings["PORTAGE_DEPCACHEDIR"], os.W_OK):
4100 - writemsg_level("ecachegen: error: " + \
4101 - "write access denied: %s\n" % (settings["PORTAGE_DEPCACHEDIR"],),
4102 - level=logging.ERROR, noiselevel=-1)
4103 - return 1
4104 -
4105 - if options.sign_manifests is not None:
4106 - repo_config.sign_manifest = options.sign_manifests == 'y'
4107 -
4108 - if options.thin_manifests is not None:
4109 - repo_config.thin_manifest = options.thin_manifests == 'y'
4110 -
4111 - gpg_cmd = None
4112 - gpg_vars = None
4113 - force_sign_key = None
4114 -
4115 - if options.update_manifests:
4116 - if repo_config.sign_manifest:
4117 -
4118 - sign_problem = False
4119 - gpg_dir = None
4120 - gpg_cmd = settings.get("PORTAGE_GPG_SIGNING_COMMAND")
4121 - if gpg_cmd is None:
4122 - writemsg_level("egencache: error: "
4123 - "PORTAGE_GPG_SIGNING_COMMAND is unset! "
4124 - "Is make.globals missing?\n",
4125 - level=logging.ERROR, noiselevel=-1)
4126 - sign_problem = True
4127 - elif "${PORTAGE_GPG_KEY}" in gpg_cmd and \
4128 - options.gpg_key is None and \
4129 - "PORTAGE_GPG_KEY" not in settings:
4130 - writemsg_level("egencache: error: "
4131 - "PORTAGE_GPG_KEY is unset!\n",
4132 - level=logging.ERROR, noiselevel=-1)
4133 - sign_problem = True
4134 - elif "${PORTAGE_GPG_DIR}" in gpg_cmd:
4135 - if options.gpg_dir is not None:
4136 - gpg_dir = options.gpg_dir
4137 - elif "PORTAGE_GPG_DIR" not in settings:
4138 - gpg_dir = os.path.expanduser("~/.gnupg")
4139 - else:
4140 - gpg_dir = os.path.expanduser(settings["PORTAGE_GPG_DIR"])
4141 - if not os.access(gpg_dir, os.X_OK):
4142 - writemsg_level(("egencache: error: "
4143 - "Unable to access directory: "
4144 - "PORTAGE_GPG_DIR='%s'\n") % gpg_dir,
4145 - level=logging.ERROR, noiselevel=-1)
4146 - sign_problem = True
4147 -
4148 - if sign_problem:
4149 - writemsg_level("egencache: You may disable manifest "
4150 - "signatures with --sign-manifests=n or by setting "
4151 - "\"sign-manifests = false\" in metadata/layout.conf\n",
4152 - level=logging.ERROR, noiselevel=-1)
4153 - return 1
4154 -
4155 - gpg_vars = {}
4156 - if gpg_dir is not None:
4157 - gpg_vars["PORTAGE_GPG_DIR"] = gpg_dir
4158 - gpg_var_names = []
4159 - if options.gpg_key is None:
4160 - gpg_var_names.append("PORTAGE_GPG_KEY")
4161 - else:
4162 - gpg_vars["PORTAGE_GPG_KEY"] = options.gpg_key
4163 -
4164 - for k in gpg_var_names:
4165 - v = settings.get(k)
4166 - if v is not None:
4167 - gpg_vars[k] = v
4168 -
4169 - force_sign_key = gpg_vars.get("PORTAGE_GPG_KEY")
4170 -
4171 - ret = [os.EX_OK]
4172 -
4173 - if options.update:
4174 - cp_iter = None
4175 - if atoms:
4176 - cp_iter = iter(atoms)
4177 -
4178 - gen_cache = GenCache(portdb, cp_iter=cp_iter,
4179 - max_jobs=options.jobs,
4180 - max_load=options.load_average,
4181 - rsync=options.rsync,
4182 - external_cache_only=options.external_cache_only)
4183 - gen_cache.run()
4184 - if options.tolerant:
4185 - ret.append(os.EX_OK)
4186 - else:
4187 - ret.append(gen_cache.returncode)
4188 -
4189 - if options.update_pkg_desc_index:
4190 - if not options.external_cache_only and repo_config.writable:
4191 - writable_location = repo_config.location
4192 - else:
4193 - writable_location = os.path.join(portdb.depcachedir,
4194 - repo_config.location.lstrip(os.sep))
4195 - if not options.external_cache_only:
4196 - msg = [
4197 - "WARNING: Repository is not writable: %s" % (
4198 - repo_config.location,),
4199 - " Using cache directory instead: %s" % (
4200 - writable_location,)
4201 - ]
4202 - msg = "".join(line + '\n' for line in msg)
4203 - writemsg_level(msg,
4204 - level=logging.WARNING, noiselevel=-1)
4205 -
4206 - gen_index = GenPkgDescIndex(repo_config, portdb, os.path.join(
4207 - writable_location, "metadata", "pkg_desc_index"),
4208 - verbose=options.verbose)
4209 - gen_index.run()
4210 - ret.append(gen_index.returncode)
4211 -
4212 - if options.update_use_local_desc:
4213 - gen_desc = GenUseLocalDesc(portdb,
4214 - output=options.uld_output,
4215 - preserve_comments=options.preserve_comments)
4216 - gen_desc.run()
4217 - ret.append(gen_desc.returncode)
4218 -
4219 - if options.update_changelogs:
4220 - gen_clogs = GenChangeLogs(portdb,
4221 - changelog_output=options.changelog_output,
4222 - changelog_reversed=options.changelog_reversed,
4223 - max_jobs=options.jobs,
4224 - max_load=options.load_average)
4225 - signum = gen_clogs.run()
4226 - if signum is not None:
4227 - sys.exit(128 + signum)
4228 - ret.append(gen_clogs.returncode)
4229 -
4230 - if options.update_manifests:
4231 -
4232 - cp_iter = None
4233 - if atoms:
4234 - cp_iter = iter(atoms)
4235 -
4236 - event_loop = global_event_loop()
4237 - scheduler = ManifestScheduler(portdb, cp_iter=cp_iter,
4238 - gpg_cmd=gpg_cmd, gpg_vars=gpg_vars,
4239 - force_sign_key=force_sign_key,
4240 - max_jobs=options.jobs,
4241 - max_load=options.load_average,
4242 - event_loop=event_loop)
4243 -
4244 - signum = run_main_scheduler(scheduler)
4245 - if signum is not None:
4246 - sys.exit(128 + signum)
4247 -
4248 - if options.tolerant:
4249 - ret.append(os.EX_OK)
4250 - else:
4251 - ret.append(scheduler.returncode)
4252 -
4253 - if options.write_timestamp:
4254 - timestamp_path = os.path.join(repo_path, 'metadata', 'timestamp.chk')
4255 - try:
4256 - portage.util.write_atomic(timestamp_path,
4257 - time.strftime('%s\n' % TIMESTAMP_FORMAT, time.gmtime()))
4258 - except (EnvironmentError, portage.exception.PortageException):
4259 - ret.append(os.EX_IOERR)
4260 - else:
4261 - ret.append(os.EX_OK)
4262 -
4263 - return max(ret)
4264
4265 if __name__ == "__main__":
4266 - portage._disable_legacy_globals()
4267 - portage.util.noiselimit = -1
4268 - try:
4269 - sys.exit(egencache_main(sys.argv[1:]))
4270 - finally:
4271 - global_event_loop().close()
4272 + portage._disable_legacy_globals()
4273 + portage.util.noiselimit = -1
4274 + try:
4275 + sys.exit(egencache_main(sys.argv[1:]))
4276 + finally:
4277 + global_event_loop().close()
4278
4279 diff --git a/bin/emaint b/bin/emaint
4280 index feef8d7e8..bd7b9083c 100755
4281 --- a/bin/emaint
4282 +++ b/bin/emaint
4283 @@ -7,37 +7,44 @@
4284
4285 import sys
4286 import errno
4287 +
4288 # This block ensures that ^C interrupts are handled quietly.
4289 try:
4290 - import signal
4291 + import signal
4292
4293 - def exithandler(signum, _frame):
4294 - signal.signal(signal.SIGINT, signal.SIG_IGN)
4295 - signal.signal(signal.SIGTERM, signal.SIG_IGN)
4296 - sys.exit(128 + signum)
4297 + def exithandler(signum, _frame):
4298 + signal.signal(signal.SIGINT, signal.SIG_IGN)
4299 + signal.signal(signal.SIGTERM, signal.SIG_IGN)
4300 + sys.exit(128 + signum)
4301
4302 - signal.signal(signal.SIGINT, exithandler)
4303 - signal.signal(signal.SIGTERM, exithandler)
4304 - signal.signal(signal.SIGPIPE, signal.SIG_DFL)
4305 + signal.signal(signal.SIGINT, exithandler)
4306 + signal.signal(signal.SIGTERM, exithandler)
4307 + signal.signal(signal.SIGPIPE, signal.SIG_DFL)
4308
4309 except KeyboardInterrupt:
4310 - sys.exit(1)
4311 + sys.exit(1)
4312
4313 from os import path as osp
4314 -if osp.isfile(osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), ".portage_not_installed")):
4315 - sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "lib"))
4316 +
4317 +if osp.isfile(
4318 + osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), ".portage_not_installed")
4319 +):
4320 + sys.path.insert(
4321 + 0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "lib")
4322 + )
4323 import portage
4324 +
4325 portage._internal_caller = True
4326 from portage.emaint.main import emaint_main
4327 from portage.util._eventloop.global_event_loop import global_event_loop
4328
4329 try:
4330 - emaint_main(sys.argv[1:])
4331 + emaint_main(sys.argv[1:])
4332 except IOError as e:
4333 - if e.errno == errno.EACCES:
4334 - print("\nemaint: Need superuser access")
4335 - sys.exit(1)
4336 - else:
4337 - raise
4338 + if e.errno == errno.EACCES:
4339 + print("\nemaint: Need superuser access")
4340 + sys.exit(1)
4341 + else:
4342 + raise
4343 finally:
4344 - global_event_loop().close()
4345 + global_event_loop().close()
4346
4347 diff --git a/bin/emerge b/bin/emerge
4348 index 33ece427c..a407b9d6c 100755
4349 --- a/bin/emerge
4350 +++ b/bin/emerge
4351 @@ -14,71 +14,81 @@ import sys
4352 global_event_loop = None
4353 try:
4354
4355 - def exithandler(signum, _frame):
4356 - signal.signal(signal.SIGTERM, signal.SIG_IGN)
4357 - sys.exit(128 + signum)
4358 + def exithandler(signum, _frame):
4359 + signal.signal(signal.SIGTERM, signal.SIG_IGN)
4360 + sys.exit(128 + signum)
4361
4362 - signal.signal(signal.SIGTERM, exithandler)
4363 - # Prevent "[Errno 32] Broken pipe" exceptions when
4364 - # writing to a pipe.
4365 - signal.signal(signal.SIGPIPE, signal.SIG_DFL)
4366 + signal.signal(signal.SIGTERM, exithandler)
4367 + # Prevent "[Errno 32] Broken pipe" exceptions when
4368 + # writing to a pipe.
4369 + signal.signal(signal.SIGPIPE, signal.SIG_DFL)
4370
4371 - def debug_signal(_signum, _frame):
4372 - import pdb
4373 - pdb.set_trace()
4374 + def debug_signal(_signum, _frame):
4375 + import pdb
4376
4377 - if platform.python_implementation() == 'Jython':
4378 - debug_signum = signal.SIGUSR2 # bug #424259
4379 - else:
4380 - debug_signum = signal.SIGUSR1
4381 + pdb.set_trace()
4382
4383 - signal.signal(debug_signum, debug_signal)
4384 + if platform.python_implementation() == "Jython":
4385 + debug_signum = signal.SIGUSR2 # bug #424259
4386 + else:
4387 + debug_signum = signal.SIGUSR1
4388
4389 - from os import path as osp
4390 - if osp.isfile(osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), ".portage_not_installed")):
4391 - sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "lib"))
4392 - import portage
4393 - portage._internal_caller = True
4394 - portage._disable_legacy_globals()
4395 - from portage.elog import mod_echo
4396 - from portage.exception import IsADirectory, ParseError, PermissionDenied
4397 - from portage.util._eventloop.global_event_loop import global_event_loop
4398 - from _emerge.main import emerge_main
4399 + signal.signal(debug_signum, debug_signal)
4400
4401 - if __name__ == "__main__":
4402 - portage.process.sanitize_fds()
4403 - try:
4404 - retval = emerge_main()
4405 - except PermissionDenied as e:
4406 - sys.stderr.write("Permission denied: '%s'\n" % str(e))
4407 - sys.exit(e.errno)
4408 - except IsADirectory as e:
4409 - sys.stderr.write("'%s' is a directory, but should be a file!\n"
4410 - "See portage man page for information on "
4411 - "which files may be directories.\n" %
4412 - str(e))
4413 - sys.exit(e.errno)
4414 - except ParseError as e:
4415 - sys.stderr.write("%s\n" % str(e))
4416 - sys.exit(1)
4417 - except (KeyboardInterrupt, SystemExit):
4418 - raise
4419 - except Exception:
4420 - # If an unexpected exception occurs then we don't want the
4421 - # mod_echo output to obscure the traceback, so dump the
4422 - # mod_echo output before showing the traceback.
4423 - import traceback
4424 - tb_str = traceback.format_exc()
4425 - mod_echo.finalize()
4426 - sys.stderr.write(tb_str)
4427 - sys.exit(1)
4428 - sys.exit(retval)
4429 + from os import path as osp
4430 +
4431 + if osp.isfile(
4432 + osp.join(
4433 + osp.dirname(osp.dirname(osp.realpath(__file__))), ".portage_not_installed"
4434 + )
4435 + ):
4436 + sys.path.insert(
4437 + 0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "lib")
4438 + )
4439 + import portage
4440 +
4441 + portage._internal_caller = True
4442 + portage._disable_legacy_globals()
4443 + from portage.elog import mod_echo
4444 + from portage.exception import IsADirectory, ParseError, PermissionDenied
4445 + from portage.util._eventloop.global_event_loop import global_event_loop
4446 + from _emerge.main import emerge_main
4447 +
4448 + if __name__ == "__main__":
4449 + portage.process.sanitize_fds()
4450 + try:
4451 + retval = emerge_main()
4452 + except PermissionDenied as e:
4453 + sys.stderr.write("Permission denied: '%s'\n" % str(e))
4454 + sys.exit(e.errno)
4455 + except IsADirectory as e:
4456 + sys.stderr.write(
4457 + "'%s' is a directory, but should be a file!\n"
4458 + "See portage man page for information on "
4459 + "which files may be directories.\n" % str(e)
4460 + )
4461 + sys.exit(e.errno)
4462 + except ParseError as e:
4463 + sys.stderr.write("%s\n" % str(e))
4464 + sys.exit(1)
4465 + except (KeyboardInterrupt, SystemExit):
4466 + raise
4467 + except Exception:
4468 + # If an unexpected exception occurs then we don't want the
4469 + # mod_echo output to obscure the traceback, so dump the
4470 + # mod_echo output before showing the traceback.
4471 + import traceback
4472 +
4473 + tb_str = traceback.format_exc()
4474 + mod_echo.finalize()
4475 + sys.stderr.write(tb_str)
4476 + sys.exit(1)
4477 + sys.exit(retval)
4478
4479 except KeyboardInterrupt:
4480 - sys.stderr.write("\n\nExiting on signal %(signal)s\n" %
4481 - {"signal": signal.SIGINT})
4482 - sys.stderr.flush()
4483 - sys.exit(128 + signal.SIGINT)
4484 + sys.stderr.write("\n\nExiting on signal %(signal)s\n" % {"signal": signal.SIGINT})
4485 + sys.stderr.flush()
4486 + sys.exit(128 + signal.SIGINT)
4487 finally:
4488 - if global_event_loop is not None:
4489 - global_event_loop().close()
4490 + if global_event_loop is not None:
4491 + global_event_loop().close()
4492
4493 diff --git a/bin/emirrordist b/bin/emirrordist
4494 index 626a055e7..35060213f 100755
4495 --- a/bin/emirrordist
4496 +++ b/bin/emirrordist
4497 @@ -6,6 +6,7 @@ import signal
4498 import sys
4499
4500 import portage
4501 +
4502 portage._internal_caller = True
4503 portage._disable_legacy_globals()
4504 from portage._emirrordist.main import emirrordist_main
4505 @@ -13,13 +14,14 @@ from portage.util._eventloop.global_event_loop import global_event_loop
4506
4507 if __name__ == "__main__":
4508
4509 - def debug_signal(_signum, _frame):
4510 - import pdb
4511 - pdb.set_trace()
4512 + def debug_signal(_signum, _frame):
4513 + import pdb
4514 +
4515 + pdb.set_trace()
4516
4517 - signal.signal(signal.SIGUSR1, debug_signal)
4518 + signal.signal(signal.SIGUSR1, debug_signal)
4519
4520 - try:
4521 - sys.exit(emirrordist_main(sys.argv[1:]))
4522 - finally:
4523 - global_event_loop().close()
4524 + try:
4525 + sys.exit(emirrordist_main(sys.argv[1:]))
4526 + finally:
4527 + global_event_loop().close()
4528
4529 diff --git a/bin/env-update b/bin/env-update
4530 index f3851afaf..c0de199e6 100755
4531 --- a/bin/env-update
4532 +++ b/bin/env-update
4533 @@ -5,35 +5,43 @@
4534 import errno
4535 import sys
4536
4537 +
4538 def usage(status):
4539 - print("Usage: env-update [--no-ldconfig]")
4540 - print("")
4541 - print("See the env-update(1) man page for more info")
4542 - sys.exit(status)
4543 + print("Usage: env-update [--no-ldconfig]")
4544 + print("")
4545 + print("See the env-update(1) man page for more info")
4546 + sys.exit(status)
4547 +
4548
4549 if "-h" in sys.argv or "--help" in sys.argv:
4550 - usage(0)
4551 + usage(0)
4552
4553 -makelinks=1
4554 +makelinks = 1
4555 if "--no-ldconfig" in sys.argv:
4556 - makelinks=0
4557 - sys.argv.pop(sys.argv.index("--no-ldconfig"))
4558 + makelinks = 0
4559 + sys.argv.pop(sys.argv.index("--no-ldconfig"))
4560
4561 if len(sys.argv) > 1:
4562 - print("!!! Invalid command line options!\n")
4563 - usage(1)
4564 + print("!!! Invalid command line options!\n")
4565 + usage(1)
4566
4567 from os import path as osp
4568 -if osp.isfile(osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), ".portage_not_installed")):
4569 - sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "lib"))
4570 +
4571 +if osp.isfile(
4572 + osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), ".portage_not_installed")
4573 +):
4574 + sys.path.insert(
4575 + 0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "lib")
4576 + )
4577 import portage
4578 +
4579 portage._internal_caller = True
4580
4581 try:
4582 - portage.env_update(makelinks)
4583 + portage.env_update(makelinks)
4584 except IOError as e:
4585 - if e.errno == errno.EACCES:
4586 - print("env-update: Need superuser access")
4587 - sys.exit(1)
4588 - else:
4589 - raise
4590 + if e.errno == errno.EACCES:
4591 + print("env-update: Need superuser access")
4592 + sys.exit(1)
4593 + else:
4594 + raise
4595
4596 diff --git a/bin/fixpackages b/bin/fixpackages
4597 index eab4b3959..34aaa786e 100755
4598 --- a/bin/fixpackages
4599 +++ b/bin/fixpackages
4600 @@ -7,14 +7,21 @@ import os
4601 import sys
4602
4603 from os import path as osp
4604 -if osp.isfile(osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), ".portage_not_installed")):
4605 - sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "lib"))
4606 +
4607 +if osp.isfile(
4608 + osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), ".portage_not_installed")
4609 +):
4610 + sys.path.insert(
4611 + 0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "lib")
4612 + )
4613 import portage
4614 +
4615 portage._internal_caller = True
4616 from portage import os
4617 from portage.output import EOutput
4618 from textwrap import wrap
4619 from portage._global_updates import _global_updates
4620 +
4621 mysettings = portage.settings
4622 mytrees = portage.db
4623 mtimedb = portage.mtimedb
4624 @@ -26,22 +33,25 @@ description = " ".join(description.split())
4625 parser = argparse.ArgumentParser(description=description)
4626 parser.parse_args()
4627
4628 -if mysettings['ROOT'] != "/":
4629 - out = EOutput()
4630 - msg = "The fixpackages program is not intended for use with " + \
4631 - "ROOT != \"/\". Instead use `emaint --fix movebin` and/or " + \
4632 - "`emaint --fix moveinst."
4633 - for line in wrap(msg, 72):
4634 - out.eerror(line)
4635 - sys.exit(1)
4636 +if mysettings["ROOT"] != "/":
4637 + out = EOutput()
4638 + msg = (
4639 + "The fixpackages program is not intended for use with "
4640 + + 'ROOT != "/". Instead use `emaint --fix movebin` and/or '
4641 + + "`emaint --fix moveinst."
4642 + )
4643 + for line in wrap(msg, 72):
4644 + out.eerror(line)
4645 + sys.exit(1)
4646
4647 try:
4648 - os.nice(int(mysettings.get("PORTAGE_NICENESS", "0")))
4649 + os.nice(int(mysettings.get("PORTAGE_NICENESS", "0")))
4650 except (OSError, ValueError) as e:
4651 - portage.writemsg("!!! Failed to change nice value to '%s'\n" % \
4652 - mysettings["PORTAGE_NICENESS"])
4653 - portage.writemsg("!!! %s\n" % str(e))
4654 - del e
4655 + portage.writemsg(
4656 + "!!! Failed to change nice value to '%s'\n" % mysettings["PORTAGE_NICENESS"]
4657 + )
4658 + portage.writemsg("!!! %s\n" % str(e))
4659 + del e
4660
4661 _global_updates(mytrees, mtimedb["updates"], if_mtime_changed=False)
4662
4663
4664 diff --git a/bin/glsa-check b/bin/glsa-check
4665 index 165123fd0..93d9efe18 100755
4666 --- a/bin/glsa-check
4667 +++ b/bin/glsa-check
4668 @@ -10,9 +10,15 @@ from functools import reduce
4669 import operator
4670
4671 from os import path as osp
4672 -if osp.isfile(osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), ".portage_not_installed")):
4673 - sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "lib"))
4674 +
4675 +if osp.isfile(
4676 + osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), ".portage_not_installed")
4677 +):
4678 + sys.path.insert(
4679 + 0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "lib")
4680 + )
4681 import portage
4682 +
4683 portage._internal_caller = True
4684 from portage import os
4685 from portage.glsa import match
4686 @@ -23,62 +29,123 @@ __author__ = "Marius Mauch <genone@g.o>"
4687 __version__ = "1.0.1"
4688
4689 # option parsing
4690 -epilog = "glsa-list can contain an arbitrary number of GLSA ids," \
4691 - " filenames containing GLSAs or the special identifiers" \
4692 - " 'all' and 'affected'"
4693 -parser = argparse.ArgumentParser(usage=__program__ + " <option> [glsa-id | all | new | affected]",
4694 - epilog=epilog)
4695 +epilog = (
4696 + "glsa-list can contain an arbitrary number of GLSA ids,"
4697 + " filenames containing GLSAs or the special identifiers"
4698 + " 'all' and 'affected'"
4699 +)
4700 +parser = argparse.ArgumentParser(
4701 + usage=__program__ + " <option> [glsa-id | all | new | affected]", epilog=epilog
4702 +)
4703
4704 modes = parser.add_argument_group("Modes")
4705 -modes.add_argument("-l", "--list", action="store_const",
4706 - const="list", dest="mode",
4707 - help="List a summary for the given GLSA(s) or set and whether they affect the system")
4708 -modes.add_argument("-d", "--dump", action="store_const",
4709 - const="dump", dest="mode",
4710 - help="Show all information about the GLSA(s) or set")
4711 -modes.add_argument("--print", action="store_const",
4712 - const="dump", dest="mode",
4713 - help="Alias for --dump")
4714 -modes.add_argument("-t", "--test", action="store_const",
4715 - const="test", dest="mode",
4716 - help="Test if this system is affected by the GLSA(s) or set and output the GLSA ID(s)")
4717 -modes.add_argument("-p", "--pretend", action="store_const",
4718 - const="pretend", dest="mode",
4719 - help="Show the necessary steps to remediate the system")
4720 -modes.add_argument("-f", "--fix", action="store_const",
4721 - const="fix", dest="mode",
4722 - help="(experimental) Attempt to remediate the system based on the instructions given in the GLSA(s) or set. This will only upgrade (when an upgrade path exists) or remove packages")
4723 -modes.add_argument("-i", "--inject", action="store_const",
4724 - const="inject", dest="mode",
4725 - help="Inject the given GLSA(s) into the glsa_injected file")
4726 -modes.add_argument("-m", "--mail", action="store_const",
4727 - const="mail", dest="mode",
4728 - help="Send a mail with the given GLSAs to the administrator")
4729 -parser.add_argument("-V", "--version", action="store_true",
4730 - help="Show information about glsa-check")
4731 -parser.add_argument("-q", "--quiet", action="store_true", dest="quiet",
4732 - help="Be less verbose and do not send empty mail")
4733 -parser.add_argument("-v", "--verbose", action="store_true", dest="verbose",
4734 - help="Print more messages")
4735 -parser.add_argument("-n", "--nocolor", action="store_true",
4736 - help="Removes color from output")
4737 -parser.add_argument("-e", "--emergelike", action="store_false", dest="least_change",
4738 - help="Upgrade to latest version (not least-change)")
4739 -parser.add_argument("-c", "--cve", action="store_true", dest="list_cve",
4740 - help="Show CVE IDs in listing mode")
4741 -parser.add_argument("-r", "--reverse", action="store_true", dest="reverse",
4742 - help="List GLSAs in reverse order")
4743 +modes.add_argument(
4744 + "-l",
4745 + "--list",
4746 + action="store_const",
4747 + const="list",
4748 + dest="mode",
4749 + help="List a summary for the given GLSA(s) or set and whether they affect the system",
4750 +)
4751 +modes.add_argument(
4752 + "-d",
4753 + "--dump",
4754 + action="store_const",
4755 + const="dump",
4756 + dest="mode",
4757 + help="Show all information about the GLSA(s) or set",
4758 +)
4759 +modes.add_argument(
4760 + "--print", action="store_const", const="dump", dest="mode", help="Alias for --dump"
4761 +)
4762 +modes.add_argument(
4763 + "-t",
4764 + "--test",
4765 + action="store_const",
4766 + const="test",
4767 + dest="mode",
4768 + help="Test if this system is affected by the GLSA(s) or set and output the GLSA ID(s)",
4769 +)
4770 +modes.add_argument(
4771 + "-p",
4772 + "--pretend",
4773 + action="store_const",
4774 + const="pretend",
4775 + dest="mode",
4776 + help="Show the necessary steps to remediate the system",
4777 +)
4778 +modes.add_argument(
4779 + "-f",
4780 + "--fix",
4781 + action="store_const",
4782 + const="fix",
4783 + dest="mode",
4784 + help="(experimental) Attempt to remediate the system based on the instructions given in the GLSA(s) or set. This will only upgrade (when an upgrade path exists) or remove packages",
4785 +)
4786 +modes.add_argument(
4787 + "-i",
4788 + "--inject",
4789 + action="store_const",
4790 + const="inject",
4791 + dest="mode",
4792 + help="Inject the given GLSA(s) into the glsa_injected file",
4793 +)
4794 +modes.add_argument(
4795 + "-m",
4796 + "--mail",
4797 + action="store_const",
4798 + const="mail",
4799 + dest="mode",
4800 + help="Send a mail with the given GLSAs to the administrator",
4801 +)
4802 +parser.add_argument(
4803 + "-V", "--version", action="store_true", help="Show information about glsa-check"
4804 +)
4805 +parser.add_argument(
4806 + "-q",
4807 + "--quiet",
4808 + action="store_true",
4809 + dest="quiet",
4810 + help="Be less verbose and do not send empty mail",
4811 +)
4812 +parser.add_argument(
4813 + "-v", "--verbose", action="store_true", dest="verbose", help="Print more messages"
4814 +)
4815 +parser.add_argument(
4816 + "-n", "--nocolor", action="store_true", help="Removes color from output"
4817 +)
4818 +parser.add_argument(
4819 + "-e",
4820 + "--emergelike",
4821 + action="store_false",
4822 + dest="least_change",
4823 + help="Upgrade to latest version (not least-change)",
4824 +)
4825 +parser.add_argument(
4826 + "-c",
4827 + "--cve",
4828 + action="store_true",
4829 + dest="list_cve",
4830 + help="Show CVE IDs in listing mode",
4831 +)
4832 +parser.add_argument(
4833 + "-r",
4834 + "--reverse",
4835 + action="store_true",
4836 + dest="reverse",
4837 + help="List GLSAs in reverse order",
4838 +)
4839
4840 options, params = parser.parse_known_args()
4841
4842 if options.nocolor:
4843 - nocolor()
4844 + nocolor()
4845
4846 if options.version:
4847 - sys.stderr.write("\n"+ __program__ + ", version " + __version__ + "\n")
4848 - sys.stderr.write("Author: " + __author__ + "\n")
4849 - sys.stderr.write("This program is licensed under the GPL, version 2\n\n")
4850 - sys.exit(0)
4851 + sys.stderr.write("\n" + __program__ + ", version " + __version__ + "\n")
4852 + sys.stderr.write("Author: " + __author__ + "\n")
4853 + sys.stderr.write("This program is licensed under the GPL, version 2\n\n")
4854 + sys.exit(0)
4855
4856 mode = options.mode
4857 least_change = options.least_change
4858 @@ -88,27 +155,34 @@ verbose = options.verbose
4859
4860 # Sanity checking
4861 if mode is None:
4862 - sys.stderr.write("No mode given: what should I do?\n")
4863 - parser.print_help()
4864 - sys.exit(1)
4865 + sys.stderr.write("No mode given: what should I do?\n")
4866 + parser.print_help()
4867 + sys.exit(1)
4868 elif mode != "list" and not params:
4869 - sys.stderr.write("\nno GLSA given, so we'll do nothing for now. \n")
4870 - sys.stderr.write("If you want to run on all GLSA please tell me so \n")
4871 - sys.stderr.write("(specify \"all\" as parameter)\n\n")
4872 - parser.print_help()
4873 - sys.exit(1)
4874 + sys.stderr.write("\nno GLSA given, so we'll do nothing for now. \n")
4875 + sys.stderr.write("If you want to run on all GLSA please tell me so \n")
4876 + sys.stderr.write('(specify "all" as parameter)\n\n')
4877 + parser.print_help()
4878 + sys.exit(1)
4879 elif mode in ["fix", "inject"] and os.geteuid() != 0:
4880 - # we need root privileges for write access
4881 - sys.stderr.write("\nThis tool needs root access to "+options.mode+" this GLSA\n\n")
4882 - sys.exit(2)
4883 + # we need root privileges for write access
4884 + sys.stderr.write(
4885 + "\nThis tool needs root access to " + options.mode + " this GLSA\n\n"
4886 + )
4887 + sys.exit(2)
4888 elif mode == "list" and not params:
4889 - params.append("affected")
4890 + params.append("affected")
4891
4892 # delay this for speed increase
4893 -from portage.glsa import (Glsa, GlsaTypeException, GlsaFormatException,
4894 - get_applied_glsas, get_glsa_list)
4895 -
4896 -eroot = portage.settings['EROOT']
4897 +from portage.glsa import (
4898 + Glsa,
4899 + GlsaTypeException,
4900 + GlsaFormatException,
4901 + get_applied_glsas,
4902 + get_glsa_list,
4903 +)
4904 +
4905 +eroot = portage.settings["EROOT"]
4906 vardb = portage.db[eroot]["vartree"].dbapi
4907 portdb = portage.db[eroot]["porttree"].dbapi
4908
4909 @@ -120,254 +194,299 @@ todolist = [e for e in completelist if e not in checklist]
4910
4911 glsalist = []
4912 if "new" in params:
4913 - params.remove("new")
4914 - sys.stderr.write("Warning: The 'new' glsa-list target has been removed, using 'affected'.\n")
4915 - params.append("affected")
4916 + params.remove("new")
4917 + sys.stderr.write(
4918 + "Warning: The 'new' glsa-list target has been removed, using 'affected'.\n"
4919 + )
4920 + params.append("affected")
4921
4922 if "all" in params:
4923 - glsalist = completelist
4924 - params.remove("all")
4925 + glsalist = completelist
4926 + params.remove("all")
4927
4928 if "affected" in params:
4929 - for x in todolist:
4930 - try:
4931 - myglsa = Glsa(x, portage.settings, vardb, portdb)
4932 - except (GlsaTypeException, GlsaFormatException) as e:
4933 - if verbose:
4934 - sys.stderr.write(("invalid GLSA: %s (error message was: %s)\n" % (x, e)))
4935 - continue
4936 - if myglsa.isVulnerable():
4937 - glsalist.append(x)
4938 - params.remove("affected")
4939 + for x in todolist:
4940 + try:
4941 + myglsa = Glsa(x, portage.settings, vardb, portdb)
4942 + except (GlsaTypeException, GlsaFormatException) as e:
4943 + if verbose:
4944 + sys.stderr.write(
4945 + ("invalid GLSA: %s (error message was: %s)\n" % (x, e))
4946 + )
4947 + continue
4948 + if myglsa.isVulnerable():
4949 + glsalist.append(x)
4950 + params.remove("affected")
4951
4952 # remove invalid parameters
4953 for p in params[:]:
4954 - if not (p in completelist or os.path.exists(p)):
4955 - sys.stderr.write(("(removing %s from parameter list as it isn't a valid GLSA specification)\n" % p))
4956 - params.remove(p)
4957 + if not (p in completelist or os.path.exists(p)):
4958 + sys.stderr.write(
4959 + (
4960 + "(removing %s from parameter list as it isn't a valid GLSA specification)\n"
4961 + % p
4962 + )
4963 + )
4964 + params.remove(p)
4965
4966 glsalist.extend([g for g in params if g not in glsalist])
4967
4968 +
4969 def summarylist(myglsalist, fd1=sys.stdout, fd2=sys.stderr, encoding="utf-8"):
4970 - # Get to the raw streams in py3k before wrapping them with an encoded writer
4971 - # to avoid writing bytes to a text stream (stdout/stderr are text streams
4972 - # by default in py3k)
4973 - if hasattr(fd1, "buffer"):
4974 - fd1 = fd1.buffer
4975 - if hasattr(fd2, "buffer"):
4976 - fd2 = fd2.buffer
4977 - fd1 = codecs.getwriter(encoding)(fd1)
4978 - fd2 = codecs.getwriter(encoding)(fd2)
4979 - if not quiet:
4980 - fd2.write(white("[A]")+" means this GLSA was marked as applied (injected),\n")
4981 - fd2.write(green("[U]")+" means the system is not affected and\n")
4982 - fd2.write(red("[N]")+" indicates that the system might be affected.\n\n")
4983 -
4984 - for myid in sorted(myglsalist, reverse=options.reverse):
4985 - try:
4986 - myglsa = Glsa(myid, portage.settings, vardb, portdb)
4987 - except (GlsaTypeException, GlsaFormatException) as e:
4988 - if verbose:
4989 - fd2.write(("invalid GLSA: %s (error message was: %s)\n" % (myid, e)))
4990 - continue
4991 - if myglsa.isInjected():
4992 - status = "[A]"
4993 - color = white
4994 - elif myglsa.isVulnerable():
4995 - status = "[N]"
4996 - color = red
4997 - else:
4998 - status = "[U]"
4999 - color = green
5000 -
5001 - if verbose:
5002 - access = ("[%-8s] " % myglsa.access)
5003 - else:
5004 - access = ""
5005 -
5006 - fd1.write(color(myglsa.nr) + " " + color(status) + " " + color(access) + myglsa.title + " (")
5007 - if not verbose:
5008 - for pkg in list(myglsa.packages)[:3]:
5009 - fd1.write(" " + pkg + " ")
5010 - if len(myglsa.packages) > 3:
5011 - fd1.write("... ")
5012 - else:
5013 - for cpv in myglsa.packages.keys():
5014 - pkg = myglsa.packages[cpv]
5015 - for path in pkg:
5016 - v_installed = reduce(operator.add, [match(v, vardb) for v in path["vul_atoms"]], [])
5017 - u_installed = reduce(operator.add, [match(u, vardb) for u in path["unaff_atoms"]], [])
5018 - mylist = sorted(set(v_installed).difference(set(u_installed)))
5019 - if len(mylist) > 0:
5020 - cpv = color(" ".join(mylist))
5021 - fd1.write(" " + cpv + " ")
5022 -
5023 - fd1.write(")")
5024 - if list_cve:
5025 - cve_ids = []
5026 - for r in myglsa.references:
5027 - m = re.search(r'(CAN|CVE)-[\d-]+', r)
5028 - if m is not None:
5029 - cve_ids.append(m.group(0))
5030 - if cve_ids:
5031 - fd1.write(" "+(",".join(cve_ids)))
5032 - fd1.write("\n")
5033 - return 0
5034 + # Get to the raw streams in py3k before wrapping them with an encoded writer
5035 + # to avoid writing bytes to a text stream (stdout/stderr are text streams
5036 + # by default in py3k)
5037 + if hasattr(fd1, "buffer"):
5038 + fd1 = fd1.buffer
5039 + if hasattr(fd2, "buffer"):
5040 + fd2 = fd2.buffer
5041 + fd1 = codecs.getwriter(encoding)(fd1)
5042 + fd2 = codecs.getwriter(encoding)(fd2)
5043 + if not quiet:
5044 + fd2.write(white("[A]") + " means this GLSA was marked as applied (injected),\n")
5045 + fd2.write(green("[U]") + " means the system is not affected and\n")
5046 + fd2.write(red("[N]") + " indicates that the system might be affected.\n\n")
5047 +
5048 + for myid in sorted(myglsalist, reverse=options.reverse):
5049 + try:
5050 + myglsa = Glsa(myid, portage.settings, vardb, portdb)
5051 + except (GlsaTypeException, GlsaFormatException) as e:
5052 + if verbose:
5053 + fd2.write(("invalid GLSA: %s (error message was: %s)\n" % (myid, e)))
5054 + continue
5055 + if myglsa.isInjected():
5056 + status = "[A]"
5057 + color = white
5058 + elif myglsa.isVulnerable():
5059 + status = "[N]"
5060 + color = red
5061 + else:
5062 + status = "[U]"
5063 + color = green
5064 +
5065 + if verbose:
5066 + access = "[%-8s] " % myglsa.access
5067 + else:
5068 + access = ""
5069 +
5070 + fd1.write(
5071 + color(myglsa.nr)
5072 + + " "
5073 + + color(status)
5074 + + " "
5075 + + color(access)
5076 + + myglsa.title
5077 + + " ("
5078 + )
5079 + if not verbose:
5080 + for pkg in list(myglsa.packages)[:3]:
5081 + fd1.write(" " + pkg + " ")
5082 + if len(myglsa.packages) > 3:
5083 + fd1.write("... ")
5084 + else:
5085 + for cpv in myglsa.packages.keys():
5086 + pkg = myglsa.packages[cpv]
5087 + for path in pkg:
5088 + v_installed = reduce(
5089 + operator.add, [match(v, vardb) for v in path["vul_atoms"]], []
5090 + )
5091 + u_installed = reduce(
5092 + operator.add, [match(u, vardb) for u in path["unaff_atoms"]], []
5093 + )
5094 + mylist = sorted(set(v_installed).difference(set(u_installed)))
5095 + if len(mylist) > 0:
5096 + cpv = color(" ".join(mylist))
5097 + fd1.write(" " + cpv + " ")
5098 +
5099 + fd1.write(")")
5100 + if list_cve:
5101 + cve_ids = []
5102 + for r in myglsa.references:
5103 + m = re.search(r"(CAN|CVE)-[\d-]+", r)
5104 + if m is not None:
5105 + cve_ids.append(m.group(0))
5106 + if cve_ids:
5107 + fd1.write(" " + (",".join(cve_ids)))
5108 + fd1.write("\n")
5109 + return 0
5110 +
5111
5112 if mode == "list":
5113 - sys.exit(summarylist(glsalist))
5114 + sys.exit(summarylist(glsalist))
5115
5116 # dump, fix, inject and fix are nearly the same code, only the glsa method call differs
5117 if mode in ["dump", "fix", "inject", "pretend"]:
5118 - for myid in glsalist:
5119 - try:
5120 - myglsa = Glsa(myid, portage.settings, vardb, portdb)
5121 - except (GlsaTypeException, GlsaFormatException) as e:
5122 - if verbose:
5123 - sys.stderr.write(("invalid GLSA: %s (error message was: %s)\n" % (myid, e)))
5124 - continue
5125 - if mode == "dump":
5126 - myglsa.dump()
5127 - elif mode == "fix":
5128 - if not quiet:
5129 - sys.stdout.write("Fixing GLSA "+myid+"\n")
5130 - if not myglsa.isVulnerable():
5131 - if not quiet:
5132 - sys.stdout.write(">>> no vulnerable packages installed\n")
5133 - else:
5134 - if quiet:
5135 - sys.stdout.write("Fixing GLSA "+myid+"\n")
5136 - mergelist = myglsa.getMergeList(least_change=least_change)
5137 - if mergelist == []:
5138 - sys.stdout.write(">>> cannot fix GLSA, no unaffected packages available\n")
5139 - sys.exit(2)
5140 - for pkg in mergelist:
5141 - sys.stdout.write(">>> merging "+pkg+"\n")
5142 - # using emerge for the actual merging as it contains the dependency
5143 - # code and we want to be consistent in behaviour. Also this functionality
5144 - # will be integrated in emerge later, so it shouldn't hurt much.
5145 - emergecmd = "emerge --oneshot" + (" --quiet" if quiet else "") + " =" + pkg
5146 - if verbose:
5147 - sys.stderr.write(emergecmd+"\n")
5148 - exitcode = os.system(emergecmd)
5149 - # system() returns the exitcode in the high byte of a 16bit integer
5150 - if exitcode >= 1 << 8:
5151 - exitcode >>= 8
5152 - if exitcode:
5153 - sys.exit(exitcode)
5154 - if len(mergelist):
5155 - sys.stdout.write("\n")
5156 - elif mode == "pretend":
5157 - if not quiet:
5158 - sys.stdout.write("Checking GLSA "+myid+"\n")
5159 - if not myglsa.isVulnerable():
5160 - if not quiet:
5161 - sys.stdout.write(">>> no vulnerable packages installed\n")
5162 - else:
5163 - if quiet:
5164 - sys.stdout.write("Checking GLSA "+myid+"\n")
5165 - mergedict = {}
5166 - for (vuln, update) in myglsa.getAffectionTable(least_change=least_change):
5167 - mergedict.setdefault(update, []).append(vuln)
5168 -
5169 - # first, extract the atoms that cannot be upgraded (where key == "")
5170 - no_upgrades = []
5171 - sys.stdout.write(">>> The following updates will be performed for this GLSA:\n")
5172 - if "" in mergedict:
5173 - no_upgrades = mergedict[""]
5174 - del mergedict[""]
5175 -
5176 - # see if anything is left that can be upgraded
5177 - if mergedict:
5178 - sys.stdout.write(">>> Updates that will be performed:\n")
5179 - for (upd, vuln) in mergedict.items():
5180 - sys.stdout.write(" " + green(upd) + " (vulnerable: " + red(", ".join(vuln)) + ")\n")
5181 -
5182 - if no_upgrades:
5183 - sys.stdout.write(">>> No upgrade path exists for these packages:\n")
5184 - sys.stdout.write(" " + red(", ".join(no_upgrades)) + "\n")
5185 - sys.stdout.write("\n")
5186 - elif mode == "inject":
5187 - sys.stdout.write("injecting " + myid + "\n")
5188 - myglsa.inject()
5189 - if not quiet:
5190 - sys.stdout.write("\n")
5191 - sys.exit(0)
5192 + for myid in glsalist:
5193 + try:
5194 + myglsa = Glsa(myid, portage.settings, vardb, portdb)
5195 + except (GlsaTypeException, GlsaFormatException) as e:
5196 + if verbose:
5197 + sys.stderr.write(
5198 + ("invalid GLSA: %s (error message was: %s)\n" % (myid, e))
5199 + )
5200 + continue
5201 + if mode == "dump":
5202 + myglsa.dump()
5203 + elif mode == "fix":
5204 + if not quiet:
5205 + sys.stdout.write("Fixing GLSA " + myid + "\n")
5206 + if not myglsa.isVulnerable():
5207 + if not quiet:
5208 + sys.stdout.write(">>> no vulnerable packages installed\n")
5209 + else:
5210 + if quiet:
5211 + sys.stdout.write("Fixing GLSA " + myid + "\n")
5212 + mergelist = myglsa.getMergeList(least_change=least_change)
5213 + if mergelist == []:
5214 + sys.stdout.write(
5215 + ">>> cannot fix GLSA, no unaffected packages available\n"
5216 + )
5217 + sys.exit(2)
5218 + for pkg in mergelist:
5219 + sys.stdout.write(">>> merging " + pkg + "\n")
5220 + # using emerge for the actual merging as it contains the dependency
5221 + # code and we want to be consistent in behaviour. Also this functionality
5222 + # will be integrated in emerge later, so it shouldn't hurt much.
5223 + emergecmd = (
5224 + "emerge --oneshot" + (" --quiet" if quiet else "") + " =" + pkg
5225 + )
5226 + if verbose:
5227 + sys.stderr.write(emergecmd + "\n")
5228 + exitcode = os.system(emergecmd)
5229 + # system() returns the exitcode in the high byte of a 16bit integer
5230 + if exitcode >= 1 << 8:
5231 + exitcode >>= 8
5232 + if exitcode:
5233 + sys.exit(exitcode)
5234 + if len(mergelist):
5235 + sys.stdout.write("\n")
5236 + elif mode == "pretend":
5237 + if not quiet:
5238 + sys.stdout.write("Checking GLSA " + myid + "\n")
5239 + if not myglsa.isVulnerable():
5240 + if not quiet:
5241 + sys.stdout.write(">>> no vulnerable packages installed\n")
5242 + else:
5243 + if quiet:
5244 + sys.stdout.write("Checking GLSA " + myid + "\n")
5245 + mergedict = {}
5246 + for (vuln, update) in myglsa.getAffectionTable(
5247 + least_change=least_change
5248 + ):
5249 + mergedict.setdefault(update, []).append(vuln)
5250 +
5251 + # first, extract the atoms that cannot be upgraded (where key == "")
5252 + no_upgrades = []
5253 + sys.stdout.write(
5254 + ">>> The following updates will be performed for this GLSA:\n"
5255 + )
5256 + if "" in mergedict:
5257 + no_upgrades = mergedict[""]
5258 + del mergedict[""]
5259 +
5260 + # see if anything is left that can be upgraded
5261 + if mergedict:
5262 + sys.stdout.write(">>> Updates that will be performed:\n")
5263 + for (upd, vuln) in mergedict.items():
5264 + sys.stdout.write(
5265 + " "
5266 + + green(upd)
5267 + + " (vulnerable: "
5268 + + red(", ".join(vuln))
5269 + + ")\n"
5270 + )
5271 +
5272 + if no_upgrades:
5273 + sys.stdout.write(">>> No upgrade path exists for these packages:\n")
5274 + sys.stdout.write(" " + red(", ".join(no_upgrades)) + "\n")
5275 + sys.stdout.write("\n")
5276 + elif mode == "inject":
5277 + sys.stdout.write("injecting " + myid + "\n")
5278 + myglsa.inject()
5279 + if not quiet:
5280 + sys.stdout.write("\n")
5281 + sys.exit(0)
5282
5283 # test is a bit different as Glsa.test() produces no output
5284 if mode == "test":
5285 - outputlist = []
5286 - for myid in glsalist:
5287 - try:
5288 - myglsa = Glsa(myid, portage.settings, vardb, portdb)
5289 - except (GlsaTypeException, GlsaFormatException) as e:
5290 - if verbose:
5291 - sys.stderr.write(("invalid GLSA: %s (error message was: %s)\n" % (myid, e)))
5292 - continue
5293 - if myglsa.isVulnerable():
5294 - outputlist.append(str(myglsa.nr))
5295 - if len(outputlist) > 0:
5296 - sys.stderr.write("This system is affected by the following GLSAs:\n")
5297 - if verbose:
5298 - summarylist(outputlist)
5299 - else:
5300 - sys.stdout.write("\n".join(outputlist)+"\n")
5301 - sys.exit(6)
5302 - else:
5303 - sys.stderr.write("This system is not affected by any of the listed GLSAs\n")
5304 - sys.exit(0)
5305 + outputlist = []
5306 + for myid in glsalist:
5307 + try:
5308 + myglsa = Glsa(myid, portage.settings, vardb, portdb)
5309 + except (GlsaTypeException, GlsaFormatException) as e:
5310 + if verbose:
5311 + sys.stderr.write(
5312 + ("invalid GLSA: %s (error message was: %s)\n" % (myid, e))
5313 + )
5314 + continue
5315 + if myglsa.isVulnerable():
5316 + outputlist.append(str(myglsa.nr))
5317 + if len(outputlist) > 0:
5318 + sys.stderr.write("This system is affected by the following GLSAs:\n")
5319 + if verbose:
5320 + summarylist(outputlist)
5321 + else:
5322 + sys.stdout.write("\n".join(outputlist) + "\n")
5323 + sys.exit(6)
5324 + else:
5325 + sys.stderr.write("This system is not affected by any of the listed GLSAs\n")
5326 + sys.exit(0)
5327
5328 # mail mode as requested by solar
5329 if mode == "mail":
5330 - import socket
5331 - from io import BytesIO
5332 - from email.mime.text import MIMEText
5333 - import portage.mail
5334 -
5335 - # color doesn't make any sense for mail
5336 - nocolor()
5337 -
5338 - if "PORTAGE_ELOG_MAILURI" in portage.settings:
5339 - myrecipient = portage.settings["PORTAGE_ELOG_MAILURI"].split()[0]
5340 - else:
5341 - myrecipient = "root@localhost"
5342 -
5343 - if "PORTAGE_ELOG_MAILFROM" in portage.settings:
5344 - myfrom = portage.settings["PORTAGE_ELOG_MAILFROM"]
5345 - else:
5346 - myfrom = "glsa-check"
5347 -
5348 - mysubject = "[glsa-check] Summary for %s" % socket.getfqdn()
5349 -
5350 - # need a file object for summarylist()
5351 - myfd = BytesIO()
5352 - line = "GLSA Summary report for host %s\n" % socket.getfqdn()
5353 - myfd.write(line.encode("utf-8"))
5354 - line = "(Command was: %s)\n\n" % " ".join(sys.argv)
5355 - myfd.write(line.encode("utf-8"))
5356 - summarylist(glsalist, fd1=myfd, fd2=myfd)
5357 - summary = myfd.getvalue().decode("utf-8")
5358 - myfd.close()
5359 -
5360 - myattachments = []
5361 - for myid in glsalist:
5362 - try:
5363 - myglsa = Glsa(myid, portage.settings, vardb, portdb)
5364 - except (GlsaTypeException, GlsaFormatException) as e:
5365 - if verbose:
5366 - sys.stderr.write(("invalid GLSA: %s (error message was: %s)\n" % (myid, e)))
5367 - continue
5368 - myfd = BytesIO()
5369 - myglsa.dump(outstream=myfd)
5370 - attachment = myfd.getvalue().decode("utf-8")
5371 - myattachments.append(MIMEText(attachment, _charset="utf8"))
5372 - myfd.close()
5373 -
5374 - if glsalist or not quiet:
5375 - mymessage = portage.mail.create_message(myfrom, myrecipient, mysubject, summary, myattachments)
5376 - portage.mail.send_mail(portage.settings, mymessage)
5377 -
5378 - sys.exit(0)
5379 + import socket
5380 + from io import BytesIO
5381 + from email.mime.text import MIMEText
5382 + import portage.mail
5383 +
5384 + # color doesn't make any sense for mail
5385 + nocolor()
5386 +
5387 + if "PORTAGE_ELOG_MAILURI" in portage.settings:
5388 + myrecipient = portage.settings["PORTAGE_ELOG_MAILURI"].split()[0]
5389 + else:
5390 + myrecipient = "root@localhost"
5391 +
5392 + if "PORTAGE_ELOG_MAILFROM" in portage.settings:
5393 + myfrom = portage.settings["PORTAGE_ELOG_MAILFROM"]
5394 + else:
5395 + myfrom = "glsa-check"
5396 +
5397 + mysubject = "[glsa-check] Summary for %s" % socket.getfqdn()
5398 +
5399 + # need a file object for summarylist()
5400 + myfd = BytesIO()
5401 + line = "GLSA Summary report for host %s\n" % socket.getfqdn()
5402 + myfd.write(line.encode("utf-8"))
5403 + line = "(Command was: %s)\n\n" % " ".join(sys.argv)
5404 + myfd.write(line.encode("utf-8"))
5405 + summarylist(glsalist, fd1=myfd, fd2=myfd)
5406 + summary = myfd.getvalue().decode("utf-8")
5407 + myfd.close()
5408 +
5409 + myattachments = []
5410 + for myid in glsalist:
5411 + try:
5412 + myglsa = Glsa(myid, portage.settings, vardb, portdb)
5413 + except (GlsaTypeException, GlsaFormatException) as e:
5414 + if verbose:
5415 + sys.stderr.write(
5416 + ("invalid GLSA: %s (error message was: %s)\n" % (myid, e))
5417 + )
5418 + continue
5419 + myfd = BytesIO()
5420 + myglsa.dump(outstream=myfd)
5421 + attachment = myfd.getvalue().decode("utf-8")
5422 + myattachments.append(MIMEText(attachment, _charset="utf8"))
5423 + myfd.close()
5424 +
5425 + if glsalist or not quiet:
5426 + mymessage = portage.mail.create_message(
5427 + myfrom, myrecipient, mysubject, summary, myattachments
5428 + )
5429 + portage.mail.send_mail(portage.settings, mymessage)
5430 +
5431 + sys.exit(0)
5432
5433 # something wrong here, all valid paths are covered with sys.exit()
5434 sys.stderr.write("nothing more to do\n")
5435
5436 diff --git a/bin/pid-ns-init b/bin/pid-ns-init
5437 index b9bf56a7b..6bac5961c 100644
5438 --- a/bin/pid-ns-init
5439 +++ b/bin/pid-ns-init
5440 @@ -57,20 +57,22 @@ def preexec_fn(uid, gid, groups, umask):
5441 os.umask(umask)
5442
5443 # CPython >= 3 subprocess.Popen handles this internally.
5444 - if platform.python_implementation() != 'CPython':
5445 + if platform.python_implementation() != "CPython":
5446 for signum in (
5447 - signal.SIGHUP,
5448 - signal.SIGINT,
5449 - signal.SIGPIPE,
5450 - signal.SIGQUIT,
5451 - signal.SIGTERM,
5452 + signal.SIGHUP,
5453 + signal.SIGINT,
5454 + signal.SIGPIPE,
5455 + signal.SIGQUIT,
5456 + signal.SIGTERM,
5457 ):
5458 signal.signal(signum, signal.SIG_DFL)
5459
5460
5461 def main(argv):
5462 if len(argv) < 2:
5463 - return 'Usage: {} <main-child-pid> or <uid> <gid> <groups> <umask> <pass_fds> <binary> <argv0> [arg]..'.format(argv[0])
5464 + return "Usage: {} <main-child-pid> or <uid> <gid> <groups> <umask> <pass_fds> <binary> <argv0> [arg]..".format(
5465 + argv[0]
5466 + )
5467
5468 if len(argv) == 2:
5469 # The child process is init (pid 1) in a child pid namespace, and
5470 @@ -82,15 +84,23 @@ def main(argv):
5471 proc = None
5472 else:
5473 # The current process is init (pid 1) in a child pid namespace.
5474 - uid, gid, groups, umask, pass_fds, binary, args = argv[1], argv[2], argv[3], argv[4], tuple(int(fd) for fd in argv[5].split(',')), argv[6], argv[7:]
5475 + uid, gid, groups, umask, pass_fds, binary, args = (
5476 + argv[1],
5477 + argv[2],
5478 + argv[3],
5479 + argv[4],
5480 + tuple(int(fd) for fd in argv[5].split(",")),
5481 + argv[6],
5482 + argv[7:],
5483 + )
5484 uid = int(uid) if uid else None
5485 gid = int(gid) if gid else None
5486 - groups = tuple(int(group) for group in groups.split(',')) if groups else None
5487 + groups = tuple(int(group) for group in groups.split(",")) if groups else None
5488 umask = int(umask) if umask else None
5489
5490 popen_kwargs = {
5491 - 'preexec_fn': functools.partial(preexec_fn, uid, gid, groups, umask),
5492 - 'pass_fds': pass_fds,
5493 + "preexec_fn": functools.partial(preexec_fn, uid, gid, groups, umask),
5494 + "pass_fds": pass_fds,
5495 }
5496
5497 # Obtain the current nice value, which will be potentially be
5498 @@ -128,12 +138,16 @@ def main(argv):
5499
5500 # If setsid has been called, use kill(0, signum) to
5501 # forward signals to the entire process group.
5502 - sig_handler = functools.partial(forward_kill_signal, 0 if setsid else main_child_pid)
5503 + sig_handler = functools.partial(
5504 + forward_kill_signal, 0 if setsid else main_child_pid
5505 + )
5506 for signum in KILL_SIGNALS:
5507 signal.signal(signum, sig_handler)
5508
5509 # For correct operation of Ctrl+Z, forward SIGTSTP and SIGCONT.
5510 - sigtstp_sigcont_handler = functools.partial(forward_sigtstp_sigcont, 0 if setsid else main_child_pid)
5511 + sigtstp_sigcont_handler = functools.partial(
5512 + forward_sigtstp_sigcont, 0 if setsid else main_child_pid
5513 + )
5514 for signum in SIGTSTP_SIGCONT:
5515 signal.signal(signum, sigtstp_sigcont_handler)
5516
5517 @@ -163,5 +177,5 @@ def main(argv):
5518 return 127
5519
5520
5521 -if __name__ == '__main__':
5522 +if __name__ == "__main__":
5523 sys.exit(main(sys.argv))
5524
5525 diff --git a/bin/portageq b/bin/portageq
5526 index 1c7e27a99..8338d4e14 100755
5527 --- a/bin/portageq
5528 +++ b/bin/portageq
5529 @@ -5,79 +5,95 @@
5530 import argparse
5531 import signal
5532 import sys
5533 +
5534 # This block ensures that ^C interrupts are handled quietly.
5535 try:
5536
5537 - def exithandler(signum, _frame):
5538 - signal.signal(signal.SIGINT, signal.SIG_IGN)
5539 - signal.signal(signal.SIGTERM, signal.SIG_IGN)
5540 - sys.exit(128 + signum)
5541 + def exithandler(signum, _frame):
5542 + signal.signal(signal.SIGINT, signal.SIG_IGN)
5543 + signal.signal(signal.SIGTERM, signal.SIG_IGN)
5544 + sys.exit(128 + signum)
5545
5546 - signal.signal(signal.SIGINT, exithandler)
5547 - signal.signal(signal.SIGTERM, exithandler)
5548 + signal.signal(signal.SIGINT, exithandler)
5549 + signal.signal(signal.SIGTERM, exithandler)
5550
5551 except KeyboardInterrupt:
5552 - sys.exit(128 + signal.SIGINT)
5553 + sys.exit(128 + signal.SIGINT)
5554
5555 import os
5556 import types
5557
5558 -if os.path.isfile(os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), ".portage_not_installed")):
5559 - pym_paths = [os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "lib")]
5560 - sys.path.insert(0, pym_paths[0])
5561 +if os.path.isfile(
5562 + os.path.join(
5563 + os.path.dirname(os.path.dirname(os.path.realpath(__file__))),
5564 + ".portage_not_installed",
5565 + )
5566 +):
5567 + pym_paths = [
5568 + os.path.join(
5569 + os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "lib"
5570 + )
5571 + ]
5572 + sys.path.insert(0, pym_paths[0])
5573 else:
5574 - import sysconfig
5575 - pym_paths = [
5576 - os.path.join(sysconfig.get_path("purelib"), x) for x in ("_emerge", "portage")
5577 - ]
5578 + import sysconfig
5579 +
5580 + pym_paths = [
5581 + os.path.join(sysconfig.get_path("purelib"), x) for x in ("_emerge", "portage")
5582 + ]
5583 # Avoid sandbox violations after Python upgrade.
5584 if os.environ.get("SANDBOX_ON") == "1":
5585 - sandbox_write = os.environ.get("SANDBOX_WRITE", "").split(":")
5586 - for pym_path in pym_paths:
5587 - if pym_path not in sandbox_write:
5588 - sandbox_write.append(pym_path)
5589 - os.environ["SANDBOX_WRITE"] = ":".join(filter(None, sandbox_write))
5590 - del pym_path, sandbox_write
5591 + sandbox_write = os.environ.get("SANDBOX_WRITE", "").split(":")
5592 + for pym_path in pym_paths:
5593 + if pym_path not in sandbox_write:
5594 + sandbox_write.append(pym_path)
5595 + os.environ["SANDBOX_WRITE"] = ":".join(filter(None, sandbox_write))
5596 + del pym_path, sandbox_write
5597 del pym_paths
5598
5599 import portage
5600 +
5601 portage._internal_caller = True
5602 from portage import os
5603 from portage.eapi import eapi_has_repo_deps
5604 from portage.util import writemsg, writemsg_stdout
5605 -portage.proxy.lazyimport.lazyimport(globals(),
5606 - 're',
5607 - 'subprocess',
5608 - '_emerge.Package:Package',
5609 - '_emerge.RootConfig:RootConfig',
5610 - '_emerge.is_valid_package_atom:insert_category_into_atom',
5611 - 'portage.dbapi._expand_new_virt:expand_new_virt',
5612 - 'portage._sets.base:InternalPackageSet',
5613 - 'portage.util._eventloop.global_event_loop:global_event_loop',
5614 - 'portage.xml.metadata:MetaDataXML'
5615 +
5616 +portage.proxy.lazyimport.lazyimport(
5617 + globals(),
5618 + "re",
5619 + "subprocess",
5620 + "_emerge.Package:Package",
5621 + "_emerge.RootConfig:RootConfig",
5622 + "_emerge.is_valid_package_atom:insert_category_into_atom",
5623 + "portage.dbapi._expand_new_virt:expand_new_virt",
5624 + "portage._sets.base:InternalPackageSet",
5625 + "portage.util._eventloop.global_event_loop:global_event_loop",
5626 + "portage.xml.metadata:MetaDataXML",
5627 )
5628
5629 +
5630 def eval_atom_use(atom):
5631 - if 'USE' in os.environ:
5632 - use = frozenset(os.environ['USE'].split())
5633 - atom = atom.evaluate_conditionals(use)
5634 - return atom
5635 + if "USE" in os.environ:
5636 + use = frozenset(os.environ["USE"].split())
5637 + atom = atom.evaluate_conditionals(use)
5638 + return atom
5639
5640
5641 def uses_configroot(function):
5642 - function.uses_configroot = True
5643 - return function
5644 + function.uses_configroot = True
5645 + return function
5646
5647
5648 def uses_eroot(function):
5649 - function.uses_eroot = True
5650 - return function
5651 + function.uses_eroot = True
5652 + return function
5653 +
5654
5655 # global to hold all function docstrings to be used for argparse help.
5656 # Avoids python compilation level 2 optimization troubles.
5657 docstrings = {}
5658
5659 -#-----------------------------------------------------------------------------
5660 +# -----------------------------------------------------------------------------
5661 #
5662 # To add functionality to this tool, add a function below.
5663 #
5664 @@ -100,573 +116,615 @@ docstrings = {}
5665 # and will automaticly add a command by the same name as the function!
5666 #
5667
5668 +
5669 @uses_eroot
5670 def has_version(argv):
5671 - if len(argv) < 2:
5672 - print("ERROR: insufficient parameters!")
5673 - return 3
5674 -
5675 - warnings = []
5676 -
5677 - allow_repo = atom_validate_strict is False or eapi_has_repo_deps(eapi)
5678 - try:
5679 - atom = portage.dep.Atom(argv[1], allow_repo=allow_repo)
5680 - except portage.exception.InvalidAtom:
5681 - if atom_validate_strict:
5682 - portage.writemsg("ERROR: Invalid atom: '%s'\n" % argv[1],
5683 - noiselevel=-1)
5684 - return 2
5685 - else:
5686 - atom = argv[1]
5687 - else:
5688 - if atom_validate_strict:
5689 - try:
5690 - atom = portage.dep.Atom(argv[1], allow_repo=allow_repo, eapi=eapi)
5691 - except portage.exception.InvalidAtom as e:
5692 - warnings.append("QA Notice: %s: %s" % ('has_version', e))
5693 - atom = eval_atom_use(atom)
5694 -
5695 - if warnings:
5696 - elog('eqawarn', warnings)
5697 -
5698 - try:
5699 - mylist = portage.db[argv[0]]["vartree"].dbapi.match(atom)
5700 - if mylist:
5701 - return 0
5702 - else:
5703 - return 1
5704 - except KeyError:
5705 - return 1
5706 - except portage.exception.InvalidAtom:
5707 - portage.writemsg("ERROR: Invalid atom: '%s'\n" % argv[1],
5708 - noiselevel=-1)
5709 - return 2
5710 -
5711 -docstrings['has_version'] = """<eroot> <category/package>
5712 + if len(argv) < 2:
5713 + print("ERROR: insufficient parameters!")
5714 + return 3
5715 +
5716 + warnings = []
5717 +
5718 + allow_repo = atom_validate_strict is False or eapi_has_repo_deps(eapi)
5719 + try:
5720 + atom = portage.dep.Atom(argv[1], allow_repo=allow_repo)
5721 + except portage.exception.InvalidAtom:
5722 + if atom_validate_strict:
5723 + portage.writemsg("ERROR: Invalid atom: '%s'\n" % argv[1], noiselevel=-1)
5724 + return 2
5725 + else:
5726 + atom = argv[1]
5727 + else:
5728 + if atom_validate_strict:
5729 + try:
5730 + atom = portage.dep.Atom(argv[1], allow_repo=allow_repo, eapi=eapi)
5731 + except portage.exception.InvalidAtom as e:
5732 + warnings.append("QA Notice: %s: %s" % ("has_version", e))
5733 + atom = eval_atom_use(atom)
5734 +
5735 + if warnings:
5736 + elog("eqawarn", warnings)
5737 +
5738 + try:
5739 + mylist = portage.db[argv[0]]["vartree"].dbapi.match(atom)
5740 + if mylist:
5741 + return 0
5742 + else:
5743 + return 1
5744 + except KeyError:
5745 + return 1
5746 + except portage.exception.InvalidAtom:
5747 + portage.writemsg("ERROR: Invalid atom: '%s'\n" % argv[1], noiselevel=-1)
5748 + return 2
5749 +
5750 +
5751 +docstrings[
5752 + "has_version"
5753 +] = """<eroot> <category/package>
5754 Return code 0 if it's available, 1 otherwise.
5755 """
5756 -has_version.__doc__ = docstrings['has_version']
5757 +has_version.__doc__ = docstrings["has_version"]
5758
5759
5760 @uses_eroot
5761 def best_version(argv):
5762 - if len(argv) < 2:
5763 - print("ERROR: insufficient parameters!")
5764 - return 3
5765 -
5766 - warnings = []
5767 -
5768 - allow_repo = atom_validate_strict is False or eapi_has_repo_deps(eapi)
5769 - try:
5770 - atom = portage.dep.Atom(argv[1], allow_repo=allow_repo)
5771 - except portage.exception.InvalidAtom:
5772 - if atom_validate_strict:
5773 - portage.writemsg("ERROR: Invalid atom: '%s'\n" % argv[1],
5774 - noiselevel=-1)
5775 - return 2
5776 - else:
5777 - atom = argv[1]
5778 - else:
5779 - if atom_validate_strict:
5780 - try:
5781 - atom = portage.dep.Atom(argv[1], allow_repo=allow_repo, eapi=eapi)
5782 - except portage.exception.InvalidAtom as e:
5783 - warnings.append("QA Notice: %s: %s" % ('best_version', e))
5784 - atom = eval_atom_use(atom)
5785 -
5786 - if warnings:
5787 - elog('eqawarn', warnings)
5788 -
5789 - try:
5790 - mylist = portage.db[argv[0]]["vartree"].dbapi.match(atom)
5791 - print(portage.best(mylist))
5792 - except KeyError:
5793 - return 1
5794 -
5795 -docstrings['best_version'] = """<eroot> <category/package>
5796 + if len(argv) < 2:
5797 + print("ERROR: insufficient parameters!")
5798 + return 3
5799 +
5800 + warnings = []
5801 +
5802 + allow_repo = atom_validate_strict is False or eapi_has_repo_deps(eapi)
5803 + try:
5804 + atom = portage.dep.Atom(argv[1], allow_repo=allow_repo)
5805 + except portage.exception.InvalidAtom:
5806 + if atom_validate_strict:
5807 + portage.writemsg("ERROR: Invalid atom: '%s'\n" % argv[1], noiselevel=-1)
5808 + return 2
5809 + else:
5810 + atom = argv[1]
5811 + else:
5812 + if atom_validate_strict:
5813 + try:
5814 + atom = portage.dep.Atom(argv[1], allow_repo=allow_repo, eapi=eapi)
5815 + except portage.exception.InvalidAtom as e:
5816 + warnings.append("QA Notice: %s: %s" % ("best_version", e))
5817 + atom = eval_atom_use(atom)
5818 +
5819 + if warnings:
5820 + elog("eqawarn", warnings)
5821 +
5822 + try:
5823 + mylist = portage.db[argv[0]]["vartree"].dbapi.match(atom)
5824 + print(portage.best(mylist))
5825 + except KeyError:
5826 + return 1
5827 +
5828 +
5829 +docstrings[
5830 + "best_version"
5831 +] = """<eroot> <category/package>
5832 Returns highest installed matching category/package-version (without .ebuild).
5833 """
5834 -best_version.__doc__ = docstrings['best_version']
5835 +best_version.__doc__ = docstrings["best_version"]
5836
5837
5838 @uses_eroot
5839 def mass_best_version(argv):
5840 - if len(argv) < 2:
5841 - print("ERROR: insufficient parameters!")
5842 - return 2
5843 - try:
5844 - for pack in argv[1:]:
5845 - mylist = portage.db[argv[0]]['vartree'].dbapi.match(pack)
5846 - print('%s:%s' % (pack, portage.best(mylist)))
5847 - except KeyError:
5848 - return 1
5849 -
5850 -docstrings['mass_best_version'] = """<eroot> [<category/package>]+
5851 + if len(argv) < 2:
5852 + print("ERROR: insufficient parameters!")
5853 + return 2
5854 + try:
5855 + for pack in argv[1:]:
5856 + mylist = portage.db[argv[0]]["vartree"].dbapi.match(pack)
5857 + print("%s:%s" % (pack, portage.best(mylist)))
5858 + except KeyError:
5859 + return 1
5860 +
5861 +
5862 +docstrings[
5863 + "mass_best_version"
5864 +] = """<eroot> [<category/package>]+
5865 Returns category/package-version (without .ebuild).
5866 """
5867 -mass_best_version.__doc__ = docstrings['mass_best_version']
5868 +mass_best_version.__doc__ = docstrings["mass_best_version"]
5869
5870
5871 @uses_eroot
5872 def metadata(argv):
5873 - if len(argv) < 4:
5874 - print('ERROR: insufficient parameters!', file=sys.stderr)
5875 - return 2
5876 -
5877 - eroot, pkgtype, pkgspec = argv[0:3]
5878 - metakeys = argv[3:]
5879 - type_map = {
5880 - 'ebuild': 'porttree',
5881 - 'binary': 'bintree',
5882 - 'installed': 'vartree'
5883 - }
5884 - if pkgtype not in type_map:
5885 - print("Unrecognized package type: '%s'" % pkgtype, file=sys.stderr)
5886 - return 1
5887 - trees = portage.db
5888 - repo = portage.dep.dep_getrepo(pkgspec)
5889 - pkgspec = portage.dep.remove_slot(pkgspec)
5890 - try:
5891 - values = trees[eroot][type_map[pkgtype]].dbapi.aux_get(
5892 - pkgspec, metakeys, myrepo=repo)
5893 - writemsg_stdout(''.join('%s\n' % x for x in values), noiselevel=-1)
5894 - except KeyError:
5895 - print("Package not found: '%s'" % pkgspec, file=sys.stderr)
5896 - return 1
5897 -
5898 -docstrings['metadata'] = """
5899 + if len(argv) < 4:
5900 + print("ERROR: insufficient parameters!", file=sys.stderr)
5901 + return 2
5902 +
5903 + eroot, pkgtype, pkgspec = argv[0:3]
5904 + metakeys = argv[3:]
5905 + type_map = {"ebuild": "porttree", "binary": "bintree", "installed": "vartree"}
5906 + if pkgtype not in type_map:
5907 + print("Unrecognized package type: '%s'" % pkgtype, file=sys.stderr)
5908 + return 1
5909 + trees = portage.db
5910 + repo = portage.dep.dep_getrepo(pkgspec)
5911 + pkgspec = portage.dep.remove_slot(pkgspec)
5912 + try:
5913 + values = trees[eroot][type_map[pkgtype]].dbapi.aux_get(
5914 + pkgspec, metakeys, myrepo=repo
5915 + )
5916 + writemsg_stdout("".join("%s\n" % x for x in values), noiselevel=-1)
5917 + except KeyError:
5918 + print("Package not found: '%s'" % pkgspec, file=sys.stderr)
5919 + return 1
5920 +
5921 +
5922 +docstrings[
5923 + "metadata"
5924 +] = """
5925 <eroot> <pkgtype> <category/package> [<key>]+
5926 Returns metadata values for the specified package.
5927 Available keys: %s
5928 -""" % ','.join(sorted(x for x in portage.auxdbkeys))
5929 -metadata.__doc__ = docstrings['metadata']
5930 +""" % ",".join(
5931 + sorted(x for x in portage.auxdbkeys)
5932 +)
5933 +metadata.__doc__ = docstrings["metadata"]
5934
5935
5936 @uses_eroot
5937 def contents(argv):
5938 - if len(argv) != 2:
5939 - print("ERROR: expected 2 parameters, got %d!" % len(argv))
5940 - return 2
5941 -
5942 - root, cpv = argv
5943 - vartree = portage.db[root]["vartree"]
5944 - if not vartree.dbapi.cpv_exists(cpv):
5945 - sys.stderr.write("Package not found: '%s'\n" % cpv)
5946 - return 1
5947 - cat, pkg = portage.catsplit(cpv)
5948 - db = portage.dblink(cat, pkg, root, vartree.settings,
5949 - treetype="vartree", vartree=vartree)
5950 - writemsg_stdout(''.join('%s\n' % x for x in sorted(db.getcontents())),
5951 - noiselevel=-1)
5952 -
5953 -docstrings['contents'] = """<eroot> <category/package>
5954 + if len(argv) != 2:
5955 + print("ERROR: expected 2 parameters, got %d!" % len(argv))
5956 + return 2
5957 +
5958 + root, cpv = argv
5959 + vartree = portage.db[root]["vartree"]
5960 + if not vartree.dbapi.cpv_exists(cpv):
5961 + sys.stderr.write("Package not found: '%s'\n" % cpv)
5962 + return 1
5963 + cat, pkg = portage.catsplit(cpv)
5964 + db = portage.dblink(
5965 + cat, pkg, root, vartree.settings, treetype="vartree", vartree=vartree
5966 + )
5967 + writemsg_stdout(
5968 + "".join("%s\n" % x for x in sorted(db.getcontents())), noiselevel=-1
5969 + )
5970 +
5971 +
5972 +docstrings[
5973 + "contents"
5974 +] = """<eroot> <category/package>
5975 List the files that are installed for a given package, with
5976 one file listed on each line. All file names will begin with
5977 <eroot>.
5978 """
5979 -contents.__doc__ = docstrings['contents']
5980 +contents.__doc__ = docstrings["contents"]
5981
5982
5983 @uses_eroot
5984 def owners(argv):
5985 - if len(argv) < 2:
5986 - sys.stderr.write("ERROR: insufficient parameters!\n")
5987 - sys.stderr.flush()
5988 - return 2
5989 -
5990 - eroot = argv[0]
5991 - vardb = portage.db[eroot]["vartree"].dbapi
5992 - root = portage.settings['ROOT']
5993 -
5994 - cwd = None
5995 - try:
5996 - cwd = os.getcwd()
5997 - except OSError:
5998 - pass
5999 -
6000 - files = []
6001 - orphan_abs_paths = set()
6002 - orphan_basenames = set()
6003 - for f in argv[1:]:
6004 - f = portage.normalize_path(f)
6005 - is_basename = os.sep not in f
6006 - if not is_basename and f[:1] != os.sep:
6007 - if cwd is None:
6008 - sys.stderr.write("ERROR: cwd does not exist!\n")
6009 - sys.stderr.flush()
6010 - return 2
6011 - f = os.path.join(cwd, f)
6012 - f = portage.normalize_path(f)
6013 - if not is_basename and not f.startswith(eroot):
6014 - sys.stderr.write("ERROR: file paths must begin with <eroot>!\n")
6015 - sys.stderr.flush()
6016 - return 2
6017 - if is_basename:
6018 - files.append(f)
6019 - orphan_basenames.add(f)
6020 - else:
6021 - files.append(f[len(root)-1:])
6022 - orphan_abs_paths.add(f)
6023 -
6024 - owners = vardb._owners.get_owners(files)
6025 -
6026 - msg = []
6027 - for pkg, owned_files in owners.items():
6028 - cpv = pkg.mycpv
6029 - msg.append("%s\n" % cpv)
6030 - for f in sorted(owned_files):
6031 - f_abs = os.path.join(root, f.lstrip(os.path.sep))
6032 - msg.append("\t%s\n" % (f_abs,))
6033 - orphan_abs_paths.discard(f_abs)
6034 - if orphan_basenames:
6035 - orphan_basenames.discard(os.path.basename(f_abs))
6036 -
6037 - writemsg_stdout(''.join(msg), noiselevel=-1)
6038 -
6039 - if orphan_abs_paths or orphan_basenames:
6040 - orphans = []
6041 - orphans.extend(orphan_abs_paths)
6042 - orphans.extend(orphan_basenames)
6043 - orphans.sort()
6044 - msg = []
6045 - msg.append("None of the installed packages claim these files:\n")
6046 - for f in orphans:
6047 - msg.append("\t%s\n" % (f,))
6048 - sys.stderr.write("".join(msg))
6049 - sys.stderr.flush()
6050 -
6051 - if owners:
6052 - return 0
6053 - return 1
6054 -
6055 -docstrings['owners'] = """<eroot> [<filename>]+
6056 + if len(argv) < 2:
6057 + sys.stderr.write("ERROR: insufficient parameters!\n")
6058 + sys.stderr.flush()
6059 + return 2
6060 +
6061 + eroot = argv[0]
6062 + vardb = portage.db[eroot]["vartree"].dbapi
6063 + root = portage.settings["ROOT"]
6064 +
6065 + cwd = None
6066 + try:
6067 + cwd = os.getcwd()
6068 + except OSError:
6069 + pass
6070 +
6071 + files = []
6072 + orphan_abs_paths = set()
6073 + orphan_basenames = set()
6074 + for f in argv[1:]:
6075 + f = portage.normalize_path(f)
6076 + is_basename = os.sep not in f
6077 + if not is_basename and f[:1] != os.sep:
6078 + if cwd is None:
6079 + sys.stderr.write("ERROR: cwd does not exist!\n")
6080 + sys.stderr.flush()
6081 + return 2
6082 + f = os.path.join(cwd, f)
6083 + f = portage.normalize_path(f)
6084 + if not is_basename and not f.startswith(eroot):
6085 + sys.stderr.write("ERROR: file paths must begin with <eroot>!\n")
6086 + sys.stderr.flush()
6087 + return 2
6088 + if is_basename:
6089 + files.append(f)
6090 + orphan_basenames.add(f)
6091 + else:
6092 + files.append(f[len(root) - 1 :])
6093 + orphan_abs_paths.add(f)
6094 +
6095 + owners = vardb._owners.get_owners(files)
6096 +
6097 + msg = []
6098 + for pkg, owned_files in owners.items():
6099 + cpv = pkg.mycpv
6100 + msg.append("%s\n" % cpv)
6101 + for f in sorted(owned_files):
6102 + f_abs = os.path.join(root, f.lstrip(os.path.sep))
6103 + msg.append("\t%s\n" % (f_abs,))
6104 + orphan_abs_paths.discard(f_abs)
6105 + if orphan_basenames:
6106 + orphan_basenames.discard(os.path.basename(f_abs))
6107 +
6108 + writemsg_stdout("".join(msg), noiselevel=-1)
6109 +
6110 + if orphan_abs_paths or orphan_basenames:
6111 + orphans = []
6112 + orphans.extend(orphan_abs_paths)
6113 + orphans.extend(orphan_basenames)
6114 + orphans.sort()
6115 + msg = []
6116 + msg.append("None of the installed packages claim these files:\n")
6117 + for f in orphans:
6118 + msg.append("\t%s\n" % (f,))
6119 + sys.stderr.write("".join(msg))
6120 + sys.stderr.flush()
6121 +
6122 + if owners:
6123 + return 0
6124 + return 1
6125 +
6126 +
6127 +docstrings[
6128 + "owners"
6129 +] = """<eroot> [<filename>]+
6130 Given a list of files, print the packages that own the files and which
6131 files belong to each package. Files owned by a package are listed on
6132 the lines below it, indented by a single tab character (\\t). All file
6133 paths must either start with <eroot> or be a basename alone.
6134 Returns 1 if no owners could be found, and 0 otherwise.
6135 """
6136 -owners.__doc__ = docstrings['owners']
6137 +owners.__doc__ = docstrings["owners"]
6138
6139
6140 @uses_eroot
6141 def is_protected(argv):
6142 - if len(argv) != 2:
6143 - sys.stderr.write("ERROR: expected 2 parameters, got %d!\n" % len(argv))
6144 - sys.stderr.flush()
6145 - return 2
6146 -
6147 - root, filename = argv
6148 -
6149 - err = sys.stderr
6150 - cwd = None
6151 - try:
6152 - cwd = os.getcwd()
6153 - except OSError:
6154 - pass
6155 -
6156 - f = portage.normalize_path(filename)
6157 - if not f.startswith(os.path.sep):
6158 - if cwd is None:
6159 - err.write("ERROR: cwd does not exist!\n")
6160 - err.flush()
6161 - return 2
6162 - f = os.path.join(cwd, f)
6163 - f = portage.normalize_path(f)
6164 -
6165 - if not f.startswith(root):
6166 - err.write("ERROR: file paths must begin with <eroot>!\n")
6167 - err.flush()
6168 - return 2
6169 -
6170 - from portage.util import ConfigProtect
6171 -
6172 - settings = portage.settings
6173 - protect = portage.util.shlex_split(settings.get("CONFIG_PROTECT", ""))
6174 - protect_mask = portage.util.shlex_split(
6175 - settings.get("CONFIG_PROTECT_MASK", ""))
6176 - protect_obj = ConfigProtect(root, protect, protect_mask,
6177 - case_insensitive=("case-insensitive-fs" in settings.features))
6178 - if protect_obj.isprotected(f):
6179 - return 0
6180 - return 1
6181 -
6182 -docstrings['is_protected'] = """<eroot> <filename>
6183 + if len(argv) != 2:
6184 + sys.stderr.write("ERROR: expected 2 parameters, got %d!\n" % len(argv))
6185 + sys.stderr.flush()
6186 + return 2
6187 +
6188 + root, filename = argv
6189 +
6190 + err = sys.stderr
6191 + cwd = None
6192 + try:
6193 + cwd = os.getcwd()
6194 + except OSError:
6195 + pass
6196 +
6197 + f = portage.normalize_path(filename)
6198 + if not f.startswith(os.path.sep):
6199 + if cwd is None:
6200 + err.write("ERROR: cwd does not exist!\n")
6201 + err.flush()
6202 + return 2
6203 + f = os.path.join(cwd, f)
6204 + f = portage.normalize_path(f)
6205 +
6206 + if not f.startswith(root):
6207 + err.write("ERROR: file paths must begin with <eroot>!\n")
6208 + err.flush()
6209 + return 2
6210 +
6211 + from portage.util import ConfigProtect
6212 +
6213 + settings = portage.settings
6214 + protect = portage.util.shlex_split(settings.get("CONFIG_PROTECT", ""))
6215 + protect_mask = portage.util.shlex_split(settings.get("CONFIG_PROTECT_MASK", ""))
6216 + protect_obj = ConfigProtect(
6217 + root,
6218 + protect,
6219 + protect_mask,
6220 + case_insensitive=("case-insensitive-fs" in settings.features),
6221 + )
6222 + if protect_obj.isprotected(f):
6223 + return 0
6224 + return 1
6225 +
6226 +
6227 +docstrings[
6228 + "is_protected"
6229 +] = """<eroot> <filename>
6230 Given a single filename, return code 0 if it's protected, 1 otherwise.
6231 The filename must begin with <eroot>.
6232 """
6233 -is_protected.__doc__ = docstrings['is_protected']
6234 +is_protected.__doc__ = docstrings["is_protected"]
6235
6236
6237 @uses_eroot
6238 def filter_protected(argv):
6239 - if len(argv) != 1:
6240 - sys.stderr.write("ERROR: expected 1 parameter, got %d!\n" % len(argv))
6241 - sys.stderr.flush()
6242 - return 2
6243 -
6244 - root, = argv
6245 - out = sys.stdout
6246 - err = sys.stderr
6247 - cwd = None
6248 - try:
6249 - cwd = os.getcwd()
6250 - except OSError:
6251 - pass
6252 -
6253 - from portage.util import ConfigProtect
6254 -
6255 - settings = portage.settings
6256 - protect = portage.util.shlex_split(settings.get("CONFIG_PROTECT", ""))
6257 - protect_mask = portage.util.shlex_split(
6258 - settings.get("CONFIG_PROTECT_MASK", ""))
6259 - protect_obj = ConfigProtect(root, protect, protect_mask,
6260 - case_insensitive=("case-insensitive-fs" in settings.features))
6261 -
6262 - errors = 0
6263 -
6264 - for line in sys.stdin:
6265 - filename = line.rstrip("\n")
6266 - f = portage.normalize_path(filename)
6267 - if not f.startswith(os.path.sep):
6268 - if cwd is None:
6269 - err.write("ERROR: cwd does not exist!\n")
6270 - err.flush()
6271 - errors += 1
6272 - continue
6273 - f = os.path.join(cwd, f)
6274 - f = portage.normalize_path(f)
6275 -
6276 - if not f.startswith(root):
6277 - err.write("ERROR: file paths must begin with <eroot>!\n")
6278 - err.flush()
6279 - errors += 1
6280 - continue
6281 -
6282 - if protect_obj.isprotected(f):
6283 - out.write("%s\n" % filename)
6284 - out.flush()
6285 -
6286 - if errors:
6287 - return 2
6288 -
6289 - return 0
6290 -
6291 -docstrings['filter_protected'] = """<eroot>
6292 + if len(argv) != 1:
6293 + sys.stderr.write("ERROR: expected 1 parameter, got %d!\n" % len(argv))
6294 + sys.stderr.flush()
6295 + return 2
6296 +
6297 + (root,) = argv
6298 + out = sys.stdout
6299 + err = sys.stderr
6300 + cwd = None
6301 + try:
6302 + cwd = os.getcwd()
6303 + except OSError:
6304 + pass
6305 +
6306 + from portage.util import ConfigProtect
6307 +
6308 + settings = portage.settings
6309 + protect = portage.util.shlex_split(settings.get("CONFIG_PROTECT", ""))
6310 + protect_mask = portage.util.shlex_split(settings.get("CONFIG_PROTECT_MASK", ""))
6311 + protect_obj = ConfigProtect(
6312 + root,
6313 + protect,
6314 + protect_mask,
6315 + case_insensitive=("case-insensitive-fs" in settings.features),
6316 + )
6317 +
6318 + errors = 0
6319 +
6320 + for line in sys.stdin:
6321 + filename = line.rstrip("\n")
6322 + f = portage.normalize_path(filename)
6323 + if not f.startswith(os.path.sep):
6324 + if cwd is None:
6325 + err.write("ERROR: cwd does not exist!\n")
6326 + err.flush()
6327 + errors += 1
6328 + continue
6329 + f = os.path.join(cwd, f)
6330 + f = portage.normalize_path(f)
6331 +
6332 + if not f.startswith(root):
6333 + err.write("ERROR: file paths must begin with <eroot>!\n")
6334 + err.flush()
6335 + errors += 1
6336 + continue
6337 +
6338 + if protect_obj.isprotected(f):
6339 + out.write("%s\n" % filename)
6340 + out.flush()
6341 +
6342 + if errors:
6343 + return 2
6344 +
6345 + return 0
6346 +
6347 +
6348 +docstrings[
6349 + "filter_protected"
6350 +] = """<eroot>
6351 Read filenames from stdin and write them to stdout if they are protected.
6352 All filenames are delimited by \\n and must begin with <eroot>.
6353 """
6354 -filter_protected.__doc__ = docstrings['filter_protected']
6355 +filter_protected.__doc__ = docstrings["filter_protected"]
6356
6357
6358 @uses_eroot
6359 def best_visible(argv):
6360 - if len(argv) < 2:
6361 - writemsg("ERROR: insufficient parameters!\n", noiselevel=-1)
6362 - return 2
6363 -
6364 - pkgtype = "ebuild"
6365 - if len(argv) > 2:
6366 - pkgtype = argv[1]
6367 - atom = argv[2]
6368 - else:
6369 - atom = argv[1]
6370 -
6371 - type_map = {
6372 - "ebuild":"porttree",
6373 - "binary":"bintree",
6374 - "installed":"vartree"}
6375 -
6376 - if pkgtype not in type_map:
6377 - writemsg("Unrecognized package type: '%s'\n" % pkgtype,
6378 - noiselevel=-1)
6379 - return 2
6380 -
6381 - eroot = argv[0]
6382 - db = portage.db[eroot][type_map[pkgtype]].dbapi
6383 -
6384 - try:
6385 - atom = portage.dep_expand(atom, mydb=db, settings=portage.settings)
6386 - except portage.exception.InvalidAtom:
6387 - writemsg("ERROR: Invalid atom: '%s'\n" % atom,
6388 - noiselevel=-1)
6389 - return 2
6390 -
6391 - root_config = RootConfig(portage.settings, portage.db[eroot], None)
6392 -
6393 - if hasattr(db, "xmatch"):
6394 - cpv_list = db.xmatch("match-all-cpv-only", atom)
6395 - else:
6396 - cpv_list = db.match(atom)
6397 -
6398 - if cpv_list:
6399 - # reversed, for descending order
6400 - cpv_list.reverse()
6401 - # verify match, since the atom may match the package
6402 - # for a given cpv from one repo but not another, and
6403 - # we can use match-all-cpv-only to avoid redundant
6404 - # metadata access.
6405 - atom_set = InternalPackageSet(initial_atoms=(atom,))
6406 -
6407 - if atom.repo is None and hasattr(db, "getRepositories"):
6408 - repo_list = db.getRepositories()
6409 - else:
6410 - repo_list = [atom.repo]
6411 -
6412 - for cpv in cpv_list:
6413 - for repo in repo_list:
6414 - try:
6415 - metadata = dict(zip(Package.metadata_keys,
6416 - db.aux_get(cpv, Package.metadata_keys, myrepo=repo)))
6417 - except KeyError:
6418 - continue
6419 - pkg = Package(built=(pkgtype != "ebuild"), cpv=cpv,
6420 - installed=(pkgtype=="installed"), metadata=metadata,
6421 - root_config=root_config, type_name=pkgtype)
6422 - if not atom_set.findAtomForPackage(pkg):
6423 - continue
6424 -
6425 - if pkg.visible:
6426 - writemsg_stdout("%s\n" % (pkg.cpv,), noiselevel=-1)
6427 - return os.EX_OK
6428 -
6429 - # No package found, write out an empty line.
6430 - writemsg_stdout("\n", noiselevel=-1)
6431 -
6432 - return 1
6433 -
6434 -docstrings['best_visible'] = """<eroot> [pkgtype] <atom>
6435 + if len(argv) < 2:
6436 + writemsg("ERROR: insufficient parameters!\n", noiselevel=-1)
6437 + return 2
6438 +
6439 + pkgtype = "ebuild"
6440 + if len(argv) > 2:
6441 + pkgtype = argv[1]
6442 + atom = argv[2]
6443 + else:
6444 + atom = argv[1]
6445 +
6446 + type_map = {"ebuild": "porttree", "binary": "bintree", "installed": "vartree"}
6447 +
6448 + if pkgtype not in type_map:
6449 + writemsg("Unrecognized package type: '%s'\n" % pkgtype, noiselevel=-1)
6450 + return 2
6451 +
6452 + eroot = argv[0]
6453 + db = portage.db[eroot][type_map[pkgtype]].dbapi
6454 +
6455 + try:
6456 + atom = portage.dep_expand(atom, mydb=db, settings=portage.settings)
6457 + except portage.exception.InvalidAtom:
6458 + writemsg("ERROR: Invalid atom: '%s'\n" % atom, noiselevel=-1)
6459 + return 2
6460 +
6461 + root_config = RootConfig(portage.settings, portage.db[eroot], None)
6462 +
6463 + if hasattr(db, "xmatch"):
6464 + cpv_list = db.xmatch("match-all-cpv-only", atom)
6465 + else:
6466 + cpv_list = db.match(atom)
6467 +
6468 + if cpv_list:
6469 + # reversed, for descending order
6470 + cpv_list.reverse()
6471 + # verify match, since the atom may match the package
6472 + # for a given cpv from one repo but not another, and
6473 + # we can use match-all-cpv-only to avoid redundant
6474 + # metadata access.
6475 + atom_set = InternalPackageSet(initial_atoms=(atom,))
6476 +
6477 + if atom.repo is None and hasattr(db, "getRepositories"):
6478 + repo_list = db.getRepositories()
6479 + else:
6480 + repo_list = [atom.repo]
6481 +
6482 + for cpv in cpv_list:
6483 + for repo in repo_list:
6484 + try:
6485 + metadata = dict(
6486 + zip(
6487 + Package.metadata_keys,
6488 + db.aux_get(cpv, Package.metadata_keys, myrepo=repo),
6489 + )
6490 + )
6491 + except KeyError:
6492 + continue
6493 + pkg = Package(
6494 + built=(pkgtype != "ebuild"),
6495 + cpv=cpv,
6496 + installed=(pkgtype == "installed"),
6497 + metadata=metadata,
6498 + root_config=root_config,
6499 + type_name=pkgtype,
6500 + )
6501 + if not atom_set.findAtomForPackage(pkg):
6502 + continue
6503 +
6504 + if pkg.visible:
6505 + writemsg_stdout("%s\n" % (pkg.cpv,), noiselevel=-1)
6506 + return os.EX_OK
6507 +
6508 + # No package found, write out an empty line.
6509 + writemsg_stdout("\n", noiselevel=-1)
6510 +
6511 + return 1
6512 +
6513 +
6514 +docstrings[
6515 + "best_visible"
6516 +] = """<eroot> [pkgtype] <atom>
6517 Returns category/package-version (without .ebuild).
6518 The pkgtype argument defaults to "ebuild" if unspecified,
6519 otherwise it must be one of ebuild, binary, or installed.
6520 """
6521 -best_visible.__doc__ = docstrings['best_visible']
6522 +best_visible.__doc__ = docstrings["best_visible"]
6523
6524
6525 @uses_eroot
6526 def mass_best_visible(argv):
6527 - type_map = {
6528 - "ebuild":"porttree",
6529 - "binary":"bintree",
6530 - "installed":"vartree"}
6531 -
6532 - if len(argv) < 2:
6533 - print("ERROR: insufficient parameters!")
6534 - return 2
6535 - try:
6536 - root = argv.pop(0)
6537 - pkgtype = "ebuild"
6538 - if argv[0] in type_map:
6539 - pkgtype = argv.pop(0)
6540 - for pack in argv:
6541 - writemsg_stdout("%s:" % pack, noiselevel=-1)
6542 - best_visible([root, pkgtype, pack])
6543 - except KeyError:
6544 - return 1
6545 -
6546 -docstrings['mass_best_visible'] = """<eroot> [<type>] [<category/package>]+
6547 + type_map = {"ebuild": "porttree", "binary": "bintree", "installed": "vartree"}
6548 +
6549 + if len(argv) < 2:
6550 + print("ERROR: insufficient parameters!")
6551 + return 2
6552 + try:
6553 + root = argv.pop(0)
6554 + pkgtype = "ebuild"
6555 + if argv[0] in type_map:
6556 + pkgtype = argv.pop(0)
6557 + for pack in argv:
6558 + writemsg_stdout("%s:" % pack, noiselevel=-1)
6559 + best_visible([root, pkgtype, pack])
6560 + except KeyError:
6561 + return 1
6562 +
6563 +
6564 +docstrings[
6565 + "mass_best_visible"
6566 +] = """<eroot> [<type>] [<category/package>]+
6567 Returns category/package-version (without .ebuild).
6568 The pkgtype argument defaults to "ebuild" if unspecified,
6569 otherwise it must be one of ebuild, binary, or installed.
6570 """
6571 -mass_best_visible.__doc__ = docstrings['mass_best_visible']
6572 +mass_best_visible.__doc__ = docstrings["mass_best_visible"]
6573
6574
6575 @uses_eroot
6576 def all_best_visible(argv):
6577 - if len(argv) < 1:
6578 - sys.stderr.write("ERROR: insufficient parameters!\n")
6579 - sys.stderr.flush()
6580 - return 2
6581 -
6582 - #print portage.db[argv[0]]["porttree"].dbapi.cp_all()
6583 - for pkg in portage.db[argv[0]]["porttree"].dbapi.cp_all():
6584 - mybest=portage.best(portage.db[argv[0]]["porttree"].dbapi.match(pkg))
6585 - if mybest:
6586 - print(mybest)
6587 -
6588 -docstrings['all_best_visible'] = """<eroot>
6589 + if len(argv) < 1:
6590 + sys.stderr.write("ERROR: insufficient parameters!\n")
6591 + sys.stderr.flush()
6592 + return 2
6593 +
6594 + # print portage.db[argv[0]]["porttree"].dbapi.cp_all()
6595 + for pkg in portage.db[argv[0]]["porttree"].dbapi.cp_all():
6596 + mybest = portage.best(portage.db[argv[0]]["porttree"].dbapi.match(pkg))
6597 + if mybest:
6598 + print(mybest)
6599 +
6600 +
6601 +docstrings[
6602 + "all_best_visible"
6603 +] = """<eroot>
6604 Returns all best_visible packages (without .ebuild).
6605 """
6606 -all_best_visible.__doc__ = docstrings['all_best_visible']
6607 +all_best_visible.__doc__ = docstrings["all_best_visible"]
6608
6609
6610 @uses_eroot
6611 def match(argv):
6612 - if len(argv) != 2:
6613 - print("ERROR: expected 2 parameters, got %d!" % len(argv))
6614 - return 2
6615 - root, atom = argv
6616 - if not atom:
6617 - atom = "*/*"
6618 -
6619 - vardb = portage.db[root]["vartree"].dbapi
6620 - try:
6621 - atom = portage.dep.Atom(atom, allow_wildcard=True, allow_repo=True)
6622 - except portage.exception.InvalidAtom:
6623 - # maybe it's valid but missing category
6624 - atom = portage.dep_expand(atom, mydb=vardb, settings=vardb.settings)
6625 -
6626 - if atom.extended_syntax:
6627 - if atom == "*/*":
6628 - results = vardb.cpv_all()
6629 - else:
6630 - results = []
6631 - require_metadata = atom.slot or atom.repo
6632 - for cpv in vardb.cpv_all():
6633 -
6634 - if not portage.match_from_list(atom, [cpv]):
6635 - continue
6636 -
6637 - if require_metadata:
6638 - try:
6639 - cpv = vardb._pkg_str(cpv, atom.repo)
6640 - except (KeyError, portage.exception.InvalidData):
6641 - continue
6642 - if not portage.match_from_list(atom, [cpv]):
6643 - continue
6644 -
6645 - results.append(cpv)
6646 -
6647 - results.sort()
6648 - else:
6649 - results = vardb.match(atom)
6650 - for cpv in results:
6651 - print(cpv)
6652 -
6653 -docstrings['match'] = """<eroot> <atom>
6654 + if len(argv) != 2:
6655 + print("ERROR: expected 2 parameters, got %d!" % len(argv))
6656 + return 2
6657 + root, atom = argv
6658 + if not atom:
6659 + atom = "*/*"
6660 +
6661 + vardb = portage.db[root]["vartree"].dbapi
6662 + try:
6663 + atom = portage.dep.Atom(atom, allow_wildcard=True, allow_repo=True)
6664 + except portage.exception.InvalidAtom:
6665 + # maybe it's valid but missing category
6666 + atom = portage.dep_expand(atom, mydb=vardb, settings=vardb.settings)
6667 +
6668 + if atom.extended_syntax:
6669 + if atom == "*/*":
6670 + results = vardb.cpv_all()
6671 + else:
6672 + results = []
6673 + require_metadata = atom.slot or atom.repo
6674 + for cpv in vardb.cpv_all():
6675 +
6676 + if not portage.match_from_list(atom, [cpv]):
6677 + continue
6678 +
6679 + if require_metadata:
6680 + try:
6681 + cpv = vardb._pkg_str(cpv, atom.repo)
6682 + except (KeyError, portage.exception.InvalidData):
6683 + continue
6684 + if not portage.match_from_list(atom, [cpv]):
6685 + continue
6686 +
6687 + results.append(cpv)
6688 +
6689 + results.sort()
6690 + else:
6691 + results = vardb.match(atom)
6692 + for cpv in results:
6693 + print(cpv)
6694 +
6695 +
6696 +docstrings[
6697 + "match"
6698 +] = """<eroot> <atom>
6699 Returns a \\n separated list of category/package-version.
6700 When given an empty string, all installed packages will
6701 be listed.
6702 """
6703 -match.__doc__ = docstrings['match']
6704 +match.__doc__ = docstrings["match"]
6705
6706
6707 @uses_eroot
6708 def expand_virtual(argv):
6709 - if len(argv) != 2:
6710 - writemsg("ERROR: expected 2 parameters, got %d!\n" % len(argv),
6711 - noiselevel=-1)
6712 - return 2
6713 + if len(argv) != 2:
6714 + writemsg("ERROR: expected 2 parameters, got %d!\n" % len(argv), noiselevel=-1)
6715 + return 2
6716 +
6717 + root, atom = argv
6718
6719 - root, atom = argv
6720 + try:
6721 + results = list(expand_new_virt(portage.db[root]["vartree"].dbapi, atom))
6722 + except portage.exception.InvalidAtom:
6723 + writemsg("ERROR: Invalid atom: '%s'\n" % atom, noiselevel=-1)
6724 + return 2
6725
6726 - try:
6727 - results = list(expand_new_virt(
6728 - portage.db[root]["vartree"].dbapi, atom))
6729 - except portage.exception.InvalidAtom:
6730 - writemsg("ERROR: Invalid atom: '%s'\n" % atom,
6731 - noiselevel=-1)
6732 - return 2
6733 + results.sort()
6734 + for x in results:
6735 + if not x.blocker:
6736 + writemsg_stdout("%s\n" % (x,))
6737
6738 - results.sort()
6739 - for x in results:
6740 - if not x.blocker:
6741 - writemsg_stdout("%s\n" % (x,))
6742 + return os.EX_OK
6743
6744 - return os.EX_OK
6745
6746 -docstrings['expand_virtual'] = """<eroot> <atom>
6747 +docstrings[
6748 + "expand_virtual"
6749 +] = """<eroot> <atom>
6750 Returns a \\n separated list of atoms expanded from a
6751 given virtual atom (GLEP 37 virtuals only),
6752 excluding blocker atoms. Satisfied
6753 @@ -677,802 +735,911 @@ docstrings['expand_virtual'] = """<eroot> <atom>
6754 resolve the returned atoms to specific installed
6755 packages.
6756 """
6757 -expand_virtual.__doc__ = docstrings['expand_virtual']
6758 +expand_virtual.__doc__ = docstrings["expand_virtual"]
6759
6760
6761 def vdb_path(_argv):
6762 - out = sys.stdout
6763 - out.write(os.path.join(portage.settings["EROOT"], portage.VDB_PATH) + "\n")
6764 - out.flush()
6765 - return os.EX_OK
6766 + out = sys.stdout
6767 + out.write(os.path.join(portage.settings["EROOT"], portage.VDB_PATH) + "\n")
6768 + out.flush()
6769 + return os.EX_OK
6770
6771 -docstrings['vdb_path'] = """
6772 +
6773 +docstrings[
6774 + "vdb_path"
6775 +] = """
6776 Returns the path used for the var(installed) package database for the
6777 set environment/configuration options.
6778 """
6779 -vdb_path.__doc__ = docstrings['vdb_path']
6780 +vdb_path.__doc__ = docstrings["vdb_path"]
6781
6782
6783 def gentoo_mirrors(_argv):
6784 - print(portage.settings["GENTOO_MIRRORS"])
6785 + print(portage.settings["GENTOO_MIRRORS"])
6786 +
6787
6788 -docstrings['gentoo_mirrors'] = """
6789 +docstrings[
6790 + "gentoo_mirrors"
6791 +] = """
6792 Returns the mirrors set to use in the portage configuration.
6793 """
6794 -gentoo_mirrors.__doc__ = docstrings['gentoo_mirrors']
6795 +gentoo_mirrors.__doc__ = docstrings["gentoo_mirrors"]
6796
6797
6798 @uses_configroot
6799 @uses_eroot
6800 def repositories_configuration(argv):
6801 - if len(argv) < 1:
6802 - print("ERROR: insufficient parameters!", file=sys.stderr)
6803 - return 3
6804 - sys.stdout.write(portage.db[argv[0]]["vartree"].settings.repositories.config_string())
6805 - sys.stdout.flush()
6806 -
6807 -docstrings['repositories_configuration'] = """<eroot>
6808 + if len(argv) < 1:
6809 + print("ERROR: insufficient parameters!", file=sys.stderr)
6810 + return 3
6811 + sys.stdout.write(
6812 + portage.db[argv[0]]["vartree"].settings.repositories.config_string()
6813 + )
6814 + sys.stdout.flush()
6815 +
6816 +
6817 +docstrings[
6818 + "repositories_configuration"
6819 +] = """<eroot>
6820 Returns the configuration of repositories.
6821 """
6822 -repositories_configuration.__doc__ = docstrings['repositories_configuration']
6823 +repositories_configuration.__doc__ = docstrings["repositories_configuration"]
6824
6825
6826 @uses_configroot
6827 @uses_eroot
6828 def repos_config(argv):
6829 - return repositories_configuration(argv)
6830 + return repositories_configuration(argv)
6831 +
6832
6833 -docstrings['repos_config'] = """
6834 +docstrings[
6835 + "repos_config"
6836 +] = """
6837 <eroot>
6838 This is an alias for the repositories_configuration command.
6839 """
6840 -repos_config.__doc__ = docstrings['repos_config']
6841 +repos_config.__doc__ = docstrings["repos_config"]
6842
6843
6844 def portdir(_argv):
6845 - print("WARNING: 'portageq portdir' is deprecated. Use the get_repo_path "
6846 - "command instead. eg: "
6847 - "'portageq get_repo_path / gentoo' instead.", file=sys.stderr)
6848 - print(portage.settings["PORTDIR"])
6849 -
6850 -docstrings['portdir'] = """
6851 + print(
6852 + "WARNING: 'portageq portdir' is deprecated. Use the get_repo_path "
6853 + "command instead. eg: "
6854 + "'portageq get_repo_path / gentoo' instead.",
6855 + file=sys.stderr,
6856 + )
6857 + print(portage.settings["PORTDIR"])
6858 +
6859 +
6860 +docstrings[
6861 + "portdir"
6862 +] = """
6863 Returns the PORTDIR path.
6864 Deprecated in favor of get_repo_path command.
6865 """
6866 -portdir.__doc__ = docstrings['portdir']
6867 +portdir.__doc__ = docstrings["portdir"]
6868
6869
6870 def config_protect(_argv):
6871 - print(portage.settings["CONFIG_PROTECT"])
6872 + print(portage.settings["CONFIG_PROTECT"])
6873 +
6874
6875 -docstrings['config_protect'] = """
6876 +docstrings[
6877 + "config_protect"
6878 +] = """
6879 Returns the CONFIG_PROTECT paths.
6880 """
6881 -config_protect.__doc__ = docstrings['config_protect']
6882 +config_protect.__doc__ = docstrings["config_protect"]
6883
6884
6885 def config_protect_mask(_argv):
6886 - print(portage.settings["CONFIG_PROTECT_MASK"])
6887 + print(portage.settings["CONFIG_PROTECT_MASK"])
6888
6889 -docstrings['config_protect_mask'] = """
6890 +
6891 +docstrings[
6892 + "config_protect_mask"
6893 +] = """
6894 Returns the CONFIG_PROTECT_MASK paths.
6895 """
6896 -config_protect_mask.__doc__ = docstrings['config_protect_mask']
6897 +config_protect_mask.__doc__ = docstrings["config_protect_mask"]
6898
6899 -def portdir_overlay(_argv):
6900 - print("WARNING: 'portageq portdir_overlay' is deprecated. Use the get_repos"
6901 - " and get_repo_path commands or the repos_config command instead. eg: "
6902 - "'portageq repos_config /'", file=sys.stderr)
6903 - print(portage.settings["PORTDIR_OVERLAY"])
6904
6905 -docstrings['portdir_overlay'] = """
6906 +def portdir_overlay(_argv):
6907 + print(
6908 + "WARNING: 'portageq portdir_overlay' is deprecated. Use the get_repos"
6909 + " and get_repo_path commands or the repos_config command instead. eg: "
6910 + "'portageq repos_config /'",
6911 + file=sys.stderr,
6912 + )
6913 + print(portage.settings["PORTDIR_OVERLAY"])
6914 +
6915 +
6916 +docstrings[
6917 + "portdir_overlay"
6918 +] = """
6919 Returns the PORTDIR_OVERLAY path.
6920 Deprecated in favor of get_repos & get_repo_path or repos_config commands.
6921 """
6922 -portdir_overlay.__doc__ = docstrings['portdir_overlay']
6923 +portdir_overlay.__doc__ = docstrings["portdir_overlay"]
6924
6925
6926 def pkgdir(_argv):
6927 - print(portage.settings["PKGDIR"])
6928 + print(portage.settings["PKGDIR"])
6929
6930 -docstrings['pkgdir'] = """
6931 +
6932 +docstrings[
6933 + "pkgdir"
6934 +] = """
6935 Returns the PKGDIR path.
6936 """
6937 -pkgdir.__doc__ = docstrings['pkgdir']
6938 +pkgdir.__doc__ = docstrings["pkgdir"]
6939
6940
6941 def distdir(_argv):
6942 - print(portage.settings["DISTDIR"])
6943 + print(portage.settings["DISTDIR"])
6944 +
6945
6946 -docstrings['distdir'] = """
6947 +docstrings[
6948 + "distdir"
6949 +] = """
6950 Returns the DISTDIR path.
6951 """
6952 -distdir.__doc__ = docstrings['distdir']
6953 +distdir.__doc__ = docstrings["distdir"]
6954
6955
6956 def colormap(_argv):
6957 - print(portage.output.colormap())
6958 + print(portage.output.colormap())
6959
6960 -docstrings['colormap'] = """
6961 +
6962 +docstrings[
6963 + "colormap"
6964 +] = """
6965 Display the color.map as environment variables.
6966 """
6967 -colormap.__doc__ = docstrings['colormap']
6968 +colormap.__doc__ = docstrings["colormap"]
6969
6970
6971 def envvar(argv):
6972 - verbose = "-v" in argv
6973 - if verbose:
6974 - argv.pop(argv.index("-v"))
6975 + verbose = "-v" in argv
6976 + if verbose:
6977 + argv.pop(argv.index("-v"))
6978 +
6979 + if len(argv) == 0:
6980 + print("ERROR: insufficient parameters!")
6981 + return 2
6982
6983 - if len(argv) == 0:
6984 - print("ERROR: insufficient parameters!")
6985 - return 2
6986 + exit_status = 0
6987
6988 - exit_status = 0
6989 + for arg in argv:
6990 + if arg in ("PORTDIR", "PORTDIR_OVERLAY", "SYNC"):
6991 + print(
6992 + "WARNING: 'portageq envvar %s' is deprecated. Use any of "
6993 + "'get_repos, get_repo_path, repos_config' instead." % arg,
6994 + file=sys.stderr,
6995 + )
6996
6997 - for arg in argv:
6998 - if arg in ("PORTDIR", "PORTDIR_OVERLAY", "SYNC"):
6999 - print("WARNING: 'portageq envvar %s' is deprecated. Use any of "
7000 - "'get_repos, get_repo_path, repos_config' instead."
7001 - % arg, file=sys.stderr)
7002 + value = portage.settings.get(arg)
7003 + if value is None:
7004 + value = ""
7005 + exit_status = 1
7006
7007 - value = portage.settings.get(arg)
7008 - if value is None:
7009 - value = ""
7010 - exit_status = 1
7011 + if verbose:
7012 + print(arg + "=" + portage._shell_quote(value))
7013 + else:
7014 + print(value)
7015
7016 - if verbose:
7017 - print(arg + "=" + portage._shell_quote(value))
7018 - else:
7019 - print(value)
7020 + return exit_status
7021
7022 - return exit_status
7023
7024 -docstrings['envvar'] = """<variable>+
7025 +docstrings[
7026 + "envvar"
7027 +] = """<variable>+
7028 Returns a specific environment variable as exists prior to ebuild.sh.
7029 Similar to: emerge --verbose --info | egrep '^<variable>='
7030 """
7031 -envvar.__doc__ = docstrings['envvar']
7032 +envvar.__doc__ = docstrings["envvar"]
7033
7034
7035 @uses_configroot
7036 @uses_eroot
7037 def get_repos(argv):
7038 - if len(argv) < 1:
7039 - print("ERROR: insufficient parameters!")
7040 - return 2
7041 - print(" ".join(reversed(portage.db[argv[0]]["vartree"].settings.repositories.prepos_order)))
7042 -
7043 -docstrings['get_repos'] = """<eroot>
7044 + if len(argv) < 1:
7045 + print("ERROR: insufficient parameters!")
7046 + return 2
7047 + print(
7048 + " ".join(
7049 + reversed(portage.db[argv[0]]["vartree"].settings.repositories.prepos_order)
7050 + )
7051 + )
7052 +
7053 +
7054 +docstrings[
7055 + "get_repos"
7056 +] = """<eroot>
7057 Returns all repos with names (repo_name file) argv[0] = $EROOT
7058 """
7059 -get_repos.__doc__ = docstrings['get_repos']
7060 +get_repos.__doc__ = docstrings["get_repos"]
7061
7062
7063 @uses_configroot
7064 @uses_eroot
7065 def master_repositories(argv):
7066 - if len(argv) < 2:
7067 - print("ERROR: insufficient parameters!", file=sys.stderr)
7068 - return 3
7069 - for arg in argv[1:]:
7070 - if portage.dep._repo_name_re.match(arg) is None:
7071 - print("ERROR: invalid repository: %s" % arg, file=sys.stderr)
7072 - return 2
7073 - try:
7074 - repo = portage.db[argv[0]]["vartree"].settings.repositories[arg]
7075 - except KeyError:
7076 - print("")
7077 - return 1
7078 - else:
7079 - print(" ".join(x.name for x in repo.masters))
7080 -
7081 -docstrings['master_repositories'] = """<eroot> <repo_id>+
7082 + if len(argv) < 2:
7083 + print("ERROR: insufficient parameters!", file=sys.stderr)
7084 + return 3
7085 + for arg in argv[1:]:
7086 + if portage.dep._repo_name_re.match(arg) is None:
7087 + print("ERROR: invalid repository: %s" % arg, file=sys.stderr)
7088 + return 2
7089 + try:
7090 + repo = portage.db[argv[0]]["vartree"].settings.repositories[arg]
7091 + except KeyError:
7092 + print("")
7093 + return 1
7094 + else:
7095 + print(" ".join(x.name for x in repo.masters))
7096 +
7097 +
7098 +docstrings[
7099 + "master_repositories"
7100 +] = """<eroot> <repo_id>+
7101 Returns space-separated list of master repositories for specified repository.
7102 """
7103 -master_repositories.__doc__ = docstrings['master_repositories']
7104 +master_repositories.__doc__ = docstrings["master_repositories"]
7105
7106
7107 @uses_configroot
7108 @uses_eroot
7109 def master_repos(argv):
7110 - return master_repositories(argv)
7111 + return master_repositories(argv)
7112 +
7113
7114 -docstrings['master_repos'] = """<eroot> <repo_id>+
7115 +docstrings[
7116 + "master_repos"
7117 +] = """<eroot> <repo_id>+
7118 This is an alias for the master_repositories command.
7119 """
7120 -master_repos.__doc__ = docstrings['master_repos']
7121 +master_repos.__doc__ = docstrings["master_repos"]
7122
7123
7124 @uses_configroot
7125 @uses_eroot
7126 def get_repo_path(argv):
7127
7128 - if len(argv) < 2:
7129 - print("ERROR: insufficient parameters!", file=sys.stderr)
7130 - return 3
7131 - for arg in argv[1:]:
7132 - if portage.dep._repo_name_re.match(arg) is None:
7133 - print("ERROR: invalid repository: %s" % arg, file=sys.stderr)
7134 - return 2
7135 - path = portage.db[argv[0]]["vartree"].settings.repositories.treemap.get(arg)
7136 - if path is None:
7137 - print("")
7138 - return 1
7139 - print(path)
7140 -
7141 -docstrings['get_repo_path'] = """<eroot> <repo_id>+
7142 + if len(argv) < 2:
7143 + print("ERROR: insufficient parameters!", file=sys.stderr)
7144 + return 3
7145 + for arg in argv[1:]:
7146 + if portage.dep._repo_name_re.match(arg) is None:
7147 + print("ERROR: invalid repository: %s" % arg, file=sys.stderr)
7148 + return 2
7149 + path = portage.db[argv[0]]["vartree"].settings.repositories.treemap.get(arg)
7150 + if path is None:
7151 + print("")
7152 + return 1
7153 + print(path)
7154 +
7155 +
7156 +docstrings[
7157 + "get_repo_path"
7158 +] = """<eroot> <repo_id>+
7159 Returns the path to the repo named argv[1], argv[0] = $EROOT
7160 """
7161 -get_repo_path.__doc__ = docstrings['get_repo_path']
7162 +get_repo_path.__doc__ = docstrings["get_repo_path"]
7163
7164
7165 @uses_eroot
7166 def available_eclasses(argv):
7167 - if len(argv) < 2:
7168 - print("ERROR: insufficient parameters!", file=sys.stderr)
7169 - return 3
7170 - for arg in argv[1:]:
7171 - if portage.dep._repo_name_re.match(arg) is None:
7172 - print("ERROR: invalid repository: %s" % arg, file=sys.stderr)
7173 - return 2
7174 - try:
7175 - repo = portage.db[argv[0]]["vartree"].settings.repositories[arg]
7176 - except KeyError:
7177 - print("")
7178 - return 1
7179 - else:
7180 - print(" ".join(sorted(repo.eclass_db.eclasses)))
7181 -
7182 -docstrings['available_eclasses'] = """<eroot> <repo_id>+
7183 + if len(argv) < 2:
7184 + print("ERROR: insufficient parameters!", file=sys.stderr)
7185 + return 3
7186 + for arg in argv[1:]:
7187 + if portage.dep._repo_name_re.match(arg) is None:
7188 + print("ERROR: invalid repository: %s" % arg, file=sys.stderr)
7189 + return 2
7190 + try:
7191 + repo = portage.db[argv[0]]["vartree"].settings.repositories[arg]
7192 + except KeyError:
7193 + print("")
7194 + return 1
7195 + else:
7196 + print(" ".join(sorted(repo.eclass_db.eclasses)))
7197 +
7198 +
7199 +docstrings[
7200 + "available_eclasses"
7201 +] = """<eroot> <repo_id>+
7202 Returns space-separated list of available eclasses for specified repository.
7203 """
7204 -available_eclasses.__doc__ = docstrings['available_eclasses']
7205 +available_eclasses.__doc__ = docstrings["available_eclasses"]
7206
7207
7208 @uses_eroot
7209 def eclass_path(argv):
7210 - if len(argv) < 3:
7211 - print("ERROR: insufficient parameters!", file=sys.stderr)
7212 - return 3
7213 - if portage.dep._repo_name_re.match(argv[1]) is None:
7214 - print("ERROR: invalid repository: %s" % argv[1], file=sys.stderr)
7215 - return 2
7216 - try:
7217 - repo = portage.db[argv[0]]["vartree"].settings.repositories[argv[1]]
7218 - except KeyError:
7219 - print("")
7220 - return 1
7221 - else:
7222 - retval = 0
7223 - for arg in argv[2:]:
7224 - try:
7225 - eclass = repo.eclass_db.eclasses[arg]
7226 - except KeyError:
7227 - print("")
7228 - retval = 1
7229 - else:
7230 - print(eclass.location)
7231 - return retval
7232 -
7233 -docstrings['eclass_path'] = """<eroot> <repo_id> <eclass>+
7234 + if len(argv) < 3:
7235 + print("ERROR: insufficient parameters!", file=sys.stderr)
7236 + return 3
7237 + if portage.dep._repo_name_re.match(argv[1]) is None:
7238 + print("ERROR: invalid repository: %s" % argv[1], file=sys.stderr)
7239 + return 2
7240 + try:
7241 + repo = portage.db[argv[0]]["vartree"].settings.repositories[argv[1]]
7242 + except KeyError:
7243 + print("")
7244 + return 1
7245 + else:
7246 + retval = 0
7247 + for arg in argv[2:]:
7248 + try:
7249 + eclass = repo.eclass_db.eclasses[arg]
7250 + except KeyError:
7251 + print("")
7252 + retval = 1
7253 + else:
7254 + print(eclass.location)
7255 + return retval
7256 +
7257 +
7258 +docstrings[
7259 + "eclass_path"
7260 +] = """<eroot> <repo_id> <eclass>+
7261 Returns the path to specified eclass for specified repository.
7262 """
7263 -eclass_path.__doc__ = docstrings['eclass_path']
7264 +eclass_path.__doc__ = docstrings["eclass_path"]
7265
7266
7267 @uses_eroot
7268 def license_path(argv):
7269 - if len(argv) < 3:
7270 - print("ERROR: insufficient parameters!", file=sys.stderr)
7271 - return 3
7272 - if portage.dep._repo_name_re.match(argv[1]) is None:
7273 - print("ERROR: invalid repository: %s" % argv[1], file=sys.stderr)
7274 - return 2
7275 - try:
7276 - repo = portage.db[argv[0]]["vartree"].settings.repositories[argv[1]]
7277 - except KeyError:
7278 - print("")
7279 - return 1
7280 - else:
7281 - retval = 0
7282 - for arg in argv[2:]:
7283 - eclass_path = ""
7284 - paths = reversed([os.path.join(x.location, 'licenses', arg) for x in list(repo.masters) + [repo]])
7285 - for path in paths:
7286 - if os.path.exists(path):
7287 - eclass_path = path
7288 - break
7289 - if eclass_path == "":
7290 - retval = 1
7291 - print(eclass_path)
7292 - return retval
7293 -
7294 -docstrings['license_path'] = """<eroot> <repo_id> <license>+
7295 + if len(argv) < 3:
7296 + print("ERROR: insufficient parameters!", file=sys.stderr)
7297 + return 3
7298 + if portage.dep._repo_name_re.match(argv[1]) is None:
7299 + print("ERROR: invalid repository: %s" % argv[1], file=sys.stderr)
7300 + return 2
7301 + try:
7302 + repo = portage.db[argv[0]]["vartree"].settings.repositories[argv[1]]
7303 + except KeyError:
7304 + print("")
7305 + return 1
7306 + else:
7307 + retval = 0
7308 + for arg in argv[2:]:
7309 + eclass_path = ""
7310 + paths = reversed(
7311 + [
7312 + os.path.join(x.location, "licenses", arg)
7313 + for x in list(repo.masters) + [repo]
7314 + ]
7315 + )
7316 + for path in paths:
7317 + if os.path.exists(path):
7318 + eclass_path = path
7319 + break
7320 + if eclass_path == "":
7321 + retval = 1
7322 + print(eclass_path)
7323 + return retval
7324 +
7325 +
7326 +docstrings[
7327 + "license_path"
7328 +] = """<eroot> <repo_id> <license>+
7329 Returns the path to specified license for specified repository.
7330 """
7331 -license_path.__doc__ = docstrings['license_path']
7332 +license_path.__doc__ = docstrings["license_path"]
7333
7334
7335 @uses_eroot
7336 def list_preserved_libs(argv):
7337 - if len(argv) != 1:
7338 - print("ERROR: wrong number of arguments")
7339 - return 2
7340 - mylibs = portage.db[argv[0]]["vartree"].dbapi._plib_registry.getPreservedLibs()
7341 - rValue = 1
7342 - msg = []
7343 - for cpv in sorted(mylibs):
7344 - msg.append(cpv)
7345 - for path in mylibs[cpv]:
7346 - msg.append(' ' + path)
7347 - rValue = 0
7348 - msg.append('\n')
7349 - writemsg_stdout(''.join(msg), noiselevel=-1)
7350 - return rValue
7351 -
7352 -docstrings['list_preserved_libs'] = """<eroot>
7353 + if len(argv) != 1:
7354 + print("ERROR: wrong number of arguments")
7355 + return 2
7356 + mylibs = portage.db[argv[0]]["vartree"].dbapi._plib_registry.getPreservedLibs()
7357 + rValue = 1
7358 + msg = []
7359 + for cpv in sorted(mylibs):
7360 + msg.append(cpv)
7361 + for path in mylibs[cpv]:
7362 + msg.append(" " + path)
7363 + rValue = 0
7364 + msg.append("\n")
7365 + writemsg_stdout("".join(msg), noiselevel=-1)
7366 + return rValue
7367 +
7368 +
7369 +docstrings[
7370 + "list_preserved_libs"
7371 +] = """<eroot>
7372 Print a list of libraries preserved during a package update in the form
7373 package: path. Returns 1 if no preserved libraries could be found,
7374 0 otherwise.
7375 """
7376 -list_preserved_libs.__doc__ = docstrings['list_preserved_libs']
7377 +list_preserved_libs.__doc__ = docstrings["list_preserved_libs"]
7378
7379
7380 class MaintainerEmailMatcher:
7381 - def __init__(self, maintainer_emails):
7382 - self._re = re.compile("^(%s)$" % "|".join(maintainer_emails), re.I)
7383 -
7384 - def __call__(self, metadata_xml):
7385 - match = False
7386 - matcher = self._re.match
7387 - for x in metadata_xml.maintainers():
7388 - if x.email is not None and matcher(x.email) is not None:
7389 - match = True
7390 - break
7391 - return match
7392 + def __init__(self, maintainer_emails):
7393 + self._re = re.compile("^(%s)$" % "|".join(maintainer_emails), re.I)
7394 +
7395 + def __call__(self, metadata_xml):
7396 + match = False
7397 + matcher = self._re.match
7398 + for x in metadata_xml.maintainers():
7399 + if x.email is not None and matcher(x.email) is not None:
7400 + match = True
7401 + break
7402 + return match
7403 +
7404
7405 # Match if metadata.xml contains no maintainer (orphaned package)
7406 def match_orphaned(metadata_xml):
7407 - if not metadata_xml.maintainers():
7408 - return True
7409 - else:
7410 - return False
7411 + if not metadata_xml.maintainers():
7412 + return True
7413 + else:
7414 + return False
7415 +
7416
7417 def pquery(parser, opts, args):
7418 - portdb = portage.db[portage.root]['porttree'].dbapi
7419 - root_config = RootConfig(portdb.settings,
7420 - portage.db[portage.root], None)
7421 -
7422 - def _pkg(cpv, repo_name):
7423 - try:
7424 - metadata = dict(zip(
7425 - Package.metadata_keys,
7426 - portdb.aux_get(cpv,
7427 - Package.metadata_keys,
7428 - myrepo=repo_name)))
7429 - except KeyError:
7430 - raise portage.exception.PackageNotFound(cpv)
7431 - return Package(built=False, cpv=cpv,
7432 - installed=False, metadata=metadata,
7433 - root_config=root_config,
7434 - type_name="ebuild")
7435 -
7436 - need_metadata = False
7437 - atoms = []
7438 - for arg in args:
7439 - if "/" not in arg.split(":")[0]:
7440 - atom = insert_category_into_atom(arg, '*')
7441 - if atom is None:
7442 - writemsg("ERROR: Invalid atom: '%s'\n" % arg,
7443 - noiselevel=-1)
7444 - return 2
7445 - else:
7446 - atom = arg
7447 -
7448 - try:
7449 - atom = portage.dep.Atom(atom, allow_wildcard=True, allow_repo=True)
7450 - except portage.exception.InvalidAtom:
7451 - writemsg("ERROR: Invalid atom: '%s'\n" % arg,
7452 - noiselevel=-1)
7453 - return 2
7454 -
7455 - if atom.slot is not None:
7456 - need_metadata = True
7457 -
7458 - atoms.append(atom)
7459 -
7460 - if "*/*" in atoms:
7461 - del atoms[:]
7462 - need_metadata = False
7463 -
7464 - if not opts.no_filters:
7465 - need_metadata = True
7466 -
7467 - xml_matchers = []
7468 - if opts.maintainer_email:
7469 - maintainer_emails = []
7470 - for x in opts.maintainer_email:
7471 - maintainer_emails.extend(x.split(","))
7472 - if opts.no_regex: # Escape regex-special characters for an exact match
7473 - maintainer_emails = [re.escape(x) for x in maintainer_emails]
7474 - xml_matchers.append(MaintainerEmailMatcher(maintainer_emails))
7475 - if opts.orphaned:
7476 - xml_matchers.append(match_orphaned)
7477 -
7478 - if opts.repo is not None:
7479 - repos = [portdb.repositories[opts.repo]]
7480 - else:
7481 - repos = list(portdb.repositories)
7482 -
7483 - if not atoms:
7484 - names = None
7485 - categories = list(portdb.categories)
7486 - else:
7487 - category_wildcard = False
7488 - name_wildcard = False
7489 - categories = []
7490 - names = []
7491 - for atom in atoms:
7492 - category, name = portage.catsplit(atom.cp)
7493 - categories.append(category)
7494 - names.append(name)
7495 - if "*" in category:
7496 - category_wildcard = True
7497 - if "*" in name:
7498 - name_wildcard = True
7499 -
7500 - if category_wildcard:
7501 - categories = list(portdb.categories)
7502 - else:
7503 - categories = list(set(categories))
7504 -
7505 - if name_wildcard:
7506 - names = None
7507 - else:
7508 - names = sorted(set(names))
7509 -
7510 - no_version = opts.no_version
7511 - categories.sort()
7512 -
7513 - for category in categories:
7514 - if names is None:
7515 - cp_list = portdb.cp_all(categories=(category,))
7516 - else:
7517 - cp_list = [category + "/" + name for name in names]
7518 - for cp in cp_list:
7519 - matches = []
7520 - for repo in repos:
7521 - match = True
7522 - if xml_matchers:
7523 - metadata_xml_path = os.path.join(
7524 - repo.location, cp, 'metadata.xml')
7525 - try:
7526 - metadata_xml = MetaDataXML(metadata_xml_path, None)
7527 - except (EnvironmentError, SyntaxError):
7528 - match = False
7529 - else:
7530 - for matcher in xml_matchers:
7531 - if not matcher(metadata_xml):
7532 - match = False
7533 - break
7534 - if not match:
7535 - continue
7536 - cpv_list = portdb.cp_list(cp, mytree=[repo.location])
7537 - if atoms:
7538 - for cpv in cpv_list:
7539 - pkg = None
7540 - for atom in atoms:
7541 - if atom.repo is not None and \
7542 - atom.repo != repo.name:
7543 - continue
7544 - if not portage.match_from_list(atom, [cpv]):
7545 - continue
7546 - if need_metadata:
7547 - if pkg is None:
7548 - try:
7549 - pkg = _pkg(cpv, repo.name)
7550 - except portage.exception.PackageNotFound:
7551 - continue
7552 -
7553 - if not (opts.no_filters or pkg.visible):
7554 - continue
7555 - if not portage.match_from_list(atom, [pkg]):
7556 - continue
7557 - matches.append(cpv)
7558 - break
7559 - if no_version and matches:
7560 - break
7561 - elif opts.no_filters:
7562 - matches.extend(cpv_list)
7563 - else:
7564 - for cpv in cpv_list:
7565 - try:
7566 - pkg = _pkg(cpv, repo.name)
7567 - except portage.exception.PackageNotFound:
7568 - continue
7569 - else:
7570 - if pkg.visible:
7571 - matches.append(cpv)
7572 - if no_version:
7573 - break
7574 -
7575 - if no_version and matches:
7576 - break
7577 -
7578 - if not matches:
7579 - continue
7580 -
7581 - if no_version:
7582 - writemsg_stdout("%s\n" % (cp,), noiselevel=-1)
7583 - else:
7584 - matches = list(set(matches))
7585 - portdb._cpv_sort_ascending(matches)
7586 - for cpv in matches:
7587 - writemsg_stdout("%s\n" % (cpv,), noiselevel=-1)
7588 -
7589 - return os.EX_OK
7590 -
7591 -docstrings['pquery'] = """[options] [atom]+
7592 + portdb = portage.db[portage.root]["porttree"].dbapi
7593 + root_config = RootConfig(portdb.settings, portage.db[portage.root], None)
7594 +
7595 + def _pkg(cpv, repo_name):
7596 + try:
7597 + metadata = dict(
7598 + zip(
7599 + Package.metadata_keys,
7600 + portdb.aux_get(cpv, Package.metadata_keys, myrepo=repo_name),
7601 + )
7602 + )
7603 + except KeyError:
7604 + raise portage.exception.PackageNotFound(cpv)
7605 + return Package(
7606 + built=False,
7607 + cpv=cpv,
7608 + installed=False,
7609 + metadata=metadata,
7610 + root_config=root_config,
7611 + type_name="ebuild",
7612 + )
7613 +
7614 + need_metadata = False
7615 + atoms = []
7616 + for arg in args:
7617 + if "/" not in arg.split(":")[0]:
7618 + atom = insert_category_into_atom(arg, "*")
7619 + if atom is None:
7620 + writemsg("ERROR: Invalid atom: '%s'\n" % arg, noiselevel=-1)
7621 + return 2
7622 + else:
7623 + atom = arg
7624 +
7625 + try:
7626 + atom = portage.dep.Atom(atom, allow_wildcard=True, allow_repo=True)
7627 + except portage.exception.InvalidAtom:
7628 + writemsg("ERROR: Invalid atom: '%s'\n" % arg, noiselevel=-1)
7629 + return 2
7630 +
7631 + if atom.slot is not None:
7632 + need_metadata = True
7633 +
7634 + atoms.append(atom)
7635 +
7636 + if "*/*" in atoms:
7637 + del atoms[:]
7638 + need_metadata = False
7639 +
7640 + if not opts.no_filters:
7641 + need_metadata = True
7642 +
7643 + xml_matchers = []
7644 + if opts.maintainer_email:
7645 + maintainer_emails = []
7646 + for x in opts.maintainer_email:
7647 + maintainer_emails.extend(x.split(","))
7648 + if opts.no_regex: # Escape regex-special characters for an exact match
7649 + maintainer_emails = [re.escape(x) for x in maintainer_emails]
7650 + xml_matchers.append(MaintainerEmailMatcher(maintainer_emails))
7651 + if opts.orphaned:
7652 + xml_matchers.append(match_orphaned)
7653 +
7654 + if opts.repo is not None:
7655 + repos = [portdb.repositories[opts.repo]]
7656 + else:
7657 + repos = list(portdb.repositories)
7658 +
7659 + if not atoms:
7660 + names = None
7661 + categories = list(portdb.categories)
7662 + else:
7663 + category_wildcard = False
7664 + name_wildcard = False
7665 + categories = []
7666 + names = []
7667 + for atom in atoms:
7668 + category, name = portage.catsplit(atom.cp)
7669 + categories.append(category)
7670 + names.append(name)
7671 + if "*" in category:
7672 + category_wildcard = True
7673 + if "*" in name:
7674 + name_wildcard = True
7675 +
7676 + if category_wildcard:
7677 + categories = list(portdb.categories)
7678 + else:
7679 + categories = list(set(categories))
7680 +
7681 + if name_wildcard:
7682 + names = None
7683 + else:
7684 + names = sorted(set(names))
7685 +
7686 + no_version = opts.no_version
7687 + categories.sort()
7688 +
7689 + for category in categories:
7690 + if names is None:
7691 + cp_list = portdb.cp_all(categories=(category,))
7692 + else:
7693 + cp_list = [category + "/" + name for name in names]
7694 + for cp in cp_list:
7695 + matches = []
7696 + for repo in repos:
7697 + match = True
7698 + if xml_matchers:
7699 + metadata_xml_path = os.path.join(repo.location, cp, "metadata.xml")
7700 + try:
7701 + metadata_xml = MetaDataXML(metadata_xml_path, None)
7702 + except (EnvironmentError, SyntaxError):
7703 + match = False
7704 + else:
7705 + for matcher in xml_matchers:
7706 + if not matcher(metadata_xml):
7707 + match = False
7708 + break
7709 + if not match:
7710 + continue
7711 + cpv_list = portdb.cp_list(cp, mytree=[repo.location])
7712 + if atoms:
7713 + for cpv in cpv_list:
7714 + pkg = None
7715 + for atom in atoms:
7716 + if atom.repo is not None and atom.repo != repo.name:
7717 + continue
7718 + if not portage.match_from_list(atom, [cpv]):
7719 + continue
7720 + if need_metadata:
7721 + if pkg is None:
7722 + try:
7723 + pkg = _pkg(cpv, repo.name)
7724 + except portage.exception.PackageNotFound:
7725 + continue
7726 +
7727 + if not (opts.no_filters or pkg.visible):
7728 + continue
7729 + if not portage.match_from_list(atom, [pkg]):
7730 + continue
7731 + matches.append(cpv)
7732 + break
7733 + if no_version and matches:
7734 + break
7735 + elif opts.no_filters:
7736 + matches.extend(cpv_list)
7737 + else:
7738 + for cpv in cpv_list:
7739 + try:
7740 + pkg = _pkg(cpv, repo.name)
7741 + except portage.exception.PackageNotFound:
7742 + continue
7743 + else:
7744 + if pkg.visible:
7745 + matches.append(cpv)
7746 + if no_version:
7747 + break
7748 +
7749 + if no_version and matches:
7750 + break
7751 +
7752 + if not matches:
7753 + continue
7754 +
7755 + if no_version:
7756 + writemsg_stdout("%s\n" % (cp,), noiselevel=-1)
7757 + else:
7758 + matches = list(set(matches))
7759 + portdb._cpv_sort_ascending(matches)
7760 + for cpv in matches:
7761 + writemsg_stdout("%s\n" % (cpv,), noiselevel=-1)
7762 +
7763 + return os.EX_OK
7764 +
7765 +
7766 +docstrings[
7767 + "pquery"
7768 +] = """[options] [atom]+
7769 Emulates a subset of Pkgcore's pquery tool.
7770 """
7771 -pquery.__doc__ = docstrings['pquery']
7772 +pquery.__doc__ = docstrings["pquery"]
7773
7774
7775 -#-----------------------------------------------------------------------------
7776 +# -----------------------------------------------------------------------------
7777 #
7778 # DO NOT CHANGE CODE BEYOND THIS POINT - IT'S NOT NEEDED!
7779 #
7780
7781 -non_commands = frozenset(['elog', 'eval_atom_use', 'exithandler', 'match_orphaned', 'main', 'usage', 'uses_eroot'])
7782 -commands = sorted(k for k, v in globals().items() \
7783 - if k not in non_commands and isinstance(v, types.FunctionType) and v.__module__ == "__main__")
7784 +non_commands = frozenset(
7785 + [
7786 + "elog",
7787 + "eval_atom_use",
7788 + "exithandler",
7789 + "match_orphaned",
7790 + "main",
7791 + "usage",
7792 + "uses_eroot",
7793 + ]
7794 +)
7795 +commands = sorted(
7796 + k
7797 + for k, v in globals().items()
7798 + if k not in non_commands
7799 + and isinstance(v, types.FunctionType)
7800 + and v.__module__ == "__main__"
7801 +)
7802
7803
7804 def add_pquery_arguments(parser):
7805 - pquery_option_groups = (
7806 - (
7807 - 'Repository matching options',
7808 - (
7809 - {
7810 - "longopt": "--no-filters",
7811 - "action": "store_true",
7812 - "help": "no visibility filters (ACCEPT_KEYWORDS, package masking, etc)"
7813 - },
7814 - {
7815 - "longopt": "--repo",
7816 - "help": "repository to use (all repositories are used by default)"
7817 - },
7818 - )
7819 - ),
7820 - (
7821 - 'Package matching options',
7822 - (
7823 - {
7824 - "longopt": "--maintainer-email",
7825 - "action": "append",
7826 - "help": "comma-separated list of maintainer email regexes to search for"
7827 - },
7828 - {
7829 - "longopt": "--no-regex",
7830 - "action": "store_true",
7831 - "help": "Use exact matching instead of regex matching for --maintainer-email"
7832 - },
7833 - {
7834 - "longopt": "--orphaned",
7835 - "action": "store_true",
7836 - "help": "match only orphaned (maintainer-needed) packages"
7837 - }
7838 - )
7839 - ),
7840 - (
7841 - 'Output formatting',
7842 - (
7843 - {
7844 - "shortopt": "-n",
7845 - "longopt": "--no-version",
7846 - "action": "store_true",
7847 - "help": "collapse multiple matching versions together"
7848 - },
7849 - )
7850 - ),
7851 - )
7852 -
7853 - for group_title, opt_data in pquery_option_groups:
7854 - arg_group = parser.add_argument_group(group_title)
7855 - for opt_info in opt_data:
7856 - pargs = []
7857 - try:
7858 - pargs.append(opt_info["shortopt"])
7859 - except KeyError:
7860 - pass
7861 - try:
7862 - pargs.append(opt_info["longopt"])
7863 - except KeyError:
7864 - pass
7865 -
7866 - kwargs = {}
7867 - try:
7868 - kwargs["action"] = opt_info["action"]
7869 - except KeyError:
7870 - pass
7871 - try:
7872 - kwargs["help"] = opt_info["help"]
7873 - except KeyError:
7874 - pass
7875 - arg_group.add_argument(*pargs, **kwargs)
7876 + pquery_option_groups = (
7877 + (
7878 + "Repository matching options",
7879 + (
7880 + {
7881 + "longopt": "--no-filters",
7882 + "action": "store_true",
7883 + "help": "no visibility filters (ACCEPT_KEYWORDS, package masking, etc)",
7884 + },
7885 + {
7886 + "longopt": "--repo",
7887 + "help": "repository to use (all repositories are used by default)",
7888 + },
7889 + ),
7890 + ),
7891 + (
7892 + "Package matching options",
7893 + (
7894 + {
7895 + "longopt": "--maintainer-email",
7896 + "action": "append",
7897 + "help": "comma-separated list of maintainer email regexes to search for",
7898 + },
7899 + {
7900 + "longopt": "--no-regex",
7901 + "action": "store_true",
7902 + "help": "Use exact matching instead of regex matching for --maintainer-email",
7903 + },
7904 + {
7905 + "longopt": "--orphaned",
7906 + "action": "store_true",
7907 + "help": "match only orphaned (maintainer-needed) packages",
7908 + },
7909 + ),
7910 + ),
7911 + (
7912 + "Output formatting",
7913 + (
7914 + {
7915 + "shortopt": "-n",
7916 + "longopt": "--no-version",
7917 + "action": "store_true",
7918 + "help": "collapse multiple matching versions together",
7919 + },
7920 + ),
7921 + ),
7922 + )
7923 +
7924 + for group_title, opt_data in pquery_option_groups:
7925 + arg_group = parser.add_argument_group(group_title)
7926 + for opt_info in opt_data:
7927 + pargs = []
7928 + try:
7929 + pargs.append(opt_info["shortopt"])
7930 + except KeyError:
7931 + pass
7932 + try:
7933 + pargs.append(opt_info["longopt"])
7934 + except KeyError:
7935 + pass
7936 +
7937 + kwargs = {}
7938 + try:
7939 + kwargs["action"] = opt_info["action"]
7940 + except KeyError:
7941 + pass
7942 + try:
7943 + kwargs["help"] = opt_info["help"]
7944 + except KeyError:
7945 + pass
7946 + arg_group.add_argument(*pargs, **kwargs)
7947
7948
7949 def usage(argv):
7950 - print(">>> Portage information query tool")
7951 - print(">>> %s" % portage.VERSION)
7952 - print(">>> Usage: portageq <command> [<option> ...]")
7953 - print("")
7954 - print("Available commands:")
7955 -
7956 - #
7957 - # Show our commands -- we do this by scanning the functions in this
7958 - # file, and formatting each functions documentation.
7959 - #
7960 - help_mode = '--help' in argv
7961 - for name in commands:
7962 - doc = docstrings.get(name)
7963 - if doc == None:
7964 - print(" " + name)
7965 - print(" MISSING DOCUMENTATION!")
7966 - print("")
7967 - continue
7968 -
7969 - lines = doc.lstrip("\n").split("\n")
7970 - print(" " + name + " " + lines[0].strip())
7971 - if len(argv) > 1:
7972 - if not help_mode:
7973 - lines = lines[:-1]
7974 - for line in lines[1:]:
7975 - print(" " + line.strip())
7976 -
7977 - print()
7978 - print('Pkgcore pquery compatible options:')
7979 - print()
7980 - parser = argparse.ArgumentParser(add_help=False,
7981 - usage='portageq pquery [options] [atom ...]')
7982 - add_pquery_arguments(parser)
7983 - parser.print_help()
7984 -
7985 - if len(argv) == 1:
7986 - print("\nRun portageq with --help for info")
7987 + print(">>> Portage information query tool")
7988 + print(">>> %s" % portage.VERSION)
7989 + print(">>> Usage: portageq <command> [<option> ...]")
7990 + print("")
7991 + print("Available commands:")
7992 +
7993 + #
7994 + # Show our commands -- we do this by scanning the functions in this
7995 + # file, and formatting each functions documentation.
7996 + #
7997 + help_mode = "--help" in argv
7998 + for name in commands:
7999 + doc = docstrings.get(name)
8000 + if doc == None:
8001 + print(" " + name)
8002 + print(" MISSING DOCUMENTATION!")
8003 + print("")
8004 + continue
8005 +
8006 + lines = doc.lstrip("\n").split("\n")
8007 + print(" " + name + " " + lines[0].strip())
8008 + if len(argv) > 1:
8009 + if not help_mode:
8010 + lines = lines[:-1]
8011 + for line in lines[1:]:
8012 + print(" " + line.strip())
8013 +
8014 + print()
8015 + print("Pkgcore pquery compatible options:")
8016 + print()
8017 + parser = argparse.ArgumentParser(
8018 + add_help=False, usage="portageq pquery [options] [atom ...]"
8019 + )
8020 + add_pquery_arguments(parser)
8021 + parser.print_help()
8022 +
8023 + if len(argv) == 1:
8024 + print("\nRun portageq with --help for info")
8025 +
8026
8027 atom_validate_strict = "EBUILD_PHASE" in os.environ
8028 eapi = None
8029 if atom_validate_strict:
8030 - eapi = os.environ.get('EAPI')
8031 + eapi = os.environ.get("EAPI")
8032
8033 - def elog(elog_funcname, lines):
8034 - cmd = "source '%s/isolated-functions.sh' ; " % \
8035 - os.environ["PORTAGE_BIN_PATH"]
8036 - for line in lines:
8037 - cmd += "%s %s ; " % (elog_funcname, portage._shell_quote(line))
8038 - subprocess.call([portage.const.BASH_BINARY, "-c", cmd])
8039 + def elog(elog_funcname, lines):
8040 + cmd = "source '%s/isolated-functions.sh' ; " % os.environ["PORTAGE_BIN_PATH"]
8041 + for line in lines:
8042 + cmd += "%s %s ; " % (elog_funcname, portage._shell_quote(line))
8043 + subprocess.call([portage.const.BASH_BINARY, "-c", cmd])
8044
8045 else:
8046 - def elog(elog_funcname, lines):
8047 - pass
8048 +
8049 + def elog(elog_funcname, lines):
8050 + pass
8051 +
8052
8053 def main(argv):
8054
8055 - argv = portage._decode_argv(argv)
8056 -
8057 - nocolor = os.environ.get('NOCOLOR')
8058 - if nocolor in ('yes', 'true'):
8059 - portage.output.nocolor()
8060 -
8061 - parser = argparse.ArgumentParser(add_help=False)
8062 -
8063 - # used by envvar
8064 - parser.add_argument("-v", dest="verbose", action="store_true")
8065 -
8066 - actions = parser.add_argument_group('Actions')
8067 - actions.add_argument("-h", "--help", action="store_true")
8068 - actions.add_argument("--version", action="store_true")
8069 -
8070 - add_pquery_arguments(parser)
8071 -
8072 - opts, args = parser.parse_known_args(argv[1:])
8073 -
8074 - if opts.help:
8075 - usage(argv)
8076 - return os.EX_OK
8077 - elif opts.version:
8078 - print("Portage", portage.VERSION)
8079 - return os.EX_OK
8080 -
8081 - cmd = None
8082 - if args and args[0] in commands:
8083 - cmd = args[0]
8084 -
8085 - if cmd == 'pquery':
8086 - cmd = None
8087 - args = args[1:]
8088 -
8089 - if cmd is None:
8090 - return pquery(parser, opts, args)
8091 -
8092 - if opts.verbose:
8093 - # used by envvar
8094 - args.append("-v")
8095 -
8096 - argv = argv[:1] + args
8097 -
8098 - if len(argv) < 2:
8099 - usage(argv)
8100 - sys.exit(os.EX_USAGE)
8101 -
8102 - function = globals()[cmd]
8103 - uses_eroot = getattr(function, "uses_eroot", False) and len(argv) > 2
8104 - if uses_eroot:
8105 - if not os.path.isdir(argv[2]):
8106 - sys.stderr.write("Not a directory: '%s'\n" % argv[2])
8107 - sys.stderr.write("Run portageq with --help for info\n")
8108 - sys.stderr.flush()
8109 - sys.exit(os.EX_USAGE)
8110 - # Calculate EPREFIX and ROOT that will be used to construct
8111 - # portage.settings later. It's tempting to use
8112 - # portage.settings["EPREFIX"] here, but that would force
8113 - # instantiation of portage.settings, which we don't want to do
8114 - # until after we've calculated ROOT (see bug #529200).
8115 - eprefix = portage.data._target_eprefix()
8116 - eroot = portage.util.normalize_path(argv[2])
8117 -
8118 - if eprefix:
8119 - if not eroot.endswith(eprefix):
8120 - sys.stderr.write("ERROR: This version of portageq"
8121 - " only supports <eroot>s ending in"
8122 - " '%s'. The provided <eroot>, '%s',"
8123 - " doesn't.\n" % (eprefix, eroot))
8124 - sys.stderr.flush()
8125 - sys.exit(os.EX_USAGE)
8126 - root = eroot[:1 - len(eprefix)]
8127 - else:
8128 - root = eroot
8129 -
8130 - os.environ["ROOT"] = root
8131 -
8132 - if getattr(function, "uses_configroot", False):
8133 - os.environ["PORTAGE_CONFIGROOT"] = eroot
8134 - # Disable RepoConfigLoader location validation, allowing raw
8135 - # configuration to pass through, since repo locations are not
8136 - # necessarily expected to exist if the configuration comes
8137 - # from a chroot.
8138 - portage._sync_mode = True
8139 -
8140 - args = argv[2:]
8141 -
8142 - try:
8143 - if uses_eroot:
8144 - args[0] = portage.settings['EROOT']
8145 - retval = function(args)
8146 - if retval:
8147 - sys.exit(retval)
8148 - except portage.exception.PermissionDenied as e:
8149 - sys.stderr.write("Permission denied: '%s'\n" % str(e))
8150 - sys.exit(e.errno)
8151 - except portage.exception.ParseError as e:
8152 - sys.stderr.write("%s\n" % str(e))
8153 - sys.exit(1)
8154 - except portage.exception.AmbiguousPackageName as e:
8155 - # Multiple matches thrown from cpv_expand
8156 - pkgs = e.args[0]
8157 - # An error has occurred so we writemsg to stderr and exit nonzero.
8158 - portage.writemsg("You specified an unqualified atom that matched multiple packages:\n", noiselevel=-1)
8159 - for pkg in pkgs:
8160 - portage.writemsg("* %s\n" % pkg, noiselevel=-1)
8161 - portage.writemsg("\nPlease use a more specific atom.\n", noiselevel=-1)
8162 - sys.exit(1)
8163 -
8164 -if __name__ == '__main__':
8165 - try:
8166 - sys.exit(main(sys.argv))
8167 - finally:
8168 - global_event_loop().close()
8169 -
8170 -#-----------------------------------------------------------------------------
8171 + argv = portage._decode_argv(argv)
8172 +
8173 + nocolor = os.environ.get("NOCOLOR")
8174 + if nocolor in ("yes", "true"):
8175 + portage.output.nocolor()
8176 +
8177 + parser = argparse.ArgumentParser(add_help=False)
8178 +
8179 + # used by envvar
8180 + parser.add_argument("-v", dest="verbose", action="store_true")
8181 +
8182 + actions = parser.add_argument_group("Actions")
8183 + actions.add_argument("-h", "--help", action="store_true")
8184 + actions.add_argument("--version", action="store_true")
8185 +
8186 + add_pquery_arguments(parser)
8187 +
8188 + opts, args = parser.parse_known_args(argv[1:])
8189 +
8190 + if opts.help:
8191 + usage(argv)
8192 + return os.EX_OK
8193 + elif opts.version:
8194 + print("Portage", portage.VERSION)
8195 + return os.EX_OK
8196 +
8197 + cmd = None
8198 + if args and args[0] in commands:
8199 + cmd = args[0]
8200 +
8201 + if cmd == "pquery":
8202 + cmd = None
8203 + args = args[1:]
8204 +
8205 + if cmd is None:
8206 + return pquery(parser, opts, args)
8207 +
8208 + if opts.verbose:
8209 + # used by envvar
8210 + args.append("-v")
8211 +
8212 + argv = argv[:1] + args
8213 +
8214 + if len(argv) < 2:
8215 + usage(argv)
8216 + sys.exit(os.EX_USAGE)
8217 +
8218 + function = globals()[cmd]
8219 + uses_eroot = getattr(function, "uses_eroot", False) and len(argv) > 2
8220 + if uses_eroot:
8221 + if not os.path.isdir(argv[2]):
8222 + sys.stderr.write("Not a directory: '%s'\n" % argv[2])
8223 + sys.stderr.write("Run portageq with --help for info\n")
8224 + sys.stderr.flush()
8225 + sys.exit(os.EX_USAGE)
8226 + # Calculate EPREFIX and ROOT that will be used to construct
8227 + # portage.settings later. It's tempting to use
8228 + # portage.settings["EPREFIX"] here, but that would force
8229 + # instantiation of portage.settings, which we don't want to do
8230 + # until after we've calculated ROOT (see bug #529200).
8231 + eprefix = portage.data._target_eprefix()
8232 + eroot = portage.util.normalize_path(argv[2])
8233 +
8234 + if eprefix:
8235 + if not eroot.endswith(eprefix):
8236 + sys.stderr.write(
8237 + "ERROR: This version of portageq"
8238 + " only supports <eroot>s ending in"
8239 + " '%s'. The provided <eroot>, '%s',"
8240 + " doesn't.\n" % (eprefix, eroot)
8241 + )
8242 + sys.stderr.flush()
8243 + sys.exit(os.EX_USAGE)
8244 + root = eroot[: 1 - len(eprefix)]
8245 + else:
8246 + root = eroot
8247 +
8248 + os.environ["ROOT"] = root
8249 +
8250 + if getattr(function, "uses_configroot", False):
8251 + os.environ["PORTAGE_CONFIGROOT"] = eroot
8252 + # Disable RepoConfigLoader location validation, allowing raw
8253 + # configuration to pass through, since repo locations are not
8254 + # necessarily expected to exist if the configuration comes
8255 + # from a chroot.
8256 + portage._sync_mode = True
8257 +
8258 + args = argv[2:]
8259 +
8260 + try:
8261 + if uses_eroot:
8262 + args[0] = portage.settings["EROOT"]
8263 + retval = function(args)
8264 + if retval:
8265 + sys.exit(retval)
8266 + except portage.exception.PermissionDenied as e:
8267 + sys.stderr.write("Permission denied: '%s'\n" % str(e))
8268 + sys.exit(e.errno)
8269 + except portage.exception.ParseError as e:
8270 + sys.stderr.write("%s\n" % str(e))
8271 + sys.exit(1)
8272 + except portage.exception.AmbiguousPackageName as e:
8273 + # Multiple matches thrown from cpv_expand
8274 + pkgs = e.args[0]
8275 + # An error has occurred so we writemsg to stderr and exit nonzero.
8276 + portage.writemsg(
8277 + "You specified an unqualified atom that matched multiple packages:\n",
8278 + noiselevel=-1,
8279 + )
8280 + for pkg in pkgs:
8281 + portage.writemsg("* %s\n" % pkg, noiselevel=-1)
8282 + portage.writemsg("\nPlease use a more specific atom.\n", noiselevel=-1)
8283 + sys.exit(1)
8284 +
8285 +
8286 +if __name__ == "__main__":
8287 + try:
8288 + sys.exit(main(sys.argv))
8289 + finally:
8290 + global_event_loop().close()
8291 +
8292 +# -----------------------------------------------------------------------------
8293
8294 diff --git a/bin/quickpkg b/bin/quickpkg
8295 index 7a3304ca4..a4a3584da 100755
8296 --- a/bin/quickpkg
8297 +++ b/bin/quickpkg
8298 @@ -10,19 +10,32 @@ import subprocess
8299 import sys
8300
8301 from os import path as osp
8302 -if osp.isfile(osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), ".portage_not_installed")):
8303 - sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "lib"))
8304 +
8305 +if osp.isfile(
8306 + osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), ".portage_not_installed")
8307 +):
8308 + sys.path.insert(
8309 + 0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "lib")
8310 + )
8311 import portage
8312 +
8313 portage._internal_caller = True
8314 from portage import os
8315 from portage import xpak, gpkg
8316 from portage.const import SUPPORTED_GENTOO_BINPKG_FORMATS
8317 from portage.dbapi.dep_expand import dep_expand
8318 from portage.dep import Atom, use_reduce
8319 -from portage.exception import (AmbiguousPackageName, InvalidAtom, InvalidData,
8320 - InvalidBinaryPackageFormat, InvalidDependString, PackageSetNotFound,
8321 - PermissionDenied)
8322 +from portage.exception import (
8323 + AmbiguousPackageName,
8324 + InvalidAtom,
8325 + InvalidData,
8326 + InvalidBinaryPackageFormat,
8327 + InvalidDependString,
8328 + PackageSetNotFound,
8329 + PermissionDenied,
8330 +)
8331 from portage.util import ensure_dirs, shlex_split, varexpand, _xattr
8332 +
8333 xattr = _xattr.xattr
8334 from portage._sets import load_default_config, SETPREFIX
8335 from portage.process import find_binary
8336 @@ -32,358 +45,391 @@ from portage.gpg import GPG
8337
8338
8339 def quickpkg_atom(options, infos, arg, eout):
8340 - settings = portage.settings
8341 - eroot = portage.settings['EROOT']
8342 - trees = portage.db[eroot]
8343 - vartree = trees["vartree"]
8344 - vardb = vartree.dbapi
8345 - bintree = trees["bintree"]
8346 -
8347 - include_config = options.include_config == "y"
8348 - include_unmodified_config = options.include_unmodified_config == "y"
8349 - fix_metadata_keys = ["PF", "CATEGORY"]
8350 -
8351 - try:
8352 - atom = dep_expand(arg, mydb=vardb, settings=vartree.settings)
8353 - except AmbiguousPackageName as e:
8354 - # Multiple matches thrown from cpv_expand
8355 - eout.eerror("Please use a more specific atom: %s" % \
8356 - " ".join(e.args[0]))
8357 - del e
8358 - infos["missing"].append(arg)
8359 - return 1
8360 - except (InvalidAtom, InvalidData):
8361 - eout.eerror("Invalid atom: %s" % (arg,))
8362 - infos["missing"].append(arg)
8363 - return 1
8364 - if atom[:1] == '=' and arg[:1] != '=':
8365 - # dep_expand() allows missing '=' but it's really invalid
8366 - eout.eerror("Invalid atom: %s" % (arg,))
8367 - infos["missing"].append(arg)
8368 - return 1
8369 -
8370 - matches = vardb.match(atom)
8371 - pkgs_for_arg = 0
8372 - retval = 0
8373 - for cpv in matches:
8374 - excluded_config_files = []
8375 - dblnk = vardb._dblink(cpv)
8376 - have_lock = False
8377 -
8378 - if "__PORTAGE_INHERIT_VARDB_LOCK" not in settings:
8379 - try:
8380 - dblnk.lockdb()
8381 - have_lock = True
8382 - except PermissionDenied:
8383 - pass
8384 -
8385 - try:
8386 - if not dblnk.exists():
8387 - # unmerged by a concurrent process
8388 - continue
8389 - iuse, use, restrict = vardb.aux_get(cpv,
8390 - ["IUSE","USE","RESTRICT"])
8391 - iuse = [ x.lstrip("+-") for x in iuse.split() ]
8392 - use = use.split()
8393 - try:
8394 - restrict = use_reduce(restrict, uselist=use, flat=True)
8395 - except InvalidDependString as e:
8396 - eout.eerror("Invalid RESTRICT metadata " + \
8397 - "for '%s': %s; skipping" % (cpv, str(e)))
8398 - del e
8399 - continue
8400 - if "bindist" in iuse and "bindist" not in use:
8401 - eout.ewarn("%s: package was emerged with USE=-bindist!" % cpv)
8402 - eout.ewarn("%s: it might not be legal to redistribute this." % cpv)
8403 - elif "bindist" in restrict:
8404 - eout.ewarn("%s: package has RESTRICT=bindist!" % cpv)
8405 - eout.ewarn("%s: it might not be legal to redistribute this." % cpv)
8406 - eout.ebegin("Building package for %s" % cpv)
8407 - pkgs_for_arg += 1
8408 - existing_metadata = dict(zip(fix_metadata_keys,
8409 - vardb.aux_get(cpv, fix_metadata_keys)))
8410 - category, pf = portage.catsplit(cpv)
8411 - required_metadata = {}
8412 - required_metadata["CATEGORY"] = category
8413 - required_metadata["PF"] = pf
8414 - update_metadata = {}
8415 - for k, v in required_metadata.items():
8416 - if v != existing_metadata[k]:
8417 - update_metadata[k] = v
8418 - if update_metadata:
8419 - vardb.aux_update(cpv, update_metadata)
8420 -
8421 - binpkg_format = settings.get("BINPKG_FORMAT", SUPPORTED_GENTOO_BINPKG_FORMATS[0])
8422 - if binpkg_format == "xpak":
8423 - xpdata = xpak.xpak(dblnk.dbdir)
8424 - binpkg_tmpfile = os.path.join(bintree.pkgdir,
8425 - cpv + ".tbz2." + str(portage.getpid()))
8426 - ensure_dirs(os.path.dirname(binpkg_tmpfile))
8427 - binpkg_compression = settings.get("BINPKG_COMPRESS", "bzip2")
8428 - try:
8429 - compression = _compressors[binpkg_compression]
8430 - except KeyError as e:
8431 - if binpkg_compression:
8432 - eout.eerror("Invalid or unsupported compression method: %s" % e.args[0])
8433 - return 1
8434 - # Empty BINPKG_COMPRESS disables compression.
8435 - binpkg_compression = 'none'
8436 - compression = {
8437 - 'compress': 'cat',
8438 - 'package': 'sys-apps/coreutils',
8439 - }
8440 - try:
8441 - compression_binary = shlex_split(varexpand(compression["compress"], mydict=settings))[0]
8442 - except IndexError as e:
8443 - eout.eerror("Invalid or unsupported compression method: %s" % e.args[0])
8444 - return 1
8445 - if find_binary(compression_binary) is None:
8446 - missing_package = compression["package"]
8447 - eout.eerror("File compression unsupported %s. Missing package: %s" % (binpkg_compression, missing_package))
8448 - return 1
8449 - cmd = [varexpand(x, mydict=settings) for x in shlex_split(compression["compress"])]
8450 - # Filter empty elements that make Popen fail
8451 - cmd = [x for x in cmd if x != ""]
8452 - with open(binpkg_tmpfile, "wb") as fobj:
8453 - proc = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=fobj)
8454 - excluded_config_files = dblnk.quickpkg(proc.stdin,
8455 - include_config=include_config,
8456 - include_unmodified_config=include_unmodified_config)
8457 - proc.stdin.close()
8458 - if proc.wait() != os.EX_OK:
8459 - eout.eend(1)
8460 - eout.eerror("Compressor failed for package %s" % cpv)
8461 - retval |= 1
8462 - try:
8463 - os.unlink(binpkg_tmpfile)
8464 - except OSError as e:
8465 - if e.errno not in (errno.ENOENT, errno.ESTALE):
8466 - raise
8467 - continue
8468 - xpak.tbz2(binpkg_tmpfile).recompose_mem(xpdata)
8469 - elif binpkg_format == "gpkg":
8470 - metadata = gpkg.gpkg(settings)._generate_metadata_from_dir(dblnk.dbdir)
8471 - binpkg_tmpfile = os.path.join(bintree.pkgdir,
8472 - cpv + ".gpkg.tar." + str(os.getpid()))
8473 - ensure_dirs(os.path.dirname(binpkg_tmpfile))
8474 - excluded_config_files = dblnk.quickpkg(binpkg_tmpfile,
8475 - metadata,
8476 - include_config=include_config,
8477 - include_unmodified_config=include_unmodified_config)
8478 - else:
8479 - raise InvalidBinaryPackageFormat(binpkg_format)
8480 - finally:
8481 - if have_lock:
8482 - dblnk.unlockdb()
8483 - pkg_info = bintree.inject(cpv, filename=binpkg_tmpfile)
8484 - # The pkg_info value ensures that the following getname call
8485 - # returns the correct path when FEATURES=binpkg-multi-instance
8486 - # is enabled, but fallback to cpv in case the inject call
8487 - # returned None due to some kind of failure.
8488 - binpkg_path = bintree.getname(pkg_info or cpv)
8489 - try:
8490 - s = os.stat(binpkg_path)
8491 - except OSError:
8492 - s = None
8493 -
8494 - if s is None or pkg_info is None:
8495 - # Sanity check, shouldn't happen normally.
8496 - eout.eend(1)
8497 - eout.eerror("Failed to create package: '%s'" % binpkg_path)
8498 - retval |= 1
8499 - else:
8500 - eout.eend(0)
8501 - infos["successes"].append((cpv, s.st_size))
8502 - infos["config_files_excluded"] += len(excluded_config_files)
8503 - for filename in excluded_config_files:
8504 - eout.ewarn("Excluded config: '%s'" % filename)
8505 - if not pkgs_for_arg:
8506 - eout.eerror("Could not find anything " + \
8507 - "to match '%s'; skipping" % arg)
8508 - infos["missing"].append(arg)
8509 - retval |= 1
8510 - return retval
8511 + settings = portage.settings
8512 + eroot = portage.settings["EROOT"]
8513 + trees = portage.db[eroot]
8514 + vartree = trees["vartree"]
8515 + vardb = vartree.dbapi
8516 + bintree = trees["bintree"]
8517 +
8518 + include_config = options.include_config == "y"
8519 + include_unmodified_config = options.include_unmodified_config == "y"
8520 + fix_metadata_keys = ["PF", "CATEGORY"]
8521 +
8522 + try:
8523 + atom = dep_expand(arg, mydb=vardb, settings=vartree.settings)
8524 + except AmbiguousPackageName as e:
8525 + # Multiple matches thrown from cpv_expand
8526 + eout.eerror("Please use a more specific atom: %s" % " ".join(e.args[0]))
8527 + del e
8528 + infos["missing"].append(arg)
8529 + return 1
8530 + except (InvalidAtom, InvalidData):
8531 + eout.eerror("Invalid atom: %s" % (arg,))
8532 + infos["missing"].append(arg)
8533 + return 1
8534 + if atom[:1] == "=" and arg[:1] != "=":
8535 + # dep_expand() allows missing '=' but it's really invalid
8536 + eout.eerror("Invalid atom: %s" % (arg,))
8537 + infos["missing"].append(arg)
8538 + return 1
8539 +
8540 + matches = vardb.match(atom)
8541 + pkgs_for_arg = 0
8542 + retval = 0
8543 + for cpv in matches:
8544 + excluded_config_files = []
8545 + dblnk = vardb._dblink(cpv)
8546 + have_lock = False
8547 +
8548 + if "__PORTAGE_INHERIT_VARDB_LOCK" not in settings:
8549 + try:
8550 + dblnk.lockdb()
8551 + have_lock = True
8552 + except PermissionDenied:
8553 + pass
8554 +
8555 + try:
8556 + if not dblnk.exists():
8557 + # unmerged by a concurrent process
8558 + continue
8559 + iuse, use, restrict = vardb.aux_get(cpv, ["IUSE", "USE", "RESTRICT"])
8560 + iuse = [x.lstrip("+-") for x in iuse.split()]
8561 + use = use.split()
8562 + try:
8563 + restrict = use_reduce(restrict, uselist=use, flat=True)
8564 + except InvalidDependString as e:
8565 + eout.eerror(
8566 + "Invalid RESTRICT metadata "
8567 + + "for '%s': %s; skipping" % (cpv, str(e))
8568 + )
8569 + del e
8570 + continue
8571 + if "bindist" in iuse and "bindist" not in use:
8572 + eout.ewarn("%s: package was emerged with USE=-bindist!" % cpv)
8573 + eout.ewarn("%s: it might not be legal to redistribute this." % cpv)
8574 + elif "bindist" in restrict:
8575 + eout.ewarn("%s: package has RESTRICT=bindist!" % cpv)
8576 + eout.ewarn("%s: it might not be legal to redistribute this." % cpv)
8577 + eout.ebegin("Building package for %s" % cpv)
8578 + pkgs_for_arg += 1
8579 + existing_metadata = dict(
8580 + zip(fix_metadata_keys, vardb.aux_get(cpv, fix_metadata_keys))
8581 + )
8582 + category, pf = portage.catsplit(cpv)
8583 + required_metadata = {}
8584 + required_metadata["CATEGORY"] = category
8585 + required_metadata["PF"] = pf
8586 + update_metadata = {}
8587 + for k, v in required_metadata.items():
8588 + if v != existing_metadata[k]:
8589 + update_metadata[k] = v
8590 + if update_metadata:
8591 + vardb.aux_update(cpv, update_metadata)
8592 +
8593 + binpkg_format = settings.get(
8594 + "BINPKG_FORMAT", SUPPORTED_GENTOO_BINPKG_FORMATS[0]
8595 + )
8596 + if binpkg_format == "xpak":
8597 + xpdata = xpak.xpak(dblnk.dbdir)
8598 + binpkg_tmpfile = os.path.join(
8599 + bintree.pkgdir, cpv + ".tbz2." + str(portage.getpid())
8600 + )
8601 + ensure_dirs(os.path.dirname(binpkg_tmpfile))
8602 + binpkg_compression = settings.get("BINPKG_COMPRESS", "bzip2")
8603 + try:
8604 + compression = _compressors[binpkg_compression]
8605 + except KeyError as e:
8606 + if binpkg_compression:
8607 + eout.eerror(
8608 + "Invalid or unsupported compression method: %s" % e.args[0]
8609 + )
8610 + return 1
8611 + # Empty BINPKG_COMPRESS disables compression.
8612 + binpkg_compression = "none"
8613 + compression = {
8614 + "compress": "cat",
8615 + "package": "sys-apps/coreutils",
8616 + }
8617 + try:
8618 + compression_binary = shlex_split(
8619 + varexpand(compression["compress"], mydict=settings)
8620 + )[0]
8621 + except IndexError as e:
8622 + eout.eerror(
8623 + "Invalid or unsupported compression method: %s" % e.args[0]
8624 + )
8625 + return 1
8626 + if find_binary(compression_binary) is None:
8627 + missing_package = compression["package"]
8628 + eout.eerror(
8629 + "File compression unsupported %s. Missing package: %s"
8630 + % (binpkg_compression, missing_package)
8631 + )
8632 + return 1
8633 + cmd = [
8634 + varexpand(x, mydict=settings)
8635 + for x in shlex_split(compression["compress"])
8636 + ]
8637 + # Filter empty elements that make Popen fail
8638 + cmd = [x for x in cmd if x != ""]
8639 + with open(binpkg_tmpfile, "wb") as fobj:
8640 + proc = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=fobj)
8641 + excluded_config_files = dblnk.quickpkg(
8642 + proc.stdin,
8643 + include_config=include_config,
8644 + include_unmodified_config=include_unmodified_config,
8645 + )
8646 + proc.stdin.close()
8647 + if proc.wait() != os.EX_OK:
8648 + eout.eend(1)
8649 + eout.eerror("Compressor failed for package %s" % cpv)
8650 + retval |= 1
8651 + try:
8652 + os.unlink(binpkg_tmpfile)
8653 + except OSError as e:
8654 + if e.errno not in (errno.ENOENT, errno.ESTALE):
8655 + raise
8656 + continue
8657 + xpak.tbz2(binpkg_tmpfile).recompose_mem(xpdata)
8658 + elif binpkg_format == "gpkg":
8659 + metadata = gpkg.gpkg(settings)._generate_metadata_from_dir(dblnk.dbdir)
8660 + binpkg_tmpfile = os.path.join(
8661 + bintree.pkgdir, cpv + ".gpkg.tar." + str(os.getpid())
8662 + )
8663 + ensure_dirs(os.path.dirname(binpkg_tmpfile))
8664 + excluded_config_files = dblnk.quickpkg(
8665 + binpkg_tmpfile,
8666 + metadata,
8667 + include_config=include_config,
8668 + include_unmodified_config=include_unmodified_config,
8669 + )
8670 + else:
8671 + raise InvalidBinaryPackageFormat(binpkg_format)
8672 + finally:
8673 + if have_lock:
8674 + dblnk.unlockdb()
8675 + pkg_info = bintree.inject(cpv, filename=binpkg_tmpfile)
8676 + # The pkg_info value ensures that the following getname call
8677 + # returns the correct path when FEATURES=binpkg-multi-instance
8678 + # is enabled, but fallback to cpv in case the inject call
8679 + # returned None due to some kind of failure.
8680 + binpkg_path = bintree.getname(pkg_info or cpv)
8681 + try:
8682 + s = os.stat(binpkg_path)
8683 + except OSError:
8684 + s = None
8685 +
8686 + if s is None or pkg_info is None:
8687 + # Sanity check, shouldn't happen normally.
8688 + eout.eend(1)
8689 + eout.eerror("Failed to create package: '%s'" % binpkg_path)
8690 + retval |= 1
8691 + else:
8692 + eout.eend(0)
8693 + infos["successes"].append((cpv, s.st_size))
8694 + infos["config_files_excluded"] += len(excluded_config_files)
8695 + for filename in excluded_config_files:
8696 + eout.ewarn("Excluded config: '%s'" % filename)
8697 + if not pkgs_for_arg:
8698 + eout.eerror("Could not find anything " + "to match '%s'; skipping" % arg)
8699 + infos["missing"].append(arg)
8700 + retval |= 1
8701 + return retval
8702 +
8703
8704 def quickpkg_set(options, infos, arg, eout):
8705 - eroot = portage.settings['EROOT']
8706 - trees = portage.db[eroot]
8707 - vartree = trees["vartree"]
8708 -
8709 - settings = vartree.settings
8710 - settings._init_dirs()
8711 - setconfig = load_default_config(settings, trees)
8712 - sets = setconfig.getSets()
8713 -
8714 - set_name = arg[1:]
8715 - if not set_name in sets:
8716 - eout.eerror("Package set not found: '%s'; skipping" % (arg,))
8717 - infos["missing"].append(arg)
8718 - return 1
8719 -
8720 - try:
8721 - atoms = setconfig.getSetAtoms(set_name)
8722 - except PackageSetNotFound as e:
8723 - eout.eerror("Failed to process package set '%s' because " % set_name +
8724 - "it contains the non-existent package set '%s'; skipping" % e)
8725 - infos["missing"].append(arg)
8726 - return 1
8727 - retval = os.EX_OK
8728 - for atom in atoms:
8729 - retval |= quickpkg_atom(options, infos, atom, eout)
8730 - return retval
8731 + eroot = portage.settings["EROOT"]
8732 + trees = portage.db[eroot]
8733 + vartree = trees["vartree"]
8734 +
8735 + settings = vartree.settings
8736 + settings._init_dirs()
8737 + setconfig = load_default_config(settings, trees)
8738 + sets = setconfig.getSets()
8739 +
8740 + set_name = arg[1:]
8741 + if not set_name in sets:
8742 + eout.eerror("Package set not found: '%s'; skipping" % (arg,))
8743 + infos["missing"].append(arg)
8744 + return 1
8745 +
8746 + try:
8747 + atoms = setconfig.getSetAtoms(set_name)
8748 + except PackageSetNotFound as e:
8749 + eout.eerror(
8750 + "Failed to process package set '%s' because " % set_name
8751 + + "it contains the non-existent package set '%s'; skipping" % e
8752 + )
8753 + infos["missing"].append(arg)
8754 + return 1
8755 + retval = os.EX_OK
8756 + for atom in atoms:
8757 + retval |= quickpkg_atom(options, infos, atom, eout)
8758 + return retval
8759
8760
8761 def quickpkg_extended_atom(options, infos, atom, eout):
8762 - eroot = portage.settings['EROOT']
8763 - trees = portage.db[eroot]
8764 - vartree = trees["vartree"]
8765 - vardb = vartree.dbapi
8766 + eroot = portage.settings["EROOT"]
8767 + trees = portage.db[eroot]
8768 + vartree = trees["vartree"]
8769 + vardb = vartree.dbapi
8770
8771 - require_metadata = atom.slot or atom.repo
8772 - atoms = []
8773 - for cpv in vardb.cpv_all():
8774 - cpv_atom = Atom("=%s" % cpv)
8775 + require_metadata = atom.slot or atom.repo
8776 + atoms = []
8777 + for cpv in vardb.cpv_all():
8778 + cpv_atom = Atom("=%s" % cpv)
8779
8780 - if atom == "*/*":
8781 - atoms.append(cpv_atom)
8782 - continue
8783 + if atom == "*/*":
8784 + atoms.append(cpv_atom)
8785 + continue
8786
8787 - if not portage.match_from_list(atom, [cpv]):
8788 - continue
8789 + if not portage.match_from_list(atom, [cpv]):
8790 + continue
8791
8792 - if require_metadata:
8793 - try:
8794 - cpv = vardb._pkg_str(cpv, atom.repo)
8795 - except (KeyError, InvalidData):
8796 - continue
8797 - if not portage.match_from_list(atom, [cpv]):
8798 - continue
8799 + if require_metadata:
8800 + try:
8801 + cpv = vardb._pkg_str(cpv, atom.repo)
8802 + except (KeyError, InvalidData):
8803 + continue
8804 + if not portage.match_from_list(atom, [cpv]):
8805 + continue
8806
8807 - atoms.append(cpv_atom)
8808 + atoms.append(cpv_atom)
8809
8810 - for atom in atoms:
8811 - quickpkg_atom(options, infos, atom, eout)
8812 + for atom in atoms:
8813 + quickpkg_atom(options, infos, atom, eout)
8814
8815
8816 def quickpkg_main(options, args, eout):
8817 - eroot = portage.settings['EROOT']
8818 - trees = portage.db[eroot]
8819 - bintree = trees["bintree"]
8820 -
8821 - try:
8822 - ensure_dirs(bintree.pkgdir)
8823 - except portage.exception.PortageException:
8824 - pass
8825 - if not os.access(bintree.pkgdir, os.W_OK):
8826 - eout.eerror("No write access to '%s'" % bintree.pkgdir)
8827 - return errno.EACCES
8828 -
8829 - if 'xattr' in portage.settings.features and not _xattr.XATTRS_WORKS:
8830 - eout.eerror("No xattr support library was found, "
8831 - "so xattrs will not be preserved!")
8832 - portage.settings.unlock()
8833 - portage.settings.features.remove('xattr')
8834 - portage.settings.lock()
8835 -
8836 - if portage.settings.get("BINPKG_GPG_SIGNING_KEY", None):
8837 - gpg = GPG(portage.settings)
8838 - gpg.unlock()
8839 -
8840 - infos = {}
8841 - infos["successes"] = []
8842 - infos["missing"] = []
8843 - infos["config_files_excluded"] = 0
8844 - for arg in args:
8845 - if arg[0] == SETPREFIX:
8846 - quickpkg_set(options, infos, arg, eout)
8847 - continue
8848 - try:
8849 - atom = Atom(arg, allow_wildcard=True, allow_repo=True)
8850 - except (InvalidAtom, InvalidData):
8851 - # maybe it's valid but missing category (requires dep_expand)
8852 - quickpkg_atom(options, infos, arg, eout)
8853 - else:
8854 - if atom.extended_syntax:
8855 - quickpkg_extended_atom(options, infos, atom, eout)
8856 - else:
8857 - quickpkg_atom(options, infos, atom, eout)
8858 -
8859 - if not infos["successes"]:
8860 - eout.eerror("No packages found")
8861 - return 1
8862 - print()
8863 - eout.einfo("Packages now in '%s':" % bintree.pkgdir)
8864 - units = {10:'K', 20:'M', 30:'G', 40:'T',
8865 - 50:'P', 60:'E', 70:'Z', 80:'Y'}
8866 - for cpv, size in infos["successes"]:
8867 - if not size:
8868 - # avoid OverflowError in math.log()
8869 - size_str = "0"
8870 - else:
8871 - power_of_2 = math.log(size, 2)
8872 - power_of_2 = 10*(power_of_2//10)
8873 - unit = units.get(power_of_2)
8874 - if unit:
8875 - size = float(size)/(2**power_of_2)
8876 - size_str = "%.1f" % size
8877 - if len(size_str) > 4:
8878 - # emulate `du -h`, don't show too many sig figs
8879 - size_str = str(int(size))
8880 - size_str += unit
8881 - else:
8882 - size_str = str(size)
8883 - eout.einfo("%s: %s" % (cpv, size_str))
8884 - if infos["config_files_excluded"]:
8885 - print()
8886 - eout.ewarn("Excluded config files: %d" % infos["config_files_excluded"])
8887 - eout.ewarn("See --help if you would like to include config files.")
8888 - if infos["missing"]:
8889 - print()
8890 - eout.ewarn("The following packages could not be found:")
8891 - eout.ewarn(" ".join(infos["missing"]))
8892 - return 2
8893 - return os.EX_OK
8894 + eroot = portage.settings["EROOT"]
8895 + trees = portage.db[eroot]
8896 + bintree = trees["bintree"]
8897 +
8898 + try:
8899 + ensure_dirs(bintree.pkgdir)
8900 + except portage.exception.PortageException:
8901 + pass
8902 + if not os.access(bintree.pkgdir, os.W_OK):
8903 + eout.eerror("No write access to '%s'" % bintree.pkgdir)
8904 + return errno.EACCES
8905 +
8906 + if "xattr" in portage.settings.features and not _xattr.XATTRS_WORKS:
8907 + eout.eerror(
8908 + "No xattr support library was found, " "so xattrs will not be preserved!"
8909 + )
8910 + portage.settings.unlock()
8911 + portage.settings.features.remove("xattr")
8912 + portage.settings.lock()
8913 +
8914 + if portage.settings.get("BINPKG_GPG_SIGNING_KEY", None):
8915 + gpg = GPG(portage.settings)
8916 + gpg.unlock()
8917 +
8918 + infos = {}
8919 + infos["successes"] = []
8920 + infos["missing"] = []
8921 + infos["config_files_excluded"] = 0
8922 + for arg in args:
8923 + if arg[0] == SETPREFIX:
8924 + quickpkg_set(options, infos, arg, eout)
8925 + continue
8926 + try:
8927 + atom = Atom(arg, allow_wildcard=True, allow_repo=True)
8928 + except (InvalidAtom, InvalidData):
8929 + # maybe it's valid but missing category (requires dep_expand)
8930 + quickpkg_atom(options, infos, arg, eout)
8931 + else:
8932 + if atom.extended_syntax:
8933 + quickpkg_extended_atom(options, infos, atom, eout)
8934 + else:
8935 + quickpkg_atom(options, infos, atom, eout)
8936 +
8937 + if not infos["successes"]:
8938 + eout.eerror("No packages found")
8939 + return 1
8940 + print()
8941 + eout.einfo("Packages now in '%s':" % bintree.pkgdir)
8942 + units = {10: "K", 20: "M", 30: "G", 40: "T", 50: "P", 60: "E", 70: "Z", 80: "Y"}
8943 + for cpv, size in infos["successes"]:
8944 + if not size:
8945 + # avoid OverflowError in math.log()
8946 + size_str = "0"
8947 + else:
8948 + power_of_2 = math.log(size, 2)
8949 + power_of_2 = 10 * (power_of_2 // 10)
8950 + unit = units.get(power_of_2)
8951 + if unit:
8952 + size = float(size) / (2**power_of_2)
8953 + size_str = "%.1f" % size
8954 + if len(size_str) > 4:
8955 + # emulate `du -h`, don't show too many sig figs
8956 + size_str = str(int(size))
8957 + size_str += unit
8958 + else:
8959 + size_str = str(size)
8960 + eout.einfo("%s: %s" % (cpv, size_str))
8961 + if infos["config_files_excluded"]:
8962 + print()
8963 + eout.ewarn("Excluded config files: %d" % infos["config_files_excluded"])
8964 + eout.ewarn("See --help if you would like to include config files.")
8965 + if infos["missing"]:
8966 + print()
8967 + eout.ewarn("The following packages could not be found:")
8968 + eout.ewarn(" ".join(infos["missing"]))
8969 + return 2
8970 + return os.EX_OK
8971 +
8972
8973 if __name__ == "__main__":
8974 - usage = "quickpkg [options] <list of package atoms or package sets>"
8975 - parser = argparse.ArgumentParser(usage=usage)
8976 - parser.add_argument("--umask",
8977 - default="0077",
8978 - help="umask used during package creation (default is 0077)")
8979 - parser.add_argument("--ignore-default-opts",
8980 - action="store_true",
8981 - help="do not use the QUICKPKG_DEFAULT_OPTS environment variable")
8982 - parser.add_argument("--include-config",
8983 - choices=["y","n"],
8984 - default="n",
8985 - metavar="<y|n>",
8986 - help="include all files protected by CONFIG_PROTECT (as a security precaution, default is 'n')")
8987 - parser.add_argument("--include-unmodified-config",
8988 - choices=["y","n"],
8989 - default="n",
8990 - metavar="<y|n>",
8991 - help="include files protected by CONFIG_PROTECT that have not been modified since installation (as a security precaution, default is 'n')")
8992 - options, args = parser.parse_known_args(sys.argv[1:])
8993 - if not options.ignore_default_opts:
8994 - default_opts = shlex_split(
8995 - portage.settings.get("QUICKPKG_DEFAULT_OPTS", ""))
8996 - options, args = parser.parse_known_args(default_opts + sys.argv[1:])
8997 - if not args:
8998 - parser.error("no packages atoms given")
8999 - try:
9000 - umask = int(options.umask, 8)
9001 - except ValueError:
9002 - parser.error("invalid umask: %s" % options.umask)
9003 - # We need to ensure a sane umask for the packages that will be created.
9004 - old_umask = os.umask(umask)
9005 - eout = portage.output.EOutput()
9006 - def sigwinch_handler(signum, frame):
9007 - lines, eout.term_columns = portage.output.get_term_size()
9008 - signal.signal(signal.SIGWINCH, sigwinch_handler)
9009 - try:
9010 - retval = quickpkg_main(options, args, eout)
9011 - finally:
9012 - os.umask(old_umask)
9013 - signal.signal(signal.SIGWINCH, signal.SIG_DFL)
9014 - global_event_loop().close()
9015 - sys.exit(retval)
9016 + usage = "quickpkg [options] <list of package atoms or package sets>"
9017 + parser = argparse.ArgumentParser(usage=usage)
9018 + parser.add_argument(
9019 + "--umask",
9020 + default="0077",
9021 + help="umask used during package creation (default is 0077)",
9022 + )
9023 + parser.add_argument(
9024 + "--ignore-default-opts",
9025 + action="store_true",
9026 + help="do not use the QUICKPKG_DEFAULT_OPTS environment variable",
9027 + )
9028 + parser.add_argument(
9029 + "--include-config",
9030 + choices=["y", "n"],
9031 + default="n",
9032 + metavar="<y|n>",
9033 + help="include all files protected by CONFIG_PROTECT (as a security precaution, default is 'n')",
9034 + )
9035 + parser.add_argument(
9036 + "--include-unmodified-config",
9037 + choices=["y", "n"],
9038 + default="n",
9039 + metavar="<y|n>",
9040 + help="include files protected by CONFIG_PROTECT that have not been modified since installation (as a security precaution, default is 'n')",
9041 + )
9042 + options, args = parser.parse_known_args(sys.argv[1:])
9043 + if not options.ignore_default_opts:
9044 + default_opts = shlex_split(portage.settings.get("QUICKPKG_DEFAULT_OPTS", ""))
9045 + options, args = parser.parse_known_args(default_opts + sys.argv[1:])
9046 + if not args:
9047 + parser.error("no packages atoms given")
9048 + try:
9049 + umask = int(options.umask, 8)
9050 + except ValueError:
9051 + parser.error("invalid umask: %s" % options.umask)
9052 + # We need to ensure a sane umask for the packages that will be created.
9053 + old_umask = os.umask(umask)
9054 + eout = portage.output.EOutput()
9055 +
9056 + def sigwinch_handler(signum, frame):
9057 + lines, eout.term_columns = portage.output.get_term_size()
9058 +
9059 + signal.signal(signal.SIGWINCH, sigwinch_handler)
9060 + try:
9061 + retval = quickpkg_main(options, args, eout)
9062 + finally:
9063 + os.umask(old_umask)
9064 + signal.signal(signal.SIGWINCH, signal.SIG_DFL)
9065 + global_event_loop().close()
9066 + sys.exit(retval)
9067
9068 diff --git a/bin/regenworld b/bin/regenworld
9069 index e3577a103..fd11ed14a 100755
9070 --- a/bin/regenworld
9071 +++ b/bin/regenworld
9072 @@ -4,9 +4,15 @@
9073
9074 import sys
9075 from os import path as osp
9076 -if osp.isfile(osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), ".portage_not_installed")):
9077 - sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "lib"))
9078 +
9079 +if osp.isfile(
9080 + osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), ".portage_not_installed")
9081 +):
9082 + sys.path.insert(
9083 + 0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "lib")
9084 + )
9085 import portage
9086 +
9087 portage._internal_caller = True
9088 from portage import os
9089 from portage._sets.files import StaticFileSet, WorldSelectedPackagesSet
9090 @@ -16,129 +22,138 @@ import tempfile
9091 import textwrap
9092
9093 __candidatematcher__ = re.compile("^[0-9]+: \\*\\*\\* emerge ")
9094 -__noncandidatematcher__ = re.compile(" sync( |$)| clean( |$)| search( |$)|--oneshot|--fetchonly| unmerge( |$)")
9095 +__noncandidatematcher__ = re.compile(
9096 + " sync( |$)| clean( |$)| search( |$)|--oneshot|--fetchonly| unmerge( |$)"
9097 +)
9098 +
9099
9100 def issyspkg(pkgline):
9101 - return pkgline[0] == "*"
9102 + return pkgline[0] == "*"
9103 +
9104
9105 def iscandidate(logline):
9106 - return (__candidatematcher__.match(logline)
9107 - and not __noncandidatematcher__.search(logline))
9108 + return __candidatematcher__.match(logline) and not __noncandidatematcher__.search(
9109 + logline
9110 + )
9111 +
9112
9113 def getpkginfo(logline):
9114 - logline = re.sub("^[0-9]+: \\*\\*\\* emerge ", "", logline)
9115 - logline = logline.strip()
9116 - logline = re.sub("(\\S+\\.(ebuild|tbz2))|(--\\S+)|inject ", "", logline)
9117 - return logline.strip()
9118 + logline = re.sub("^[0-9]+: \\*\\*\\* emerge ", "", logline)
9119 + logline = logline.strip()
9120 + logline = re.sub("(\\S+\\.(ebuild|tbz2))|(--\\S+)|inject ", "", logline)
9121 + return logline.strip()
9122 +
9123
9124 __uniqlist__ = []
9125 +
9126 +
9127 def isunwanted(pkgline):
9128 - if pkgline in ["world", "system", "depclean", "info", "regen", ""]:
9129 - return False
9130 - elif pkgline in __uniqlist__:
9131 - return False
9132 - elif not re.search("^[a-zA-Z<>=~]", pkgline):
9133 - return False
9134 - else:
9135 - __uniqlist__.append(pkgline)
9136 - return True
9137 -
9138 -eroot = portage.settings['EROOT']
9139 + if pkgline in ["world", "system", "depclean", "info", "regen", ""]:
9140 + return False
9141 + elif pkgline in __uniqlist__:
9142 + return False
9143 + elif not re.search("^[a-zA-Z<>=~]", pkgline):
9144 + return False
9145 + else:
9146 + __uniqlist__.append(pkgline)
9147 + return True
9148 +
9149 +
9150 +eroot = portage.settings["EROOT"]
9151 world_file = os.path.join(eroot, portage.WORLD_FILE)
9152
9153 # show a little description if we have arguments
9154 if len(sys.argv) >= 2 and sys.argv[1] in ["-h", "--help"]:
9155 - print("This script regenerates the portage world file by checking the portage")
9156 - print("logfile for all actions that you've done in the past. It ignores any")
9157 - print("arguments except --help. It is recommended that you make a backup of")
9158 - print("your existing world file (%s) before using this tool." % world_file)
9159 - sys.exit(0)
9160 + print("This script regenerates the portage world file by checking the portage")
9161 + print("logfile for all actions that you've done in the past. It ignores any")
9162 + print("arguments except --help. It is recommended that you make a backup of")
9163 + print("your existing world file (%s) before using this tool." % world_file)
9164 + sys.exit(0)
9165
9166 worldlist = portage.grabfile(world_file)
9167 syslist = [x for x in portage.settings.packages if issyspkg(x)]
9168
9169 if portage.settings.get("EMERGE_LOG_DIR"):
9170 - logfile = portage.grabfile(
9171 - os.path.join(portage.settings["EMERGE_LOG_DIR"], "emerge.log")
9172 - )
9173 + logfile = portage.grabfile(
9174 + os.path.join(portage.settings["EMERGE_LOG_DIR"], "emerge.log")
9175 + )
9176 else:
9177 - logfile = portage.grabfile(os.path.join(eroot, "var/log/emerge.log"))
9178 + logfile = portage.grabfile(os.path.join(eroot, "var/log/emerge.log"))
9179 biglist = [getpkginfo(x) for x in logfile if iscandidate(x)]
9180 tmplist = []
9181 for l in biglist:
9182 - tmplist += l.split()
9183 + tmplist += l.split()
9184 biglist = [x for x in tmplist if isunwanted(x)]
9185 -#for p in biglist:
9186 -# print(p)
9187 -#sys.exit(0)
9188 +# for p in biglist:
9189 +# print(p)
9190 +# sys.exit(0)
9191
9192 # resolving virtuals
9193 realsyslist = []
9194 for mykey in syslist:
9195 - # drop the asterix
9196 - mykey = mykey[1:]
9197 - #print("candidate:",mykey)
9198 - mylist = portage.db[eroot]["vartree"].dbapi.match(mykey)
9199 - if mylist:
9200 - mykey=portage.cpv_getkey(mylist[0])
9201 - if mykey not in realsyslist:
9202 - realsyslist.append(mykey)
9203 + # drop the asterix
9204 + mykey = mykey[1:]
9205 + # print("candidate:",mykey)
9206 + mylist = portage.db[eroot]["vartree"].dbapi.match(mykey)
9207 + if mylist:
9208 + mykey = portage.cpv_getkey(mylist[0])
9209 + if mykey not in realsyslist:
9210 + realsyslist.append(mykey)
9211
9212 for mykey in biglist:
9213 - #print("checking:",mykey)
9214 - try:
9215 - mylist = portage.db[eroot]["vartree"].dbapi.match(mykey)
9216 - except (portage.exception.InvalidAtom, KeyError):
9217 - if "--debug" in sys.argv:
9218 - print("* ignoring broken log entry for %s (likely injected)" % mykey)
9219 - except ValueError as e:
9220 - try:
9221 - print("* %s is an ambiguous package name, candidates are:\n%s" % (mykey, e))
9222 - except AttributeError:
9223 - # FIXME: Find out what causes this (bug #344845).
9224 - print("* %s is an ambiguous package name" % (mykey,))
9225 - continue
9226 - if mylist:
9227 - #print "mylist:",mylist
9228 - myfavkey=portage.cpv_getkey(mylist[0])
9229 - if (myfavkey not in realsyslist) and (myfavkey not in worldlist):
9230 - print("add to world:",myfavkey)
9231 - worldlist.append(myfavkey)
9232 + # print("checking:",mykey)
9233 + try:
9234 + mylist = portage.db[eroot]["vartree"].dbapi.match(mykey)
9235 + except (portage.exception.InvalidAtom, KeyError):
9236 + if "--debug" in sys.argv:
9237 + print("* ignoring broken log entry for %s (likely injected)" % mykey)
9238 + except ValueError as e:
9239 + try:
9240 + print("* %s is an ambiguous package name, candidates are:\n%s" % (mykey, e))
9241 + except AttributeError:
9242 + # FIXME: Find out what causes this (bug #344845).
9243 + print("* %s is an ambiguous package name" % (mykey,))
9244 + continue
9245 + if mylist:
9246 + # print "mylist:",mylist
9247 + myfavkey = portage.cpv_getkey(mylist[0])
9248 + if (myfavkey not in realsyslist) and (myfavkey not in worldlist):
9249 + print("add to world:", myfavkey)
9250 + worldlist.append(myfavkey)
9251
9252 if not worldlist:
9253 - pass
9254 + pass
9255 else:
9256 - existing_set = WorldSelectedPackagesSet(eroot)
9257 - existing_set.load()
9258 -
9259 - if not existing_set:
9260 - existing_set.replace(worldlist)
9261 - else:
9262 - old_world = existing_set._filename
9263 - fd, tmp_filename = tempfile.mkstemp(suffix=".tmp",
9264 - prefix=os.path.basename(old_world) + ".",
9265 - dir=os.path.dirname(old_world))
9266 - os.close(fd)
9267 -
9268 - new_set = StaticFileSet(tmp_filename)
9269 - new_set.update(worldlist)
9270 -
9271 - if existing_set.getAtoms() == new_set.getAtoms():
9272 - os.unlink(tmp_filename)
9273 - else:
9274 - new_set.write()
9275 -
9276 - msg = "Please review differences between old and new files, " + \
9277 - "and replace the old file if desired."
9278 -
9279 - portage.util.writemsg_stdout("\n",
9280 - noiselevel=-1)
9281 - for line in textwrap.wrap(msg, 65):
9282 - portage.util.writemsg_stdout("%s\n" % line,
9283 - noiselevel=-1)
9284 - portage.util.writemsg_stdout("\n",
9285 - noiselevel=-1)
9286 - portage.util.writemsg_stdout(" old: %s\n\n" % old_world,
9287 - noiselevel=-1)
9288 - portage.util.writemsg_stdout(" new: %s\n\n" % tmp_filename,
9289 - noiselevel=-1)
9290 + existing_set = WorldSelectedPackagesSet(eroot)
9291 + existing_set.load()
9292 +
9293 + if not existing_set:
9294 + existing_set.replace(worldlist)
9295 + else:
9296 + old_world = existing_set._filename
9297 + fd, tmp_filename = tempfile.mkstemp(
9298 + suffix=".tmp",
9299 + prefix=os.path.basename(old_world) + ".",
9300 + dir=os.path.dirname(old_world),
9301 + )
9302 + os.close(fd)
9303 +
9304 + new_set = StaticFileSet(tmp_filename)
9305 + new_set.update(worldlist)
9306 +
9307 + if existing_set.getAtoms() == new_set.getAtoms():
9308 + os.unlink(tmp_filename)
9309 + else:
9310 + new_set.write()
9311 +
9312 + msg = (
9313 + "Please review differences between old and new files, "
9314 + + "and replace the old file if desired."
9315 + )
9316 +
9317 + portage.util.writemsg_stdout("\n", noiselevel=-1)
9318 + for line in textwrap.wrap(msg, 65):
9319 + portage.util.writemsg_stdout("%s\n" % line, noiselevel=-1)
9320 + portage.util.writemsg_stdout("\n", noiselevel=-1)
9321 + portage.util.writemsg_stdout(" old: %s\n\n" % old_world, noiselevel=-1)
9322 + portage.util.writemsg_stdout(" new: %s\n\n" % tmp_filename, noiselevel=-1)
9323
9324 diff --git a/bin/shelve-utils b/bin/shelve-utils
9325 index 6cfa36a81..3c513bd17 100755
9326 --- a/bin/shelve-utils
9327 +++ b/bin/shelve-utils
9328 @@ -6,31 +6,37 @@ import argparse
9329 import sys
9330
9331 from os import path as osp
9332 -if osp.isfile(osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), ".portage_not_installed")):
9333 - sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "lib"))
9334 +
9335 +if osp.isfile(
9336 + osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), ".portage_not_installed")
9337 +):
9338 + sys.path.insert(
9339 + 0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "lib")
9340 + )
9341 import portage
9342 +
9343 portage._internal_caller = True
9344 from portage.util.shelve import dump, restore
9345
9346
9347 def main(argv=None):
9348 - parser = argparse.ArgumentParser(prog="shelve-utils")
9349 - subparsers = parser.add_subparsers(help="sub-command help")
9350 + parser = argparse.ArgumentParser(prog="shelve-utils")
9351 + subparsers = parser.add_subparsers(help="sub-command help")
9352
9353 - dump_command = subparsers.add_parser("dump", help="dump shelve database")
9354 - dump_command.add_argument("src", help="input shelve file")
9355 - dump_command.add_argument("dest", help="output pickle file")
9356 - dump_command.set_defaults(func=dump)
9357 + dump_command = subparsers.add_parser("dump", help="dump shelve database")
9358 + dump_command.add_argument("src", help="input shelve file")
9359 + dump_command.add_argument("dest", help="output pickle file")
9360 + dump_command.set_defaults(func=dump)
9361
9362 - restore_command = subparsers.add_parser("restore", help="restore shelve database")
9363 - restore_command.add_argument("src", help="input pickle file")
9364 - restore_command.add_argument("dest", help="output shelve file")
9365 - restore_command.set_defaults(func=restore)
9366 + restore_command = subparsers.add_parser("restore", help="restore shelve database")
9367 + restore_command.add_argument("src", help="input pickle file")
9368 + restore_command.add_argument("dest", help="output shelve file")
9369 + restore_command.set_defaults(func=restore)
9370
9371 - args = parser.parse_args(args=portage._decode_argv(argv or sys.argv)[1:])
9372 - args.func(args)
9373 + args = parser.parse_args(args=portage._decode_argv(argv or sys.argv)[1:])
9374 + args.func(args)
9375
9376
9377 if __name__ == "__main__":
9378 - portage.util.initialize_logger()
9379 - main(argv=sys.argv)
9380 + portage.util.initialize_logger()
9381 + main(argv=sys.argv)
9382
9383 diff --git a/repoman/bin/repoman b/repoman/bin/repoman
9384 index 427cb3162..beaf8147a 100755
9385 --- a/repoman/bin/repoman
9386 +++ b/repoman/bin/repoman
9387 @@ -25,17 +25,21 @@ except KeyboardInterrupt:
9388 sys.exit(1)
9389
9390 from os import path as osp
9391 +
9392 here = osp.realpath(__file__)
9393 if osp.isfile(osp.join(osp.dirname(osp.dirname(here)), ".repoman_not_installed")):
9394 # Add the repoman subpkg
9395 pym_path = osp.join(osp.dirname(osp.dirname(here)), "lib")
9396 sys.path.insert(0, pym_path)
9397 - if osp.isfile(osp.join(osp.dirname(osp.dirname(osp.dirname(here))), ".portage_not_installed")):
9398 + if osp.isfile(
9399 + osp.join(osp.dirname(osp.dirname(osp.dirname(here))), ".portage_not_installed")
9400 + ):
9401 # Add the base portage pkg
9402 pym_path = osp.join(osp.dirname(osp.dirname(osp.dirname(here))), "lib")
9403 sys.path.insert(0, pym_path)
9404
9405 import portage
9406 +
9407 portage._internal_caller = True
9408 from portage.util._eventloop.global_event_loop import global_event_loop
9409 from repoman.main import repoman_main
9410
9411 diff --git a/repoman/runtests b/repoman/runtests
9412 index 5b1306e59..f02bfe875 100755
9413 --- a/repoman/runtests
9414 +++ b/repoman/runtests
9415 @@ -20,62 +20,53 @@ import tempfile
9416
9417
9418 # These are the versions we fully support and require to pass tests.
9419 -PYTHON_SUPPORTED_VERSIONS = [
9420 - '2.7',
9421 - '3.6',
9422 - '3.7',
9423 - '3.8',
9424 - '3.9'
9425 -]
9426 +PYTHON_SUPPORTED_VERSIONS = ["2.7", "3.6", "3.7", "3.8", "3.9"]
9427 # The rest are just "nice to have".
9428 -PYTHON_NICE_VERSIONS = [
9429 - 'pypy3',
9430 - '3.10'
9431 -]
9432 +PYTHON_NICE_VERSIONS = ["pypy3", "3.10"]
9433
9434 -EPREFIX = os.environ.get('PORTAGE_OVERRIDE_EPREFIX', '/')
9435 +EPREFIX = os.environ.get("PORTAGE_OVERRIDE_EPREFIX", "/")
9436
9437
9438 class Colors(object):
9439 """Simple object holding color constants."""
9440
9441 - _COLORS_YES = ('y', 'yes', 'true')
9442 - _COLORS_NO = ('n', 'no', 'false')
9443 + _COLORS_YES = ("y", "yes", "true")
9444 + _COLORS_NO = ("n", "no", "false")
9445
9446 - WARN = GOOD = BAD = NORMAL = ''
9447 + WARN = GOOD = BAD = NORMAL = ""
9448
9449 def __init__(self, colorize=None):
9450 if colorize is None:
9451 - nocolors = os.environ.get('NOCOLOR', 'false')
9452 + nocolors = os.environ.get("NOCOLOR", "false")
9453 # Ugh, look away, for here we invert the world!
9454 if nocolors in self._COLORS_YES:
9455 colorize = False
9456 elif nocolors in self._COLORS_NO:
9457 colorize = True
9458 else:
9459 - raise ValueError('$NOCOLORS is invalid: %s' % nocolors)
9460 + raise ValueError("$NOCOLORS is invalid: %s" % nocolors)
9461 else:
9462 if colorize in self._COLORS_YES:
9463 colorize = True
9464 elif colorize in self._COLORS_NO:
9465 colorize = False
9466 else:
9467 - raise ValueError('--colors is invalid: %s' % colorize)
9468 + raise ValueError("--colors is invalid: %s" % colorize)
9469
9470 if colorize:
9471 - self.WARN = '\033[1;33m'
9472 - self.GOOD = '\033[1;32m'
9473 - self.BAD = '\033[1;31m'
9474 - self.NORMAL = '\033[0m'
9475 + self.WARN = "\033[1;33m"
9476 + self.GOOD = "\033[1;32m"
9477 + self.BAD = "\033[1;31m"
9478 + self.NORMAL = "\033[0m"
9479
9480
9481 def get_python_executable(ver):
9482 """Find the right python executable for |ver|"""
9483 - if ver in ('pypy', 'pypy3'):
9484 + if ver in ("pypy", "pypy3"):
9485 prog = ver
9486 else:
9487 - prog = 'python' + ver
9488 - return os.path.join(EPREFIX, 'usr', 'bin', prog)
9489 + prog = "python" + ver
9490 + return os.path.join(EPREFIX, "usr", "bin", prog)
9491
9492
9493 def get_parser():
9494 @@ -93,13 +84,25 @@ $ %(prog)s lib/portage/tests/xpak/test_decodeint.py
9495 parser = argparse.ArgumentParser(
9496 description=__doc__,
9497 formatter_class=argparse.RawDescriptionHelpFormatter,
9498 - epilog=epilog)
9499 - parser.add_argument('--keep-temp', default=False, action='store_true',
9500 - help='Do not delete the temporary directory when exiting')
9501 - parser.add_argument('--color', type=str, default=None,
9502 - help='Whether to use colorized output (default is auto)')
9503 - parser.add_argument('--python-versions', action='append',
9504 - help='Versions of python to test (default is test available)')
9505 + epilog=epilog,
9506 + )
9507 + parser.add_argument(
9508 + "--keep-temp",
9509 + default=False,
9510 + action="store_true",
9511 + help="Do not delete the temporary directory when exiting",
9512 + )
9513 + parser.add_argument(
9514 + "--color",
9515 + type=str,
9516 + default=None,
9517 + help="Whether to use colorized output (default is auto)",
9518 + )
9519 + parser.add_argument(
9520 + "--python-versions",
9521 + action="append",
9522 + help="Versions of python to test (default is test available)",
9523 + )
9524 return parser
9525
9526
9527 @@ -116,67 +119,71 @@ def main(argv):
9528 ignore_missing = False
9529 pyversions = []
9530 for ver in opts.python_versions:
9531 - if ver == 'supported':
9532 + if ver == "supported":
9533 pyversions.extend(PYTHON_SUPPORTED_VERSIONS)
9534 else:
9535 pyversions.extend(ver.split())
9536
9537 here = os.path.dirname(__file__)
9538 - run_path = os.path.join(here, 'lib/repoman/tests/runTests.py')
9539 + run_path = os.path.join(here, "lib/repoman/tests/runTests.py")
9540 tempdir = None
9541 try:
9542 # Set up a single tempdir for all the tests to use.
9543 # This way we know the tests won't leak things on us.
9544 - tempdir = tempfile.mkdtemp(prefix='repoman.runtests.')
9545 - os.environ['TMPDIR'] = tempdir
9546 + tempdir = tempfile.mkdtemp(prefix="repoman.runtests.")
9547 + os.environ["TMPDIR"] = tempdir
9548
9549 # Actually test those versions now.
9550 statuses = []
9551 for ver in pyversions:
9552 prog = get_python_executable(ver)
9553 - cmd = [prog, '-b', '-Wd', run_path] + args
9554 + cmd = [prog, "-b", "-Wd", run_path] + args
9555 if os.access(prog, os.X_OK):
9556 - print('%sTesting with Python %s...%s' %
9557 - (colors.GOOD, ver, colors.NORMAL))
9558 + print(
9559 + "%sTesting with Python %s...%s" % (colors.GOOD, ver, colors.NORMAL)
9560 + )
9561 statuses.append((ver, subprocess.call(cmd)))
9562 elif not ignore_missing:
9563 - print('%sCould not find requested Python %s%s' %
9564 - (colors.BAD, ver, colors.NORMAL))
9565 + print(
9566 + "%sCould not find requested Python %s%s"
9567 + % (colors.BAD, ver, colors.NORMAL)
9568 + )
9569 statuses.append((ver, 1))
9570 else:
9571 - print('%sSkip Python %s...%s' %
9572 - (colors.WARN, ver, colors.NORMAL))
9573 + print("%sSkip Python %s...%s" % (colors.WARN, ver, colors.NORMAL))
9574 print()
9575 finally:
9576 if tempdir is not None:
9577 if opts.keep_temp:
9578 - print('Temporary directory left behind:\n%s' % tempdir)
9579 + print("Temporary directory left behind:\n%s" % tempdir)
9580 else:
9581 # Nuke our tempdir and anything that might be under it.
9582 shutil.rmtree(tempdir, True)
9583
9584 # Then summarize it all.
9585 - print('\nSummary:\n')
9586 + print("\nSummary:\n")
9587 width = 10
9588 - header = '| %-*s | %s' % (width, 'Version', 'Status')
9589 - print('%s\n|%s' % (header, '-' * (len(header) - 1)))
9590 + header = "| %-*s | %s" % (width, "Version", "Status")
9591 + print("%s\n|%s" % (header, "-" * (len(header) - 1)))
9592 exit_status = 0
9593 for ver, status in statuses:
9594 exit_status += status
9595 if status:
9596 color = colors.BAD
9597 - msg = 'FAIL'
9598 + msg = "FAIL"
9599 else:
9600 color = colors.GOOD
9601 - msg = 'PASS'
9602 - print('| %s%-*s%s | %s%s%s' %
9603 - (color, width, ver, colors.NORMAL, color, msg, colors.NORMAL))
9604 + msg = "PASS"
9605 + print(
9606 + "| %s%-*s%s | %s%s%s"
9607 + % (color, width, ver, colors.NORMAL, color, msg, colors.NORMAL)
9608 + )
9609 exit(exit_status)
9610
9611
9612 -if __name__ == '__main__':
9613 +if __name__ == "__main__":
9614 try:
9615 main(sys.argv[1:])
9616 except KeyboardInterrupt:
9617 - print('interrupted ...', file=sys.stderr)
9618 + print("interrupted ...", file=sys.stderr)
9619 exit(1)
9620
9621 diff --git a/runtests b/runtests
9622 index bc3105026..2a653e3d4 100755
9623 --- a/runtests
9624 +++ b/runtests
9625 @@ -20,61 +20,53 @@ import tempfile
9626
9627
9628 # These are the versions we fully support and require to pass tests.
9629 -PYTHON_SUPPORTED_VERSIONS = [
9630 - '3.6',
9631 - '3.7',
9632 - '3.8',
9633 - '3.9'
9634 -]
9635 +PYTHON_SUPPORTED_VERSIONS = ["3.6", "3.7", "3.8", "3.9"]
9636 # The rest are just "nice to have".
9637 -PYTHON_NICE_VERSIONS = [
9638 - 'pypy3',
9639 - '3.10'
9640 -]
9641 +PYTHON_NICE_VERSIONS = ["pypy3", "3.10"]
9642
9643 -EPREFIX = os.environ.get('PORTAGE_OVERRIDE_EPREFIX', '/')
9644 +EPREFIX = os.environ.get("PORTAGE_OVERRIDE_EPREFIX", "/")
9645
9646
9647 class Colors:
9648 """Simple object holding color constants."""
9649
9650 - _COLORS_YES = ('y', 'yes', 'true')
9651 - _COLORS_NO = ('n', 'no', 'false')
9652 + _COLORS_YES = ("y", "yes", "true")
9653 + _COLORS_NO = ("n", "no", "false")
9654
9655 - WARN = GOOD = BAD = NORMAL = ''
9656 + WARN = GOOD = BAD = NORMAL = ""
9657
9658 def __init__(self, colorize=None):
9659 if colorize is None:
9660 - nocolors = os.environ.get('NOCOLOR', 'false')
9661 + nocolors = os.environ.get("NOCOLOR", "false")
9662 # Ugh, look away, for here we invert the world!
9663 if nocolors in self._COLORS_YES:
9664 colorize = False
9665 elif nocolors in self._COLORS_NO:
9666 colorize = True
9667 else:
9668 - raise ValueError('$NOCOLORS is invalid: %s' % nocolors)
9669 + raise ValueError("$NOCOLORS is invalid: %s" % nocolors)
9670 else:
9671 if colorize in self._COLORS_YES:
9672 colorize = True
9673 elif colorize in self._COLORS_NO:
9674 colorize = False
9675 else:
9676 - raise ValueError('--colors is invalid: %s' % colorize)
9677 + raise ValueError("--colors is invalid: %s" % colorize)
9678
9679 if colorize:
9680 - self.WARN = '\033[1;33m'
9681 - self.GOOD = '\033[1;32m'
9682 - self.BAD = '\033[1;31m'
9683 - self.NORMAL = '\033[0m'
9684 + self.WARN = "\033[1;33m"
9685 + self.GOOD = "\033[1;32m"
9686 + self.BAD = "\033[1;31m"
9687 + self.NORMAL = "\033[0m"
9688
9689
9690 def get_python_executable(ver):
9691 """Find the right python executable for |ver|"""
9692 - if ver in ('pypy', 'pypy3'):
9693 + if ver in ("pypy", "pypy3"):
9694 prog = ver
9695 else:
9696 - prog = 'python' + ver
9697 - return os.path.join(EPREFIX, 'usr', 'bin', prog)
9698 + prog = "python" + ver
9699 + return os.path.join(EPREFIX, "usr", "bin", prog)
9700
9701
9702 def get_parser():
9703 @@ -92,13 +84,25 @@ $ %(prog)s lib/portage/tests/xpak/test_decodeint.py
9704 parser = argparse.ArgumentParser(
9705 description=__doc__,
9706 formatter_class=argparse.RawDescriptionHelpFormatter,
9707 - epilog=epilog)
9708 - parser.add_argument('--keep-temp', default=False, action='store_true',
9709 - help='Do not delete the temporary directory when exiting')
9710 - parser.add_argument('--color', type=str, default=None,
9711 - help='Whether to use colorized output (default is auto)')
9712 - parser.add_argument('--python-versions', action='append',
9713 - help='Versions of python to test (default is test available)')
9714 + epilog=epilog,
9715 + )
9716 + parser.add_argument(
9717 + "--keep-temp",
9718 + default=False,
9719 + action="store_true",
9720 + help="Do not delete the temporary directory when exiting",
9721 + )
9722 + parser.add_argument(
9723 + "--color",
9724 + type=str,
9725 + default=None,
9726 + help="Whether to use colorized output (default is auto)",
9727 + )
9728 + parser.add_argument(
9729 + "--python-versions",
9730 + action="append",
9731 + help="Versions of python to test (default is test available)",
9732 + )
9733 return parser
9734
9735
9736 @@ -115,7 +119,7 @@ def main(argv):
9737 ignore_missing = False
9738 pyversions = []
9739 for ver in opts.python_versions:
9740 - if ver == 'supported':
9741 + if ver == "supported":
9742 pyversions.extend(PYTHON_SUPPORTED_VERSIONS)
9743 else:
9744 pyversions.extend(ver.split())
9745 @@ -124,56 +128,60 @@ def main(argv):
9746 try:
9747 # Set up a single tempdir for all the tests to use.
9748 # This way we know the tests won't leak things on us.
9749 - tempdir = tempfile.mkdtemp(prefix='portage.runtests.')
9750 - os.environ['TMPDIR'] = tempdir
9751 + tempdir = tempfile.mkdtemp(prefix="portage.runtests.")
9752 + os.environ["TMPDIR"] = tempdir
9753
9754 # Actually test those versions now.
9755 statuses = []
9756 for ver in pyversions:
9757 prog = get_python_executable(ver)
9758 - cmd = [prog, '-b', '-Wd', 'lib/portage/tests/runTests.py'] + args
9759 + cmd = [prog, "-b", "-Wd", "lib/portage/tests/runTests.py"] + args
9760 if os.access(prog, os.X_OK):
9761 - print('%sTesting with Python %s...%s' %
9762 - (colors.GOOD, ver, colors.NORMAL))
9763 + print(
9764 + "%sTesting with Python %s...%s" % (colors.GOOD, ver, colors.NORMAL)
9765 + )
9766 statuses.append((ver, subprocess.call(cmd)))
9767 elif not ignore_missing:
9768 - print('%sCould not find requested Python %s%s' %
9769 - (colors.BAD, ver, colors.NORMAL))
9770 + print(
9771 + "%sCould not find requested Python %s%s"
9772 + % (colors.BAD, ver, colors.NORMAL)
9773 + )
9774 statuses.append((ver, 1))
9775 else:
9776 - print('%sSkip Python %s...%s' %
9777 - (colors.WARN, ver, colors.NORMAL))
9778 + print("%sSkip Python %s...%s" % (colors.WARN, ver, colors.NORMAL))
9779 print()
9780 finally:
9781 if tempdir is not None:
9782 if opts.keep_temp:
9783 - print('Temporary directory left behind:\n%s' % tempdir)
9784 + print("Temporary directory left behind:\n%s" % tempdir)
9785 else:
9786 # Nuke our tempdir and anything that might be under it.
9787 shutil.rmtree(tempdir, True)
9788
9789 # Then summarize it all.
9790 - print('\nSummary:\n')
9791 + print("\nSummary:\n")
9792 width = 10
9793 - header = '| %-*s | %s' % (width, 'Version', 'Status')
9794 - print('%s\n|%s' % (header, '-' * (len(header) - 1)))
9795 + header = "| %-*s | %s" % (width, "Version", "Status")
9796 + print("%s\n|%s" % (header, "-" * (len(header) - 1)))
9797 exit_status = 0
9798 for ver, status in statuses:
9799 exit_status += status
9800 if status:
9801 color = colors.BAD
9802 - msg = 'FAIL'
9803 + msg = "FAIL"
9804 else:
9805 color = colors.GOOD
9806 - msg = 'PASS'
9807 - print('| %s%-*s%s | %s%s%s' %
9808 - (color, width, ver, colors.NORMAL, color, msg, colors.NORMAL))
9809 + msg = "PASS"
9810 + print(
9811 + "| %s%-*s%s | %s%s%s"
9812 + % (color, width, ver, colors.NORMAL, color, msg, colors.NORMAL)
9813 + )
9814 exit(exit_status)
9815
9816
9817 -if __name__ == '__main__':
9818 +if __name__ == "__main__":
9819 try:
9820 main(sys.argv[1:])
9821 except KeyboardInterrupt:
9822 - print('interrupted ...', file=sys.stderr)
9823 + print("interrupted ...", file=sys.stderr)
9824 exit(1)