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', |