Gentoo Archives: gentoo-commits

From: Fabian Groffen <grobian@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] proj/portage:prefix commit in: /
Date: Thu, 18 Feb 2016 19:36:05
Message-Id: 1455824085.ac7a15e255d0c239fb52aeb3df160378518aa496.grobian@gentoo
1 commit: ac7a15e255d0c239fb52aeb3df160378518aa496
2 Author: Fabian Groffen <grobian <AT> gentoo <DOT> org>
3 AuthorDate: Thu Feb 18 19:34:45 2016 +0000
4 Commit: Fabian Groffen <grobian <AT> gentoo <DOT> org>
5 CommitDate: Thu Feb 18 19:34:45 2016 +0000
6 URL: https://gitweb.gentoo.org/proj/portage.git/commit/?id=ac7a15e2
7
8 Merge remote-tracking branch 'overlays-gentoo-org/master' into prefix
9
10 .travis.yml | 1 +
11 NEWS | 17 +
12 README | 10 +-
13 RELEASE-NOTES | 133 +
14 bin/binhost-snapshot | 4 +-
15 bin/cgroup-release-agent | 2 +
16 bin/{ebuild-ipc => chmod-lite} | 8 +-
17 bin/chmod-lite.py | 30 +
18 bin/chpathtool.py | 45 +-
19 bin/dohtml.py | 47 +-
20 bin/eapi.sh | 8 +
21 bin/ebuild | 24 +-
22 bin/ebuild.sh | 68 +-
23 bin/egencache | 200 +-
24 bin/fixpackages | 4 +-
25 bin/glsa-check | 4 +-
26 bin/install-qa-check.d/60openrc | 2 +-
27 bin/install.py | 4 +-
28 bin/isolated-functions.sh | 12 +-
29 bin/misc-functions.sh | 19 +-
30 bin/phase-functions.sh | 42 +
31 bin/phase-helpers.sh | 97 +-
32 bin/portageq | 22 +-
33 bin/quickpkg | 16 +-
34 bin/repoman | 3161 +-------------------
35 bin/save-ebuild-env.sh | 11 +-
36 bin/socks5-server.py | 9 +-
37 bin/xattr-helper.py | 15 +-
38 bin/xpak-helper.py | 4 +-
39 cnf/make.globals | 2 +-
40 cnf/sets/portage.conf | 2 +-
41 doc/qa.docbook | 3 +-
42 man/ebuild.5 | 13 +-
43 man/egencache.1 | 20 +-
44 man/emerge.1 | 16 +-
45 man/emirrordist.1 | 10 +-
46 man/make.conf.5 | 49 +-
47 man/portage.5 | 18 +-
48 man/repoman.1 | 5 +-
49 misc/emerge-delta-webrsync | 2 +-
50 pym/_emerge/AbstractEbuildProcess.py | 41 +-
51 pym/_emerge/Binpkg.py | 24 +-
52 pym/_emerge/BinpkgFetcher.py | 9 +-
53 pym/_emerge/BlockerDB.py | 5 +-
54 pym/_emerge/EbuildBuild.py | 21 +-
55 pym/_emerge/PackageVirtualDbapi.py | 4 +-
56 pym/_emerge/Scheduler.py | 40 +-
57 pym/_emerge/SpawnProcess.py | 41 +-
58 pym/_emerge/UserQuery.py | 15 +-
59 pym/_emerge/actions.py | 145 +-
60 pym/_emerge/chk_updated_cfg_files.py | 8 +-
61 pym/_emerge/depgraph.py | 111 +-
62 pym/_emerge/main.py | 31 +-
63 pym/_emerge/resolver/circular_dependency.py | 21 +-
64 pym/_emerge/resolver/slot_collision.py | 11 +-
65 pym/_emerge/search.py | 3 +-
66 pym/portage/_emirrordist/Config.py | 10 +-
67 pym/portage/_emirrordist/main.py | 27 +-
68 pym/portage/_legacy_globals.py | 2 +-
69 pym/portage/_sets/__init__.py | 4 +
70 pym/portage/cache/anydbm.py | 3 +
71 pym/portage/cache/flat_hash.py | 5 +
72 pym/portage/cache/sqlite.py | 9 +-
73 pym/portage/cache/template.py | 61 +-
74 pym/portage/checksum.py | 4 +-
75 pym/portage/const.py | 4 +-
76 pym/portage/data.py | 2 +-
77 pym/portage/dbapi/IndexedPortdb.py | 4 +-
78 pym/portage/dbapi/IndexedVardb.py | 6 +-
79 pym/portage/dbapi/__init__.py | 27 +-
80 pym/portage/dbapi/bintree.py | 6 +-
81 pym/portage/dbapi/porttree.py | 44 +-
82 pym/portage/dbapi/vartree.py | 22 +-
83 pym/portage/dbapi/virtual.py | 12 +-
84 pym/portage/dep/__init__.py | 7 +-
85 pym/portage/dep/dep_check.py | 6 +-
86 pym/portage/eapi.py | 11 +-
87 pym/portage/elog/mod_save.py | 3 +-
88 pym/portage/emaint/main.py | 6 +-
89 pym/portage/emaint/modules/merges/__init__.py | 2 +-
90 pym/portage/emaint/modules/sync/sync.py | 191 +-
91 pym/portage/exception.py | 5 +-
92 pym/portage/manifest.py | 61 +
93 pym/portage/news.py | 2 +-
94 .../package/ebuild/_config/KeywordsManager.py | 35 +-
95 .../package/ebuild/_config/LicenseManager.py | 4 +-
96 .../package/ebuild/_config/special_env_vars.py | 2 +-
97 pym/portage/package/ebuild/config.py | 64 +-
98 pym/portage/package/ebuild/doebuild.py | 35 +-
99 pym/portage/package/ebuild/fetch.py | 9 +-
100 pym/portage/repository/config.py | 83 +-
101 pym/portage/sync/__init__.py | 20 +-
102 pym/portage/sync/controller.py | 90 +-
103 pym/portage/sync/modules/cvs/__init__.py | 5 +-
104 pym/portage/sync/modules/cvs/cvs.py | 2 +-
105 pym/portage/sync/modules/git/__init__.py | 1 +
106 pym/portage/sync/modules/git/git.py | 31 +-
107 pym/portage/sync/modules/rsync/__init__.py | 4 +
108 pym/portage/sync/modules/rsync/rsync.py | 34 +-
109 pym/portage/sync/modules/svn/__init__.py | 1 +
110 pym/portage/sync/modules/webrsync/__init__.py | 1 +
111 pym/portage/sync/syncbase.py | 2 +-
112 pym/portage/tests/__init__.py | 4 +-
113 pym/portage/tests/dbapi/test_portdb_cache.py | 3 +-
114 pym/portage/tests/dep/test_match_from_list.py | 21 +-
115 pym/portage/tests/ebuild/test_config.py | 4 +-
116 pym/portage/tests/ebuild/test_doebuild_fd_pipes.py | 37 +-
117 pym/portage/tests/ebuild/test_doebuild_spawn.py | 3 +-
118 pym/portage/tests/ebuild/test_ipc_daemon.py | 3 +-
119 pym/portage/tests/emerge/test_config_protect.py | 3 +-
120 pym/portage/tests/emerge/test_emerge_slot_abi.py | 3 +-
121 pym/portage/tests/emerge/test_simple.py | 3 +-
122 pym/portage/tests/repoman/test_simple.py | 9 +-
123 .../tests/resolver/test_autounmask_parent.py | 43 +
124 pym/portage/tests/resolver/test_depclean.py | 10 +-
125 pym/portage/tests/sync/test_sync_local.py | 82 +-
126 pym/portage/tests/util/test_xattr.py | 178 ++
127 pym/portage/util/__init__.py | 97 +-
128 pym/portage/util/_argparse.py | 42 -
129 pym/portage/util/_async/AsyncFunction.py | 70 +
130 pym/portage/util/_xattr.py | 228 ++
131 pym/portage/util/locale.py | 142 +
132 pym/portage/util/movefile.py | 100 +-
133 pym/portage/util/xattr.py | 20 -
134 pym/portage/xml/metadata.py | 3 +
135 pym/repoman/_portage.py | 25 +
136 pym/repoman/_subprocess.py | 83 +
137 pym/repoman/_xml.py | 106 +
138 pym/repoman/actions.py | 836 ++++++
139 pym/repoman/argparser.py | 225 ++
140 pym/repoman/check_missingslot.py | 7 +-
141 pym/repoman/{ => checks}/__init__.py | 0
142 pym/repoman/{ => checks/directories}/__init__.py | 0
143 pym/repoman/checks/directories/files.py | 81 +
144 pym/repoman/{ => checks/ebuilds}/__init__.py | 0
145 pym/repoman/{ => checks/ebuilds}/checks.py | 219 +-
146 .../{ => checks/ebuilds/eclasses}/__init__.py | 0
147 pym/repoman/checks/ebuilds/eclasses/live.py | 39 +
148 pym/repoman/checks/ebuilds/eclasses/ruby.py | 32 +
149 pym/repoman/checks/ebuilds/errors.py | 49 +
150 pym/repoman/checks/ebuilds/fetches.py | 135 +
151 pym/repoman/checks/ebuilds/isebuild.py | 71 +
152 pym/repoman/checks/ebuilds/keywords.py | 122 +
153 pym/repoman/checks/ebuilds/manifests.py | 102 +
154 pym/repoman/checks/ebuilds/misc.py | 57 +
155 pym/repoman/checks/ebuilds/pkgmetadata.py | 177 ++
156 pym/repoman/checks/ebuilds/thirdpartymirrors.py | 39 +
157 pym/repoman/checks/ebuilds/use_flags.py | 90 +
158 .../{ => checks/ebuilds/variables}/__init__.py | 0
159 .../checks/ebuilds/variables/description.py | 32 +
160 pym/repoman/checks/ebuilds/variables/eapi.py | 44 +
161 pym/repoman/checks/ebuilds/variables/license.py | 47 +
162 pym/repoman/checks/ebuilds/variables/restrict.py | 41 +
163 pym/repoman/{ => checks/herds}/__init__.py | 0
164 pym/repoman/{ => checks/herds}/herdbase.py | 28 +-
165 pym/repoman/checks/herds/metadata.py | 26 +
166 pym/repoman/copyrights.py | 120 +
167 pym/repoman/ebuild.py | 29 +
168 pym/repoman/errors.py | 49 +-
169 pym/repoman/gpg.py | 82 +
170 pym/repoman/main.py | 169 ++
171 pym/repoman/metadata.py | 153 +
172 pym/repoman/{ => modules}/__init__.py | 0
173 pym/repoman/{ => modules/commit}/__init__.py | 0
174 pym/repoman/modules/commit/repochecks.py | 35 +
175 pym/repoman/{ => modules/fix}/__init__.py | 0
176 pym/repoman/{ => modules/full}/__init__.py | 0
177 pym/repoman/{ => modules/manifest}/__init__.py | 0
178 pym/repoman/{ => modules/scan}/__init__.py | 0
179 pym/repoman/profile.py | 87 +
180 pym/repoman/qa_data.py | 439 +++
181 pym/repoman/qa_tracker.py | 45 +
182 pym/repoman/repos.py | 307 ++
183 pym/repoman/scan.py | 172 ++
184 pym/repoman/scanner.py | 755 +++++
185 pym/repoman/utilities.py | 572 +---
186 pym/repoman/{ => vcs}/__init__.py | 0
187 pym/repoman/vcs/vcs.py | 287 ++
188 pym/repoman/vcs/vcsstatus.py | 114 +
189 runtests | 50 +-
190 setup.py | 21 +-
191 181 files changed, 8297 insertions(+), 4668 deletions(-)
192
193 diff --cc bin/ebuild
194 index 1e9dd4b,1f99177..1692a92
195 --- a/bin/ebuild
196 +++ b/bin/ebuild
197 @@@ -1,5 -1,5 +1,5 @@@
198 -#!/usr/bin/python -bO
199 +#!@PREFIX_PORTAGE_PYTHON@ -bO
200 - # Copyright 1999-2014 Gentoo Foundation
201 + # Copyright 1999-2015 Gentoo Foundation
202 # Distributed under the terms of the GNU General Public License v2
203
204 from __future__ import print_function
205 diff --cc bin/egencache
206 index b26fd8e,7e3387e..843f374
207 --- a/bin/egencache
208 +++ b/bin/egencache
209 @@@ -1,5 -1,5 +1,5 @@@
210 -#!/usr/bin/python -b
211 +#!@PREFIX_PORTAGE_PYTHON@ -b
212 - # Copyright 2009-2014 Gentoo Foundation
213 + # Copyright 2009-2015 Gentoo Foundation
214 # Distributed under the terms of the GNU General Public License v2
215
216 # unicode_literals for compat with TextIOWrapper in Python 2
217 diff --cc bin/isolated-functions.sh
218 index a37130c,e320f71..5126bf9
219 --- a/bin/isolated-functions.sh
220 +++ b/bin/isolated-functions.sh
221 @@@ -1,5 -1,5 +1,5 @@@
222 -#!/bin/bash
223 +#!@PORTAGE_BASH@
224 - # Copyright 1999-2014 Gentoo Foundation
225 + # Copyright 1999-2016 Gentoo Foundation
226 # Distributed under the terms of the GNU General Public License v2
227
228 source "${PORTAGE_BIN_PATH}/eapi.sh" || exit 1
229 diff --cc bin/misc-functions.sh
230 index a1d4088,15651b9..080e366
231 mode 100644,100755..100644
232 --- a/bin/misc-functions.sh
233 +++ b/bin/misc-functions.sh
234 diff --cc bin/portageq
235 index be35dc6,925640b..2e90cfa
236 --- a/bin/portageq
237 +++ b/bin/portageq
238 @@@ -1,5 -1,5 +1,5 @@@
239 -#!/usr/bin/python -bO
240 +#!@PREFIX_PORTAGE_PYTHON@ -bO
241 - # Copyright 1999-2014 Gentoo Foundation
242 + # Copyright 1999-2015 Gentoo Foundation
243 # Distributed under the terms of the GNU General Public License v2
244
245 from __future__ import print_function, unicode_literals
246 diff --cc bin/repoman
247 index afc26c3,819e0f5..81b33f7
248 --- a/bin/repoman
249 +++ b/bin/repoman
250 @@@ -1,3152 -1,43 +1,43 @@@
251 -#!/usr/bin/python -bO
252 +#!@PREFIX_PORTAGE_PYTHON@ -bO
253 - # Copyright 1999-2015 Gentoo Foundation
254 + # Copyright 1999-2014 Gentoo Foundation
255 # Distributed under the terms of the GNU General Public License v2
256
257 - # Next to do: dep syntax checking in mask files
258 - # Then, check to make sure deps are satisfiable (to avoid "can't find match for" problems)
259 - # that last one is tricky because multiple profiles need to be checked.
260 + """Ebuild and tree health checks and maintenance utilities.
261 + """
262
263 - from __future__ import print_function, unicode_literals
264 + from __future__ import print_function
265
266 - import codecs
267 - import copy
268 - import errno
269 - import io
270 - import logging
271 - import re
272 - import signal
273 - import stat
274 - import subprocess
275 import sys
276 - import tempfile
277 - import textwrap
278 - import time
279 - import platform
280 - from itertools import chain
281 - from stat import S_ISDIR
282 - from pprint import pformat
283 -
284 - try:
285 - from urllib.parse import urlparse
286 - except ImportError:
287 - from urlparse import urlparse
288 -
289 - from os import path as osp
290 - if osp.isfile(osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), ".portage_not_installed")):
291 - sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym"))
292 - import portage
293 - portage._internal_caller = True
294 - portage._disable_legacy_globals()
295 -
296 + import errno
297 + # This block ensures that ^C interrupts are handled quietly.
298 try:
299 - import xml.etree.ElementTree
300 - from xml.parsers.expat import ExpatError
301 - except (SystemExit, KeyboardInterrupt):
302 - raise
303 - except (ImportError, SystemError, RuntimeError, Exception):
304 - # broken or missing xml support
305 - # http://bugs.python.org/issue14988
306 - msg = ["Please enable python's \"xml\" USE flag in order to use repoman."]
307 - from portage.output import EOutput
308 - out = EOutput()
309 - for line in msg:
310 - out.eerror(line)
311 - sys.exit(1)
312 -
313 - from portage import os
314 - from portage import _encodings
315 - from portage import _unicode_encode
316 - import portage.util.formatter as formatter
317 - import repoman.checks
318 - from repoman.checks import run_checks
319 - from repoman.check_missingslot import check_missingslot
320 - from repoman import utilities
321 - from repoman.herdbase import make_herd_base
322 - from _emerge.Package import Package
323 - from _emerge.RootConfig import RootConfig
324 - from _emerge.UserQuery import UserQuery
325 - import portage.checksum
326 - import portage.const
327 - import portage.repository.config
328 - from portage import cvstree, normalize_path
329 - from portage import util
330 - from portage.exception import (FileNotFound, InvalidAtom, MissingParameter,
331 - ParseError, PermissionDenied)
332 - from portage.dep import Atom
333 - from portage.process import find_binary, spawn
334 - from portage.output import bold, create_color_func, \
335 - green, nocolor, red
336 - from portage.output import ConsoleStyleFile, StyleWriter
337 - from portage.util import writemsg_level
338 - from portage.util._argparse import ArgumentParser
339 - from portage.package.ebuild.digestgen import digestgen
340 - from portage.eapi import eapi_has_iuse_defaults, eapi_has_required_use
341 -
342 - if sys.hexversion >= 0x3000000:
343 - basestring = str
344 + import signal
345
346 - util.initialize_logger()
347 -
348 - # 14 is the length of DESCRIPTION=""
349 - max_desc_len = 100
350 - allowed_filename_chars="a-zA-Z0-9._+-"
351 - pv_toolong_re = re.compile(r'[0-9]{19,}')
352 - GPG_KEY_ID_REGEX = r'(0x)?([0-9a-fA-F]{8}|[0-9a-fA-F]{16}|[0-9a-fA-F]{24}|[0-9a-fA-F]{32}|[0-9a-fA-F]{40})!?'
353 - bad = create_color_func("BAD")
354 -
355 - # A sane umask is needed for files that portage creates.
356 - os.umask(0o22)
357 - # Repoman sets it's own ACCEPT_KEYWORDS and we don't want it to
358 - # behave incrementally.
359 - repoman_incrementals = tuple(x for x in \
360 - portage.const.INCREMENTALS if x != 'ACCEPT_KEYWORDS')
361 - config_root = os.environ.get("PORTAGE_CONFIGROOT")
362 - repoman_settings = portage.config(config_root=config_root, local_config=False)
363 -
364 - if repoman_settings.get("NOCOLOR", "").lower() in ("yes", "true") or \
365 - repoman_settings.get('TERM') == 'dumb' or \
366 - not sys.stdout.isatty():
367 - nocolor()
368 -
369 - def warn(txt):
370 - print("repoman: " + txt)
371 -
372 - def err(txt):
373 - warn(txt)
374 - sys.exit(1)
375 -
376 - def exithandler(signum=None, _frame=None):
377 - logging.fatal("Interrupted; exiting...")
378 - if signum is None:
379 - sys.exit(1)
380 - else:
381 + def exithandler(signum, _frame):
382 + signal.signal(signal.SIGINT, signal.SIG_IGN)
383 + signal.signal(signal.SIGTERM, signal.SIG_IGN)
384 sys.exit(128 + signum)
385
386 - signal.signal(signal.SIGINT, exithandler)
387 -
388 - def ParseArgs(argv, qahelp):
389 - """This function uses a customized optionParser to parse command line arguments for repoman
390 - Args:
391 - argv - a sequence of command line arguments
392 - qahelp - a dict of qa warning to help message
393 - Returns:
394 - (opts, args), just like a call to parser.parse_args()
395 - """
396 -
397 - argv = portage._decode_argv(argv)
398 -
399 - modes = {
400 - 'commit' : 'Run a scan then commit changes',
401 - 'ci' : 'Run a scan then commit changes',
402 - 'fix' : 'Fix simple QA issues (stray digests, missing digests)',
403 - 'full' : 'Scan directory tree and print all issues (not a summary)',
404 - 'help' : 'Show this screen',
405 - 'manifest' : 'Generate a Manifest (fetches files if necessary)',
406 - 'manifest-check' : 'Check Manifests for missing or incorrect digests',
407 - 'scan' : 'Scan directory tree for QA issues'
408 - }
409 -
410 - output_choices = {
411 - 'default' : 'The normal output format',
412 - 'column' : 'Columnar output suitable for use with grep'
413 - }
414 -
415 - mode_keys = list(modes)
416 - mode_keys.sort()
417 -
418 - output_keys = sorted(output_choices)
419 -
420 - parser = ArgumentParser(usage="repoman [options] [mode]",
421 - description="Modes: %s" % " | ".join(mode_keys),
422 - epilog="For more help consult the man page.")
423 -
424 - parser.add_argument('-a', '--ask', dest='ask', action='store_true', default=False,
425 - help='Request a confirmation before commiting')
426 -
427 - parser.add_argument('-m', '--commitmsg', dest='commitmsg',
428 - help='specify a commit message on the command line')
429 -
430 - parser.add_argument('-M', '--commitmsgfile', dest='commitmsgfile',
431 - help='specify a path to a file that contains a commit message')
432 -
433 - parser.add_argument('--digest',
434 - choices=('y', 'n'), metavar='<y|n>',
435 - help='Automatically update Manifest digests for modified files')
436 -
437 - parser.add_argument('-p', '--pretend', dest='pretend', default=False,
438 - action='store_true', help='don\'t commit or fix anything; just show what would be done')
439 -
440 - parser.add_argument('-q', '--quiet', dest="quiet", action="count", default=0,
441 - help='do not print unnecessary messages')
442 -
443 - parser.add_argument(
444 - '--echangelog', choices=('y', 'n', 'force'), metavar="<y|n|force>",
445 - help='for commit mode, call echangelog if ChangeLog is unmodified (or '
446 - 'regardless of modification if \'force\' is specified)')
447 -
448 - parser.add_argument('--experimental-inherit', choices=('y', 'n'),
449 - metavar="<y|n>", default='n',
450 - help='Enable experimental inherit.missing checks which may misbehave'
451 - ' when the internal eclass database becomes outdated')
452 -
453 - parser.add_argument('-f', '--force', dest='force', default=False, action='store_true',
454 - help='Commit with QA violations')
455 -
456 - parser.add_argument('-S', '--straight-to-stable', dest='straight_to_stable', default=False,
457 - action='store_true', help='Allow committing straight to stable')
458 -
459 - parser.add_argument('--vcs', dest='vcs',
460 - help='Force using specific VCS instead of autodetection')
461 -
462 - parser.add_argument('-v', '--verbose', dest="verbosity", action='count',
463 - help='be very verbose in output', default=0)
464 -
465 - parser.add_argument('-V', '--version', dest='version', action='store_true',
466 - help='show version info')
467 -
468 - parser.add_argument('-x', '--xmlparse', dest='xml_parse', action='store_true',
469 - default=False, help='forces the metadata.xml parse check to be carried out')
470 -
471 - parser.add_argument(
472 - '--if-modified', choices=('y', 'n'), default='n',
473 - metavar="<y|n>",
474 - help='only check packages that have uncommitted modifications')
475 -
476 - parser.add_argument('-i', '--ignore-arches', dest='ignore_arches', action='store_true',
477 - default=False, help='ignore arch-specific failures (where arch != host)')
478 -
479 - parser.add_argument("--ignore-default-opts",
480 - action="store_true",
481 - help="do not use the REPOMAN_DEFAULT_OPTS environment variable")
482 -
483 - parser.add_argument('-I', '--ignore-masked', dest='ignore_masked', action='store_true',
484 - default=False, help='ignore masked packages (not allowed with commit mode)')
485 -
486 - parser.add_argument('--include-arches', dest='include_arches',
487 - metavar='ARCHES', action='append',
488 - help='A space separated list of arches used to '
489 - 'filter the selection of profiles for dependency checks')
490 -
491 - parser.add_argument('-d', '--include-dev', dest='include_dev', action='store_true',
492 - default=False, help='include dev profiles in dependency checks')
493 -
494 - parser.add_argument('-e', '--include-exp-profiles', choices=('y', 'n'),
495 - default=False, help='include exp profiles in dependency checks',
496 - metavar='<y|n>')
497 -
498 - parser.add_argument('--unmatched-removal', dest='unmatched_removal', action='store_true',
499 - default=False, help='enable strict checking of package.mask and package.unmask files for unmatched removal atoms')
500 -
501 - parser.add_argument('--without-mask', dest='without_mask', action='store_true',
502 - default=False, help='behave as if no package.mask entries exist (not allowed with commit mode)')
503 -
504 - parser.add_argument('--output-style', dest='output_style', choices=output_keys,
505 - help='select output type', default='default')
506 -
507 - parser.add_argument('--mode', dest='mode', choices=mode_keys,
508 - help='specify which mode repoman will run in (default=full)')
509 -
510 - opts, args = parser.parse_known_args(argv[1:])
511 -
512 - if not opts.ignore_default_opts:
513 - default_opts = portage.util.shlex_split(
514 - repoman_settings.get("REPOMAN_DEFAULT_OPTS", ""))
515 - if default_opts:
516 - opts, args = parser.parse_known_args(default_opts + sys.argv[1:])
517 -
518 - if opts.mode == 'help':
519 - parser.print_help(short=False)
520 -
521 - for arg in args:
522 - if arg in modes:
523 - if not opts.mode:
524 - opts.mode = arg
525 - break
526 - else:
527 - parser.error("invalid mode: %s" % arg)
528 -
529 - if not opts.mode:
530 - opts.mode = 'full'
531 -
532 - if opts.mode == 'ci':
533 - opts.mode = 'commit' # backwards compat shortcut
534 -
535 - # Use the verbosity and quiet options to fiddle with the loglevel appropriately
536 - for val in range(opts.verbosity):
537 - logger = logging.getLogger()
538 - logger.setLevel(logger.getEffectiveLevel() - 10)
539 -
540 - for val in range(opts.quiet):
541 - logger = logging.getLogger()
542 - logger.setLevel(logger.getEffectiveLevel() + 10)
543 -
544 - if opts.mode == 'commit' and not (opts.force or opts.pretend):
545 - if opts.ignore_masked:
546 - opts.ignore_masked = False
547 - logging.warning('Commit mode automatically disables --ignore-masked')
548 - if opts.without_mask:
549 - opts.without_mask = False
550 - logging.warning('Commit mode automatically disables --without-mask')
551 -
552 - return (opts, args)
553 -
554 - qahelp = {
555 - "CVS/Entries.IO_error": "Attempting to commit, and an IO error was encountered access the Entries file",
556 - "ebuild.invalidname": "Ebuild files with a non-parseable or syntactically incorrect name (or using 2.1 versioning extensions)",
557 - "ebuild.namenomatch": "Ebuild files that do not have the same name as their parent directory",
558 - "changelog.ebuildadded": "An ebuild was added but the ChangeLog was not modified",
559 - "changelog.missing": "Missing ChangeLog files",
560 - "ebuild.notadded": "Ebuilds that exist but have not been added to cvs",
561 - "ebuild.patches": "PATCHES variable should be a bash array to ensure white space safety",
562 - "changelog.notadded": "ChangeLogs that exist but have not been added to cvs",
563 - "dependency.bad": "User-visible ebuilds with unsatisfied dependencies (matched against *visible* ebuilds)",
564 - "dependency.badmasked": "Masked ebuilds with unsatisfied dependencies (matched against *all* ebuilds)",
565 - "dependency.badindev": "User-visible ebuilds with unsatisfied dependencies (matched against *visible* ebuilds) in developing arch",
566 - "dependency.badmaskedindev": "Masked ebuilds with unsatisfied dependencies (matched against *all* ebuilds) in developing arch",
567 - "dependency.badtilde": "Uses the ~ dep operator with a non-zero revision part, which is useless (the revision is ignored)",
568 - "dependency.missingslot": "RDEPEND matches more than one SLOT but does not specify a slot and/or use the := or :* slot operator",
569 - "dependency.perlcore": "This ebuild directly depends on a package in perl-core; it should use the corresponding virtual instead.",
570 - "dependency.syntax": "Syntax error in dependency string (usually an extra/missing space/parenthesis)",
571 - "dependency.unknown": "Ebuild has a dependency that refers to an unknown package (which may be valid if it is a blocker for a renamed/removed package, or is an alternative choice provided by an overlay)",
572 - "file.executable": "Ebuilds, digests, metadata.xml, Manifest, and ChangeLog do not need the executable bit",
573 - "file.size": "Files in the files directory must be under 20 KiB",
574 - "file.size.fatal": "Files in the files directory must be under 60 KiB",
575 - "file.name": "File/dir name must be composed of only the following chars: %s " % allowed_filename_chars,
576 - "file.UTF8": "File is not UTF8 compliant",
577 - "inherit.deprecated": "Ebuild inherits a deprecated eclass",
578 - "inherit.missing": "Ebuild uses functions from an eclass but does not inherit it",
579 - "inherit.unused": "Ebuild inherits an eclass but does not use it",
580 - "java.eclassesnotused": "With virtual/jdk in DEPEND you must inherit a java eclass",
581 - "wxwidgets.eclassnotused": "Ebuild DEPENDs on x11-libs/wxGTK without inheriting wxwidgets.eclass",
582 - "KEYWORDS.dropped": "Ebuilds that appear to have dropped KEYWORDS for some arch",
583 - "KEYWORDS.missing": "Ebuilds that have a missing or empty KEYWORDS variable",
584 - "KEYWORDS.stable": "Ebuilds that have been added directly with stable KEYWORDS",
585 - "KEYWORDS.stupid": "Ebuilds that use KEYWORDS=-* instead of package.mask",
586 - "LICENSE.missing": "Ebuilds that have a missing or empty LICENSE variable",
587 - "LICENSE.virtual": "Virtuals that have a non-empty LICENSE variable",
588 - "DESCRIPTION.missing": "Ebuilds that have a missing or empty DESCRIPTION variable",
589 - "DESCRIPTION.toolong": "DESCRIPTION is over %d characters" % max_desc_len,
590 - "EAPI.definition": "EAPI definition does not conform to PMS section 7.3.1 (first non-comment, non-blank line)",
591 - "EAPI.deprecated": "Ebuilds that use features that are deprecated in the current EAPI",
592 - "EAPI.incompatible": "Ebuilds that use features that are only available with a different EAPI",
593 - "EAPI.unsupported": "Ebuilds that have an unsupported EAPI version (you must upgrade portage)",
594 - "SLOT.invalid": "Ebuilds that have a missing or invalid SLOT variable value",
595 - "HOMEPAGE.missing": "Ebuilds that have a missing or empty HOMEPAGE variable",
596 - "HOMEPAGE.virtual": "Virtuals that have a non-empty HOMEPAGE variable",
597 - "PDEPEND.suspect": "PDEPEND contains a package that usually only belongs in DEPEND.",
598 - "LICENSE.syntax": "Syntax error in LICENSE (usually an extra/missing space/parenthesis)",
599 - "PROVIDE.syntax": "Syntax error in PROVIDE (usually an extra/missing space/parenthesis)",
600 - "PROPERTIES.syntax": "Syntax error in PROPERTIES (usually an extra/missing space/parenthesis)",
601 - "RESTRICT.syntax": "Syntax error in RESTRICT (usually an extra/missing space/parenthesis)",
602 - "REQUIRED_USE.syntax": "Syntax error in REQUIRED_USE (usually an extra/missing space/parenthesis)",
603 - "SRC_URI.syntax": "Syntax error in SRC_URI (usually an extra/missing space/parenthesis)",
604 - "SRC_URI.mirror": "A uri listed in profiles/thirdpartymirrors is found in SRC_URI",
605 - "ebuild.syntax": "Error generating cache entry for ebuild; typically caused by ebuild syntax error or digest verification failure",
606 - "ebuild.output": "A simple sourcing of the ebuild produces output; this breaks ebuild policy.",
607 - "ebuild.nesteddie": "Placing 'die' inside ( ) prints an error, but doesn't stop the ebuild.",
608 - "variable.invalidchar": "A variable contains an invalid character that is not part of the ASCII character set",
609 - "variable.readonly": "Assigning a readonly variable",
610 - "variable.usedwithhelpers": "Ebuild uses D, ROOT, ED, EROOT or EPREFIX with helpers",
611 - "LIVEVCS.stable": "This ebuild is a live checkout from a VCS but has stable keywords.",
612 - "LIVEVCS.unmasked": "This ebuild is a live checkout from a VCS but has keywords and is not masked in the global package.mask.",
613 - "IUSE.invalid": "This ebuild has a variable in IUSE that is not in the use.desc or its metadata.xml file",
614 - "IUSE.missing": "This ebuild has a USE conditional which references a flag that is not listed in IUSE",
615 - "IUSE.rubydeprecated": "The ebuild has set a ruby interpreter in USE_RUBY, that is not available as a ruby target anymore",
616 - "LICENSE.invalid": "This ebuild is listing a license that doesnt exist in portages license/ dir.",
617 - "LICENSE.deprecated": "This ebuild is listing a deprecated license.",
618 - "KEYWORDS.invalid": "This ebuild contains KEYWORDS that are not listed in profiles/arch.list or for which no valid profile was found",
619 - "RDEPEND.implicit": "RDEPEND is unset in the ebuild which triggers implicit RDEPEND=$DEPEND assignment (prior to EAPI 4)",
620 - "RDEPEND.suspect": "RDEPEND contains a package that usually only belongs in DEPEND.",
621 - "RESTRICT.invalid": "This ebuild contains invalid RESTRICT values.",
622 - "digest.assumed": "Existing digest must be assumed correct (Package level only)",
623 - "digest.missing": "Some files listed in SRC_URI aren't referenced in the Manifest",
624 - "digest.unused": "Some files listed in the Manifest aren't referenced in SRC_URI",
625 - "ebuild.majorsyn": "This ebuild has a major syntax error that may cause the ebuild to fail partially or fully",
626 - "ebuild.minorsyn": "This ebuild has a minor syntax error that contravenes gentoo coding style",
627 - "ebuild.badheader": "This ebuild has a malformed header",
628 - "manifest.bad": "Manifest has missing or incorrect digests",
629 - "metadata.missing": "Missing metadata.xml files",
630 - "metadata.bad": "Bad metadata.xml files",
631 - "metadata.warning": "Warnings in metadata.xml files",
632 - "portage.internal": "The ebuild uses an internal Portage function or variable",
633 - "repo.eapi.banned": "The ebuild uses an EAPI which is banned by the repository's metadata/layout.conf settings",
634 - "repo.eapi.deprecated": "The ebuild uses an EAPI which is deprecated by the repository's metadata/layout.conf settings",
635 - "virtual.oldstyle": "The ebuild PROVIDEs an old-style virtual (see GLEP 37)",
636 - "virtual.suspect": "Ebuild contains a package that usually should be pulled via virtual/, not directly.",
637 - "usage.obsolete": "The ebuild makes use of an obsolete construct",
638 - "upstream.workaround": "The ebuild works around an upstream bug, an upstream bug should be filed and tracked in bugs.gentoo.org"
639 - }
640 -
641 - qacats = list(qahelp)
642 - qacats.sort()
643 -
644 - qawarnings = set((
645 - "changelog.ebuildadded",
646 - "changelog.missing",
647 - "changelog.notadded",
648 - "dependency.unknown",
649 - "digest.assumed",
650 - "digest.unused",
651 - "ebuild.notadded",
652 - "ebuild.nesteddie",
653 - "dependency.badmasked",
654 - "dependency.badindev",
655 - "dependency.badmaskedindev",
656 - "dependency.badtilde",
657 - "dependency.missingslot",
658 - "dependency.perlcore",
659 - "DESCRIPTION.toolong",
660 - "EAPI.deprecated",
661 - "HOMEPAGE.virtual",
662 - "LICENSE.deprecated",
663 - "LICENSE.virtual",
664 - "KEYWORDS.dropped",
665 - "KEYWORDS.stupid",
666 - "KEYWORDS.missing",
667 - "IUSE.invalid",
668 - "PDEPEND.suspect",
669 - "RDEPEND.implicit",
670 - "RDEPEND.suspect",
671 - "virtual.suspect",
672 - "RESTRICT.invalid",
673 - "ebuild.minorsyn",
674 - "ebuild.badheader",
675 - "ebuild.patches",
676 - "file.size",
677 - "inherit.unused",
678 - "inherit.deprecated",
679 - "java.eclassesnotused",
680 - "wxwidgets.eclassnotused",
681 - "metadata.warning",
682 - "portage.internal",
683 - "repo.eapi.deprecated",
684 - "usage.obsolete",
685 - "upstream.workaround",
686 - "LIVEVCS.stable",
687 - "LIVEVCS.unmasked",
688 - "IUSE.rubydeprecated",
689 - "SRC_URI.mirror",
690 - ))
691 -
692 - non_ascii_re = re.compile(r'[^\x00-\x7f]')
693 -
694 - missingvars = ["KEYWORDS", "LICENSE", "DESCRIPTION", "HOMEPAGE"]
695 - allvars = set(x for x in portage.auxdbkeys if not x.startswith("UNUSED_"))
696 - allvars.update(Package.metadata_keys)
697 - allvars = sorted(allvars)
698 - commitmessage = None
699 - for x in missingvars:
700 - x += ".missing"
701 - if x not in qacats:
702 - logging.warning('* missingvars values need to be added to qahelp ("%s")' % x)
703 - qacats.append(x)
704 - qawarnings.add(x)
705 -
706 - valid_restrict = frozenset(["binchecks", "bindist",
707 - "fetch", "installsources", "mirror", "preserve-libs",
708 - "primaryuri", "splitdebug", "strip", "test", "userpriv"])
709 -
710 - live_eclasses = portage.const.LIVE_ECLASSES
711 -
712 - suspect_rdepend = frozenset([
713 - "app-arch/cabextract",
714 - "app-arch/rpm2targz",
715 - "app-doc/doxygen",
716 - "dev-lang/nasm",
717 - "dev-lang/swig",
718 - "dev-lang/yasm",
719 - "dev-perl/extutils-pkgconfig",
720 - "dev-util/byacc",
721 - "dev-util/cmake",
722 - "dev-util/ftjam",
723 - "dev-util/gperf",
724 - "dev-util/gtk-doc",
725 - "dev-util/gtk-doc-am",
726 - "dev-util/intltool",
727 - "dev-util/jam",
728 - "dev-util/pkg-config-lite",
729 - "dev-util/pkgconf",
730 - "dev-util/pkgconfig",
731 - "dev-util/pkgconfig-openbsd",
732 - "dev-util/scons",
733 - "dev-util/unifdef",
734 - "dev-util/yacc",
735 - "media-gfx/ebdftopcf",
736 - "sys-apps/help2man",
737 - "sys-devel/autoconf",
738 - "sys-devel/automake",
739 - "sys-devel/bin86",
740 - "sys-devel/bison",
741 - "sys-devel/dev86",
742 - "sys-devel/flex",
743 - "sys-devel/m4",
744 - "sys-devel/pmake",
745 - "virtual/linux-sources",
746 - "virtual/pkgconfig",
747 - "x11-misc/bdftopcf",
748 - "x11-misc/imake",
749 - ])
750 -
751 - suspect_virtual = {
752 - "dev-util/pkg-config-lite":"virtual/pkgconfig",
753 - "dev-util/pkgconf":"virtual/pkgconfig",
754 - "dev-util/pkgconfig":"virtual/pkgconfig",
755 - "dev-util/pkgconfig-openbsd":"virtual/pkgconfig",
756 - "dev-libs/libusb":"virtual/libusb",
757 - "dev-libs/libusbx":"virtual/libusb",
758 - "dev-libs/libusb-compat":"virtual/libusb",
759 - }
760 -
761 - ruby_deprecated = frozenset([
762 - "ruby_targets_ree18",
763 - "ruby_targets_ruby18",
764 - ])
765 -
766 - metadata_xml_encoding = 'UTF-8'
767 - metadata_xml_declaration = '<?xml version="1.0" encoding="%s"?>' % \
768 - (metadata_xml_encoding,)
769 - metadata_doctype_name = 'pkgmetadata'
770 - metadata_dtd_uri = 'http://www.gentoo.org/dtd/metadata.dtd'
771 - # force refetch if the local copy creation time is older than this
772 - metadata_dtd_ctime_interval = 60 * 60 * 24 * 7 # 7 days
773 -
774 - # file.executable
775 - no_exec = frozenset(["Manifest", "ChangeLog", "metadata.xml"])
776 -
777 - options, arguments = ParseArgs(sys.argv, qahelp)
778 -
779 - if options.version:
780 - print("Portage", portage.VERSION)
781 - sys.exit(0)
782 -
783 - if options.experimental_inherit == 'y':
784 - # This is experimental, so it's non-fatal.
785 - qawarnings.add("inherit.missing")
786 - repoman.checks._init(experimental_inherit=True)
787 -
788 - # Set this to False when an extraordinary issue (generally
789 - # something other than a QA issue) makes it impossible to
790 - # commit (like if Manifest generation fails).
791 - can_force = True
792 -
793 - portdir, portdir_overlay, mydir = utilities.FindPortdir(repoman_settings)
794 - if portdir is None:
795 - sys.exit(1)
796 -
797 - myreporoot = os.path.basename(portdir_overlay)
798 - myreporoot += mydir[len(portdir_overlay):]
799 -
800 - if options.vcs:
801 - if options.vcs in ('cvs', 'svn', 'git', 'bzr', 'hg'):
802 - vcs = options.vcs
803 - else:
804 - vcs = None
805 - else:
806 - vcses = utilities.FindVCS()
807 - if len(vcses) > 1:
808 - print(red('*** Ambiguous workdir -- more than one VCS found at the same depth: %s.' % ', '.join(vcses)))
809 - print(red('*** Please either clean up your workdir or specify --vcs option.'))
810 - sys.exit(1)
811 - elif vcses:
812 - vcs = vcses[0]
813 - else:
814 - vcs = None
815 -
816 - if options.if_modified == "y" and vcs is None:
817 - logging.info("Not in a version controlled repository; "
818 - "disabling --if-modified.")
819 - options.if_modified = "n"
820 -
821 - # Disable copyright/mtime check if vcs does not preserve mtime (bug #324075).
822 - vcs_preserves_mtime = vcs in ('cvs', None)
823 -
824 - vcs_local_opts = repoman_settings.get("REPOMAN_VCS_LOCAL_OPTS", "").split()
825 - vcs_global_opts = repoman_settings.get("REPOMAN_VCS_GLOBAL_OPTS")
826 - if vcs_global_opts is None:
827 - if vcs in ('cvs', 'svn'):
828 - vcs_global_opts = "-q"
829 - else:
830 - vcs_global_opts = ""
831 - vcs_global_opts = vcs_global_opts.split()
832 -
833 - if options.mode == 'commit' and not options.pretend and not vcs:
834 - logging.info("Not in a version controlled repository; enabling pretend mode.")
835 - options.pretend = True
836 -
837 - # Ensure that current repository is in the list of enabled repositories.
838 - repodir = os.path.realpath(portdir_overlay)
839 - try:
840 - repoman_settings.repositories.get_repo_for_location(repodir)
841 - except KeyError:
842 - repo_name = portage.repository.config.RepoConfig._read_valid_repo_name(portdir_overlay)[0]
843 - layout_conf_data = portage.repository.config.parse_layout_conf(portdir_overlay)[0]
844 - if layout_conf_data['repo-name']:
845 - repo_name = layout_conf_data['repo-name']
846 - tmp_conf_file = io.StringIO(textwrap.dedent("""
847 - [%s]
848 - location = %s
849 - """) % (repo_name, portdir_overlay))
850 - # Ensure that the repository corresponding to $PWD overrides a
851 - # repository of the same name referenced by the existing PORTDIR
852 - # or PORTDIR_OVERLAY settings.
853 - repoman_settings['PORTDIR_OVERLAY'] = "%s %s" % \
854 - (repoman_settings.get('PORTDIR_OVERLAY', ''),
855 - portage._shell_quote(portdir_overlay))
856 - repositories = portage.repository.config.load_repository_config(repoman_settings, extra_files=[tmp_conf_file])
857 - # We have to call the config constructor again so that attributes
858 - # dependent on config.repositories are initialized correctly.
859 - repoman_settings = portage.config(config_root=config_root, local_config=False, repositories=repositories)
860 -
861 - root = repoman_settings['EROOT']
862 - trees = {
863 - root : {'porttree' : portage.portagetree(settings=repoman_settings)}
864 - }
865 - portdb = trees[root]['porttree'].dbapi
866 -
867 - # Constrain dependency resolution to the master(s)
868 - # that are specified in layout.conf.
869 - repo_config = repoman_settings.repositories.get_repo_for_location(repodir)
870 - portdb.porttrees = list(repo_config.eclass_db.porttrees)
871 - portdir = portdb.porttrees[0]
872 - commit_env = os.environ.copy()
873 - # list() is for iteration on a copy.
874 - for repo in list(repoman_settings.repositories):
875 - # all paths are canonical
876 - if repo.location not in repo_config.eclass_db.porttrees:
877 - del repoman_settings.repositories[repo.name]
878 -
879 - if repo_config.allow_provide_virtual:
880 - qawarnings.add("virtual.oldstyle")
881 -
882 - if repo_config.sign_commit:
883 - if vcs == 'git':
884 - # NOTE: It's possible to use --gpg-sign=key_id to specify the key in
885 - # the commit arguments. If key_id is unspecified, then it must be
886 - # configured by `git config user.signingkey key_id`.
887 - vcs_local_opts.append("--gpg-sign")
888 - if repoman_settings.get("PORTAGE_GPG_DIR"):
889 - # Pass GNUPGHOME to git for bug #462362.
890 - commit_env["GNUPGHOME"] = repoman_settings["PORTAGE_GPG_DIR"]
891 -
892 - # Pass GPG_TTY to git for bug #477728.
893 - try:
894 - commit_env["GPG_TTY"] = os.ttyname(sys.stdin.fileno())
895 - except OSError:
896 - pass
897 -
898 - # In order to disable manifest signatures, repos may set
899 - # "sign-manifests = false" in metadata/layout.conf. This
900 - # can be used to prevent merge conflicts like those that
901 - # thin-manifests is designed to prevent.
902 - sign_manifests = "sign" in repoman_settings.features and \
903 - repo_config.sign_manifest
904 + signal.signal(signal.SIGINT, exithandler)
905 + signal.signal(signal.SIGTERM, exithandler)
906 + signal.signal(signal.SIGPIPE, signal.SIG_DFL)
907
908 - if repo_config.sign_manifest and repo_config.name == "gentoo" and \
909 - options.mode in ("commit",) and not sign_manifests:
910 - msg = ("The '%s' repository has manifest signatures enabled, "
911 - "but FEATURES=sign is currently disabled. In order to avoid this "
912 - "warning, enable FEATURES=sign in make.conf. Alternatively, "
913 - "repositories can disable manifest signatures by setting "
914 - "'sign-manifests = false' in metadata/layout.conf.") % \
915 - (repo_config.name,)
916 - for line in textwrap.wrap(msg, 60):
917 - logging.warning(line)
918 -
919 - if sign_manifests and options.mode in ("commit",) and \
920 - repoman_settings.get("PORTAGE_GPG_KEY") and \
921 - re.match(r'^%s$' % GPG_KEY_ID_REGEX,
922 - repoman_settings["PORTAGE_GPG_KEY"]) is None:
923 - logging.error("PORTAGE_GPG_KEY value is invalid: %s" %
924 - repoman_settings["PORTAGE_GPG_KEY"])
925 - sys.exit(1)
926 -
927 - manifest_hashes = repo_config.manifest_hashes
928 - if manifest_hashes is None:
929 - manifest_hashes = portage.const.MANIFEST2_HASH_DEFAULTS
930 -
931 - if options.mode in ("commit", "fix", "manifest"):
932 - if portage.const.MANIFEST2_REQUIRED_HASH not in manifest_hashes:
933 - msg = ("The 'manifest-hashes' setting in the '%s' repository's "
934 - "metadata/layout.conf does not contain the '%s' hash which "
935 - "is required by this portage version. You will have to "
936 - "upgrade portage if you want to generate valid manifests for "
937 - "this repository.") % \
938 - (repo_config.name, portage.const.MANIFEST2_REQUIRED_HASH)
939 - for line in textwrap.wrap(msg, 70):
940 - logging.error(line)
941 - sys.exit(1)
942 -
943 - unsupported_hashes = manifest_hashes.difference(
944 - portage.const.MANIFEST2_HASH_FUNCTIONS)
945 - if unsupported_hashes:
946 - msg = ("The 'manifest-hashes' setting in the '%s' repository's "
947 - "metadata/layout.conf contains one or more hash types '%s' "
948 - "which are not supported by this portage version. You will "
949 - "have to upgrade portage if you want to generate valid "
950 - "manifests for this repository.") % \
951 - (repo_config.name, " ".join(sorted(unsupported_hashes)))
952 - for line in textwrap.wrap(msg, 70):
953 - logging.error(line)
954 - sys.exit(1)
955 -
956 - if options.echangelog is None and repo_config.update_changelog:
957 - options.echangelog = 'y'
958 -
959 - if vcs is None:
960 - options.echangelog = 'n'
961 -
962 - # The --echangelog option causes automatic ChangeLog generation,
963 - # which invalidates changelog.ebuildadded and changelog.missing
964 - # checks.
965 - # Note: Some don't use ChangeLogs in distributed SCMs.
966 - # It will be generated on server side from scm log,
967 - # before package moves to the rsync server.
968 - # This is needed because they try to avoid merge collisions.
969 - # Gentoo's Council decided to always use the ChangeLog file.
970 - # TODO: shouldn't this just be switched on the repo, iso the VCS?
971 - check_changelog = options.echangelog not in ('y', 'force') and vcs in ('cvs', 'svn')
972 -
973 - if 'digest' in repoman_settings.features and options.digest != 'n':
974 - options.digest = 'y'
975 -
976 - logging.debug("vcs: %s" % (vcs,))
977 - logging.debug("repo config: %s" % (repo_config,))
978 - logging.debug("options: %s" % (options,))
979 -
980 - # It's confusing if these warnings are displayed without the user
981 - # being told which profile they come from, so disable them.
982 - env = os.environ.copy()
983 - env['FEATURES'] = env.get('FEATURES', '') + ' -unknown-features-warn'
984 -
985 - categories = []
986 - for path in repo_config.eclass_db.porttrees:
987 - categories.extend(portage.util.grabfile(
988 - os.path.join(path, 'profiles', 'categories')))
989 - repoman_settings.categories = frozenset(
990 - portage.util.stack_lists([categories], incremental=1))
991 - categories = repoman_settings.categories
992 -
993 - portdb.settings = repoman_settings
994 - root_config = RootConfig(repoman_settings, trees[root], None)
995 - # We really only need to cache the metadata that's necessary for visibility
996 - # filtering. Anything else can be discarded to reduce memory consumption.
997 - portdb._aux_cache_keys.clear()
998 - portdb._aux_cache_keys.update(["EAPI", "IUSE", "KEYWORDS", "repository", "SLOT"])
999 -
1000 - reposplit = myreporoot.split(os.path.sep)
1001 - repolevel = len(reposplit)
1002 -
1003 - # check if it's in $PORTDIR/$CATEGORY/$PN , otherwise bail if commiting.
1004 - # Reason for this is if they're trying to commit in just $FILESDIR/*, the Manifest needs updating.
1005 - # this check ensures that repoman knows where it is, and the manifest recommit is at least possible.
1006 - if options.mode == 'commit' and repolevel not in [1, 2, 3]:
1007 - print(red("***")+" Commit attempts *must* be from within a vcs co, category, or package directory.")
1008 - print(red("***")+" Attempting to commit from a packages files directory will be blocked for instance.")
1009 - print(red("***")+" This is intended behaviour, to ensure the manifest is recommitted for a package.")
1010 - print(red("***"))
1011 - err("Unable to identify level we're commiting from for %s" % '/'.join(reposplit))
1012 -
1013 - # Make startdir relative to the canonical repodir, so that we can pass
1014 - # it to digestgen and it won't have to be canonicalized again.
1015 - if repolevel == 1:
1016 - startdir = repodir
1017 - else:
1018 - startdir = normalize_path(mydir)
1019 - startdir = os.path.join(repodir, *startdir.split(os.sep)[-2 - repolevel + 3:])
1020 -
1021 - def caterror(mycat):
1022 - err(mycat + " is not an official category. Skipping QA checks in this directory.\nPlease ensure that you add " + catdir + " to " + repodir + "/profiles/categories\nif it is a new category.")
1023 -
1024 - def repoman_getstatusoutput(cmd):
1025 - """
1026 - Implements an interface similar to getstatusoutput(), but with
1027 - customized unicode handling (see bug #310789) and without the shell.
1028 - """
1029 - args = portage.util.shlex_split(cmd)
1030 -
1031 - if sys.hexversion < 0x3020000 and sys.hexversion >= 0x3000000 and \
1032 - not os.path.isabs(args[0]):
1033 - # Python 3.1 _execvp throws TypeError for non-absolute executable
1034 - # path passed as bytes (see http://bugs.python.org/issue8513).
1035 - fullname = find_binary(args[0])
1036 - if fullname is None:
1037 - raise portage.exception.CommandNotFound(args[0])
1038 - args[0] = fullname
1039 -
1040 - encoding = _encodings['fs']
1041 - args = [_unicode_encode(x,
1042 - encoding=encoding, errors='strict') for x in args]
1043 - proc = subprocess.Popen(args, stdout=subprocess.PIPE,
1044 - stderr=subprocess.STDOUT)
1045 - output = portage._unicode_decode(proc.communicate()[0],
1046 - encoding=encoding, errors='strict')
1047 - if output and output[-1] == "\n":
1048 - # getstatusoutput strips one newline
1049 - output = output[:-1]
1050 - return (proc.wait(), output)
1051 -
1052 - class repoman_popen(portage.proxy.objectproxy.ObjectProxy):
1053 - """
1054 - Implements an interface similar to os.popen(), but with customized
1055 - unicode handling (see bug #310789) and without the shell.
1056 - """
1057 -
1058 - __slots__ = ('_proc', '_stdout')
1059 -
1060 - def __init__(self, cmd):
1061 - args = portage.util.shlex_split(cmd)
1062 -
1063 - if sys.hexversion < 0x3020000 and sys.hexversion >= 0x3000000 and \
1064 - not os.path.isabs(args[0]):
1065 - # Python 3.1 _execvp throws TypeError for non-absolute executable
1066 - # path passed as bytes (see http://bugs.python.org/issue8513).
1067 - fullname = find_binary(args[0])
1068 - if fullname is None:
1069 - raise portage.exception.CommandNotFound(args[0])
1070 - args[0] = fullname
1071 -
1072 - encoding = _encodings['fs']
1073 - args = [_unicode_encode(x,
1074 - encoding=encoding, errors='strict') for x in args]
1075 - proc = subprocess.Popen(args, stdout=subprocess.PIPE)
1076 - object.__setattr__(self, '_proc', proc)
1077 - object.__setattr__(self, '_stdout',
1078 - codecs.getreader(encoding)(proc.stdout, 'strict'))
1079 -
1080 - def _get_target(self):
1081 - return object.__getattribute__(self, '_stdout')
1082 -
1083 - __enter__ = _get_target
1084 -
1085 - def __exit__(self, exc_type, exc_value, traceback):
1086 - proc = object.__getattribute__(self, '_proc')
1087 - proc.wait()
1088 - proc.stdout.close()
1089 -
1090 - class ProfileDesc(object):
1091 - __slots__ = ('abs_path', 'arch', 'status', 'sub_path', 'tree_path',)
1092 - def __init__(self, arch, status, sub_path, tree_path):
1093 - self.arch = arch
1094 - self.status = status
1095 - if sub_path:
1096 - sub_path = normalize_path(sub_path.lstrip(os.sep))
1097 - self.sub_path = sub_path
1098 - self.tree_path = tree_path
1099 - if tree_path:
1100 - self.abs_path = os.path.join(tree_path, 'profiles', self.sub_path)
1101 - else:
1102 - self.abs_path = tree_path
1103 -
1104 - def __str__(self):
1105 - if self.sub_path:
1106 - return self.sub_path
1107 - return 'empty profile'
1108 -
1109 - profile_list = []
1110 - valid_profile_types = frozenset(['dev', 'exp', 'stable'])
1111 -
1112 - # get lists of valid keywords, licenses, and use
1113 - kwlist = set()
1114 - liclist = set()
1115 - uselist = set()
1116 - global_pmasklines = []
1117 -
1118 - for path in portdb.porttrees:
1119 - try:
1120 - liclist.update(os.listdir(os.path.join(path, "licenses")))
1121 - except OSError:
1122 - pass
1123 - kwlist.update(portage.grabfile(os.path.join(path,
1124 - "profiles", "arch.list")))
1125 -
1126 - use_desc = portage.grabfile(os.path.join(path, 'profiles', 'use.desc'))
1127 - for x in use_desc:
1128 - x = x.split()
1129 - if x:
1130 - uselist.add(x[0])
1131 -
1132 - expand_desc_dir = os.path.join(path, 'profiles', 'desc')
1133 - try:
1134 - expand_list = os.listdir(expand_desc_dir)
1135 - except OSError:
1136 - pass
1137 - else:
1138 - for fn in expand_list:
1139 - if not fn[-5:] == '.desc':
1140 - continue
1141 - use_prefix = fn[:-5].lower() + '_'
1142 - for x in portage.grabfile(os.path.join(expand_desc_dir, fn)):
1143 - x = x.split()
1144 - if x:
1145 - uselist.add(use_prefix + x[0])
1146 -
1147 - global_pmasklines.append(portage.util.grabfile_package(
1148 - os.path.join(path, 'profiles', 'package.mask'), recursive=1, verify_eapi=True))
1149 -
1150 - desc_path = os.path.join(path, 'profiles', 'profiles.desc')
1151 - try:
1152 - desc_file = io.open(_unicode_encode(desc_path,
1153 - encoding=_encodings['fs'], errors='strict'),
1154 - mode='r', encoding=_encodings['repo.content'], errors='replace')
1155 - except EnvironmentError:
1156 - pass
1157 - else:
1158 - for i, x in enumerate(desc_file):
1159 - if x[0] == "#":
1160 - continue
1161 - arch = x.split()
1162 - if len(arch) == 0:
1163 - continue
1164 - if len(arch) != 3:
1165 - err("wrong format: \"" + bad(x.strip()) + "\" in " + \
1166 - desc_path + " line %d" % (i + 1, ))
1167 - elif arch[0] not in kwlist:
1168 - err("invalid arch: \"" + bad(arch[0]) + "\" in " + \
1169 - desc_path + " line %d" % (i + 1, ))
1170 - elif arch[2] not in valid_profile_types:
1171 - err("invalid profile type: \"" + bad(arch[2]) + "\" in " + \
1172 - desc_path + " line %d" % (i + 1, ))
1173 - profile_desc = ProfileDesc(arch[0], arch[2], arch[1], path)
1174 - if not os.path.isdir(profile_desc.abs_path):
1175 - logging.error(
1176 - "Invalid %s profile (%s) for arch %s in %s line %d",
1177 - arch[2], arch[1], arch[0], desc_path, i + 1)
1178 - continue
1179 - if os.path.exists(
1180 - os.path.join(profile_desc.abs_path, 'deprecated')):
1181 - continue
1182 - profile_list.append(profile_desc)
1183 - desc_file.close()
1184 -
1185 - repoman_settings['PORTAGE_ARCHLIST'] = ' '.join(sorted(kwlist))
1186 - repoman_settings.backup_changes('PORTAGE_ARCHLIST')
1187 -
1188 - global_pmasklines = portage.util.stack_lists(global_pmasklines, incremental=1)
1189 - global_pmaskdict = {}
1190 - for x in global_pmasklines:
1191 - global_pmaskdict.setdefault(x.cp, []).append(x)
1192 - del global_pmasklines
1193 -
1194 - def has_global_mask(pkg):
1195 - mask_atoms = global_pmaskdict.get(pkg.cp)
1196 - if mask_atoms:
1197 - pkg_list = [pkg]
1198 - for x in mask_atoms:
1199 - if portage.dep.match_from_list(x, pkg_list):
1200 - return x
1201 - return None
1202 -
1203 - # Ensure that profile sub_path attributes are unique. Process in reverse order
1204 - # so that profiles with duplicate sub_path from overlays will override
1205 - # profiles with the same sub_path from parent repos.
1206 - profiles = {}
1207 - profile_list.reverse()
1208 - profile_sub_paths = set()
1209 - for prof in profile_list:
1210 - if prof.sub_path in profile_sub_paths:
1211 - continue
1212 - profile_sub_paths.add(prof.sub_path)
1213 - profiles.setdefault(prof.arch, []).append(prof)
1214 -
1215 - # Use an empty profile for checking dependencies of
1216 - # packages that have empty KEYWORDS.
1217 - prof = ProfileDesc('**', 'stable', '', '')
1218 - profiles.setdefault(prof.arch, []).append(prof)
1219 -
1220 - for x in repoman_settings.archlist():
1221 - if x[0] == "~":
1222 - continue
1223 - if x not in profiles:
1224 - print(red("\"" + x + "\" doesn't have a valid profile listed in profiles.desc."))
1225 - print(red("You need to either \"cvs update\" your profiles dir or follow this"))
1226 - print(red("up with the " + x + " team."))
1227 - print()
1228 -
1229 - liclist_deprecated = set()
1230 - if "DEPRECATED" in repoman_settings._license_manager._license_groups:
1231 - liclist_deprecated.update(
1232 - repoman_settings._license_manager.expandLicenseTokens(["@DEPRECATED"]))
1233 -
1234 - if not liclist:
1235 - logging.fatal("Couldn't find licenses?")
1236 - sys.exit(1)
1237 -
1238 - if not kwlist:
1239 - logging.fatal("Couldn't read KEYWORDS from arch.list")
1240 - sys.exit(1)
1241 -
1242 - if not uselist:
1243 - logging.fatal("Couldn't find use.desc?")
1244 + except KeyboardInterrupt:
1245 sys.exit(1)
1246
1247 - scanlist = []
1248 - if repolevel == 2:
1249 - # we are inside a category directory
1250 - catdir = reposplit[-1]
1251 - if catdir not in categories:
1252 - caterror(catdir)
1253 - mydirlist = os.listdir(startdir)
1254 - for x in mydirlist:
1255 - if x == "CVS" or x.startswith("."):
1256 - continue
1257 - if os.path.isdir(startdir + "/" + x):
1258 - scanlist.append(catdir + "/" + x)
1259 - repo_subdir = catdir + os.sep
1260 - elif repolevel == 1:
1261 - for x in categories:
1262 - if not os.path.isdir(startdir + "/" + x):
1263 - continue
1264 - for y in os.listdir(startdir + "/" + x):
1265 - if y == "CVS" or y.startswith("."):
1266 - continue
1267 - if os.path.isdir(startdir + "/" + x + "/" + y):
1268 - scanlist.append(x + "/" + y)
1269 - repo_subdir = ""
1270 - elif repolevel == 3:
1271 - catdir = reposplit[-2]
1272 - if catdir not in categories:
1273 - caterror(catdir)
1274 - scanlist.append(catdir + "/" + reposplit[-1])
1275 - repo_subdir = scanlist[-1] + os.sep
1276 - else:
1277 - msg = 'Repoman is unable to determine PORTDIR or PORTDIR_OVERLAY' + \
1278 - ' from the current working directory'
1279 - logging.critical(msg)
1280 - sys.exit(1)
1281 -
1282 - repo_subdir_len = len(repo_subdir)
1283 - scanlist.sort()
1284 -
1285 - logging.debug("Found the following packages to scan:\n%s" % '\n'.join(scanlist))
1286 -
1287 - def vcs_files_to_cps(vcs_file_iter):
1288 - """
1289 - Iterate over the given modified file paths returned from the vcs,
1290 - and return a frozenset containing category/pn strings for each
1291 - modified package.
1292 - """
1293 -
1294 - modified_cps = []
1295 -
1296 - if repolevel == 3:
1297 - if reposplit[-2] in categories and \
1298 - next(vcs_file_iter, None) is not None:
1299 - modified_cps.append("/".join(reposplit[-2:]))
1300 -
1301 - elif repolevel == 2:
1302 - category = reposplit[-1]
1303 - if category in categories:
1304 - for filename in vcs_file_iter:
1305 - f_split = filename.split(os.sep)
1306 - # ['.', pn, ...]
1307 - if len(f_split) > 2:
1308 - modified_cps.append(category + "/" + f_split[1])
1309 -
1310 - else:
1311 - # repolevel == 1
1312 - for filename in vcs_file_iter:
1313 - f_split = filename.split(os.sep)
1314 - # ['.', category, pn, ...]
1315 - if len(f_split) > 3 and f_split[1] in categories:
1316 - modified_cps.append("/".join(f_split[1:3]))
1317 -
1318 - # Exclude packages that have been removed, since calling
1319 - # code assumes that the packages exist.
1320 - return frozenset(x for x in frozenset(modified_cps)
1321 - if os.path.exists(os.path.join(repodir, x)))
1322 -
1323 - def git_supports_gpg_sign():
1324 - status, cmd_output = \
1325 - repoman_getstatusoutput("git --version")
1326 - cmd_output = cmd_output.split()
1327 - if cmd_output:
1328 - version = re.match(r'^(\d+)\.(\d+)\.(\d+)', cmd_output[-1])
1329 - if version is not None:
1330 - version = [int(x) for x in version.groups()]
1331 - if version[0] > 1 or \
1332 - (version[0] == 1 and version[1] > 7) or \
1333 - (version[0] == 1 and version[1] == 7 and version[2] >= 9):
1334 - return True
1335 - return False
1336 -
1337 - def dev_keywords(profiles):
1338 - """
1339 - Create a set of KEYWORDS values that exist in 'dev'
1340 - profiles. These are used
1341 - to trigger a message notifying the user when they might
1342 - want to add the --include-dev option.
1343 - """
1344 - type_arch_map = {}
1345 - for arch, arch_profiles in profiles.items():
1346 - for prof in arch_profiles:
1347 - arch_set = type_arch_map.get(prof.status)
1348 - if arch_set is None:
1349 - arch_set = set()
1350 - type_arch_map[prof.status] = arch_set
1351 - arch_set.add(arch)
1352 -
1353 - dev_keywords = type_arch_map.get('dev', set())
1354 - dev_keywords.update(['~' + arch for arch in dev_keywords])
1355 - return frozenset(dev_keywords)
1356 -
1357 - dev_keywords = dev_keywords(profiles)
1358 -
1359 - stats = {}
1360 - fails = {}
1361 -
1362 - for x in qacats:
1363 - stats[x] = 0
1364 - fails[x] = []
1365 -
1366 - xmllint_capable = False
1367 - metadata_dtd = os.path.join(repoman_settings["DISTDIR"], 'metadata.dtd')
1368 -
1369 - def fetch_metadata_dtd():
1370 - """
1371 - Fetch metadata.dtd if it doesn't exist or the ctime is older than
1372 - metadata_dtd_ctime_interval.
1373 - @rtype: bool
1374 - @return: True if successful, otherwise False
1375 - """
1376 -
1377 - must_fetch = True
1378 - metadata_dtd_st = None
1379 - current_time = int(time.time())
1380 - try:
1381 - metadata_dtd_st = os.stat(metadata_dtd)
1382 - except EnvironmentError as e:
1383 - if e.errno not in (errno.ENOENT, errno.ESTALE):
1384 - raise
1385 - del e
1386 - else:
1387 - # Trigger fetch if metadata.dtd mtime is old or clock is wrong.
1388 - if abs(current_time - metadata_dtd_st.st_ctime) \
1389 - < metadata_dtd_ctime_interval:
1390 - must_fetch = False
1391 -
1392 - if must_fetch:
1393 - print()
1394 - print(green("***") + " the local copy of metadata.dtd " + \
1395 - "needs to be refetched, doing that now")
1396 - print()
1397 - parsed_url = urlparse(metadata_dtd_uri)
1398 - setting = 'FETCHCOMMAND_' + parsed_url.scheme.upper()
1399 - fcmd = repoman_settings.get(setting)
1400 - if not fcmd:
1401 - fcmd = repoman_settings.get('FETCHCOMMAND')
1402 - if not fcmd:
1403 - logging.error("FETCHCOMMAND is unset")
1404 - return False
1405 -
1406 - destdir = repoman_settings["DISTDIR"]
1407 - fd, metadata_dtd_tmp = tempfile.mkstemp(
1408 - prefix='metadata.dtd.', dir=destdir)
1409 - os.close(fd)
1410 -
1411 - try:
1412 - if not portage.getbinpkg.file_get(metadata_dtd_uri,
1413 - destdir, fcmd=fcmd,
1414 - filename=os.path.basename(metadata_dtd_tmp)):
1415 - logging.error("failed to fetch metadata.dtd from '%s'" %
1416 - metadata_dtd_uri)
1417 - return False
1418 -
1419 - try:
1420 - portage.util.apply_secpass_permissions(metadata_dtd_tmp,
1421 - gid=portage.data.portage_gid, mode=0o664, mask=0o2)
1422 - except portage.exception.PortageException:
1423 - pass
1424 -
1425 - os.rename(metadata_dtd_tmp, metadata_dtd)
1426 - finally:
1427 - try:
1428 - os.unlink(metadata_dtd_tmp)
1429 - except OSError:
1430 - pass
1431 -
1432 - return True
1433 -
1434 - if options.mode == "manifest":
1435 - pass
1436 - elif not find_binary('xmllint'):
1437 - print(red("!!! xmllint not found. Can't check metadata.xml.\n"))
1438 - if options.xml_parse or repolevel == 3:
1439 - print(red("!!!")+" sorry, xmllint is needed. failing\n")
1440 - sys.exit(1)
1441 - else:
1442 - if not fetch_metadata_dtd():
1443 - sys.exit(1)
1444 - # this can be problematic if xmllint changes their output
1445 - xmllint_capable = True
1446 -
1447 - if options.mode == 'commit' and vcs:
1448 - utilities.detect_vcs_conflicts(options, vcs)
1449 -
1450 - if options.mode == "manifest":
1451 - pass
1452 - elif options.pretend:
1453 - print(green("\nRepoMan does a once-over of the neighborhood..."))
1454 - else:
1455 - print(green("\nRepoMan scours the neighborhood..."))
1456 -
1457 - new_ebuilds = set()
1458 - modified_ebuilds = set()
1459 - modified_changelogs = set()
1460 - mychanged = []
1461 - mynew = []
1462 - myremoved = []
1463 -
1464 - if (options.if_modified != "y" and
1465 - options.mode in ("manifest", "manifest-check")):
1466 - pass
1467 - elif vcs == "cvs":
1468 - mycvstree = cvstree.getentries("./", recursive=1)
1469 - mychanged = cvstree.findchanged(mycvstree, recursive=1, basedir="./")
1470 - mynew = cvstree.findnew(mycvstree, recursive=1, basedir="./")
1471 - if options.if_modified == "y":
1472 - myremoved = cvstree.findremoved(mycvstree, recursive=1, basedir="./")
1473 -
1474 - elif vcs == "svn":
1475 - with repoman_popen("svn status") as f:
1476 - svnstatus = f.readlines()
1477 - mychanged = ["./" + elem.split()[-1:][0] for elem in svnstatus if elem and elem[:1] in "MR"]
1478 - mynew = ["./" + elem.split()[-1:][0] for elem in svnstatus if elem.startswith("A")]
1479 - if options.if_modified == "y":
1480 - myremoved = ["./" + elem.split()[-1:][0] for elem in svnstatus if elem.startswith("D")]
1481 -
1482 - elif vcs == "git":
1483 - with repoman_popen("git diff-index --name-only "
1484 - "--relative --diff-filter=M HEAD") as f:
1485 - mychanged = f.readlines()
1486 - mychanged = ["./" + elem[:-1] for elem in mychanged]
1487 -
1488 - with repoman_popen("git diff-index --name-only "
1489 - "--relative --diff-filter=A HEAD") as f:
1490 - mynew = f.readlines()
1491 - mynew = ["./" + elem[:-1] for elem in mynew]
1492 - if options.if_modified == "y":
1493 - with repoman_popen("git diff-index --name-only "
1494 - "--relative --diff-filter=D HEAD") as f:
1495 - myremoved = f.readlines()
1496 - myremoved = ["./" + elem[:-1] for elem in myremoved]
1497 -
1498 - elif vcs == "bzr":
1499 - with repoman_popen("bzr status -S .") as f:
1500 - bzrstatus = f.readlines()
1501 - mychanged = ["./" + elem.split()[-1:][0].split('/')[-1:][0] for elem in bzrstatus if elem and elem[1:2] == "M"]
1502 - mynew = ["./" + elem.split()[-1:][0].split('/')[-1:][0] for elem in bzrstatus if elem and (elem[1:2] == "NK" or elem[0:1] == "R")]
1503 - if options.if_modified == "y":
1504 - myremoved = ["./" + elem.split()[-3:-2][0].split('/')[-1:][0] for elem in bzrstatus if elem and (elem[1:2] == "K" or elem[0:1] == "R")]
1505 -
1506 - elif vcs == "hg":
1507 - with repoman_popen("hg status --no-status --modified .") as f:
1508 - mychanged = f.readlines()
1509 - mychanged = ["./" + elem.rstrip() for elem in mychanged]
1510 - with repoman_popen("hg status --no-status --added .") as f:
1511 - mynew = f.readlines()
1512 - mynew = ["./" + elem.rstrip() for elem in mynew]
1513 - if options.if_modified == "y":
1514 - with repoman_popen("hg status --no-status --removed .") as f:
1515 - myremoved = f.readlines()
1516 - myremoved = ["./" + elem.rstrip() for elem in myremoved]
1517 -
1518 - if vcs:
1519 - new_ebuilds.update(x for x in mynew if x.endswith(".ebuild"))
1520 - modified_ebuilds.update(x for x in mychanged if x.endswith(".ebuild"))
1521 - modified_changelogs.update(x for x in chain(mychanged, mynew) \
1522 - if os.path.basename(x) == "ChangeLog")
1523 -
1524 - def vcs_new_changed(relative_path):
1525 - for x in chain(mychanged, mynew):
1526 - if x == relative_path:
1527 - return True
1528 - return False
1529 -
1530 - have_pmasked = False
1531 - have_dev_keywords = False
1532 - dofail = 0
1533 -
1534 - # NOTE: match-all caches are not shared due to potential
1535 - # differences between profiles in _get_implicit_iuse.
1536 - arch_caches = {}
1537 - arch_xmatch_caches = {}
1538 - shared_xmatch_caches = {"cp-list":{}}
1539 -
1540 - include_arches = None
1541 - if options.include_arches:
1542 - include_arches = set()
1543 - include_arches.update(*[x.split() for x in options.include_arches])
1544 -
1545 - # Disable the "ebuild.notadded" check when not in commit mode and
1546 - # running `svn status` in every package dir will be too expensive.
1547 -
1548 - check_ebuild_notadded = not \
1549 - (vcs == "svn" and repolevel < 3 and options.mode != "commit")
1550 -
1551 - # Build a regex from thirdpartymirrors for the SRC_URI.mirror check.
1552 - thirdpartymirrors = {}
1553 - for k, v in repoman_settings.thirdpartymirrors().items():
1554 - for v in v:
1555 - if not v.endswith("/"):
1556 - v += "/"
1557 - thirdpartymirrors[v] = k
1558 -
1559 - class _XMLParser(xml.etree.ElementTree.XMLParser):
1560 -
1561 - def __init__(self, data, **kwargs):
1562 - xml.etree.ElementTree.XMLParser.__init__(self, **kwargs)
1563 - self._portage_data = data
1564 - if hasattr(self, 'parser'):
1565 - self._base_XmlDeclHandler = self.parser.XmlDeclHandler
1566 - self.parser.XmlDeclHandler = self._portage_XmlDeclHandler
1567 - self._base_StartDoctypeDeclHandler = \
1568 - self.parser.StartDoctypeDeclHandler
1569 - self.parser.StartDoctypeDeclHandler = \
1570 - self._portage_StartDoctypeDeclHandler
1571 -
1572 - def _portage_XmlDeclHandler(self, version, encoding, standalone):
1573 - if self._base_XmlDeclHandler is not None:
1574 - self._base_XmlDeclHandler(version, encoding, standalone)
1575 - self._portage_data["XML_DECLARATION"] = (version, encoding, standalone)
1576 -
1577 - def _portage_StartDoctypeDeclHandler(self, doctypeName, systemId, publicId,
1578 - has_internal_subset):
1579 - if self._base_StartDoctypeDeclHandler is not None:
1580 - self._base_StartDoctypeDeclHandler(doctypeName, systemId, publicId,
1581 - has_internal_subset)
1582 - self._portage_data["DOCTYPE"] = (doctypeName, systemId, publicId)
1583 -
1584 - class _MetadataTreeBuilder(xml.etree.ElementTree.TreeBuilder):
1585 - """
1586 - Implements doctype() as required to avoid deprecation warnings with
1587 - >=python-2.7.
1588 - """
1589 - def doctype(self, name, pubid, system):
1590 - pass
1591 + from os import path as osp
1592 + if osp.isfile(osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), ".portage_not_installed")):
1593 + pym_path = osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym")
1594 + sys.path.insert(0, pym_path)
1595 + import portage
1596 + portage._internal_caller = True
1597 + from repoman.main import repoman_main
1598
1599 try:
1600 - herd_base = make_herd_base(os.path.join(repoman_settings["PORTDIR"], "metadata/herds.xml"))
1601 - except (EnvironmentError, ParseError, PermissionDenied) as e:
1602 - err(str(e))
1603 - except FileNotFound:
1604 - # TODO: Download as we do for metadata.dtd, but add a way to
1605 - # disable for non-gentoo repoman users who may not have herds.
1606 - herd_base = None
1607 -
1608 - effective_scanlist = scanlist
1609 - if options.if_modified == "y":
1610 - effective_scanlist = sorted(vcs_files_to_cps(
1611 - chain(mychanged, mynew, myremoved)))
1612 -
1613 - for x in effective_scanlist:
1614 - # ebuilds and digests added to cvs respectively.
1615 - logging.info("checking package %s" % x)
1616 - # save memory by discarding xmatch caches from previous package(s)
1617 - arch_xmatch_caches.clear()
1618 - eadded = []
1619 - catdir, pkgdir = x.split("/")
1620 - checkdir = repodir + "/" + x
1621 - checkdir_relative = ""
1622 - if repolevel < 3:
1623 - checkdir_relative = os.path.join(pkgdir, checkdir_relative)
1624 - if repolevel < 2:
1625 - checkdir_relative = os.path.join(catdir, checkdir_relative)
1626 - checkdir_relative = os.path.join(".", checkdir_relative)
1627 - generated_manifest = False
1628 -
1629 - if options.mode == "manifest" or \
1630 - (options.mode != 'manifest-check' and options.digest == 'y') or \
1631 - options.mode in ('commit', 'fix') and not options.pretend:
1632 - auto_assumed = set()
1633 - fetchlist_dict = portage.FetchlistDict(checkdir,
1634 - repoman_settings, portdb)
1635 - if options.mode == 'manifest' and options.force:
1636 - portage._doebuild_manifest_exempt_depend += 1
1637 - try:
1638 - distdir = repoman_settings['DISTDIR']
1639 - mf = repoman_settings.repositories.get_repo_for_location(
1640 - os.path.dirname(os.path.dirname(checkdir)))
1641 - mf = mf.load_manifest(checkdir, distdir,
1642 - fetchlist_dict=fetchlist_dict)
1643 - mf.create(requiredDistfiles=None,
1644 - assumeDistHashesAlways=True)
1645 - for distfiles in fetchlist_dict.values():
1646 - for distfile in distfiles:
1647 - if os.path.isfile(os.path.join(distdir, distfile)):
1648 - mf.fhashdict['DIST'].pop(distfile, None)
1649 - else:
1650 - auto_assumed.add(distfile)
1651 - mf.write()
1652 - finally:
1653 - portage._doebuild_manifest_exempt_depend -= 1
1654 -
1655 - repoman_settings["O"] = checkdir
1656 - try:
1657 - generated_manifest = digestgen(
1658 - mysettings=repoman_settings, myportdb=portdb)
1659 - except portage.exception.PermissionDenied as e:
1660 - generated_manifest = False
1661 - writemsg_level("!!! Permission denied: '%s'\n" % (e,),
1662 - level=logging.ERROR, noiselevel=-1)
1663 -
1664 - if not generated_manifest:
1665 - print("Unable to generate manifest.")
1666 - dofail = 1
1667 -
1668 - if options.mode == "manifest":
1669 - if not dofail and options.force and auto_assumed and \
1670 - 'assume-digests' in repoman_settings.features:
1671 - # Show which digests were assumed despite the --force option
1672 - # being given. This output will already have been shown by
1673 - # digestgen() if assume-digests is not enabled, so only show
1674 - # it here if assume-digests is enabled.
1675 - pkgs = list(fetchlist_dict)
1676 - pkgs.sort()
1677 - portage.writemsg_stdout(" digest.assumed" + \
1678 - portage.output.colorize("WARN",
1679 - str(len(auto_assumed)).rjust(18)) + "\n")
1680 - for cpv in pkgs:
1681 - fetchmap = fetchlist_dict[cpv]
1682 - pf = portage.catsplit(cpv)[1]
1683 - for distfile in sorted(fetchmap):
1684 - if distfile in auto_assumed:
1685 - portage.writemsg_stdout(
1686 - " %s::%s\n" % (pf, distfile))
1687 - continue
1688 - elif dofail:
1689 - sys.exit(1)
1690 -
1691 - if not generated_manifest:
1692 - repoman_settings['O'] = checkdir
1693 - repoman_settings['PORTAGE_QUIET'] = '1'
1694 - if not portage.digestcheck([], repoman_settings, strict=1):
1695 - stats["manifest.bad"] += 1
1696 - fails["manifest.bad"].append(os.path.join(x, 'Manifest'))
1697 - repoman_settings.pop('PORTAGE_QUIET', None)
1698 -
1699 - if options.mode == 'manifest-check':
1700 - continue
1701 -
1702 - checkdirlist = os.listdir(checkdir)
1703 - ebuildlist = []
1704 - pkgs = {}
1705 - allvalid = True
1706 - for y in checkdirlist:
1707 - if (y in no_exec or y.endswith(".ebuild")) and \
1708 - stat.S_IMODE(os.stat(os.path.join(checkdir, y)).st_mode) & 0o111:
1709 - stats["file.executable"] += 1
1710 - fails["file.executable"].append(os.path.join(checkdir, y))
1711 - if y.endswith(".ebuild"):
1712 - pf = y[:-7]
1713 - ebuildlist.append(pf)
1714 - cpv = "%s/%s" % (catdir, pf)
1715 - try:
1716 - myaux = dict(zip(allvars, portdb.aux_get(cpv, allvars)))
1717 - except KeyError:
1718 - allvalid = False
1719 - stats["ebuild.syntax"] += 1
1720 - fails["ebuild.syntax"].append(os.path.join(x, y))
1721 - continue
1722 - except IOError:
1723 - allvalid = False
1724 - stats["ebuild.output"] += 1
1725 - fails["ebuild.output"].append(os.path.join(x, y))
1726 - continue
1727 - if not portage.eapi_is_supported(myaux["EAPI"]):
1728 - allvalid = False
1729 - stats["EAPI.unsupported"] += 1
1730 - fails["EAPI.unsupported"].append(os.path.join(x, y))
1731 - continue
1732 - pkgs[pf] = Package(cpv=cpv, metadata=myaux,
1733 - root_config=root_config, type_name="ebuild")
1734 -
1735 - slot_keywords = {}
1736 -
1737 - if len(pkgs) != len(ebuildlist):
1738 - # If we can't access all the metadata then it's totally unsafe to
1739 - # commit since there's no way to generate a correct Manifest.
1740 - # Do not try to do any more QA checks on this package since missing
1741 - # metadata leads to false positives for several checks, and false
1742 - # positives confuse users.
1743 - can_force = False
1744 - continue
1745 -
1746 - # Sort ebuilds in ascending order for the KEYWORDS.dropped check.
1747 - ebuildlist = sorted(pkgs.values())
1748 - ebuildlist = [pkg.pf for pkg in ebuildlist]
1749 -
1750 - for y in checkdirlist:
1751 - index = repo_config.find_invalid_path_char(y)
1752 - if index != -1:
1753 - y_relative = os.path.join(checkdir_relative, y)
1754 - if vcs is not None and not vcs_new_changed(y_relative):
1755 - # If the file isn't in the VCS new or changed set, then
1756 - # assume that it's an irrelevant temporary file (Manifest
1757 - # entries are not generated for file names containing
1758 - # prohibited characters). See bug #406877.
1759 - index = -1
1760 - if index != -1:
1761 - stats["file.name"] += 1
1762 - fails["file.name"].append("%s/%s: char '%s'" % \
1763 - (checkdir, y, y[index]))
1764 -
1765 - if not (y in ("ChangeLog", "metadata.xml") or y.endswith(".ebuild")):
1766 - continue
1767 - f = None
1768 - try:
1769 - line = 1
1770 - f = io.open(_unicode_encode(os.path.join(checkdir, y),
1771 - encoding=_encodings['fs'], errors='strict'),
1772 - mode='r', encoding=_encodings['repo.content'])
1773 - for l in f:
1774 - line += 1
1775 - except UnicodeDecodeError as ue:
1776 - stats["file.UTF8"] += 1
1777 - s = ue.object[:ue.start]
1778 - l2 = s.count("\n")
1779 - line += l2
1780 - if l2 != 0:
1781 - s = s[s.rfind("\n") + 1:]
1782 - fails["file.UTF8"].append("%s/%s: line %i, just after: '%s'" % (checkdir, y, line, s))
1783 - finally:
1784 - if f is not None:
1785 - f.close()
1786 -
1787 - if vcs in ("git", "hg") and check_ebuild_notadded:
1788 - if vcs == "git":
1789 - myf = repoman_popen("git ls-files --others %s" % \
1790 - (portage._shell_quote(checkdir_relative),))
1791 - if vcs == "hg":
1792 - myf = repoman_popen("hg status --no-status --unknown %s" % \
1793 - (portage._shell_quote(checkdir_relative),))
1794 - for l in myf:
1795 - if l[:-1][-7:] == ".ebuild":
1796 - stats["ebuild.notadded"] += 1
1797 - fails["ebuild.notadded"].append(
1798 - os.path.join(x, os.path.basename(l[:-1])))
1799 - myf.close()
1800 -
1801 - if vcs in ("cvs", "svn", "bzr") and check_ebuild_notadded:
1802 - try:
1803 - if vcs == "cvs":
1804 - myf = open(checkdir + "/CVS/Entries", "r")
1805 - if vcs == "svn":
1806 - myf = repoman_popen("svn status --depth=files --verbose " +
1807 - portage._shell_quote(checkdir))
1808 - if vcs == "bzr":
1809 - myf = repoman_popen("bzr ls -v --kind=file " +
1810 - portage._shell_quote(checkdir))
1811 - myl = myf.readlines()
1812 - myf.close()
1813 - for l in myl:
1814 - if vcs == "cvs":
1815 - if l[0] != "/":
1816 - continue
1817 - splitl = l[1:].split("/")
1818 - if not len(splitl):
1819 - continue
1820 - if splitl[0][-7:] == ".ebuild":
1821 - eadded.append(splitl[0][:-7])
1822 - if vcs == "svn":
1823 - if l[:1] == "?":
1824 - continue
1825 - if l[:7] == ' >':
1826 - # tree conflict, new in subversion 1.6
1827 - continue
1828 - l = l.split()[-1]
1829 - if l[-7:] == ".ebuild":
1830 - eadded.append(os.path.basename(l[:-7]))
1831 - if vcs == "bzr":
1832 - if l[1:2] == "?":
1833 - continue
1834 - l = l.split()[-1]
1835 - if l[-7:] == ".ebuild":
1836 - eadded.append(os.path.basename(l[:-7]))
1837 - if vcs == "svn":
1838 - myf = repoman_popen("svn status " +
1839 - portage._shell_quote(checkdir))
1840 - myl = myf.readlines()
1841 - myf.close()
1842 - for l in myl:
1843 - if l[0] == "A":
1844 - l = l.rstrip().split(' ')[-1]
1845 - if l[-7:] == ".ebuild":
1846 - eadded.append(os.path.basename(l[:-7]))
1847 - except IOError:
1848 - if vcs == "cvs":
1849 - stats["CVS/Entries.IO_error"] += 1
1850 - fails["CVS/Entries.IO_error"].append(checkdir + "/CVS/Entries")
1851 - else:
1852 - raise
1853 - continue
1854 -
1855 - mf = repoman_settings.repositories.get_repo_for_location(
1856 - os.path.dirname(os.path.dirname(checkdir)))
1857 - mf = mf.load_manifest(checkdir, repoman_settings["DISTDIR"])
1858 - mydigests = mf.getTypeDigests("DIST")
1859 -
1860 - fetchlist_dict = portage.FetchlistDict(checkdir, repoman_settings, portdb)
1861 - myfiles_all = []
1862 - src_uri_error = False
1863 - for mykey in fetchlist_dict:
1864 - try:
1865 - myfiles_all.extend(fetchlist_dict[mykey])
1866 - except portage.exception.InvalidDependString as e:
1867 - src_uri_error = True
1868 - try:
1869 - portdb.aux_get(mykey, ["SRC_URI"])
1870 - except KeyError:
1871 - # This will be reported as an "ebuild.syntax" error.
1872 - pass
1873 - else:
1874 - stats["SRC_URI.syntax"] += 1
1875 - fails["SRC_URI.syntax"].append(
1876 - "%s.ebuild SRC_URI: %s" % (mykey, e))
1877 - del fetchlist_dict
1878 - if not src_uri_error:
1879 - # This test can produce false positives if SRC_URI could not
1880 - # be parsed for one or more ebuilds. There's no point in
1881 - # producing a false error here since the root cause will
1882 - # produce a valid error elsewhere, such as "SRC_URI.syntax"
1883 - # or "ebuild.sytax".
1884 - myfiles_all = set(myfiles_all)
1885 - for entry in mydigests:
1886 - if entry not in myfiles_all:
1887 - stats["digest.unused"] += 1
1888 - fails["digest.unused"].append(checkdir + "::" + entry)
1889 - for entry in myfiles_all:
1890 - if entry not in mydigests:
1891 - stats["digest.missing"] += 1
1892 - fails["digest.missing"].append(checkdir + "::" + entry)
1893 - del myfiles_all
1894 -
1895 - if os.path.exists(checkdir + "/files"):
1896 - filesdirlist = os.listdir(checkdir + "/files")
1897 -
1898 - # recurse through files directory
1899 - # use filesdirlist as a stack, appending directories as needed so people can't hide > 20k files in a subdirectory.
1900 - while filesdirlist:
1901 - y = filesdirlist.pop(0)
1902 - relative_path = os.path.join(x, "files", y)
1903 - full_path = os.path.join(repodir, relative_path)
1904 - try:
1905 - mystat = os.stat(full_path)
1906 - except OSError as oe:
1907 - if oe.errno == 2:
1908 - # don't worry about it. it likely was removed via fix above.
1909 - continue
1910 - else:
1911 - raise oe
1912 - if S_ISDIR(mystat.st_mode):
1913 - # !!! VCS "portability" alert! Need some function isVcsDir() or alike !!!
1914 - if y == "CVS" or y == ".svn":
1915 - continue
1916 - for z in os.listdir(checkdir + "/files/" + y):
1917 - if z == "CVS" or z == ".svn":
1918 - continue
1919 - filesdirlist.append(y + "/" + z)
1920 - # Current policy is no files over 20 KiB, these are the checks. File size between
1921 - # 20 KiB and 60 KiB causes a warning, while file size over 60 KiB causes an error.
1922 - elif mystat.st_size > 61440:
1923 - stats["file.size.fatal"] += 1
1924 - fails["file.size.fatal"].append("(" + str(mystat.st_size//1024) + " KiB) " + x + "/files/" + y)
1925 - elif mystat.st_size > 20480:
1926 - stats["file.size"] += 1
1927 - fails["file.size"].append("(" + str(mystat.st_size//1024) + " KiB) " + x + "/files/" + y)
1928 -
1929 - index = repo_config.find_invalid_path_char(y)
1930 - if index != -1:
1931 - y_relative = os.path.join(checkdir_relative, "files", y)
1932 - if vcs is not None and not vcs_new_changed(y_relative):
1933 - # If the file isn't in the VCS new or changed set, then
1934 - # assume that it's an irrelevant temporary file (Manifest
1935 - # entries are not generated for file names containing
1936 - # prohibited characters). See bug #406877.
1937 - index = -1
1938 - if index != -1:
1939 - stats["file.name"] += 1
1940 - fails["file.name"].append("%s/files/%s: char '%s'" % \
1941 - (checkdir, y, y[index]))
1942 - del mydigests
1943 -
1944 - if check_changelog and "ChangeLog" not in checkdirlist:
1945 - stats["changelog.missing"] += 1
1946 - fails["changelog.missing"].append(x + "/ChangeLog")
1947 -
1948 - musedict = {}
1949 - # metadata.xml file check
1950 - if "metadata.xml" not in checkdirlist:
1951 - stats["metadata.missing"] += 1
1952 - fails["metadata.missing"].append(x + "/metadata.xml")
1953 - # metadata.xml parse check
1954 - else:
1955 - metadata_bad = False
1956 - xml_info = {}
1957 - xml_parser = _XMLParser(xml_info, target=_MetadataTreeBuilder())
1958 -
1959 - # read metadata.xml into memory
1960 - try:
1961 - _metadata_xml = xml.etree.ElementTree.parse(
1962 - _unicode_encode(os.path.join(checkdir, "metadata.xml"),
1963 - encoding=_encodings['fs'], errors='strict'),
1964 - parser=xml_parser)
1965 - except (ExpatError, SyntaxError, EnvironmentError) as e:
1966 - metadata_bad = True
1967 - stats["metadata.bad"] += 1
1968 - fails["metadata.bad"].append("%s/metadata.xml: %s" % (x, e))
1969 - del e
1970 - else:
1971 - if not hasattr(xml_parser, 'parser') or \
1972 - sys.hexversion < 0x2070000 or \
1973 - (sys.hexversion > 0x3000000 and sys.hexversion < 0x3020000):
1974 - # doctype is not parsed with python 2.6 or 3.1
1975 - pass
1976 - else:
1977 - if "XML_DECLARATION" not in xml_info:
1978 - stats["metadata.bad"] += 1
1979 - fails["metadata.bad"].append("%s/metadata.xml: "
1980 - "xml declaration is missing on first line, "
1981 - "should be '%s'" % (x, metadata_xml_declaration))
1982 - else:
1983 - xml_version, xml_encoding, xml_standalone = \
1984 - xml_info["XML_DECLARATION"]
1985 - if xml_encoding is None or \
1986 - xml_encoding.upper() != metadata_xml_encoding:
1987 - stats["metadata.bad"] += 1
1988 - if xml_encoding is None:
1989 - encoding_problem = "but it is undefined"
1990 - else:
1991 - encoding_problem = "not '%s'" % xml_encoding
1992 - fails["metadata.bad"].append("%s/metadata.xml: "
1993 - "xml declaration encoding should be '%s', %s" %
1994 - (x, metadata_xml_encoding, encoding_problem))
1995 -
1996 - if "DOCTYPE" not in xml_info:
1997 - metadata_bad = True
1998 - stats["metadata.bad"] += 1
1999 - fails["metadata.bad"].append("%s/metadata.xml: %s" % (x,
2000 - "DOCTYPE is missing"))
2001 - else:
2002 - doctype_name, doctype_system, doctype_pubid = \
2003 - xml_info["DOCTYPE"]
2004 - if doctype_system != metadata_dtd_uri:
2005 - stats["metadata.bad"] += 1
2006 - if doctype_system is None:
2007 - system_problem = "but it is undefined"
2008 - else:
2009 - system_problem = "not '%s'" % doctype_system
2010 - fails["metadata.bad"].append("%s/metadata.xml: "
2011 - "DOCTYPE: SYSTEM should refer to '%s', %s" %
2012 - (x, metadata_dtd_uri, system_problem))
2013 -
2014 - if doctype_name != metadata_doctype_name:
2015 - stats["metadata.bad"] += 1
2016 - fails["metadata.bad"].append("%s/metadata.xml: "
2017 - "DOCTYPE: name should be '%s', not '%s'" %
2018 - (x, metadata_doctype_name, doctype_name))
2019 -
2020 - # load USE flags from metadata.xml
2021 - try:
2022 - musedict = utilities.parse_metadata_use(_metadata_xml)
2023 - except portage.exception.ParseError as e:
2024 - metadata_bad = True
2025 - stats["metadata.bad"] += 1
2026 - fails["metadata.bad"].append("%s/metadata.xml: %s" % (x, e))
2027 - else:
2028 - for atom in chain(*musedict.values()):
2029 - if atom is None:
2030 - continue
2031 - try:
2032 - atom = Atom(atom)
2033 - except InvalidAtom as e:
2034 - stats["metadata.bad"] += 1
2035 - fails["metadata.bad"].append(
2036 - "%s/metadata.xml: Invalid atom: %s" % (x, e))
2037 - else:
2038 - if atom.cp != x:
2039 - stats["metadata.bad"] += 1
2040 - fails["metadata.bad"].append(
2041 - ("%s/metadata.xml: Atom contains "
2042 - "unexpected cat/pn: %s") % (x, atom))
2043 -
2044 - # Run other metadata.xml checkers
2045 - try:
2046 - utilities.check_metadata(_metadata_xml, herd_base)
2047 - except (utilities.UnknownHerdsError, ) as e:
2048 - metadata_bad = True
2049 - stats["metadata.bad"] += 1
2050 - fails["metadata.bad"].append("%s/metadata.xml: %s" % (x, e))
2051 - del e
2052 -
2053 - # Only carry out if in package directory or check forced
2054 - if xmllint_capable and not metadata_bad:
2055 - # xmlint can produce garbage output even on success, so only dump
2056 - # the ouput when it fails.
2057 - st, out = repoman_getstatusoutput(
2058 - "xmllint --nonet --noout --dtdvalid %s %s" % \
2059 - (portage._shell_quote(metadata_dtd),
2060 - portage._shell_quote(os.path.join(checkdir, "metadata.xml"))))
2061 - if st != os.EX_OK:
2062 - print(red("!!!") + " metadata.xml is invalid:")
2063 - for z in out.splitlines():
2064 - print(red("!!! ") + z)
2065 - stats["metadata.bad"] += 1
2066 - fails["metadata.bad"].append(x + "/metadata.xml")
2067 -
2068 - del metadata_bad
2069 - muselist = frozenset(musedict)
2070 -
2071 - changelog_path = os.path.join(checkdir_relative, "ChangeLog")
2072 - changelog_modified = changelog_path in modified_changelogs
2073 -
2074 - # detect unused local USE-descriptions
2075 - used_useflags = set()
2076 -
2077 - for y in ebuildlist:
2078 - relative_path = os.path.join(x, y + ".ebuild")
2079 - full_path = os.path.join(repodir, relative_path)
2080 - ebuild_path = y + ".ebuild"
2081 - if repolevel < 3:
2082 - ebuild_path = os.path.join(pkgdir, ebuild_path)
2083 - if repolevel < 2:
2084 - ebuild_path = os.path.join(catdir, ebuild_path)
2085 - ebuild_path = os.path.join(".", ebuild_path)
2086 - if check_changelog and not changelog_modified \
2087 - and ebuild_path in new_ebuilds:
2088 - stats['changelog.ebuildadded'] += 1
2089 - fails['changelog.ebuildadded'].append(relative_path)
2090 -
2091 - if vcs in ("cvs", "svn", "bzr") and check_ebuild_notadded and y not in eadded:
2092 - # ebuild not added to vcs
2093 - stats["ebuild.notadded"] += 1
2094 - fails["ebuild.notadded"].append(x + "/" + y + ".ebuild")
2095 - myesplit = portage.pkgsplit(y)
2096 - if myesplit is None or myesplit[0] != x.split("/")[-1] \
2097 - or pv_toolong_re.search(myesplit[1]) \
2098 - or pv_toolong_re.search(myesplit[2]):
2099 - stats["ebuild.invalidname"] += 1
2100 - fails["ebuild.invalidname"].append(x + "/" + y + ".ebuild")
2101 - continue
2102 - elif myesplit[0] != pkgdir:
2103 - print(pkgdir, myesplit[0])
2104 - stats["ebuild.namenomatch"] += 1
2105 - fails["ebuild.namenomatch"].append(x + "/" + y + ".ebuild")
2106 - continue
2107 -
2108 - pkg = pkgs[y]
2109 -
2110 - if pkg.invalid:
2111 - allvalid = False
2112 - for k, msgs in pkg.invalid.items():
2113 - for msg in msgs:
2114 - stats[k] += 1
2115 - fails[k].append("%s: %s" % (relative_path, msg))
2116 - continue
2117 -
2118 - myaux = pkg._metadata
2119 - eapi = myaux["EAPI"]
2120 - inherited = pkg.inherited
2121 - live_ebuild = live_eclasses.intersection(inherited)
2122 -
2123 - if repo_config.eapi_is_banned(eapi):
2124 - stats["repo.eapi.banned"] += 1
2125 - fails["repo.eapi.banned"].append(
2126 - "%s: %s" % (relative_path, eapi))
2127 -
2128 - elif repo_config.eapi_is_deprecated(eapi):
2129 - stats["repo.eapi.deprecated"] += 1
2130 - fails["repo.eapi.deprecated"].append(
2131 - "%s: %s" % (relative_path, eapi))
2132 -
2133 - for k, v in myaux.items():
2134 - if not isinstance(v, basestring):
2135 - continue
2136 - m = non_ascii_re.search(v)
2137 - if m is not None:
2138 - stats["variable.invalidchar"] += 1
2139 - fails["variable.invalidchar"].append(
2140 - ("%s: %s variable contains non-ASCII " + \
2141 - "character at position %s") % \
2142 - (relative_path, k, m.start() + 1))
2143 -
2144 - if not src_uri_error:
2145 - # Check that URIs don't reference a server from thirdpartymirrors.
2146 - for uri in portage.dep.use_reduce( \
2147 - myaux["SRC_URI"], matchall=True, is_src_uri=True, eapi=eapi, flat=True):
2148 - contains_mirror = False
2149 - for mirror, mirror_alias in thirdpartymirrors.items():
2150 - if uri.startswith(mirror):
2151 - contains_mirror = True
2152 - break
2153 - if not contains_mirror:
2154 - continue
2155 -
2156 - new_uri = "mirror://%s/%s" % (mirror_alias, uri[len(mirror):])
2157 - stats["SRC_URI.mirror"] += 1
2158 - fails["SRC_URI.mirror"].append(
2159 - "%s: '%s' found in thirdpartymirrors, use '%s'" % \
2160 - (relative_path, mirror, new_uri))
2161 -
2162 - if myaux.get("PROVIDE"):
2163 - stats["virtual.oldstyle"] += 1
2164 - fails["virtual.oldstyle"].append(relative_path)
2165 -
2166 - for pos, missing_var in enumerate(missingvars):
2167 - if not myaux.get(missing_var):
2168 - if catdir == "virtual" and \
2169 - missing_var in ("HOMEPAGE", "LICENSE"):
2170 - continue
2171 - if live_ebuild and missing_var == "KEYWORDS":
2172 - continue
2173 - myqakey = missingvars[pos] + ".missing"
2174 - stats[myqakey] += 1
2175 - fails[myqakey].append(x + "/" + y + ".ebuild")
2176 -
2177 - if catdir == "virtual":
2178 - for var in ("HOMEPAGE", "LICENSE"):
2179 - if myaux.get(var):
2180 - myqakey = var + ".virtual"
2181 - stats[myqakey] += 1
2182 - fails[myqakey].append(relative_path)
2183 -
2184 - # 14 is the length of DESCRIPTION=""
2185 - if len(myaux['DESCRIPTION']) > max_desc_len:
2186 - stats['DESCRIPTION.toolong'] += 1
2187 - fails['DESCRIPTION.toolong'].append(
2188 - "%s: DESCRIPTION is %d characters (max %d)" % \
2189 - (relative_path, len(myaux['DESCRIPTION']), max_desc_len))
2190 -
2191 - keywords = myaux["KEYWORDS"].split()
2192 - if not options.straight_to_stable:
2193 - stable_keywords = []
2194 - for keyword in keywords:
2195 - if not keyword.startswith("~") and \
2196 - not keyword.startswith("-"):
2197 - stable_keywords.append(keyword)
2198 - if stable_keywords:
2199 - if ebuild_path in new_ebuilds and catdir != "virtual":
2200 - stable_keywords.sort()
2201 - stats["KEYWORDS.stable"] += 1
2202 - fails["KEYWORDS.stable"].append(
2203 - relative_path + " added with stable keywords: %s" % \
2204 - " ".join(stable_keywords))
2205 -
2206 - ebuild_archs = set(kw.lstrip("~") for kw in keywords \
2207 - if not kw.startswith("-"))
2208 -
2209 - previous_keywords = slot_keywords.get(pkg.slot)
2210 - if previous_keywords is None:
2211 - slot_keywords[pkg.slot] = set()
2212 - elif ebuild_archs and "*" not in ebuild_archs and not live_ebuild:
2213 - dropped_keywords = previous_keywords.difference(ebuild_archs)
2214 - if dropped_keywords:
2215 - stats["KEYWORDS.dropped"] += 1
2216 - fails["KEYWORDS.dropped"].append(
2217 - relative_path + ": %s" % \
2218 - " ".join(sorted(dropped_keywords)))
2219 -
2220 - slot_keywords[pkg.slot].update(ebuild_archs)
2221 -
2222 - # KEYWORDS="-*" is a stupid replacement for package.mask and screws general KEYWORDS semantics
2223 - if "-*" in keywords:
2224 - haskeyword = False
2225 - for kw in keywords:
2226 - if kw[0] == "~":
2227 - kw = kw[1:]
2228 - if kw in kwlist:
2229 - haskeyword = True
2230 - if not haskeyword:
2231 - stats["KEYWORDS.stupid"] += 1
2232 - fails["KEYWORDS.stupid"].append(x + "/" + y + ".ebuild")
2233 -
2234 - """
2235 - Ebuilds that inherit a "Live" eclass (darcs,subversion,git,cvs,etc..) should
2236 - not be allowed to be marked stable
2237 - """
2238 - if live_ebuild and repo_config.name == "gentoo":
2239 - bad_stable_keywords = []
2240 - for keyword in keywords:
2241 - if not keyword.startswith("~") and \
2242 - not keyword.startswith("-"):
2243 - bad_stable_keywords.append(keyword)
2244 - del keyword
2245 - if bad_stable_keywords:
2246 - stats["LIVEVCS.stable"] += 1
2247 - fails["LIVEVCS.stable"].append(
2248 - x + "/" + y + ".ebuild with stable keywords:%s " % \
2249 - bad_stable_keywords)
2250 - del bad_stable_keywords
2251 -
2252 - if keywords and not has_global_mask(pkg):
2253 - stats["LIVEVCS.unmasked"] += 1
2254 - fails["LIVEVCS.unmasked"].append(relative_path)
2255 -
2256 - if options.ignore_arches:
2257 - arches = [[repoman_settings["ARCH"], repoman_settings["ARCH"],
2258 - repoman_settings["ACCEPT_KEYWORDS"].split()]]
2259 - else:
2260 - arches = set()
2261 - for keyword in keywords:
2262 - if keyword[0] == "-":
2263 - continue
2264 - elif keyword[0] == "~":
2265 - arch = keyword[1:]
2266 - if arch == "*":
2267 - for expanded_arch in profiles:
2268 - if expanded_arch == "**":
2269 - continue
2270 - arches.add((keyword, expanded_arch,
2271 - (expanded_arch, "~" + expanded_arch)))
2272 - else:
2273 - arches.add((keyword, arch, (arch, keyword)))
2274 - else:
2275 - if keyword == "*":
2276 - for expanded_arch in profiles:
2277 - if expanded_arch == "**":
2278 - continue
2279 - arches.add((keyword, expanded_arch,
2280 - (expanded_arch,)))
2281 - else:
2282 - arches.add((keyword, keyword, (keyword,)))
2283 - if not arches:
2284 - # Use an empty profile for checking dependencies of
2285 - # packages that have empty KEYWORDS.
2286 - arches.add(('**', '**', ('**',)))
2287 -
2288 - unknown_pkgs = set()
2289 - baddepsyntax = False
2290 - badlicsyntax = False
2291 - badprovsyntax = False
2292 - catpkg = catdir + "/" + y
2293 -
2294 - inherited_java_eclass = "java-pkg-2" in inherited or \
2295 - "java-pkg-opt-2" in inherited
2296 - inherited_wxwidgets_eclass = "wxwidgets" in inherited
2297 - operator_tokens = set(["||", "(", ")"])
2298 - type_list, badsyntax = [], []
2299 - for mytype in Package._dep_keys + ("LICENSE", "PROPERTIES", "PROVIDE"):
2300 - mydepstr = myaux[mytype]
2301 -
2302 - buildtime = mytype in Package._buildtime_keys
2303 - runtime = mytype in Package._runtime_keys
2304 - token_class = None
2305 - if mytype.endswith("DEPEND"):
2306 - token_class = portage.dep.Atom
2307 -
2308 - try:
2309 - atoms = portage.dep.use_reduce(mydepstr, matchall=1, flat=True, \
2310 - is_valid_flag=pkg.iuse.is_valid_flag, token_class=token_class)
2311 - except portage.exception.InvalidDependString as e:
2312 - atoms = None
2313 - badsyntax.append(str(e))
2314 -
2315 - if atoms and mytype.endswith("DEPEND"):
2316 - if runtime and \
2317 - "test?" in mydepstr.split():
2318 - stats[mytype + '.suspect'] += 1
2319 - fails[mytype + '.suspect'].append(relative_path + \
2320 - ": 'test?' USE conditional in %s" % mytype)
2321 -
2322 - for atom in atoms:
2323 - if atom == "||":
2324 - continue
2325 -
2326 - is_blocker = atom.blocker
2327 -
2328 - # Skip dependency.unknown for blockers, so that we
2329 - # don't encourage people to remove necessary blockers,
2330 - # as discussed in bug 382407. We use atom.without_use
2331 - # due to bug 525376.
2332 - if not is_blocker and \
2333 - not portdb.xmatch("match-all", atom.without_use) and \
2334 - not atom.cp.startswith("virtual/"):
2335 - unknown_pkgs.add((mytype, atom.unevaluated_atom))
2336 -
2337 - if catdir != "virtual":
2338 - if not is_blocker and \
2339 - atom.cp in suspect_virtual:
2340 - stats['virtual.suspect'] += 1
2341 - fails['virtual.suspect'].append(
2342 - relative_path +
2343 - ": %s: consider using '%s' instead of '%s'" %
2344 - (mytype, suspect_virtual[atom.cp], atom))
2345 - if not is_blocker and \
2346 - atom.cp.startswith("perl-core/"):
2347 - stats['dependency.perlcore'] += 1
2348 - fails['dependency.perlcore'].append(
2349 - relative_path +
2350 - ": %s: please use '%s' instead of '%s'" %
2351 - (mytype, atom.replace("perl-core/","virtual/perl-"), atom))
2352 -
2353 - if buildtime and \
2354 - not is_blocker and \
2355 - not inherited_java_eclass and \
2356 - atom.cp == "virtual/jdk":
2357 - stats['java.eclassesnotused'] += 1
2358 - fails['java.eclassesnotused'].append(relative_path)
2359 - elif buildtime and \
2360 - not is_blocker and \
2361 - not inherited_wxwidgets_eclass and \
2362 - atom.cp == "x11-libs/wxGTK":
2363 - stats['wxwidgets.eclassnotused'] += 1
2364 - fails['wxwidgets.eclassnotused'].append(
2365 - (relative_path + ": %ss on x11-libs/wxGTK"
2366 - " without inheriting wxwidgets.eclass") % mytype)
2367 - elif runtime:
2368 - if not is_blocker and \
2369 - atom.cp in suspect_rdepend:
2370 - stats[mytype + '.suspect'] += 1
2371 - fails[mytype + '.suspect'].append(
2372 - relative_path + ": '%s'" % atom)
2373 -
2374 - if atom.operator == "~" and \
2375 - portage.versions.catpkgsplit(atom.cpv)[3] != "r0":
2376 - qacat = 'dependency.badtilde'
2377 - stats[qacat] += 1
2378 - fails[qacat].append(
2379 - (relative_path + ": %s uses the ~ operator"
2380 - " with a non-zero revision:" + \
2381 - " '%s'") % (mytype, atom))
2382 -
2383 - check_missingslot(atom, mytype, eapi, portdb, stats, fails,
2384 - relative_path, myaux)
2385 -
2386 - type_list.extend([mytype] * (len(badsyntax) - len(type_list)))
2387 -
2388 - for m, b in zip(type_list, badsyntax):
2389 - if m.endswith("DEPEND"):
2390 - qacat = "dependency.syntax"
2391 - else:
2392 - qacat = m + ".syntax"
2393 - stats[qacat] += 1
2394 - fails[qacat].append("%s: %s: %s" % (relative_path, m, b))
2395 -
2396 - badlicsyntax = len([z for z in type_list if z == "LICENSE"])
2397 - badprovsyntax = len([z for z in type_list if z == "PROVIDE"])
2398 - baddepsyntax = len(type_list) != badlicsyntax + badprovsyntax
2399 - badlicsyntax = badlicsyntax > 0
2400 - badprovsyntax = badprovsyntax > 0
2401 -
2402 - # uselist checks - global
2403 - myuse = []
2404 - default_use = []
2405 - for myflag in myaux["IUSE"].split():
2406 - flag_name = myflag.lstrip("+-")
2407 - used_useflags.add(flag_name)
2408 - if myflag != flag_name:
2409 - default_use.append(myflag)
2410 - if flag_name not in uselist:
2411 - myuse.append(flag_name)
2412 -
2413 - # uselist checks - metadata
2414 - for mypos in range(len(myuse)-1, -1, -1):
2415 - if myuse[mypos] and (myuse[mypos] in muselist):
2416 - del myuse[mypos]
2417 -
2418 - if default_use and not eapi_has_iuse_defaults(eapi):
2419 - for myflag in default_use:
2420 - stats['EAPI.incompatible'] += 1
2421 - fails['EAPI.incompatible'].append(
2422 - (relative_path + ": IUSE defaults" + \
2423 - " not supported with EAPI='%s':" + \
2424 - " '%s'") % (eapi, myflag))
2425 -
2426 - for mypos in range(len(myuse)):
2427 - stats["IUSE.invalid"] += 1
2428 - fails["IUSE.invalid"].append(x + "/" + y + ".ebuild: %s" % myuse[mypos])
2429 -
2430 - # Check for outdated RUBY targets
2431 - if "ruby-ng" in inherited or "ruby-fakegem" in inherited or "ruby" in inherited:
2432 - ruby_intersection = pkg.iuse.all.intersection(ruby_deprecated)
2433 - if ruby_intersection:
2434 - for myruby in ruby_intersection:
2435 - stats["IUSE.rubydeprecated"] += 1
2436 - fails["IUSE.rubydeprecated"].append(
2437 - (relative_path + ": Deprecated ruby target: %s") % myruby)
2438 -
2439 - # license checks
2440 - if not badlicsyntax:
2441 - # Parse the LICENSE variable, remove USE conditions and
2442 - # flatten it.
2443 - licenses = portage.dep.use_reduce(myaux["LICENSE"], matchall=1, flat=True)
2444 - # Check each entry to ensure that it exists in PORTDIR's
2445 - # license directory.
2446 - for lic in licenses:
2447 - # Need to check for "||" manually as no portage
2448 - # function will remove it without removing values.
2449 - if lic not in liclist and lic != "||":
2450 - stats["LICENSE.invalid"] += 1
2451 - fails["LICENSE.invalid"].append(x + "/" + y + ".ebuild: %s" % lic)
2452 - elif lic in liclist_deprecated:
2453 - stats["LICENSE.deprecated"] += 1
2454 - fails["LICENSE.deprecated"].append("%s: %s" % (relative_path, lic))
2455 -
2456 - # keyword checks
2457 - myuse = myaux["KEYWORDS"].split()
2458 - for mykey in myuse:
2459 - if mykey not in ("-*", "*", "~*"):
2460 - myskey = mykey
2461 - if myskey[:1] == "-":
2462 - myskey = myskey[1:]
2463 - if myskey[:1] == "~":
2464 - myskey = myskey[1:]
2465 - if myskey not in kwlist:
2466 - stats["KEYWORDS.invalid"] += 1
2467 - fails["KEYWORDS.invalid"].append(x + "/" + y + ".ebuild: %s" % mykey)
2468 - elif myskey not in profiles:
2469 - stats["KEYWORDS.invalid"] += 1
2470 - fails["KEYWORDS.invalid"].append(x + "/" + y + ".ebuild: %s (profile invalid)" % mykey)
2471 -
2472 - # restrict checks
2473 - myrestrict = None
2474 - try:
2475 - myrestrict = portage.dep.use_reduce(myaux["RESTRICT"], matchall=1, flat=True)
2476 - except portage.exception.InvalidDependString as e:
2477 - stats["RESTRICT.syntax"] += 1
2478 - fails["RESTRICT.syntax"].append(
2479 - "%s: RESTRICT: %s" % (relative_path, e))
2480 - del e
2481 - if myrestrict:
2482 - myrestrict = set(myrestrict)
2483 - mybadrestrict = myrestrict.difference(valid_restrict)
2484 - if mybadrestrict:
2485 - stats["RESTRICT.invalid"] += len(mybadrestrict)
2486 - for mybad in mybadrestrict:
2487 - fails["RESTRICT.invalid"].append(x + "/" + y + ".ebuild: %s" % mybad)
2488 - # REQUIRED_USE check
2489 - required_use = myaux["REQUIRED_USE"]
2490 - if required_use:
2491 - if not eapi_has_required_use(eapi):
2492 - stats['EAPI.incompatible'] += 1
2493 - fails['EAPI.incompatible'].append(
2494 - relative_path + ": REQUIRED_USE" + \
2495 - " not supported with EAPI='%s'" % (eapi,))
2496 - try:
2497 - portage.dep.check_required_use(required_use, (),
2498 - pkg.iuse.is_valid_flag, eapi=eapi)
2499 - except portage.exception.InvalidDependString as e:
2500 - stats["REQUIRED_USE.syntax"] += 1
2501 - fails["REQUIRED_USE.syntax"].append(
2502 - "%s: REQUIRED_USE: %s" % (relative_path, e))
2503 - del e
2504 -
2505 - # Syntax Checks
2506 - relative_path = os.path.join(x, y + ".ebuild")
2507 - full_path = os.path.join(repodir, relative_path)
2508 - if not vcs_preserves_mtime:
2509 - if ebuild_path not in new_ebuilds and \
2510 - ebuild_path not in modified_ebuilds:
2511 - pkg.mtime = None
2512 - try:
2513 - # All ebuilds should have utf_8 encoding.
2514 - f = io.open(_unicode_encode(full_path,
2515 - encoding=_encodings['fs'], errors='strict'),
2516 - mode='r', encoding=_encodings['repo.content'])
2517 - try:
2518 - for check_name, e in run_checks(f, pkg):
2519 - stats[check_name] += 1
2520 - fails[check_name].append(relative_path + ': %s' % e)
2521 - finally:
2522 - f.close()
2523 - except UnicodeDecodeError:
2524 - # A file.UTF8 failure will have already been recorded above.
2525 - pass
2526 -
2527 - if options.force:
2528 - # The dep_check() calls are the most expensive QA test. If --force
2529 - # is enabled, there's no point in wasting time on these since the
2530 - # user is intent on forcing the commit anyway.
2531 - continue
2532 -
2533 - relevant_profiles = []
2534 - for keyword, arch, groups in arches:
2535 - if arch not in profiles:
2536 - # A missing profile will create an error further down
2537 - # during the KEYWORDS verification.
2538 - continue
2539 -
2540 - if include_arches is not None:
2541 - if arch not in include_arches:
2542 - continue
2543 -
2544 - relevant_profiles.extend((keyword, groups, prof)
2545 - for prof in profiles[arch])
2546 -
2547 - def sort_key(item):
2548 - return item[2].sub_path
2549 -
2550 - relevant_profiles.sort(key=sort_key)
2551 -
2552 - for keyword, groups, prof in relevant_profiles:
2553 -
2554 - if not (prof.status == "stable" or \
2555 - (prof.status == "dev" and options.include_dev) or \
2556 - (prof.status == "exp" and options.include_exp_profiles == 'y')):
2557 - continue
2558 -
2559 - dep_settings = arch_caches.get(prof.sub_path)
2560 - if dep_settings is None:
2561 - dep_settings = portage.config(
2562 - config_profile_path=prof.abs_path,
2563 - config_incrementals=repoman_incrementals,
2564 - config_root=config_root,
2565 - local_config=False,
2566 - _unmatched_removal=options.unmatched_removal,
2567 - env=env, repositories=repoman_settings.repositories)
2568 - dep_settings.categories = repoman_settings.categories
2569 - if options.without_mask:
2570 - dep_settings._mask_manager_obj = \
2571 - copy.deepcopy(dep_settings._mask_manager)
2572 - dep_settings._mask_manager._pmaskdict.clear()
2573 - arch_caches[prof.sub_path] = dep_settings
2574 -
2575 - xmatch_cache_key = (prof.sub_path, tuple(groups))
2576 - xcache = arch_xmatch_caches.get(xmatch_cache_key)
2577 - if xcache is None:
2578 - portdb.melt()
2579 - portdb.freeze()
2580 - xcache = portdb.xcache
2581 - xcache.update(shared_xmatch_caches)
2582 - arch_xmatch_caches[xmatch_cache_key] = xcache
2583 -
2584 - trees[root]["porttree"].settings = dep_settings
2585 - portdb.settings = dep_settings
2586 - portdb.xcache = xcache
2587 -
2588 - dep_settings["ACCEPT_KEYWORDS"] = " ".join(groups)
2589 - # just in case, prevent config.reset() from nuking these.
2590 - dep_settings.backup_changes("ACCEPT_KEYWORDS")
2591 -
2592 - # This attribute is used in dbapi._match_use() to apply
2593 - # use.stable.{mask,force} settings based on the stable
2594 - # status of the parent package. This is required in order
2595 - # for USE deps of unstable packages to be resolved correctly,
2596 - # since otherwise use.stable.{mask,force} settings of
2597 - # dependencies may conflict (see bug #456342).
2598 - dep_settings._parent_stable = dep_settings._isStable(pkg)
2599 -
2600 - # Handle package.use*.{force,mask) calculation, for use
2601 - # in dep_check.
2602 - dep_settings.useforce = dep_settings._use_manager.getUseForce(
2603 - pkg, stable=dep_settings._parent_stable)
2604 - dep_settings.usemask = dep_settings._use_manager.getUseMask(
2605 - pkg, stable=dep_settings._parent_stable)
2606 -
2607 - if not baddepsyntax:
2608 - ismasked = not ebuild_archs or \
2609 - pkg.cpv not in portdb.xmatch("match-visible",
2610 - Atom("%s::%s" % (pkg.cp, repo_config.name)))
2611 - if ismasked:
2612 - if not have_pmasked:
2613 - have_pmasked = bool(dep_settings._getMaskAtom(
2614 - pkg.cpv, pkg._metadata))
2615 - if options.ignore_masked:
2616 - continue
2617 - # we are testing deps for a masked package; give it some lee-way
2618 - suffix = "masked"
2619 - matchmode = "minimum-all"
2620 - else:
2621 - suffix = ""
2622 - matchmode = "minimum-visible"
2623 -
2624 - if not have_dev_keywords:
2625 - have_dev_keywords = \
2626 - bool(dev_keywords.intersection(keywords))
2627 -
2628 - if prof.status == "dev":
2629 - suffix = suffix + "indev"
2630 -
2631 - for mytype in Package._dep_keys:
2632 -
2633 - mykey = "dependency.bad" + suffix
2634 - myvalue = myaux[mytype]
2635 - if not myvalue:
2636 - continue
2637 -
2638 - success, atoms = portage.dep_check(myvalue, portdb,
2639 - dep_settings, use="all", mode=matchmode,
2640 - trees=trees)
2641 -
2642 - if success:
2643 - if atoms:
2644 -
2645 - # Don't bother with dependency.unknown for
2646 - # cases in which *DEPEND.bad is triggered.
2647 - for atom in atoms:
2648 - # dep_check returns all blockers and they
2649 - # aren't counted for *DEPEND.bad, so we
2650 - # ignore them here.
2651 - if not atom.blocker:
2652 - unknown_pkgs.discard(
2653 - (mytype, atom.unevaluated_atom))
2654 -
2655 - if not prof.sub_path:
2656 - # old-style virtuals currently aren't
2657 - # resolvable with empty profile, since
2658 - # 'virtuals' mappings are unavailable
2659 - # (it would be expensive to search
2660 - # for PROVIDE in all ebuilds)
2661 - atoms = [atom for atom in atoms if not \
2662 - (atom.cp.startswith('virtual/') and \
2663 - not portdb.cp_list(atom.cp))]
2664 -
2665 - # we have some unsolvable deps
2666 - # remove ! deps, which always show up as unsatisfiable
2667 - atoms = [str(atom.unevaluated_atom) \
2668 - for atom in atoms if not atom.blocker]
2669 -
2670 - # if we emptied out our list, continue:
2671 - if not atoms:
2672 - continue
2673 - stats[mykey] += 1
2674 - fails[mykey].append("%s: %s: %s(%s)\n%s" % \
2675 - (relative_path, mytype, keyword,
2676 - prof, pformat(atoms, indent=6)))
2677 - else:
2678 - stats[mykey] += 1
2679 - fails[mykey].append("%s: %s: %s(%s)\n%s" % \
2680 - (relative_path, mytype, keyword,
2681 - prof, pformat(atoms, indent=6)))
2682 -
2683 - if not baddepsyntax and unknown_pkgs:
2684 - type_map = {}
2685 - for mytype, atom in unknown_pkgs:
2686 - type_map.setdefault(mytype, set()).add(atom)
2687 - for mytype, atoms in type_map.items():
2688 - stats["dependency.unknown"] += 1
2689 - fails["dependency.unknown"].append("%s: %s: %s" %
2690 - (relative_path, mytype, ", ".join(sorted(atoms))))
2691 -
2692 - # check if there are unused local USE-descriptions in metadata.xml
2693 - # (unless there are any invalids, to avoid noise)
2694 - if allvalid:
2695 - for myflag in muselist.difference(used_useflags):
2696 - stats["metadata.warning"] += 1
2697 - fails["metadata.warning"].append(
2698 - "%s/metadata.xml: unused local USE-description: '%s'" % \
2699 - (x, myflag))
2700 -
2701 - if options.if_modified == "y" and len(effective_scanlist) < 1:
2702 - logging.warning("--if-modified is enabled, but no modified packages were found!")
2703 -
2704 - if options.mode == "manifest":
2705 - sys.exit(dofail)
2706 -
2707 - # dofail will be set to 1 if we have failed in at least one non-warning category
2708 - dofail = 0
2709 - # dowarn will be set to 1 if we tripped any warnings
2710 - dowarn = 0
2711 - # dofull will be set if we should print a "repoman full" informational message
2712 - dofull = options.mode != 'full'
2713 -
2714 - for x in qacats:
2715 - if not stats[x]:
2716 - continue
2717 - dowarn = 1
2718 - if x not in qawarnings:
2719 - dofail = 1
2720 -
2721 - if dofail or \
2722 - (dowarn and not (options.quiet or options.mode == "scan")):
2723 - dofull = 0
2724 -
2725 - # Save QA output so that it can be conveniently displayed
2726 - # in $EDITOR while the user creates a commit message.
2727 - # Otherwise, the user would not be able to see this output
2728 - # once the editor has taken over the screen.
2729 - qa_output = io.StringIO()
2730 - style_file = ConsoleStyleFile(sys.stdout)
2731 - if options.mode == 'commit' and \
2732 - (not commitmessage or not commitmessage.strip()):
2733 - style_file.write_listener = qa_output
2734 - console_writer = StyleWriter(file=style_file, maxcol=9999)
2735 - console_writer.style_listener = style_file.new_styles
2736 -
2737 - f = formatter.AbstractFormatter(console_writer)
2738 -
2739 - format_outputs = {
2740 - 'column': utilities.format_qa_output_column,
2741 - 'default': utilities.format_qa_output
2742 - }
2743 -
2744 - format_output = format_outputs.get(options.output_style,
2745 - format_outputs['default'])
2746 - format_output(f, stats, fails, dofull, dofail, options, qawarnings)
2747 -
2748 - style_file.flush()
2749 - del console_writer, f, style_file
2750 - qa_output = qa_output.getvalue()
2751 - qa_output = qa_output.splitlines(True)
2752 -
2753 - suggest_ignore_masked = False
2754 - suggest_include_dev = False
2755 -
2756 - if have_pmasked and not (options.without_mask or options.ignore_masked):
2757 - suggest_ignore_masked = True
2758 - if have_dev_keywords and not options.include_dev:
2759 - suggest_include_dev = True
2760 -
2761 - if suggest_ignore_masked or suggest_include_dev:
2762 - print()
2763 - if suggest_ignore_masked:
2764 - print(bold("Note: use --without-mask to check " + \
2765 - "KEYWORDS on dependencies of masked packages"))
2766 -
2767 - if suggest_include_dev:
2768 - print(bold("Note: use --include-dev (-d) to check " + \
2769 - "dependencies for 'dev' profiles"))
2770 - print()
2771 -
2772 - if options.mode != 'commit':
2773 - if dofull:
2774 - print(bold("Note: type \"repoman full\" for a complete listing."))
2775 - if dowarn and not dofail:
2776 - print(green("RepoMan sez:"),"\"You're only giving me a partial QA payment?\n I'll take it this time, but I'm not happy.\"")
2777 - elif not dofail:
2778 - print(green("RepoMan sez:"),"\"If everyone were like you, I'd be out of business!\"")
2779 - elif dofail:
2780 - print(bad("Please fix these important QA issues first."))
2781 - print(green("RepoMan sez:"),"\"Make your QA payment on time and you'll never see the likes of me.\"\n")
2782 + repoman_main(sys.argv[1:])
2783 + except IOError as e:
2784 + if e.errno == errno.EACCES:
2785 + print("\nRepoman: Need user access")
2786 sys.exit(1)
2787 - else:
2788 - if dofail and can_force and options.force and not options.pretend:
2789 - print(green("RepoMan sez:") + \
2790 - " \"You want to commit even with these QA issues?\n" + \
2791 - " I'll take it this time, but I'm not happy.\"\n")
2792 - elif dofail:
2793 - if options.force and not can_force:
2794 - print(bad("The --force option has been disabled due to extraordinary issues."))
2795 - print(bad("Please fix these important QA issues first."))
2796 - print(green("RepoMan sez:"),"\"Make your QA payment on time and you'll never see the likes of me.\"\n")
2797 - sys.exit(1)
2798 -
2799 - if options.pretend:
2800 - print(green("RepoMan sez:"), "\"So, you want to play it safe. Good call.\"\n")
2801 -
2802 - myunadded = []
2803 - if vcs == "cvs":
2804 - try:
2805 - myvcstree = portage.cvstree.getentries("./", recursive=1)
2806 - myunadded = portage.cvstree.findunadded(myvcstree, recursive=1, basedir="./")
2807 - except SystemExit as e:
2808 - raise # TODO propagate this
2809 - except:
2810 - err("Error retrieving CVS tree; exiting.")
2811 - if vcs == "svn":
2812 - try:
2813 - with repoman_popen("svn status --no-ignore") as f:
2814 - svnstatus = f.readlines()
2815 - myunadded = ["./" + elem.rstrip().split()[1] for elem in svnstatus if elem.startswith("?") or elem.startswith("I")]
2816 - except SystemExit as e:
2817 - raise # TODO propagate this
2818 - except:
2819 - err("Error retrieving SVN info; exiting.")
2820 - if vcs == "git":
2821 - # get list of files not under version control or missing
2822 - myf = repoman_popen("git ls-files --others")
2823 - myunadded = ["./" + elem[:-1] for elem in myf]
2824 - myf.close()
2825 - if vcs == "bzr":
2826 - try:
2827 - with repoman_popen("bzr status -S .") as f:
2828 - bzrstatus = f.readlines()
2829 - myunadded = ["./" + elem.rstrip().split()[1].split('/')[-1:][0] for elem in bzrstatus if elem.startswith("?") or elem[0:2] == " D"]
2830 - except SystemExit as e:
2831 - raise # TODO propagate this
2832 - except:
2833 - err("Error retrieving bzr info; exiting.")
2834 - if vcs == "hg":
2835 - with repoman_popen("hg status --no-status --unknown .") as f:
2836 - myunadded = f.readlines()
2837 - myunadded = ["./" + elem.rstrip() for elem in myunadded]
2838 -
2839 - # Mercurial doesn't handle manually deleted files as removed from
2840 - # the repository, so the user need to remove them before commit,
2841 - # using "hg remove [FILES]"
2842 - with repoman_popen("hg status --no-status --deleted .") as f:
2843 - mydeleted = f.readlines()
2844 - mydeleted = ["./" + elem.rstrip() for elem in mydeleted]
2845 -
2846 -
2847 - myautoadd = []
2848 - if myunadded:
2849 - for x in range(len(myunadded)-1, -1, -1):
2850 - xs = myunadded[x].split("/")
2851 - if xs[-1] == "files":
2852 - print("!!! files dir is not added! Please correct this.")
2853 - sys.exit(-1)
2854 - elif xs[-1] == "Manifest":
2855 - # It's a manifest... auto add
2856 - myautoadd += [myunadded[x]]
2857 - del myunadded[x]
2858 -
2859 - if myunadded:
2860 - print(red("!!! The following files are in your local tree but are not added to the master"))
2861 - print(red("!!! tree. Please remove them from the local tree or add them to the master tree."))
2862 - for x in myunadded:
2863 - print(" ", x)
2864 - print()
2865 - print()
2866 - sys.exit(1)
2867 -
2868 - if vcs == "hg" and mydeleted:
2869 - print(red("!!! The following files are removed manually from your local tree but are not"))
2870 - print(red("!!! removed from the repository. Please remove them, using \"hg remove [FILES]\"."))
2871 - for x in mydeleted:
2872 - print(" ", x)
2873 - print()
2874 - print()
2875 - sys.exit(1)
2876 -
2877 - if vcs == "cvs":
2878 - mycvstree = cvstree.getentries("./", recursive=1)
2879 - mychanged = cvstree.findchanged(mycvstree, recursive=1, basedir="./")
2880 - mynew = cvstree.findnew(mycvstree, recursive=1, basedir="./")
2881 - myremoved = portage.cvstree.findremoved(mycvstree, recursive=1, basedir="./")
2882 - bin_blob_pattern = re.compile("^-kb$")
2883 - no_expansion = set(portage.cvstree.findoption(mycvstree, bin_blob_pattern,
2884 - recursive=1, basedir="./"))
2885 -
2886 - if vcs == "svn":
2887 - with repoman_popen("svn status") as f:
2888 - svnstatus = f.readlines()
2889 - mychanged = ["./" + elem.split()[-1:][0] for elem in svnstatus if (elem[:1] in "MR" or elem[1:2] in "M")]
2890 - mynew = ["./" + elem.split()[-1:][0] for elem in svnstatus if elem.startswith("A")]
2891 - myremoved = ["./" + elem.split()[-1:][0] for elem in svnstatus if elem.startswith("D")]
2892 -
2893 - # Subversion expands keywords specified in svn:keywords properties.
2894 - with repoman_popen("svn propget -R svn:keywords") as f:
2895 - props = f.readlines()
2896 - expansion = dict(("./" + prop.split(" - ")[0], prop.split(" - ")[1].split()) \
2897 - for prop in props if " - " in prop)
2898 -
2899 - elif vcs == "git":
2900 - with repoman_popen("git diff-index --name-only "
2901 - "--relative --diff-filter=M HEAD") as f:
2902 - mychanged = f.readlines()
2903 - mychanged = ["./" + elem[:-1] for elem in mychanged]
2904 -
2905 - with repoman_popen("git diff-index --name-only "
2906 - "--relative --diff-filter=A HEAD") as f:
2907 - mynew = f.readlines()
2908 - mynew = ["./" + elem[:-1] for elem in mynew]
2909 -
2910 - with repoman_popen("git diff-index --name-only "
2911 - "--relative --diff-filter=D HEAD") as f:
2912 - myremoved = f.readlines()
2913 - myremoved = ["./" + elem[:-1] for elem in myremoved]
2914 -
2915 - if vcs == "bzr":
2916 - with repoman_popen("bzr status -S .") as f:
2917 - bzrstatus = f.readlines()
2918 - mychanged = ["./" + elem.split()[-1:][0].split('/')[-1:][0] for elem in bzrstatus if elem and elem[1:2] == "M"]
2919 - mynew = ["./" + elem.split()[-1:][0].split('/')[-1:][0] for elem in bzrstatus if elem and (elem[1:2] in "NK" or elem[0:1] == "R")]
2920 - myremoved = ["./" + elem.split()[-1:][0].split('/')[-1:][0] for elem in bzrstatus if elem.startswith("-")]
2921 - myremoved = ["./" + elem.split()[-3:-2][0].split('/')[-1:][0] for elem in bzrstatus if elem and (elem[1:2] == "K" or elem[0:1] == "R")]
2922 - # Bazaar expands nothing.
2923 -
2924 - if vcs == "hg":
2925 - with repoman_popen("hg status --no-status --modified .") as f:
2926 - mychanged = f.readlines()
2927 - mychanged = ["./" + elem.rstrip() for elem in mychanged]
2928 -
2929 - with repoman_popen("hg status --no-status --added .") as f:
2930 - mynew = f.readlines()
2931 - mynew = ["./" + elem.rstrip() for elem in mynew]
2932 -
2933 - with repoman_popen("hg status --no-status --removed .") as f:
2934 - myremoved = f.readlines()
2935 - myremoved = ["./" + elem.rstrip() for elem in myremoved]
2936 -
2937 - if vcs:
2938 - if not (mychanged or mynew or myremoved or (vcs == "hg" and mydeleted)):
2939 - print(green("RepoMan sez:"), "\"Doing nothing is not always good for QA.\"")
2940 - print()
2941 - print("(Didn't find any changed files...)")
2942 - print()
2943 - sys.exit(1)
2944 -
2945 - # Manifests need to be regenerated after all other commits, so don't commit
2946 - # them now even if they have changed.
2947 - mymanifests = set()
2948 - myupdates = set()
2949 - for f in mychanged + mynew:
2950 - if "Manifest" == os.path.basename(f):
2951 - mymanifests.add(f)
2952 - else:
2953 - myupdates.add(f)
2954 - myupdates.difference_update(myremoved)
2955 - myupdates = list(myupdates)
2956 - mymanifests = list(mymanifests)
2957 - myheaders = []
2958 - mydirty = []
2959 -
2960 - commitmessage = options.commitmsg
2961 - if options.commitmsgfile:
2962 - try:
2963 - f = io.open(_unicode_encode(options.commitmsgfile,
2964 - encoding=_encodings['fs'], errors='strict'),
2965 - mode='r', encoding=_encodings['content'], errors='replace')
2966 - commitmessage = f.read()
2967 - f.close()
2968 - del f
2969 - except (IOError, OSError) as e:
2970 - if e.errno == errno.ENOENT:
2971 - portage.writemsg("!!! File Not Found: --commitmsgfile='%s'\n" % options.commitmsgfile)
2972 - else:
2973 - raise
2974 - # We've read the content so the file is no longer needed.
2975 - commitmessagefile = None
2976 - if not commitmessage or not commitmessage.strip():
2977 - try:
2978 - editor = os.environ.get("EDITOR")
2979 - if editor and utilities.editor_is_executable(editor):
2980 - commitmessage = utilities.get_commit_message_with_editor(
2981 - editor, message=qa_output)
2982 - else:
2983 - commitmessage = utilities.get_commit_message_with_stdin()
2984 - except KeyboardInterrupt:
2985 - exithandler()
2986 - if not commitmessage or not commitmessage.strip():
2987 - print("* no commit message? aborting commit.")
2988 - sys.exit(1)
2989 - commitmessage = commitmessage.rstrip()
2990 - changelog_msg = commitmessage
2991 - portage_version = getattr(portage, "VERSION", None)
2992 - gpg_key = repoman_settings.get("PORTAGE_GPG_KEY", "")
2993 - dco_sob = repoman_settings.get("DCO_SIGNED_OFF_BY", "")
2994 - if portage_version is None:
2995 - sys.stderr.write("Failed to insert portage version in message!\n")
2996 - sys.stderr.flush()
2997 - portage_version = "Unknown"
2998 -
2999 - report_options = []
3000 - if options.force:
3001 - report_options.append("--force")
3002 - if options.ignore_arches:
3003 - report_options.append("--ignore-arches")
3004 - if include_arches is not None:
3005 - report_options.append("--include-arches=\"%s\"" %
3006 - " ".join(sorted(include_arches)))
3007 -
3008 - if vcs == "git":
3009 - # Use new footer only for git (see bug #438364).
3010 - commit_footer = "\n\nPackage-Manager: portage-%s" % portage_version
3011 - if report_options:
3012 - commit_footer += "\nRepoMan-Options: " + " ".join(report_options)
3013 - if sign_manifests:
3014 - commit_footer += "\nManifest-Sign-Key: %s" % (gpg_key, )
3015 - if dco_sob:
3016 - commit_footer += "\nSigned-off-by: %s" % (dco_sob, )
3017 - else:
3018 - unameout = platform.system() + " "
3019 - if platform.system() in ["Darwin", "SunOS"]:
3020 - unameout += platform.processor()
3021 - else:
3022 - unameout += platform.machine()
3023 - commit_footer = "\n\n"
3024 - if dco_sob:
3025 - commit_footer += "Signed-off-by: %s\n" % (dco_sob, )
3026 - commit_footer += "(Portage version: %s/%s/%s" % \
3027 - (portage_version, vcs, unameout)
3028 - if report_options:
3029 - commit_footer += ", RepoMan options: " + " ".join(report_options)
3030 - if sign_manifests:
3031 - commit_footer += ", signed Manifest commit with key %s" % \
3032 - (gpg_key, )
3033 - else:
3034 - commit_footer += ", unsigned Manifest commit"
3035 - commit_footer += ")"
3036 -
3037 - commitmessage += commit_footer
3038 -
3039 - broken_changelog_manifests = []
3040 - if options.echangelog in ('y', 'force'):
3041 - logging.info("checking for unmodified ChangeLog files")
3042 - committer_name = utilities.get_committer_name(env=repoman_settings)
3043 - for x in sorted(vcs_files_to_cps(
3044 - chain(myupdates, mymanifests, myremoved))):
3045 - catdir, pkgdir = x.split("/")
3046 - checkdir = repodir + "/" + x
3047 - checkdir_relative = ""
3048 - if repolevel < 3:
3049 - checkdir_relative = os.path.join(pkgdir, checkdir_relative)
3050 - if repolevel < 2:
3051 - checkdir_relative = os.path.join(catdir, checkdir_relative)
3052 - checkdir_relative = os.path.join(".", checkdir_relative)
3053 -
3054 - changelog_path = os.path.join(checkdir_relative, "ChangeLog")
3055 - changelog_modified = changelog_path in modified_changelogs
3056 - if changelog_modified and options.echangelog != 'force':
3057 - continue
3058 -
3059 - # get changes for this package
3060 - cdrlen = len(checkdir_relative)
3061 - clnew = [elem[cdrlen:] for elem in mynew if elem.startswith(checkdir_relative)]
3062 - clremoved = [elem[cdrlen:] for elem in myremoved if elem.startswith(checkdir_relative)]
3063 - clchanged = [elem[cdrlen:] for elem in mychanged if elem.startswith(checkdir_relative)]
3064 -
3065 - # Skip ChangeLog generation if only the Manifest was modified,
3066 - # as discussed in bug #398009.
3067 - nontrivial_cl_files = set()
3068 - nontrivial_cl_files.update(clnew, clremoved, clchanged)
3069 - nontrivial_cl_files.difference_update(['Manifest'])
3070 - if not nontrivial_cl_files and options.echangelog != 'force':
3071 - continue
3072 -
3073 - new_changelog = utilities.UpdateChangeLog(checkdir_relative,
3074 - committer_name, changelog_msg,
3075 - os.path.join(repodir, 'skel.ChangeLog'),
3076 - catdir, pkgdir,
3077 - new=clnew, removed=clremoved, changed=clchanged,
3078 - pretend=options.pretend)
3079 - if new_changelog is None:
3080 - writemsg_level("!!! Updating the ChangeLog failed\n", \
3081 - level=logging.ERROR, noiselevel=-1)
3082 - sys.exit(1)
3083 -
3084 - # if the ChangeLog was just created, add it to vcs
3085 - if new_changelog:
3086 - myautoadd.append(changelog_path)
3087 - # myautoadd is appended to myupdates below
3088 - else:
3089 - myupdates.append(changelog_path)
3090 -
3091 - if options.ask and not options.pretend:
3092 - # regenerate Manifest for modified ChangeLog (bug #420735)
3093 - repoman_settings["O"] = checkdir
3094 - digestgen(mysettings=repoman_settings, myportdb=portdb)
3095 - else:
3096 - broken_changelog_manifests.append(x)
3097 -
3098 - if myautoadd:
3099 - print(">>> Auto-Adding missing Manifest/ChangeLog file(s)...")
3100 - add_cmd = [vcs, "add"]
3101 - add_cmd += myautoadd
3102 - if options.pretend:
3103 - portage.writemsg_stdout("(%s)\n" % " ".join(add_cmd),
3104 - noiselevel=-1)
3105 - else:
3106 -
3107 - if sys.hexversion < 0x3020000 and sys.hexversion >= 0x3000000 and \
3108 - not os.path.isabs(add_cmd[0]):
3109 - # Python 3.1 _execvp throws TypeError for non-absolute executable
3110 - # path passed as bytes (see http://bugs.python.org/issue8513).
3111 - fullname = find_binary(add_cmd[0])
3112 - if fullname is None:
3113 - raise portage.exception.CommandNotFound(add_cmd[0])
3114 - add_cmd[0] = fullname
3115 -
3116 - add_cmd = [_unicode_encode(arg) for arg in add_cmd]
3117 - retcode = subprocess.call(add_cmd)
3118 - if retcode != os.EX_OK:
3119 - logging.error(
3120 - "Exiting on %s error code: %s\n" % (vcs, retcode))
3121 - sys.exit(retcode)
3122 -
3123 - myupdates += myautoadd
3124 -
3125 - print("* %s files being committed..." % green(str(len(myupdates))), end=' ')
3126 -
3127 - if vcs not in ('cvs', 'svn'):
3128 - # With git, bzr and hg, there's never any keyword expansion, so
3129 - # there's no need to regenerate manifests and all files will be
3130 - # committed in one big commit at the end.
3131 - print()
3132 - elif not repo_config.thin_manifest:
3133 - if vcs == 'cvs':
3134 - headerstring = "'\$(Header|Id).*\$'"
3135 - elif vcs == "svn":
3136 - svn_keywords = dict((k.lower(), k) for k in [
3137 - "Rev",
3138 - "Revision",
3139 - "LastChangedRevision",
3140 - "Date",
3141 - "LastChangedDate",
3142 - "Author",
3143 - "LastChangedBy",
3144 - "URL",
3145 - "HeadURL",
3146 - "Id",
3147 - "Header",
3148 - ])
3149 -
3150 - for myfile in myupdates:
3151 -
3152 - # for CVS, no_expansion contains files that are excluded from expansion
3153 - if vcs == "cvs":
3154 - if myfile in no_expansion:
3155 - continue
3156 -
3157 - # for SVN, expansion contains files that are included in expansion
3158 - elif vcs == "svn":
3159 - if myfile not in expansion:
3160 - continue
3161 -
3162 - # Subversion keywords are case-insensitive in svn:keywords properties, but case-sensitive in contents of files.
3163 - enabled_keywords = []
3164 - for k in expansion[myfile]:
3165 - keyword = svn_keywords.get(k.lower())
3166 - if keyword is not None:
3167 - enabled_keywords.append(keyword)
3168 -
3169 - headerstring = "'\$(%s).*\$'" % "|".join(enabled_keywords)
3170 -
3171 - myout = repoman_getstatusoutput("egrep -q " + headerstring + " " +
3172 - portage._shell_quote(myfile))
3173 - if myout[0] == 0:
3174 - myheaders.append(myfile)
3175 -
3176 - print("%s have headers that will change." % green(str(len(myheaders))))
3177 - print("* Files with headers will cause the manifests to be changed and committed separately.")
3178 -
3179 - logging.info("myupdates: %s", myupdates)
3180 - logging.info("myheaders: %s", myheaders)
3181 -
3182 - uq = UserQuery(options)
3183 - if options.ask and uq.query('Commit changes?', True) != 'Yes':
3184 - print("* aborting commit.")
3185 - sys.exit(128 + signal.SIGINT)
3186 -
3187 - # Handle the case where committed files have keywords which
3188 - # will change and need a priming commit before the Manifest
3189 - # can be committed.
3190 - if (myupdates or myremoved) and myheaders:
3191 - myfiles = myupdates + myremoved
3192 - fd, commitmessagefile = tempfile.mkstemp(".repoman.msg")
3193 - mymsg = os.fdopen(fd, "wb")
3194 - mymsg.write(_unicode_encode(commitmessage))
3195 - mymsg.close()
3196 -
3197 - print()
3198 - print(green("Using commit message:"))
3199 - print(green("------------------------------------------------------------------------------"))
3200 - print(commitmessage)
3201 - print(green("------------------------------------------------------------------------------"))
3202 - print()
3203 -
3204 - # Having a leading ./ prefix on file paths can trigger a bug in
3205 - # the cvs server when committing files to multiple directories,
3206 - # so strip the prefix.
3207 - myfiles = [f.lstrip("./") for f in myfiles]
3208 -
3209 - commit_cmd = [vcs]
3210 - commit_cmd.extend(vcs_global_opts)
3211 - commit_cmd.append("commit")
3212 - commit_cmd.extend(vcs_local_opts)
3213 - commit_cmd.extend(["-F", commitmessagefile])
3214 - commit_cmd.extend(myfiles)
3215 -
3216 - try:
3217 - if options.pretend:
3218 - print("(%s)" % (" ".join(commit_cmd),))
3219 - else:
3220 - retval = spawn(commit_cmd, env=commit_env)
3221 - if retval != os.EX_OK:
3222 - writemsg_level(("!!! Exiting on %s (shell) " + \
3223 - "error code: %s\n") % (vcs, retval),
3224 - level=logging.ERROR, noiselevel=-1)
3225 - sys.exit(retval)
3226 - finally:
3227 - try:
3228 - os.unlink(commitmessagefile)
3229 - except OSError:
3230 - pass
3231 -
3232 - # Setup the GPG commands
3233 - def gpgsign(filename):
3234 - gpgcmd = repoman_settings.get("PORTAGE_GPG_SIGNING_COMMAND")
3235 - if gpgcmd in [None, '']:
3236 - raise MissingParameter("PORTAGE_GPG_SIGNING_COMMAND is unset!" + \
3237 - " Is make.globals missing?")
3238 - if "${PORTAGE_GPG_KEY}" in gpgcmd and \
3239 - "PORTAGE_GPG_KEY" not in repoman_settings:
3240 - raise MissingParameter("PORTAGE_GPG_KEY is unset!")
3241 - if "${PORTAGE_GPG_DIR}" in gpgcmd:
3242 - if "PORTAGE_GPG_DIR" not in repoman_settings:
3243 - repoman_settings["PORTAGE_GPG_DIR"] = \
3244 - os.path.expanduser("~/.gnupg")
3245 - logging.info("Automatically setting PORTAGE_GPG_DIR to '%s'" \
3246 - % repoman_settings["PORTAGE_GPG_DIR"])
3247 - else:
3248 - repoman_settings["PORTAGE_GPG_DIR"] = \
3249 - os.path.expanduser(repoman_settings["PORTAGE_GPG_DIR"])
3250 - if not os.access(repoman_settings["PORTAGE_GPG_DIR"], os.X_OK):
3251 - raise portage.exception.InvalidLocation(
3252 - "Unable to access directory: PORTAGE_GPG_DIR='%s'" % \
3253 - repoman_settings["PORTAGE_GPG_DIR"])
3254 - gpgvars = {"FILE": filename}
3255 - for k in ("PORTAGE_GPG_DIR", "PORTAGE_GPG_KEY"):
3256 - v = repoman_settings.get(k)
3257 - if v is not None:
3258 - gpgvars[k] = v
3259 - gpgcmd = portage.util.varexpand(gpgcmd, mydict=gpgvars)
3260 - if options.pretend:
3261 - print("(" + gpgcmd + ")")
3262 - else:
3263 - # Encode unicode manually for bug #310789.
3264 - gpgcmd = portage.util.shlex_split(gpgcmd)
3265 -
3266 - if sys.hexversion < 0x3020000 and sys.hexversion >= 0x3000000 and \
3267 - not os.path.isabs(gpgcmd[0]):
3268 - # Python 3.1 _execvp throws TypeError for non-absolute executable
3269 - # path passed as bytes (see http://bugs.python.org/issue8513).
3270 - fullname = find_binary(gpgcmd[0])
3271 - if fullname is None:
3272 - raise portage.exception.CommandNotFound(gpgcmd[0])
3273 - gpgcmd[0] = fullname
3274 -
3275 - gpgcmd = [_unicode_encode(arg,
3276 - encoding=_encodings['fs'], errors='strict') for arg in gpgcmd]
3277 - rValue = subprocess.call(gpgcmd)
3278 - if rValue == os.EX_OK:
3279 - os.rename(filename + ".asc", filename)
3280 - else:
3281 - raise portage.exception.PortageException("!!! gpg exited with '" + str(rValue) + "' status")
3282 -
3283 - def need_signature(filename):
3284 - try:
3285 - with open(_unicode_encode(filename,
3286 - encoding=_encodings['fs'], errors='strict'), 'rb') as f:
3287 - return b"BEGIN PGP SIGNED MESSAGE" not in f.readline()
3288 - except IOError as e:
3289 - if e.errno in (errno.ENOENT, errno.ESTALE):
3290 - return False
3291 - raise
3292 -
3293 - # When files are removed and re-added, the cvs server will put /Attic/
3294 - # inside the $Header path. This code detects the problem and corrects it
3295 - # so that the Manifest will generate correctly. See bug #169500.
3296 - # Use binary mode in order to avoid potential character encoding issues.
3297 - cvs_header_re = re.compile(br'^#\s*\$Header.*\$$')
3298 - attic_str = b'/Attic/'
3299 - attic_replace = b'/'
3300 - for x in myheaders:
3301 - f = open(_unicode_encode(x,
3302 - encoding=_encodings['fs'], errors='strict'),
3303 - mode='rb')
3304 - mylines = f.readlines()
3305 - f.close()
3306 - modified = False
3307 - for i, line in enumerate(mylines):
3308 - if cvs_header_re.match(line) is not None and \
3309 - attic_str in line:
3310 - mylines[i] = line.replace(attic_str, attic_replace)
3311 - modified = True
3312 - if modified:
3313 - portage.util.write_atomic(x, b''.join(mylines),
3314 - mode='wb')
3315 -
3316 - if repolevel == 1:
3317 - print(green("RepoMan sez:"), "\"You're rather crazy... "
3318 - "doing the entire repository.\"\n")
3319 -
3320 - if vcs in ('cvs', 'svn') and (myupdates or myremoved):
3321 -
3322 - for x in sorted(vcs_files_to_cps(
3323 - chain(myupdates, myremoved, mymanifests))):
3324 - repoman_settings["O"] = os.path.join(repodir, x)
3325 - digestgen(mysettings=repoman_settings, myportdb=portdb)
3326 -
3327 - elif broken_changelog_manifests:
3328 - for x in broken_changelog_manifests:
3329 - repoman_settings["O"] = os.path.join(repodir, x)
3330 - digestgen(mysettings=repoman_settings, myportdb=portdb)
3331 -
3332 - signed = False
3333 - if sign_manifests:
3334 - signed = True
3335 - try:
3336 - for x in sorted(vcs_files_to_cps(
3337 - chain(myupdates, myremoved, mymanifests))):
3338 - repoman_settings["O"] = os.path.join(repodir, x)
3339 - manifest_path = os.path.join(repoman_settings["O"], "Manifest")
3340 - if not need_signature(manifest_path):
3341 - continue
3342 - gpgsign(manifest_path)
3343 - except portage.exception.PortageException as e:
3344 - portage.writemsg("!!! %s\n" % str(e))
3345 - portage.writemsg("!!! Disabled FEATURES='sign'\n")
3346 - signed = False
3347 -
3348 - if vcs == 'git':
3349 - # It's not safe to use the git commit -a option since there might
3350 - # be some modified files elsewhere in the working tree that the
3351 - # user doesn't want to commit. Therefore, call git update-index
3352 - # in order to ensure that the index is updated with the latest
3353 - # versions of all new and modified files in the relevant portion
3354 - # of the working tree.
3355 - myfiles = mymanifests + myupdates
3356 - myfiles.sort()
3357 - update_index_cmd = ["git", "update-index"]
3358 - update_index_cmd.extend(f.lstrip("./") for f in myfiles)
3359 - if options.pretend:
3360 - print("(%s)" % (" ".join(update_index_cmd),))
3361 - else:
3362 - retval = spawn(update_index_cmd, env=os.environ)
3363 - if retval != os.EX_OK:
3364 - writemsg_level(("!!! Exiting on %s (shell) " + \
3365 - "error code: %s\n") % (vcs, retval),
3366 - level=logging.ERROR, noiselevel=-1)
3367 - sys.exit(retval)
3368 -
3369 - if True:
3370 - myfiles = mymanifests[:]
3371 - # If there are no header (SVN/CVS keywords) changes in
3372 - # the files, this Manifest commit must include the
3373 - # other (yet uncommitted) files.
3374 - if not myheaders:
3375 - myfiles += myupdates
3376 - myfiles += myremoved
3377 - myfiles.sort()
3378 -
3379 - fd, commitmessagefile = tempfile.mkstemp(".repoman.msg")
3380 - mymsg = os.fdopen(fd, "wb")
3381 - mymsg.write(_unicode_encode(commitmessage))
3382 - mymsg.close()
3383 -
3384 - commit_cmd = []
3385 - if options.pretend and vcs is None:
3386 - # substitute a bogus value for pretend output
3387 - commit_cmd.append("cvs")
3388 - else:
3389 - commit_cmd.append(vcs)
3390 - commit_cmd.extend(vcs_global_opts)
3391 - commit_cmd.append("commit")
3392 - commit_cmd.extend(vcs_local_opts)
3393 - if vcs == "hg":
3394 - commit_cmd.extend(["--logfile", commitmessagefile])
3395 - commit_cmd.extend(myfiles)
3396 - else:
3397 - commit_cmd.extend(["-F", commitmessagefile])
3398 - commit_cmd.extend(f.lstrip("./") for f in myfiles)
3399 -
3400 - try:
3401 - if options.pretend:
3402 - print("(%s)" % (" ".join(commit_cmd),))
3403 - else:
3404 - retval = spawn(commit_cmd, env=commit_env)
3405 - if retval != os.EX_OK:
3406 - if repo_config.sign_commit and vcs == 'git' and \
3407 - not git_supports_gpg_sign():
3408 - # Inform user that newer git is needed (bug #403323).
3409 - logging.error(
3410 - "Git >=1.7.9 is required for signed commits!")
3411 -
3412 - writemsg_level(("!!! Exiting on %s (shell) " + \
3413 - "error code: %s\n") % (vcs, retval),
3414 - level=logging.ERROR, noiselevel=-1)
3415 - sys.exit(retval)
3416 - finally:
3417 - try:
3418 - os.unlink(commitmessagefile)
3419 - except OSError:
3420 - pass
3421 -
3422 - print()
3423 - if vcs:
3424 - print("Commit complete.")
3425 else:
3426 - print("repoman was too scared by not seeing any familiar version control file that he forgot to commit anything")
3427 - print(green("RepoMan sez:"), "\"If everyone were like you, I'd be out of business!\"\n")
3428 - sys.exit(0)
3429 + raise
3430 diff --cc bin/save-ebuild-env.sh
3431 index 599d6ea,ddef1fd..28162d1
3432 --- a/bin/save-ebuild-env.sh
3433 +++ b/bin/save-ebuild-env.sh
3434 @@@ -88,8 -89,9 +89,12 @@@ __save_ebuild_env()
3435 ___eapi_has_package_manager_build_user && unset -f package_manager_build_user
3436 ___eapi_has_package_manager_build_group && unset -f package_manager_build_group
3437
3438 - # Clear out the triple underscore namespace as it is reserved by the PM.
3439 - unset -f $(compgen -A function ___)
3440 - unset ${!___*}
3441 + # PREFIX: compgen is not compiled in during bootstrap
3442 - type compgen >& /dev/null && unset -f $(compgen -A function ___eapi_)
3443 ++ if type compgen >& /dev/null ; then
3444 ++ # Clear out the triple underscore namespace as it is reserved by the PM.
3445 ++ unset -f $(compgen -A function ___)
3446 ++ unset ${!___*}
3447 ++ fi
3448
3449 # portage config variables and variables set directly by portage
3450 unset ACCEPT_LICENSE BAD BRACKET BUILD_PREFIX COLS \
3451 diff --cc pym/_emerge/actions.py
3452 index 3218cde,59626ad..1d324aa
3453 --- a/pym/_emerge/actions.py
3454 +++ b/pym/_emerge/actions.py
3455 @@@ -2376,39 -2412,34 +2418,40 @@@ def getgccversion(chost=None)
3456 "!!! other terminals also.\n"
3457 )
3458
3459 + def getclangversion(output):
3460 + version = re.search('clang version ([0-9.]+) ', output)
3461 + if version:
3462 + return version.group(1)
3463 + return "unknown"
3464 +
3465 - try:
3466 - proc = subprocess.Popen([ubinpath + "/gcc-config", "-c"],
3467 - stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
3468 - except OSError:
3469 - myoutput = None
3470 - mystatus = 1
3471 - else:
3472 - myoutput = _unicode_decode(proc.communicate()[0]).rstrip("\n")
3473 - mystatus = proc.wait()
3474 - if mystatus == os.EX_OK and myoutput.startswith(chost + "-"):
3475 - return myoutput.replace(chost + "-", gcc_ver_prefix, 1)
3476 + if chost:
3477 + try:
3478 + proc = subprocess.Popen(["gcc-config", "-c"],
3479 + stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
3480 + except OSError:
3481 + myoutput = None
3482 + mystatus = 1
3483 + else:
3484 + myoutput = _unicode_decode(proc.communicate()[0]).rstrip("\n")
3485 + mystatus = proc.wait()
3486 + if mystatus == os.EX_OK and myoutput.startswith(chost + "-"):
3487 + return myoutput.replace(chost + "-", gcc_ver_prefix, 1)
3488
3489 - try:
3490 - proc = subprocess.Popen(
3491 - [ubinpath + "/" + chost + "-" + gcc_ver_command[0]] + gcc_ver_command[1:],
3492 - stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
3493 - except OSError:
3494 - myoutput = None
3495 - mystatus = 1
3496 - else:
3497 - myoutput = _unicode_decode(proc.communicate()[0]).rstrip("\n")
3498 - mystatus = proc.wait()
3499 - if mystatus == os.EX_OK:
3500 - return gcc_ver_prefix + myoutput
3501 + try:
3502 + proc = subprocess.Popen(
3503 + [chost + "-" + gcc_ver_command[0]] + gcc_ver_command[1:],
3504 + stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
3505 + except OSError:
3506 + myoutput = None
3507 + mystatus = 1
3508 + else:
3509 + myoutput = _unicode_decode(proc.communicate()[0]).rstrip("\n")
3510 + mystatus = proc.wait()
3511 + if mystatus == os.EX_OK:
3512 + return gcc_ver_prefix + myoutput
3513
3514 try:
3515 - proc = subprocess.Popen(gcc_ver_command,
3516 + proc = subprocess.Popen([ubinpath + "/" + gcc_ver_command[0]] + gcc_ver_command[1:],
3517 stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
3518 except OSError:
3519 myoutput = None
3520 diff --cc pym/portage/dbapi/vartree.py
3521 index f4c7cdc,e7effca..670221f
3522 --- a/pym/portage/dbapi/vartree.py
3523 +++ b/pym/portage/dbapi/vartree.py
3524 @@@ -35,12 -35,9 +35,12 @@@ portage.proxy.lazyimport.lazyimport(glo
3525 'portage.util.movefile:movefile',
3526 'portage.util.path:first_existing,iter_parents',
3527 'portage.util.writeable_check:get_ro_checker',
3528 - 'portage.util:xattr@_xattr',
3529 + 'portage.util._xattr:xattr',
3530 'portage.util._dyn_libs.PreservedLibsRegistry:PreservedLibsRegistry',
3531 'portage.util._dyn_libs.LinkageMapELF:LinkageMapELF@LinkageMap',
3532 + 'portage.util._dyn_libs.LinkageMapMachO:LinkageMapMachO',
3533 + 'portage.util._dyn_libs.LinkageMapPeCoff:LinkageMapPeCoff',
3534 + 'portage.util._dyn_libs.LinkageMapXCoff:LinkageMapXCoff',
3535 'portage.util._async.SchedulerInterface:SchedulerInterface',
3536 'portage.util._eventloop.EventLoop:EventLoop',
3537 'portage.util._eventloop.global_event_loop:global_event_loop',