Gentoo Archives: gentoo-commits

From: Magnus Granberg <zorry@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] proj/tinderbox-cluster:master commit in: pym/tbc/repoman/modules/manifest/, pym/tbc/repoman/modules/fix/, ...
Date: Sun, 04 Oct 2015 19:36:20
Message-Id: 1443987285.71487c91f475dd47afff595b183bebf32ded0281.zorry@gentoo
1 commit: 71487c91f475dd47afff595b183bebf32ded0281
2 Author: Magnus Granberg <zorry <AT> gentoo <DOT> org>
3 AuthorDate: Sun Oct 4 19:34:45 2015 +0000
4 Commit: Magnus Granberg <zorry <AT> gentoo <DOT> org>
5 CommitDate: Sun Oct 4 19:34:45 2015 +0000
6 URL: https://gitweb.gentoo.org/proj/tinderbox-cluster.git/commit/?id=71487c91
7
8 use repoman from portage 2.2.22
9
10 patches/portage.patch | 40 +-
11 pym/tbc/repoman/__init__.py | 0
12 pym/tbc/repoman/_portage.py | 25 -
13 pym/tbc/repoman/_subprocess.py | 82 -
14 pym/tbc/repoman/_xml.py | 101 --
15 pym/tbc/repoman/argparser.py | 221 ---
16 pym/tbc/repoman/check_missingslot.py | 29 -
17 pym/tbc/repoman/checks/__init__.py | 0
18 pym/tbc/repoman/checks/directories/__init__.py | 0
19 pym/tbc/repoman/checks/directories/files.py | 80 -
20 pym/tbc/repoman/checks/ebuilds/__init__.py | 0
21 pym/tbc/repoman/checks/ebuilds/checks.py | 990 ------------
22 .../repoman/checks/ebuilds/eclasses/__init__.py | 0
23 pym/tbc/repoman/checks/ebuilds/eclasses/live.py | 39 -
24 pym/tbc/repoman/checks/ebuilds/eclasses/ruby.py | 32 -
25 pym/tbc/repoman/checks/ebuilds/errors.py | 48 -
26 pym/tbc/repoman/checks/ebuilds/fetches.py | 138 --
27 pym/tbc/repoman/checks/ebuilds/isebuild.py | 70 -
28 pym/tbc/repoman/checks/ebuilds/keywords.py | 121 --
29 pym/tbc/repoman/checks/ebuilds/manifests.py | 101 --
30 pym/tbc/repoman/checks/ebuilds/misc.py | 54 -
31 pym/tbc/repoman/checks/ebuilds/pkgmetadata.py | 174 --
32 .../repoman/checks/ebuilds/thirdpartymirrors.py | 38 -
33 pym/tbc/repoman/checks/ebuilds/use_flags.py | 89 --
34 .../repoman/checks/ebuilds/variables/__init__.py | 0
35 .../checks/ebuilds/variables/description.py | 32 -
36 pym/tbc/repoman/checks/ebuilds/variables/eapi.py | 44 -
37 .../repoman/checks/ebuilds/variables/license.py | 47 -
38 .../repoman/checks/ebuilds/variables/restrict.py | 41 -
39 pym/tbc/repoman/checks/herds/__init__.py | 0
40 pym/tbc/repoman/checks/herds/herdbase.py | 135 --
41 pym/tbc/repoman/checks/herds/metadata.py | 25 -
42 pym/tbc/repoman/copyrights.py | 119 --
43 pym/tbc/repoman/ebuild.py | 28 -
44 pym/tbc/repoman/errors.py | 19 -
45 pym/tbc/repoman/main.py | 1655 --------------------
46 pym/tbc/repoman/metadata.py | 150 --
47 pym/tbc/repoman/modules/__init__.py | 0
48 pym/tbc/repoman/modules/commit/__init__.py | 0
49 pym/tbc/repoman/modules/commit/repochecks.py | 32 -
50 pym/tbc/repoman/modules/fix/__init__.py | 0
51 pym/tbc/repoman/modules/full/__init__.py | 0
52 pym/tbc/repoman/modules/manifest/__init__.py | 0
53 pym/tbc/repoman/modules/scan/__init__.py | 0
54 pym/tbc/repoman/profile.py | 84 -
55 pym/tbc/repoman/qa_data.py | 430 -----
56 pym/tbc/repoman/qa_tracker.py | 45 -
57 pym/tbc/repoman/repos.py | 303 ----
58 pym/tbc/repoman/scan.py | 170 --
59 pym/tbc/repoman/utilities.py | 595 -------
60 pym/tbc/repoman/vcs/__init__.py | 0
61 pym/tbc/repoman/vcs/vcs.py | 274 ----
62 pym/tbc/repoman/vcs/vcsstatus.py | 113 --
63 53 files changed, 39 insertions(+), 6774 deletions(-)
64
65 diff --git a/patches/portage.patch b/patches/portage.patch
66 index fadbd32..fa8e6ca 100644
67 --- a/patches/portage.patch
68 +++ b/patches/portage.patch
69 @@ -1,4 +1,4 @@
70 -2015-07-18 Magnus Granberg <zorry@g.o>
71 +2015-10-04 Magnus Granberg <zorry@g.o>
72
73 * tbc/pym/actions.py
74 Use the patched Scheduler and add build_dict so it can be ust.
75 @@ -12,6 +12,8 @@
76 We copy Scheduler.py from portage and patch it.
77 Fix so we can use add_buildlog_main()
78 We use add_buildlog_main() for loging.
79 + * tbc/pym/repoman/main.py
80 + We add config_root pkdir and remove action
81
82 --- a/pym/tbc/actions.py 2013-03-22 17:57:23.000000000 +0100
83 +++ b/pym/tbc/actions.py 2013-03-22 19:00:43.265582143 +0100
84 @@ -285,3 +287,39 @@
85 self._jobs -= 1
86 self._status_display.running = self._jobs
87 self._schedule()
88 +--- a/pym/repoman/main.py 2015-09-22 02:20:41.000000000 +0200
89 ++++ b/pym/repoman/main.py 2015-10-04 20:21:57.586494104 +0200
90 +@@ -45,8 +45,9 @@ bad = create_color_func("BAD")
91 + os.umask(0o22)
92 +
93 +
94 +-def repoman_main(argv):
95 +- config_root = os.environ.get("PORTAGE_CONFIGROOT")
96 ++def repoman_main:(argv, config_root=None, pkgdir=None):
97 ++ if config_root is None:
98 ++ config_root = os.environ.get("PORTAGE_CONFIGROOT")
99 + repoman_settings = portage.config(config_root=config_root, local_config=False)
100 +
101 + if repoman_settings.get("NOCOLOR", "").lower() in ("yes", "true") or \
102 +@@ -71,6 +72,9 @@ def repoman_main(argv):
103 + # commit (like if Manifest generation fails).
104 + can_force = True
105 +
106 ++ if not pkgdir is None:
107 ++ os.chdir(pkgdir)
108 ++
109 + portdir, portdir_overlay, mydir = utilities.FindPortdir(repoman_settings)
110 + if portdir is None:
111 + sys.exit(1)
112 +@@ -159,10 +163,4 @@ def repoman_main(argv):
113 + qa_output = qa_output.getvalue()
114 + qa_output = qa_output.splitlines(True)
115 +
116 +- # output the results
117 +- actions = Actions(repo_settings, options, scanner, vcs_settings)
118 +- if actions.inform(can_force, result):
119 +- # perform any other actions
120 +- actions.perform(qa_output)
121 +-
122 +- sys.exit(0)
123 ++ return qatracker, qawarnings
124
125 diff --git a/pym/tbc/repoman/__init__.py b/pym/tbc/repoman/__init__.py
126 deleted file mode 100644
127 index e69de29..0000000
128
129 diff --git a/pym/tbc/repoman/_portage.py b/pym/tbc/repoman/_portage.py
130 deleted file mode 100644
131 index 0f611f7..0000000
132 --- a/pym/tbc/repoman/_portage.py
133 +++ /dev/null
134 @@ -1,25 +0,0 @@
135 -
136 -'''repoman/_portage.py
137 -Central location for the portage import.
138 -There were problems when portage was imported by submodules
139 -due to the portage instance was somehow different that the
140 -initial portage import in main.py. The later portage imports
141 -did not contain the repo it was working on. That repo was my cvs tree
142 -and not listed in those subsequent portage imports.
143 -
144 -All modules should import portage from this one
145 -
146 -from repoman._portage import portage
147 -
148 -Then continue to import the remaining portage modules needed
149 -'''
150 -
151 -import sys
152 -
153 -from os import path as osp
154 -pym_path = osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))))
155 -sys.path.insert(0, pym_path)
156 -
157 -import portage
158 -portage._internal_caller = True
159 -portage._disable_legacy_globals()
160
161 diff --git a/pym/tbc/repoman/_subprocess.py b/pym/tbc/repoman/_subprocess.py
162 deleted file mode 100644
163 index e303e5e..0000000
164 --- a/pym/tbc/repoman/_subprocess.py
165 +++ /dev/null
166 @@ -1,82 +0,0 @@
167 -
168 -
169 -import codecs
170 -import subprocess
171 -import sys
172 -
173 -# import our initialized portage instance
174 -from tbc.repoman._portage import portage
175 -
176 -from portage import os
177 -from portage.process import find_binary
178 -from portage import _encodings, _unicode_encode
179 -
180 -
181 -def repoman_getstatusoutput(cmd):
182 - """
183 - Implements an interface similar to getstatusoutput(), but with
184 - customized unicode handling (see bug #310789) and without the shell.
185 - """
186 - args = portage.util.shlex_split(cmd)
187 -
188 - if sys.hexversion < 0x3020000 and sys.hexversion >= 0x3000000 and \
189 - not os.path.isabs(args[0]):
190 - # Python 3.1 _execvp throws TypeError for non-absolute executable
191 - # path passed as bytes (see http://bugs.python.org/issue8513).
192 - fullname = find_binary(args[0])
193 - if fullname is None:
194 - raise portage.exception.CommandNotFound(args[0])
195 - args[0] = fullname
196 -
197 - encoding = _encodings['fs']
198 - args = [
199 - _unicode_encode(x, encoding=encoding, errors='strict') for x in args]
200 - proc = subprocess.Popen(
201 - args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
202 - output = portage._unicode_decode(
203 - proc.communicate()[0], encoding=encoding, errors='strict')
204 - if output and output[-1] == "\n":
205 - # getstatusoutput strips one newline
206 - output = output[:-1]
207 - return (proc.wait(), output)
208 -
209 -
210 -class repoman_popen(portage.proxy.objectproxy.ObjectProxy):
211 - """
212 - Implements an interface similar to os.popen(), but with customized
213 - unicode handling (see bug #310789) and without the shell.
214 - """
215 -
216 - __slots__ = ('_proc', '_stdout')
217 -
218 - def __init__(self, cmd):
219 - args = portage.util.shlex_split(cmd)
220 -
221 - if sys.hexversion < 0x3020000 and sys.hexversion >= 0x3000000 and \
222 - not os.path.isabs(args[0]):
223 - # Python 3.1 _execvp throws TypeError for non-absolute executable
224 - # path passed as bytes (see http://bugs.python.org/issue8513).
225 - fullname = find_binary(args[0])
226 - if fullname is None:
227 - raise portage.exception.CommandNotFound(args[0])
228 - args[0] = fullname
229 -
230 - encoding = _encodings['fs']
231 - args = [
232 - _unicode_encode(x, encoding=encoding, errors='strict')
233 - for x in args]
234 - proc = subprocess.Popen(args, stdout=subprocess.PIPE)
235 - object.__setattr__(
236 - self, '_proc', proc)
237 - object.__setattr__(
238 - self, '_stdout', codecs.getreader(encoding)(proc.stdout, 'strict'))
239 -
240 - def _get_target(self):
241 - return object.__getattribute__(self, '_stdout')
242 -
243 - __enter__ = _get_target
244 -
245 - def __exit__(self, exc_type, exc_value, traceback):
246 - proc = object.__getattribute__(self, '_proc')
247 - proc.wait()
248 - proc.stdout.close()
249
250 diff --git a/pym/tbc/repoman/_xml.py b/pym/tbc/repoman/_xml.py
251 deleted file mode 100644
252 index 7bf6698..0000000
253 --- a/pym/tbc/repoman/_xml.py
254 +++ /dev/null
255 @@ -1,101 +0,0 @@
256 -
257 -import sys
258 -import xml
259 -
260 -# import our initialized portage instance
261 -from repoman._portage import portage
262 -
263 -from portage import os
264 -from portage.output import red
265 -from portage.process import find_binary
266 -
267 -from repoman.metadata import fetch_metadata_dtd
268 -from repoman._subprocess import repoman_getstatusoutput
269 -
270 -
271 -class _XMLParser(xml.etree.ElementTree.XMLParser):
272 -
273 - def __init__(self, data, **kwargs):
274 - xml.etree.ElementTree.XMLParser.__init__(self, **kwargs)
275 - self._portage_data = data
276 - if hasattr(self, 'parser'):
277 - self._base_XmlDeclHandler = self.parser.XmlDeclHandler
278 - self.parser.XmlDeclHandler = self._portage_XmlDeclHandler
279 - self._base_StartDoctypeDeclHandler = \
280 - self.parser.StartDoctypeDeclHandler
281 - self.parser.StartDoctypeDeclHandler = \
282 - self._portage_StartDoctypeDeclHandler
283 -
284 - def _portage_XmlDeclHandler(self, version, encoding, standalone):
285 - if self._base_XmlDeclHandler is not None:
286 - self._base_XmlDeclHandler(version, encoding, standalone)
287 - self._portage_data["XML_DECLARATION"] = (version, encoding, standalone)
288 -
289 - def _portage_StartDoctypeDeclHandler(
290 - self, doctypeName, systemId, publicId, has_internal_subset):
291 - if self._base_StartDoctypeDeclHandler is not None:
292 - self._base_StartDoctypeDeclHandler(
293 - doctypeName, systemId, publicId, has_internal_subset)
294 - self._portage_data["DOCTYPE"] = (doctypeName, systemId, publicId)
295 -
296 -
297 -class _MetadataTreeBuilder(xml.etree.ElementTree.TreeBuilder):
298 - """
299 - Implements doctype() as required to avoid deprecation warnings with
300 - >=python-2.7.
301 - """
302 - def doctype(self, name, pubid, system):
303 - pass
304 -
305 -
306 -class XmlLint(object):
307 -
308 - def __init__(self, options, repoman_settings):
309 - self.metadata_dtd = os.path.join(repoman_settings["DISTDIR"], 'metadata.dtd')
310 - self.options = options
311 - self.repoman_settings = repoman_settings
312 - self._is_capable = False
313 - self.binary = None
314 - self._check_capable()
315 -
316 - def _check_capable(self):
317 - if self.options.mode == "manifest":
318 - return
319 - self.binary = find_binary('xmllint')
320 - if not self.binary:
321 - print(red("!!! xmllint not found. Can't check metadata.xml.\n"))
322 - else:
323 - if not fetch_metadata_dtd(self.metadata_dtd, self.repoman_settings):
324 - sys.exit(1)
325 - # this can be problematic if xmllint changes their output
326 - self._is_capable = True
327 -
328 - @property
329 - def capable(self):
330 - return self._is_capable
331 -
332 - def check(self, checkdir, repolevel):
333 - '''Runs checks on the package metadata.xml file
334 -
335 - @param checkdir: string, path
336 - @param repolevel: integer
337 - @return boolean, False == bad metadata
338 - '''
339 - if not self.capable:
340 - if self.options.xml_parse or repolevel == 3:
341 - print("%s sorry, xmllint is needed. failing\n" % red("!!!"))
342 - sys.exit(1)
343 - return True
344 - # xmlint can produce garbage output even on success, so only dump
345 - # the ouput when it fails.
346 - st, out = repoman_getstatusoutput(
347 - self.binary + " --nonet --noout --dtdvalid %s %s" % (
348 - portage._shell_quote(self.metadata_dtd),
349 - portage._shell_quote(
350 - os.path.join(checkdir, "metadata.xml"))))
351 - if st != os.EX_OK:
352 - print(red("!!!") + " metadata.xml is invalid:")
353 - for z in out.splitlines():
354 - print(red("!!! ") + z)
355 - return False
356 - return True
357
358 diff --git a/pym/tbc/repoman/argparser.py b/pym/tbc/repoman/argparser.py
359 deleted file mode 100644
360 index 1c9bd45..0000000
361 --- a/pym/tbc/repoman/argparser.py
362 +++ /dev/null
363 @@ -1,221 +0,0 @@
364 -# repoman: Argument parser
365 -# Copyright 2007-2014 Gentoo Foundation
366 -# Distributed under the terms of the GNU General Public License v2
367 -
368 -"""This module contains functions used in Repoman to parse CLI arguments."""
369 -
370 -import logging
371 -import sys
372 -
373 -# import our initialized portage instance
374 -from repoman._portage import portage
375 -
376 -from portage import util
377 -from portage.util._argparse import ArgumentParser
378 -
379 -
380 -def parse_args(argv, qahelp, repoman_default_opts):
381 - """Use a customized optionParser to parse command line arguments for repoman
382 - Args:
383 - argv - a sequence of command line arguments
384 - qahelp - a dict of qa warning to help message
385 - Returns:
386 - (opts, args), just like a call to parser.parse_args()
387 - """
388 -
389 - argv = portage._decode_argv(argv)
390 -
391 - modes = {
392 - 'commit': 'Run a scan then commit changes',
393 - 'ci': 'Run a scan then commit changes',
394 - 'fix': 'Fix simple QA issues (stray digests, missing digests)',
395 - 'full': 'Scan directory tree and print all issues (not a summary)',
396 - 'help': 'Show this screen',
397 - 'manifest': 'Generate a Manifest (fetches files if necessary)',
398 - 'manifest-check': 'Check Manifests for missing or incorrect digests',
399 - 'scan': 'Scan directory tree for QA issues'
400 - }
401 -
402 - output_choices = {
403 - 'default': 'The normal output format',
404 - 'column': 'Columnar output suitable for use with grep'
405 - }
406 -
407 - mode_keys = list(modes)
408 - mode_keys.sort()
409 -
410 - output_keys = sorted(output_choices)
411 -
412 - parser = ArgumentParser(
413 - usage="repoman [options] [mode]",
414 - description="Modes: %s" % " | ".join(mode_keys),
415 - epilog="For more help consult the man page.")
416 -
417 - parser.add_argument(
418 - '-a', '--ask', dest='ask', action='store_true',
419 - default=False,
420 - help='Request a confirmation before commiting')
421 -
422 - parser.add_argument(
423 - '-m', '--commitmsg', dest='commitmsg',
424 - help='specify a commit message on the command line')
425 -
426 - parser.add_argument(
427 - '-M', '--commitmsgfile', dest='commitmsgfile',
428 - help='specify a path to a file that contains a commit message')
429 -
430 - parser.add_argument(
431 - '--digest', choices=('y', 'n'), metavar='<y|n>',
432 - help='Automatically update Manifest digests for modified files')
433 -
434 - parser.add_argument(
435 - '-p', '--pretend', dest='pretend', default=False,
436 - action='store_true',
437 - help='don\'t commit or fix anything; just show what would be done')
438 -
439 - parser.add_argument(
440 - '-q', '--quiet', dest="quiet", action="count",
441 - default=0,
442 - help='do not print unnecessary messages')
443 -
444 - parser.add_argument(
445 - '--echangelog', choices=('y', 'n', 'force'), metavar="<y|n|force>",
446 - help=(
447 - 'for commit mode, call echangelog if ChangeLog is unmodified (or '
448 - 'regardless of modification if \'force\' is specified)'))
449 -
450 - parser.add_argument(
451 - '--experimental-inherit', choices=('y', 'n'), metavar="<y|n>",
452 - default='n',
453 - help=(
454 - 'Enable experimental inherit.missing checks which may misbehave'
455 - ' when the internal eclass database becomes outdated'))
456 -
457 - parser.add_argument(
458 - '-f', '--force', dest='force', action='store_true',
459 - default=False,
460 - help='Commit with QA violations')
461 -
462 - parser.add_argument(
463 - '-S', '--straight-to-stable', dest='straight_to_stable',
464 - default=False, action='store_true',
465 - help='Allow committing straight to stable')
466 -
467 - parser.add_argument(
468 - '--vcs', dest='vcs',
469 - help='Force using specific VCS instead of autodetection')
470 -
471 - parser.add_argument(
472 - '-v', '--verbose', dest="verbosity", action='count',
473 - help='be very verbose in output', default=0)
474 -
475 - parser.add_argument(
476 - '-V', '--version', dest='version', action='store_true',
477 - help='show version info')
478 -
479 - parser.add_argument(
480 - '-x', '--xmlparse', dest='xml_parse', action='store_true',
481 - default=False,
482 - help='forces the metadata.xml parse check to be carried out')
483 -
484 - parser.add_argument(
485 - '--if-modified', choices=('y', 'n'), default='n',
486 - metavar="<y|n>",
487 - help='only check packages that have uncommitted modifications')
488 -
489 - parser.add_argument(
490 - '-i', '--ignore-arches', dest='ignore_arches', action='store_true',
491 - default=False,
492 - help='ignore arch-specific failures (where arch != host)')
493 -
494 - parser.add_argument(
495 - "--ignore-default-opts",
496 - action="store_true",
497 - help="do not use the REPOMAN_DEFAULT_OPTS environment variable")
498 -
499 - parser.add_argument(
500 - '-I', '--ignore-masked', dest='ignore_masked', action='store_true',
501 - default=False,
502 - help='ignore masked packages (not allowed with commit mode)')
503 -
504 - parser.add_argument(
505 - '--include-arches',
506 - dest='include_arches', metavar='ARCHES', action='append',
507 - help=(
508 - 'A space separated list of arches used to '
509 - 'filter the selection of profiles for dependency checks'))
510 -
511 - parser.add_argument(
512 - '-d', '--include-dev', dest='include_dev', action='store_true',
513 - default=False,
514 - help='include dev profiles in dependency checks')
515 -
516 - parser.add_argument(
517 - '-e', '--include-exp-profiles', choices=('y', 'n'), metavar='<y|n>',
518 - default=False,
519 - help='include exp profiles in dependency checks')
520 -
521 - parser.add_argument(
522 - '--unmatched-removal', dest='unmatched_removal', action='store_true',
523 - default=False,
524 - help=(
525 - 'enable strict checking of package.mask and package.unmask files'
526 - ' for unmatched removal atoms'))
527 -
528 - parser.add_argument(
529 - '--without-mask', dest='without_mask', action='store_true',
530 - default=False,
531 - help=(
532 - 'behave as if no package.mask entries exist'
533 - ' (not allowed with commit mode)'))
534 -
535 - parser.add_argument(
536 - '--output-style', dest='output_style', choices=output_keys,
537 - help='select output type', default='default')
538 -
539 - parser.add_argument(
540 - '--mode', dest='mode', choices=mode_keys,
541 - help='specify which mode repoman will run in (default=full)')
542 -
543 - opts, args = parser.parse_known_args(argv[1:])
544 -
545 - if not opts.ignore_default_opts:
546 - default_opts = util.shlex_split(repoman_default_opts)
547 - if default_opts:
548 - opts, args = parser.parse_known_args(default_opts + sys.argv[1:])
549 -
550 - if opts.mode == 'help':
551 - parser.print_help(short=False)
552 -
553 - for arg in args:
554 - if arg in modes:
555 - if not opts.mode:
556 - opts.mode = arg
557 - break
558 - else:
559 - parser.error("invalid mode: %s" % arg)
560 -
561 - if not opts.mode:
562 - opts.mode = 'full'
563 -
564 - if opts.mode == 'ci':
565 - opts.mode = 'commit' # backwards compat shortcut
566 -
567 - # Use verbosity and quiet options to appropriately fiddle with the loglevel
568 - for val in range(opts.verbosity):
569 - logger = logging.getLogger()
570 - logger.setLevel(logger.getEffectiveLevel() - 10)
571 -
572 - for val in range(opts.quiet):
573 - logger = logging.getLogger()
574 - logger.setLevel(logger.getEffectiveLevel() + 10)
575 -
576 - if opts.mode == 'commit' and not (opts.force or opts.pretend):
577 - if opts.ignore_masked:
578 - opts.ignore_masked = False
579 - logging.warn('Commit mode automatically disables --ignore-masked')
580 - if opts.without_mask:
581 - opts.without_mask = False
582 - logging.warn('Commit mode automatically disables --without-mask')
583 -
584 - return (opts, args)
585
586 diff --git a/pym/tbc/repoman/check_missingslot.py b/pym/tbc/repoman/check_missingslot.py
587 deleted file mode 100644
588 index 3f79435..0000000
589 --- a/pym/tbc/repoman/check_missingslot.py
590 +++ /dev/null
591 @@ -1,29 +0,0 @@
592 -# repoman: missing slot check
593 -# Copyright 2014 Gentoo Foundation
594 -# Distributed under the terms of the GNU General Public License v2
595 -
596 -"""This module contains the check used to find missing slot values
597 -in dependencies."""
598 -
599 -from portage.eapi import eapi_has_slot_operator
600 -
601 -def check_missingslot(atom, mytype, eapi, portdb, qatracker, relative_path, my_aux):
602 - # If no slot or slot operator is specified in RDEP...
603 - if (not atom.blocker and not atom.slot and not atom.slot_operator
604 - and mytype == 'RDEPEND' and eapi_has_slot_operator(eapi)):
605 - # Check whether it doesn't match more than one.
606 - atom_matches = portdb.xmatch("match-all", atom)
607 - dep_slots = frozenset(
608 - portdb.aux_get(cpv, ['SLOT'])[0].split('/')[0]
609 - for cpv in atom_matches)
610 -
611 - if len(dep_slots) > 1:
612 - # See if it is a DEPEND as well. It's a very simple & dumb
613 - # check but should suffice for catching it.
614 - depend = my_aux['DEPEND'].split()
615 - if atom not in depend:
616 - return
617 -
618 - qatracker.add_error("dependency.missingslot", relative_path +
619 - ": %s: '%s' matches more than one slot, please specify an explicit slot and/or use the := or :* slot operator" %
620 - (mytype, atom))
621
622 diff --git a/pym/tbc/repoman/checks/__init__.py b/pym/tbc/repoman/checks/__init__.py
623 deleted file mode 100644
624 index e69de29..0000000
625
626 diff --git a/pym/tbc/repoman/checks/directories/__init__.py b/pym/tbc/repoman/checks/directories/__init__.py
627 deleted file mode 100644
628 index e69de29..0000000
629
630 diff --git a/pym/tbc/repoman/checks/directories/files.py b/pym/tbc/repoman/checks/directories/files.py
631 deleted file mode 100644
632 index 10cb7aa..0000000
633 --- a/pym/tbc/repoman/checks/directories/files.py
634 +++ /dev/null
635 @@ -1,80 +0,0 @@
636 -
637 -'''repoman/checks/diretories/files.py
638 -
639 -'''
640 -
641 -import io
642 -
643 -from portage import _encodings, _unicode_encode
644 -from portage import os
645 -
646 -from tbc.repoman.vcs.vcs import vcs_new_changed
647 -
648 -
649 -class FileChecks(object):
650 -
651 - def __init__(
652 - self, qatracker, repoman_settings, repo_settings, portdb, vcs_settings):
653 - '''
654 - @param qatracker: QATracker instance
655 - @param repoman_settings: settings instance
656 - @param repo_settings: repository settings instance
657 - @param portdb: portdb instance
658 - '''
659 - self.portdb = portdb
660 - self.qatracker = qatracker
661 - self.repo_settings = repo_settings
662 - self.repoman_settings = repoman_settings
663 - self.vcs_settings = vcs_settings
664 -
665 - def check(self, checkdir, checkdirlist, checkdir_relative, changed, new):
666 - '''Checks the ebuild sources and files for errors
667 -
668 - @param xpkg: the pacakge being checked
669 - @param checkdir: string, directory path
670 - @param checkdir_relative: repolevel determined path
671 - '''
672 - for y_file in checkdirlist:
673 - index = self.repo_settings.repo_config.find_invalid_path_char(y_file)
674 - if index != -1:
675 - y_relative = os.path.join(checkdir_relative, y_file)
676 - invcs = self.vcs_settings.vcs is not None
677 - inchangeset = vcs_new_changed(y_relative, changed, new)
678 - if invcs and not inchangeset:
679 - # If the file isn't in the VCS new or changed set, then
680 - # assume that it's an irrelevant temporary file (Manifest
681 - # entries are not generated for file names containing
682 - # prohibited characters). See bug #406877.
683 - index = -1
684 - if index != -1:
685 - self.qatracker.add_error(
686 - "file.name",
687 - "%s/%s: char '%s'" % (checkdir, y_file, y_file[index]))
688 -
689 - if not (
690 - y_file in ("ChangeLog", "metadata.xml")
691 - or y_file.endswith(".ebuild")):
692 - continue
693 - f = None
694 - try:
695 - line = 1
696 - f = io.open(
697 - _unicode_encode(
698 - os.path.join(checkdir, y_file),
699 - encoding=_encodings['fs'], errors='strict'),
700 - mode='r', encoding=_encodings['repo.content'])
701 - for l in f:
702 - line += 1
703 - except UnicodeDecodeError as ue:
704 - s = ue.object[:ue.start]
705 - l2 = s.count("\n")
706 - line += l2
707 - if l2 != 0:
708 - s = s[s.rfind("\n") + 1:]
709 - self.qatracker.add_error(
710 - "file.UTF8", "%s/%s: line %i, just after: '%s'" % (
711 - checkdir, y_file, line, s))
712 - finally:
713 - if f is not None:
714 - f.close()
715 - return
716
717 diff --git a/pym/tbc/repoman/checks/ebuilds/__init__.py b/pym/tbc/repoman/checks/ebuilds/__init__.py
718 deleted file mode 100644
719 index e69de29..0000000
720
721 diff --git a/pym/tbc/repoman/checks/ebuilds/checks.py b/pym/tbc/repoman/checks/ebuilds/checks.py
722 deleted file mode 100644
723 index 3028a4a..0000000
724 --- a/pym/tbc/repoman/checks/ebuilds/checks.py
725 +++ /dev/null
726 @@ -1,990 +0,0 @@
727 -# repoman: Checks
728 -# Copyright 2007-2014 Gentoo Foundation
729 -# Distributed under the terms of the GNU General Public License v2
730 -
731 -"""This module contains functions used in Repoman to ascertain the quality
732 -and correctness of an ebuild."""
733 -
734 -from __future__ import unicode_literals
735 -
736 -import codecs
737 -from itertools import chain
738 -import re
739 -import time
740 -
741 -# import our initialized portage instance
742 -from tbc.repoman._portage import portage
743 -
744 -from portage.eapi import (
745 - eapi_supports_prefix, eapi_has_implicit_rdepend,
746 - eapi_has_src_prepare_and_src_configure, eapi_has_dosed_dohard,
747 - eapi_exports_AA, eapi_has_pkg_pretend)
748 -
749 -import tbc.repoman.checks.ebuilds.errors as errors
750 -
751 -
752 -class LineCheck(object):
753 - """Run a check on a line of an ebuild."""
754 - """A regular expression to determine whether to ignore the line"""
755 - ignore_line = False
756 - """True if lines containing nothing more than comments with optional
757 - leading whitespace should be ignored"""
758 - ignore_comment = True
759 -
760 - def new(self, pkg):
761 - pass
762 -
763 - def check_eapi(self, eapi):
764 - """Returns if check should be run in the given EAPI (default: True)"""
765 - return True
766 -
767 - def check(self, num, line):
768 - """Run the check on line and return error if there is one"""
769 - if self.re.match(line):
770 - return self.error
771 -
772 - def end(self):
773 - pass
774 -
775 -
776 -class PhaseCheck(LineCheck):
777 - """ basic class for function detection """
778 -
779 - func_end_re = re.compile(r'^\}$')
780 - phases_re = re.compile('(%s)' % '|'.join((
781 - 'pkg_pretend', 'pkg_setup', 'src_unpack', 'src_prepare',
782 - 'src_configure', 'src_compile', 'src_test', 'src_install',
783 - 'pkg_preinst', 'pkg_postinst', 'pkg_prerm', 'pkg_postrm',
784 - 'pkg_config')))
785 - in_phase = ''
786 -
787 - def check(self, num, line):
788 - m = self.phases_re.match(line)
789 - if m is not None:
790 - self.in_phase = m.group(1)
791 - if self.in_phase != '' and self.func_end_re.match(line) is not None:
792 - self.in_phase = ''
793 -
794 - return self.phase_check(num, line)
795 -
796 - def phase_check(self, num, line):
797 - """ override this function for your checks """
798 - pass
799 -
800 -
801 -class EbuildHeader(LineCheck):
802 - """Ensure ebuilds have proper headers
803 - Copyright header errors
804 - CVS header errors
805 - License header errors
806 -
807 - Args:
808 - modification_year - Year the ebuild was last modified
809 - """
810 -
811 - repoman_check_name = 'ebuild.badheader'
812 -
813 - gentoo_copyright = r'^# Copyright ((1999|2\d\d\d)-)?%s Gentoo Foundation$'
814 - gentoo_license = (
815 - '# Distributed under the terms'
816 - ' of the GNU General Public License v2')
817 - cvs_header = re.compile(r'^# \$Header: .*\$$')
818 - ignore_comment = False
819 -
820 - def new(self, pkg):
821 - if pkg.mtime is None:
822 - self.modification_year = r'2\d\d\d'
823 - else:
824 - self.modification_year = str(time.gmtime(pkg.mtime)[0])
825 - self.gentoo_copyright_re = re.compile(
826 - self.gentoo_copyright % self.modification_year)
827 -
828 - def check(self, num, line):
829 - if num > 2:
830 - return
831 - elif num == 0:
832 - if not self.gentoo_copyright_re.match(line):
833 - return errors.COPYRIGHT_ERROR
834 - elif num == 1 and line.rstrip('\n') != self.gentoo_license:
835 - return errors.LICENSE_ERROR
836 - elif num == 2:
837 - if not self.cvs_header.match(line):
838 - return errors.CVS_HEADER_ERROR
839 -
840 -
841 -class EbuildWhitespace(LineCheck):
842 - """Ensure ebuilds have proper whitespacing"""
843 -
844 - repoman_check_name = 'ebuild.minorsyn'
845 -
846 - ignore_line = re.compile(r'(^$)|(^(\t)*#)')
847 - ignore_comment = False
848 - leading_spaces = re.compile(r'^[\S\t]')
849 - trailing_whitespace = re.compile(r'.*([\S]$)')
850 -
851 - def check(self, num, line):
852 - if self.leading_spaces.match(line) is None:
853 - return errors.LEADING_SPACES_ERROR
854 - if self.trailing_whitespace.match(line) is None:
855 - return errors.TRAILING_WHITESPACE_ERROR
856 -
857 -
858 -class EbuildBlankLine(LineCheck):
859 - repoman_check_name = 'ebuild.minorsyn'
860 - ignore_comment = False
861 - blank_line = re.compile(r'^$')
862 -
863 - def new(self, pkg):
864 - self.line_is_blank = False
865 -
866 - def check(self, num, line):
867 - if self.line_is_blank and self.blank_line.match(line):
868 - return 'Useless blank line on line: %d'
869 - if self.blank_line.match(line):
870 - self.line_is_blank = True
871 - else:
872 - self.line_is_blank = False
873 -
874 - def end(self):
875 - if self.line_is_blank:
876 - yield 'Useless blank line on last line'
877 -
878 -
879 -class EbuildQuote(LineCheck):
880 - """Ensure ebuilds have valid quoting around things like D,FILESDIR, etc..."""
881 -
882 - repoman_check_name = 'ebuild.minorsyn'
883 - _message_commands = [
884 - "die", "echo", "eerror", "einfo", "elog", "eqawarn", "ewarn"]
885 - _message_re = re.compile(
886 - r'\s(' + "|".join(_message_commands) + r')\s+"[^"]*"\s*$')
887 - _ignored_commands = ["local", "export"] + _message_commands
888 - ignore_line = re.compile(
889 - r'(^$)|(^\s*#.*)|(^\s*\w+=.*)' +
890 - r'|(^\s*(' + "|".join(_ignored_commands) + r')\s+)')
891 - ignore_comment = False
892 - var_names = ["D", "DISTDIR", "FILESDIR", "S", "T", "ROOT", "WORKDIR"]
893 -
894 - # EAPI=3/Prefix vars
895 - var_names += ["ED", "EPREFIX", "EROOT"]
896 -
897 - # variables for games.eclass
898 - var_names += [
899 - "Ddir", "GAMES_PREFIX_OPT", "GAMES_DATADIR",
900 - "GAMES_DATADIR_BASE", "GAMES_SYSCONFDIR", "GAMES_STATEDIR",
901 - "GAMES_LOGDIR", "GAMES_BINDIR"]
902 -
903 - # variables for multibuild.eclass
904 - var_names += ["BUILD_DIR"]
905 -
906 - var_names = "(%s)" % "|".join(var_names)
907 - var_reference = re.compile(
908 - r'\$(\{%s\}|%s\W)' % (var_names, var_names))
909 - missing_quotes = re.compile(
910 - r'(\s|^)[^"\'\s]*\$\{?%s\}?[^"\'\s]*(\s|$)' % var_names)
911 - cond_begin = re.compile(r'(^|\s+)\[\[($|\\$|\s+)')
912 - cond_end = re.compile(r'(^|\s+)\]\]($|\\$|\s+)')
913 -
914 - def check(self, num, line):
915 - if self.var_reference.search(line) is None:
916 - return
917 - # There can be multiple matches / violations on a single line. We
918 - # have to make sure none of the matches are violators. Once we've
919 - # found one violator, any remaining matches on the same line can
920 - # be ignored.
921 - pos = 0
922 - while pos <= len(line) - 1:
923 - missing_quotes = self.missing_quotes.search(line, pos)
924 - if not missing_quotes:
925 - break
926 - # If the last character of the previous match is a whitespace
927 - # character, that character may be needed for the next
928 - # missing_quotes match, so search overlaps by 1 character.
929 - group = missing_quotes.group()
930 - pos = missing_quotes.end() - 1
931 -
932 - # Filter out some false positives that can
933 - # get through the missing_quotes regex.
934 - if self.var_reference.search(group) is None:
935 - continue
936 -
937 - # Filter matches that appear to be an
938 - # argument to a message command.
939 - # For example: false || ewarn "foo $WORKDIR/bar baz"
940 - message_match = self._message_re.search(line)
941 - if message_match is not None and \
942 - message_match.start() < pos and \
943 - message_match.end() > pos:
944 - break
945 -
946 - # This is an attempt to avoid false positives without getting
947 - # too complex, while possibly allowing some (hopefully
948 - # unlikely) violations to slip through. We just assume
949 - # everything is correct if the there is a ' [[ ' or a ' ]] '
950 - # anywhere in the whole line (possibly continued over one
951 - # line).
952 - if self.cond_begin.search(line) is not None:
953 - continue
954 - if self.cond_end.search(line) is not None:
955 - continue
956 -
957 - # Any remaining matches on the same line can be ignored.
958 - return errors.MISSING_QUOTES_ERROR
959 -
960 -
961 -class EbuildAssignment(LineCheck):
962 - """Ensure ebuilds don't assign to readonly variables."""
963 -
964 - repoman_check_name = 'variable.readonly'
965 - read_only_vars = 'A|CATEGORY|P|P[VNRF]|PVR|D|WORKDIR|FILESDIR|FEATURES|USE'
966 - readonly_assignment = re.compile(r'^\s*(export\s+)?(%s)=' % read_only_vars)
967 -
968 - def check(self, num, line):
969 - match = self.readonly_assignment.match(line)
970 - e = None
971 - if match is not None:
972 - e = errors.READONLY_ASSIGNMENT_ERROR
973 - return e
974 -
975 -
976 -class Eapi3EbuildAssignment(EbuildAssignment):
977 - """Ensure ebuilds don't assign to readonly EAPI 3-introduced variables."""
978 -
979 - readonly_assignment = re.compile(r'\s*(export\s+)?(ED|EPREFIX|EROOT)=')
980 -
981 - def check_eapi(self, eapi):
982 - return eapi_supports_prefix(eapi)
983 -
984 -
985 -class EbuildNestedDie(LineCheck):
986 - """Check ebuild for nested die statements (die statements in subshells)"""
987 -
988 - repoman_check_name = 'ebuild.nesteddie'
989 - nesteddie_re = re.compile(r'^[^#]*\s\(\s[^)]*\bdie\b')
990 -
991 - def check(self, num, line):
992 - if self.nesteddie_re.match(line):
993 - return errors.NESTED_DIE_ERROR
994 -
995 -
996 -class EbuildUselessDodoc(LineCheck):
997 - """Check ebuild for useless files in dodoc arguments."""
998 - repoman_check_name = 'ebuild.minorsyn'
999 - uselessdodoc_re = re.compile(
1000 - r'^\s*dodoc(\s+|\s+.*\s+)(ABOUT-NLS|COPYING|LICENCE|LICENSE)($|\s)')
1001 -
1002 - def check(self, num, line):
1003 - match = self.uselessdodoc_re.match(line)
1004 - if match:
1005 - return "Useless dodoc '%s'" % (match.group(2), ) + " on line: %d"
1006 -
1007 -
1008 -class EbuildUselessCdS(LineCheck):
1009 - """Check for redundant cd ${S} statements"""
1010 - repoman_check_name = 'ebuild.minorsyn'
1011 - _src_phases = r'^\s*src_(prepare|configure|compile|install|test)\s*\(\)'
1012 - method_re = re.compile(_src_phases)
1013 - cds_re = re.compile(r'^\s*cd\s+("\$(\{S\}|S)"|\$(\{S\}|S))\s')
1014 -
1015 - def __init__(self):
1016 - self.check_next_line = False
1017 -
1018 - def check(self, num, line):
1019 - if self.check_next_line:
1020 - self.check_next_line = False
1021 - if self.cds_re.match(line):
1022 - return errors.REDUNDANT_CD_S_ERROR
1023 - elif self.method_re.match(line):
1024 - self.check_next_line = True
1025 -
1026 -
1027 -class EapiDefinition(LineCheck):
1028 - """
1029 - Check that EAPI assignment conforms to PMS section 7.3.1
1030 - (first non-comment, non-blank line).
1031 - """
1032 - repoman_check_name = 'EAPI.definition'
1033 - ignore_comment = True
1034 - _eapi_re = portage._pms_eapi_re
1035 -
1036 - def new(self, pkg):
1037 - self._cached_eapi = pkg.eapi
1038 - self._parsed_eapi = None
1039 - self._eapi_line_num = None
1040 -
1041 - def check(self, num, line):
1042 - if self._eapi_line_num is None and line.strip():
1043 - self._eapi_line_num = num + 1
1044 - m = self._eapi_re.match(line)
1045 - if m is not None:
1046 - self._parsed_eapi = m.group(2)
1047 -
1048 - def end(self):
1049 - if self._parsed_eapi is None:
1050 - if self._cached_eapi != "0":
1051 - yield "valid EAPI assignment must occur on or before line: %s" % \
1052 - self._eapi_line_num
1053 - elif self._parsed_eapi != self._cached_eapi:
1054 - yield (
1055 - "bash returned EAPI '%s' which does not match "
1056 - "assignment on line: %s" %
1057 - (self._cached_eapi, self._eapi_line_num))
1058 -
1059 -
1060 -class EbuildPatches(LineCheck):
1061 - """Ensure ebuilds use bash arrays for PATCHES to ensure white space safety"""
1062 - repoman_check_name = 'ebuild.patches'
1063 - re = re.compile(r'^\s*PATCHES=[^\(]')
1064 - error = errors.PATCHES_ERROR
1065 -
1066 -
1067 -class EbuildQuotedA(LineCheck):
1068 - """Ensure ebuilds have no quoting around ${A}"""
1069 -
1070 - repoman_check_name = 'ebuild.minorsyn'
1071 - a_quoted = re.compile(r'.*\"\$(\{A\}|A)\"')
1072 -
1073 - def check(self, num, line):
1074 - match = self.a_quoted.match(line)
1075 - if match:
1076 - return "Quoted \"${A}\" on line: %d"
1077 -
1078 -
1079 -class NoOffsetWithHelpers(LineCheck):
1080 - """ Check that the image location, the alternate root offset, and the
1081 - offset prefix (D, ROOT, ED, EROOT and EPREFIX) are not used with
1082 - helpers """
1083 -
1084 - repoman_check_name = 'variable.usedwithhelpers'
1085 - # Ignore matches in quoted strings like this:
1086 - # elog "installed into ${ROOT}usr/share/php5/apc/."
1087 - _install_funcs = (
1088 - 'docinto|do(compress|dir|hard)'
1089 - '|exeinto|fowners|fperms|insinto|into')
1090 - _quoted_vars = 'D|ROOT|ED|EROOT|EPREFIX'
1091 - re = re.compile(
1092 - r'^[^#"\']*\b(%s)\s+"?\$\{?(%s)\b.*' %
1093 - (_install_funcs, _quoted_vars))
1094 - error = errors.NO_OFFSET_WITH_HELPERS
1095 -
1096 -
1097 -class ImplicitRuntimeDeps(LineCheck):
1098 - """
1099 - Detect the case where DEPEND is set and RDEPEND is unset in the ebuild,
1100 - since this triggers implicit RDEPEND=$DEPEND assignment (prior to EAPI 4).
1101 - """
1102 -
1103 - repoman_check_name = 'RDEPEND.implicit'
1104 - _assignment_re = re.compile(r'^\s*(R?DEPEND)\+?=')
1105 -
1106 - def new(self, pkg):
1107 - self._rdepend = False
1108 - self._depend = False
1109 -
1110 - def check_eapi(self, eapi):
1111 - # Beginning with EAPI 4, there is no
1112 - # implicit RDEPEND=$DEPEND assignment
1113 - # to be concerned with.
1114 - return eapi_has_implicit_rdepend(eapi)
1115 -
1116 - def check(self, num, line):
1117 - if not self._rdepend:
1118 - m = self._assignment_re.match(line)
1119 - if m is None:
1120 - pass
1121 - elif m.group(1) == "RDEPEND":
1122 - self._rdepend = True
1123 - elif m.group(1) == "DEPEND":
1124 - self._depend = True
1125 -
1126 - def end(self):
1127 - if self._depend and not self._rdepend:
1128 - yield 'RDEPEND is not explicitly assigned'
1129 -
1130 -
1131 -class InheritDeprecated(LineCheck):
1132 - """Check if ebuild directly or indirectly inherits a deprecated eclass."""
1133 -
1134 - repoman_check_name = 'inherit.deprecated'
1135 -
1136 - # deprecated eclass : new eclass (False if no new eclass)
1137 - deprecated_classes = {
1138 - "bash-completion": "bash-completion-r1",
1139 - "boost-utils": False,
1140 - "distutils": "distutils-r1",
1141 - "gems": "ruby-fakegem",
1142 - "mono": "mono-env",
1143 - "python": "python-r1 / python-single-r1 / python-any-r1",
1144 - "ruby": "ruby-ng",
1145 - "x-modular": "xorg-2",
1146 - }
1147 -
1148 - _inherit_re = re.compile(r'^\s*inherit\s(.*)$')
1149 -
1150 - def new(self, pkg):
1151 - self._errors = []
1152 -
1153 - def check(self, num, line):
1154 - direct_inherits = None
1155 - m = self._inherit_re.match(line)
1156 - if m is not None:
1157 - direct_inherits = m.group(1)
1158 - if direct_inherits:
1159 - direct_inherits = direct_inherits.split()
1160 -
1161 - if not direct_inherits:
1162 - return
1163 -
1164 - for eclass in direct_inherits:
1165 - replacement = self.deprecated_classes.get(eclass)
1166 - if replacement is None:
1167 - pass
1168 - elif replacement is False:
1169 - self._errors.append(
1170 - "please migrate from "
1171 - "'%s' (no replacement) on line: %d" % (eclass, num + 1))
1172 - else:
1173 - self._errors.append(
1174 - "please migrate from "
1175 - "'%s' to '%s' on line: %d" % (eclass, replacement, num + 1))
1176 -
1177 - def end(self):
1178 - for error in self._errors:
1179 - yield error
1180 - del self._errors
1181 -
1182 -
1183 -
1184 -class InheritEclass(LineCheck):
1185 - """
1186 - Base class for checking for missing inherits, as well as excess inherits.
1187 -
1188 - Args:
1189 - eclass: Set to the name of your eclass.
1190 - funcs: A tuple of functions that this eclass provides.
1191 - comprehensive: Is the list of functions complete?
1192 - exempt_eclasses: If these eclasses are inherited, disable the missing
1193 - inherit check.
1194 - """
1195 -
1196 - def __init__(
1197 - self, eclass, funcs=None, comprehensive=False,
1198 - exempt_eclasses=None, ignore_missing=False, **kwargs):
1199 - self._eclass = eclass
1200 - self._comprehensive = comprehensive
1201 - self._exempt_eclasses = exempt_eclasses
1202 - self._ignore_missing = ignore_missing
1203 - inherit_re = eclass
1204 - self._inherit_re = re.compile(
1205 - r'^(\s*|.*[|&]\s*)\binherit\s(.*\s)?%s(\s|$)' % inherit_re)
1206 - # Match when the function is preceded only by leading whitespace, a
1207 - # shell operator such as (, {, |, ||, or &&, or optional variable
1208 - # setting(s). This prevents false positives in things like elog
1209 - # messages, as reported in bug #413285.
1210 - self._func_re = re.compile(
1211 - r'(^|[|&{(])\s*(\w+=.*)?\b(' + '|'.join(funcs) + r')\b')
1212 -
1213 - def new(self, pkg):
1214 - self.repoman_check_name = 'inherit.missing'
1215 - # We can't use pkg.inherited because that tells us all the eclasses that
1216 - # have been inherited and not just the ones we inherit directly.
1217 - self._inherit = False
1218 - self._func_call = False
1219 - if self._exempt_eclasses is not None:
1220 - inherited = pkg.inherited
1221 - self._disabled = any(x in inherited for x in self._exempt_eclasses)
1222 - else:
1223 - self._disabled = False
1224 - self._eapi = pkg.eapi
1225 -
1226 - def check(self, num, line):
1227 - if not self._inherit:
1228 - self._inherit = self._inherit_re.match(line)
1229 - if not self._inherit:
1230 - if self._disabled or self._ignore_missing:
1231 - return
1232 - s = self._func_re.search(line)
1233 - if s is not None:
1234 - func_name = s.group(3)
1235 - eapi_func = _eclass_eapi_functions.get(func_name)
1236 - if eapi_func is None or not eapi_func(self._eapi):
1237 - self._func_call = True
1238 - return (
1239 - '%s.eclass is not inherited, '
1240 - 'but "%s" found at line: %s' %
1241 - (self._eclass, func_name, '%d'))
1242 - elif not self._func_call:
1243 - self._func_call = self._func_re.search(line)
1244 -
1245 - def end(self):
1246 - if not self._disabled and self._comprehensive and self._inherit \
1247 - and not self._func_call:
1248 - self.repoman_check_name = 'inherit.unused'
1249 - yield 'no function called from %s.eclass; please drop' % self._eclass
1250 -
1251 -_usex_supported_eapis = ("0", "1", "2", "3", "4", "4-python", "4-slot-abi")
1252 -_eclass_eapi_functions = {
1253 - "usex": lambda eapi: eapi not in _usex_supported_eapis
1254 -}
1255 -
1256 -# eclasses that export ${ECLASS}_src_(compile|configure|install)
1257 -_eclass_export_functions = (
1258 - 'ant-tasks', 'apache-2', 'apache-module', 'aspell-dict',
1259 - 'autotools-utils', 'base', 'bsdmk', 'cannadic',
1260 - 'clutter', 'cmake-utils', 'db', 'distutils', 'elisp',
1261 - 'embassy', 'emboss', 'emul-linux-x86', 'enlightenment',
1262 - 'font-ebdftopcf', 'font', 'fox', 'freebsd', 'freedict',
1263 - 'games', 'games-ggz', 'games-mods', 'gdesklets',
1264 - 'gems', 'gkrellm-plugin', 'gnatbuild', 'gnat', 'gnome2',
1265 - 'gnome-python-common', 'gnustep-base', 'go-mono', 'gpe',
1266 - 'gst-plugins-bad', 'gst-plugins-base', 'gst-plugins-good',
1267 - 'gst-plugins-ugly', 'gtk-sharp-module', 'haskell-cabal',
1268 - 'horde', 'java-ant-2', 'java-pkg-2', 'java-pkg-simple',
1269 - 'java-virtuals-2', 'kde4-base', 'kde4-meta', 'kernel-2',
1270 - 'latex-package', 'linux-mod', 'mozlinguas', 'myspell',
1271 - 'myspell-r2', 'mysql', 'mysql-v2', 'mythtv-plugins',
1272 - 'oasis', 'obs-service', 'office-ext', 'perl-app',
1273 - 'perl-module', 'php-ext-base-r1', 'php-ext-pecl-r2',
1274 - 'php-ext-source-r2', 'php-lib-r1', 'php-pear-lib-r1',
1275 - 'php-pear-r1', 'python-distutils-ng', 'python',
1276 - 'qt4-build', 'qt4-r2', 'rox-0install', 'rox', 'ruby',
1277 - 'ruby-ng', 'scsh', 'selinux-policy-2', 'sgml-catalog',
1278 - 'stardict', 'sword-module', 'tetex-3', 'tetex',
1279 - 'texlive-module', 'toolchain-binutils', 'toolchain',
1280 - 'twisted', 'vdr-plugin-2', 'vdr-plugin', 'vim',
1281 - 'vim-plugin', 'vim-spell', 'virtuoso', 'vmware',
1282 - 'vmware-mod', 'waf-utils', 'webapp', 'xemacs-elisp',
1283 - 'xemacs-packages', 'xfconf', 'x-modular', 'xorg-2',
1284 - 'zproduct'
1285 -)
1286 -
1287 -_eclass_info = {
1288 - 'autotools': {
1289 - 'funcs': (
1290 - 'eaclocal', 'eautoconf', 'eautoheader',
1291 - 'eautomake', 'eautoreconf', '_elibtoolize',
1292 - 'eautopoint'
1293 - ),
1294 - 'comprehensive': True,
1295 -
1296 - # Exempt eclasses:
1297 - # git - An EGIT_BOOTSTRAP variable may be used to call one of
1298 - # the autotools functions.
1299 - # subversion - An ESVN_BOOTSTRAP variable may be used to call one of
1300 - # the autotools functions.
1301 - 'exempt_eclasses': ('git', 'git-2', 'subversion', 'autotools-utils')
1302 - },
1303 -
1304 - 'eutils': {
1305 - 'funcs': (
1306 - 'estack_push', 'estack_pop', 'eshopts_push', 'eshopts_pop',
1307 - 'eumask_push', 'eumask_pop', 'epatch', 'epatch_user',
1308 - 'emktemp', 'edos2unix', 'in_iuse', 'use_if_iuse', 'usex'
1309 - ),
1310 - 'comprehensive': False,
1311 -
1312 - # These are "eclasses are the whole ebuild" type thing.
1313 - 'exempt_eclasses': _eclass_export_functions,
1314 - },
1315 -
1316 - 'flag-o-matic': {
1317 - 'funcs': (
1318 - 'filter-(ld)?flags', 'strip-flags', 'strip-unsupported-flags',
1319 - 'append-((ld|c(pp|xx)?))?flags', 'append-libs',
1320 - ),
1321 - 'comprehensive': False
1322 - },
1323 -
1324 - 'libtool': {
1325 - 'funcs': (
1326 - 'elibtoolize',
1327 - ),
1328 - 'comprehensive': True,
1329 - 'exempt_eclasses': ('autotools',)
1330 - },
1331 -
1332 - 'multilib': {
1333 - 'funcs': (
1334 - 'get_libdir',
1335 - ),
1336 -
1337 - # These are "eclasses are the whole ebuild" type thing.
1338 - 'exempt_eclasses': _eclass_export_functions + (
1339 - 'autotools', 'libtool', 'multilib-minimal'),
1340 -
1341 - 'comprehensive': False
1342 - },
1343 -
1344 - 'multiprocessing': {
1345 - 'funcs': (
1346 - 'makeopts_jobs',
1347 - ),
1348 - 'comprehensive': False
1349 - },
1350 -
1351 - 'prefix': {
1352 - 'funcs': (
1353 - 'eprefixify',
1354 - ),
1355 - 'comprehensive': True
1356 - },
1357 -
1358 - 'toolchain-funcs': {
1359 - 'funcs': (
1360 - 'gen_usr_ldscript',
1361 - ),
1362 - 'comprehensive': False
1363 - },
1364 -
1365 - 'user': {
1366 - 'funcs': (
1367 - 'enewuser', 'enewgroup',
1368 - 'egetent', 'egethome', 'egetshell', 'esethome'
1369 - ),
1370 - 'comprehensive': True
1371 - }
1372 -}
1373 -
1374 -
1375 -class EMakeParallelDisabled(PhaseCheck):
1376 - """Check for emake -j1 calls which disable parallelization."""
1377 - repoman_check_name = 'upstream.workaround'
1378 - re = re.compile(r'^\s*emake\s+.*-j\s*1\b')
1379 - error = errors.EMAKE_PARALLEL_DISABLED
1380 -
1381 - def phase_check(self, num, line):
1382 - if self.in_phase == 'src_compile' or self.in_phase == 'src_install':
1383 - if self.re.match(line):
1384 - return self.error
1385 -
1386 -
1387 -class EMakeParallelDisabledViaMAKEOPTS(LineCheck):
1388 - """Check for MAKEOPTS=-j1 that disables parallelization."""
1389 - repoman_check_name = 'upstream.workaround'
1390 - re = re.compile(r'^\s*MAKEOPTS=(\'|")?.*-j\s*1\b')
1391 - error = errors.EMAKE_PARALLEL_DISABLED_VIA_MAKEOPTS
1392 -
1393 -
1394 -class NoAsNeeded(LineCheck):
1395 - """Check for calls to the no-as-needed function."""
1396 - repoman_check_name = 'upstream.workaround'
1397 - re = re.compile(r'.*\$\(no-as-needed\)')
1398 - error = errors.NO_AS_NEEDED
1399 -
1400 -
1401 -class PreserveOldLib(LineCheck):
1402 - """Check for calls to the deprecated preserve_old_lib function."""
1403 - repoman_check_name = 'ebuild.minorsyn'
1404 - re = re.compile(r'.*preserve_old_lib')
1405 - error = errors.PRESERVE_OLD_LIB
1406 -
1407 -
1408 -class SandboxAddpredict(LineCheck):
1409 - """Check for calls to the addpredict function."""
1410 - repoman_check_name = 'upstream.workaround'
1411 - re = re.compile(r'(^|\s)addpredict\b')
1412 - error = errors.SANDBOX_ADDPREDICT
1413 -
1414 -
1415 -class DeprecatedBindnowFlags(LineCheck):
1416 - """Check for calls to the deprecated bindnow-flags function."""
1417 - repoman_check_name = 'ebuild.minorsyn'
1418 - re = re.compile(r'.*\$\(bindnow-flags\)')
1419 - error = errors.DEPRECATED_BINDNOW_FLAGS
1420 -
1421 -
1422 -class WantAutoDefaultValue(LineCheck):
1423 - """Check setting WANT_AUTO* to latest (default value)."""
1424 - repoman_check_name = 'ebuild.minorsyn'
1425 - _re = re.compile(r'^WANT_AUTO(CONF|MAKE)=(\'|")?latest')
1426 -
1427 - def check(self, num, line):
1428 - m = self._re.match(line)
1429 - if m is not None:
1430 - return 'WANT_AUTO' + m.group(1) + \
1431 - ' redundantly set to default value "latest" on line: %d'
1432 -
1433 -
1434 -class SrcCompileEconf(PhaseCheck):
1435 - repoman_check_name = 'ebuild.minorsyn'
1436 - configure_re = re.compile(r'\s(econf|./configure)')
1437 -
1438 - def check_eapi(self, eapi):
1439 - return eapi_has_src_prepare_and_src_configure(eapi)
1440 -
1441 - def phase_check(self, num, line):
1442 - if self.in_phase == 'src_compile':
1443 - m = self.configure_re.match(line)
1444 - if m is not None:
1445 - return ("'%s'" % m.group(1)) + \
1446 - " call should be moved to src_configure from line: %d"
1447 -
1448 -
1449 -class SrcUnpackPatches(PhaseCheck):
1450 - repoman_check_name = 'ebuild.minorsyn'
1451 - src_prepare_tools_re = re.compile(r'\s(e?patch|sed)\s')
1452 -
1453 - def check_eapi(self, eapi):
1454 - return eapi_has_src_prepare_and_src_configure(eapi)
1455 -
1456 - def phase_check(self, num, line):
1457 - if self.in_phase == 'src_unpack':
1458 - m = self.src_prepare_tools_re.search(line)
1459 - if m is not None:
1460 - return ("'%s'" % m.group(1)) + \
1461 - " call should be moved to src_prepare from line: %d"
1462 -
1463 -
1464 -class BuiltWithUse(LineCheck):
1465 - repoman_check_name = 'ebuild.minorsyn'
1466 - re = re.compile(r'(^|.*\b)built_with_use\b')
1467 - error = errors.BUILT_WITH_USE
1468 -
1469 -
1470 -class DeprecatedUseq(LineCheck):
1471 - """Checks for use of the deprecated useq function"""
1472 - repoman_check_name = 'ebuild.minorsyn'
1473 - re = re.compile(r'(^|.*\b)useq\b')
1474 - error = errors.USEQ_ERROR
1475 -
1476 -
1477 -class DeprecatedHasq(LineCheck):
1478 - """Checks for use of the deprecated hasq function"""
1479 - repoman_check_name = 'ebuild.minorsyn'
1480 - re = re.compile(r'(^|.*\b)hasq\b')
1481 - error = errors.HASQ_ERROR
1482 -
1483 -
1484 -# EAPI <2 checks
1485 -class UndefinedSrcPrepareSrcConfigurePhases(LineCheck):
1486 - repoman_check_name = 'EAPI.incompatible'
1487 - src_configprepare_re = re.compile(r'\s*(src_configure|src_prepare)\s*\(\)')
1488 -
1489 - def check_eapi(self, eapi):
1490 - return not eapi_has_src_prepare_and_src_configure(eapi)
1491 -
1492 - def check(self, num, line):
1493 - m = self.src_configprepare_re.match(line)
1494 - if m is not None:
1495 - return ("'%s'" % m.group(1)) + \
1496 - " phase is not defined in EAPI < 2 on line: %d"
1497 -
1498 -
1499 -# EAPI-3 checks
1500 -class Eapi3DeprecatedFuncs(LineCheck):
1501 - repoman_check_name = 'EAPI.deprecated'
1502 - deprecated_commands_re = re.compile(r'^\s*(check_license)\b')
1503 -
1504 - def check_eapi(self, eapi):
1505 - return eapi not in ('0', '1', '2')
1506 -
1507 - def check(self, num, line):
1508 - m = self.deprecated_commands_re.match(line)
1509 - if m is not None:
1510 - return ("'%s'" % m.group(1)) + \
1511 - " has been deprecated in EAPI=3 on line: %d"
1512 -
1513 -
1514 -# EAPI <4 checks
1515 -class UndefinedPkgPretendPhase(LineCheck):
1516 - repoman_check_name = 'EAPI.incompatible'
1517 - pkg_pretend_re = re.compile(r'\s*(pkg_pretend)\s*\(\)')
1518 -
1519 - def check_eapi(self, eapi):
1520 - return not eapi_has_pkg_pretend(eapi)
1521 -
1522 - def check(self, num, line):
1523 - m = self.pkg_pretend_re.match(line)
1524 - if m is not None:
1525 - return ("'%s'" % m.group(1)) + \
1526 - " phase is not defined in EAPI < 4 on line: %d"
1527 -
1528 -
1529 -# EAPI-4 checks
1530 -class Eapi4IncompatibleFuncs(LineCheck):
1531 - repoman_check_name = 'EAPI.incompatible'
1532 - banned_commands_re = re.compile(r'^\s*(dosed|dohard)')
1533 -
1534 - def check_eapi(self, eapi):
1535 - return not eapi_has_dosed_dohard(eapi)
1536 -
1537 - def check(self, num, line):
1538 - m = self.banned_commands_re.match(line)
1539 - if m is not None:
1540 - return ("'%s'" % m.group(1)) + \
1541 - " has been banned in EAPI=4 on line: %d"
1542 -
1543 -
1544 -class Eapi4GoneVars(LineCheck):
1545 - repoman_check_name = 'EAPI.incompatible'
1546 - undefined_vars_re = re.compile(
1547 - r'.*\$(\{(AA|KV|EMERGE_FROM)\}|(AA|KV|EMERGE_FROM))')
1548 -
1549 - def check_eapi(self, eapi):
1550 - # AA, KV, and EMERGE_FROM should not be referenced in EAPI 4 or later.
1551 - return not eapi_exports_AA(eapi)
1552 -
1553 - def check(self, num, line):
1554 - m = self.undefined_vars_re.match(line)
1555 - if m is not None:
1556 - return ("variable '$%s'" % m.group(1)) + \
1557 - " is gone in EAPI=4 on line: %d"
1558 -
1559 -
1560 -class PortageInternal(LineCheck):
1561 - repoman_check_name = 'portage.internal'
1562 - ignore_comment = True
1563 - # Match when the command is preceded only by leading whitespace or a shell
1564 - # operator such as (, {, |, ||, or &&. This prevents false positives in
1565 - # things like elog messages, as reported in bug #413285.
1566 -
1567 - internal_portage_func_or_var = (
1568 - 'ecompress|ecompressdir|env-update|prepall|prepalldocs|preplib')
1569 - re = re.compile(
1570 - r'^(\s*|.*[|&{(]+\s*)\b(%s)\b' % internal_portage_func_or_var)
1571 -
1572 - def check(self, num, line):
1573 - """Run the check on line and return error if there is one"""
1574 - m = self.re.match(line)
1575 - if m is not None:
1576 - return ("'%s'" % m.group(2)) + " called on line: %d"
1577 -
1578 -
1579 -class PortageInternalVariableAssignment(LineCheck):
1580 - repoman_check_name = 'portage.internal'
1581 - internal_assignment = re.compile(
1582 - r'\s*(export\s+)?(EXTRA_ECONF|EXTRA_EMAKE)\+?=')
1583 -
1584 - def check(self, num, line):
1585 - match = self.internal_assignment.match(line)
1586 - e = None
1587 - if match is not None:
1588 - e = 'Assignment to variable %s' % match.group(2)
1589 - e += ' on line: %d'
1590 - return e
1591 -
1592 -_base_check_classes = (InheritEclass, LineCheck, PhaseCheck)
1593 -_constant_checks = None
1594 -
1595 -
1596 -def checks_init(experimental_inherit=False):
1597 -
1598 - global _constant_checks, _eclass_info
1599 -
1600 - if not experimental_inherit:
1601 - # Emulate the old eprefixify.defined and inherit.autotools checks.
1602 - _eclass_info = {
1603 - 'autotools': {
1604 - 'funcs': (
1605 - 'eaclocal', 'eautoconf', 'eautoheader',
1606 - 'eautomake', 'eautoreconf', '_elibtoolize',
1607 - 'eautopoint'
1608 - ),
1609 - 'comprehensive': True,
1610 - 'ignore_missing': True,
1611 - 'exempt_eclasses': ('git', 'git-2', 'subversion', 'autotools-utils')
1612 - },
1613 -
1614 - 'prefix': {
1615 - 'funcs': (
1616 - 'eprefixify',
1617 - ),
1618 - 'comprehensive': False
1619 - }
1620 - }
1621 -
1622 - _constant_checks = tuple(
1623 - chain((
1624 - v() for k, v in globals().items()
1625 - if (
1626 - isinstance(v, type)
1627 - and issubclass(v, LineCheck)
1628 - and v not in _base_check_classes)), (
1629 - InheritEclass(k, **portage._native_kwargs(kwargs))
1630 - for k, kwargs in _eclass_info.items())))
1631 -
1632 -
1633 -_here_doc_re = re.compile(r'.*\s<<[-]?(\w+)$')
1634 -_ignore_comment_re = re.compile(r'^\s*#')
1635 -
1636 -
1637 -def run_checks(contents, pkg):
1638 - unicode_escape_codec = codecs.lookup('unicode_escape')
1639 - unicode_escape = lambda x: unicode_escape_codec.decode(x)[0]
1640 - if _constant_checks is None:
1641 - checks_init()
1642 - checks = _constant_checks
1643 - here_doc_delim = None
1644 - multiline = None
1645 -
1646 - for lc in checks:
1647 - lc.new(pkg)
1648 -
1649 - multinum = 0
1650 - for num, line in enumerate(contents):
1651 -
1652 - # Check if we're inside a here-document.
1653 - if here_doc_delim is not None:
1654 - if here_doc_delim.match(line):
1655 - here_doc_delim = None
1656 - if here_doc_delim is None:
1657 - here_doc = _here_doc_re.match(line)
1658 - if here_doc is not None:
1659 - here_doc_delim = re.compile(r'^\s*%s$' % here_doc.group(1))
1660 - if here_doc_delim is not None:
1661 - continue
1662 -
1663 - # Unroll multiline escaped strings so that we can check things:
1664 - # inherit foo bar \
1665 - # moo \
1666 - # cow
1667 - # This will merge these lines like so:
1668 - # inherit foo bar moo cow
1669 - try:
1670 - # A normal line will end in the two bytes: <\> <\n>. So decoding
1671 - # that will result in python thinking the <\n> is being escaped
1672 - # and eat the single <\> which makes it hard for us to detect.
1673 - # Instead, strip the newline (which we know all lines have), and
1674 - # append a <0>. Then when python escapes it, if the line ended
1675 - # in a <\>, we'll end up with a <\0> marker to key off of. This
1676 - # shouldn't be a problem with any valid ebuild ...
1677 - line_escaped = unicode_escape(line.rstrip('\n') + '0')
1678 - except SystemExit:
1679 - raise
1680 - except:
1681 - # Who knows what kind of crazy crap an ebuild will have
1682 - # in it -- don't allow it to kill us.
1683 - line_escaped = line
1684 - if multiline:
1685 - # Chop off the \ and \n bytes from the previous line.
1686 - multiline = multiline[:-2] + line
1687 - if not line_escaped.endswith('\0'):
1688 - line = multiline
1689 - num = multinum
1690 - multiline = None
1691 - else:
1692 - continue
1693 - else:
1694 - if line_escaped.endswith('\0'):
1695 - multinum = num
1696 - multiline = line
1697 - continue
1698 -
1699 - if not line.endswith("#nowarn\n"):
1700 - # Finally we have a full line to parse.
1701 - is_comment = _ignore_comment_re.match(line) is not None
1702 - for lc in checks:
1703 - if is_comment and lc.ignore_comment:
1704 - continue
1705 - if lc.check_eapi(pkg.eapi):
1706 - ignore = lc.ignore_line
1707 - if not ignore or not ignore.match(line):
1708 - e = lc.check(num, line)
1709 - if e:
1710 - yield lc.repoman_check_name, e % (num + 1)
1711 -
1712 - for lc in checks:
1713 - i = lc.end()
1714 - if i is not None:
1715 - for e in i:
1716 - yield lc.repoman_check_name, e
1717
1718 diff --git a/pym/tbc/repoman/checks/ebuilds/eclasses/__init__.py b/pym/tbc/repoman/checks/ebuilds/eclasses/__init__.py
1719 deleted file mode 100644
1720 index e69de29..0000000
1721
1722 diff --git a/pym/tbc/repoman/checks/ebuilds/eclasses/live.py b/pym/tbc/repoman/checks/ebuilds/eclasses/live.py
1723 deleted file mode 100644
1724 index 754c557..0000000
1725 --- a/pym/tbc/repoman/checks/ebuilds/eclasses/live.py
1726 +++ /dev/null
1727 @@ -1,39 +0,0 @@
1728 -
1729 -'''live.py
1730 -Performs Live eclass checks
1731 -'''
1732 -
1733 -from tbc.repoman.repos import has_global_mask
1734 -
1735 -
1736 -class LiveEclassChecks(object):
1737 - '''Performs checks for the usage of Live eclasses in ebuilds'''
1738 -
1739 - def __init__(self, qatracker):
1740 - '''
1741 - @param qatracker: QATracker instance
1742 - '''
1743 - self.qatracker = qatracker
1744 -
1745 - def check(self, pkg, package, ebuild, y_ebuild, keywords, global_pmaskdict):
1746 - '''Ebuilds that inherit a "Live" eclass (darcs, subversion, git, cvs,
1747 - etc..) should not be allowed to be marked stable
1748 -
1749 - @param pkg: Package in which we check (object).
1750 - @param package: Package in which we check (string).
1751 - @param ebuild: Ebuild which we check (object).
1752 - @param y_ebuild: Ebuild which we check (string).
1753 - @param keywords: The keywords of the ebuild.
1754 - @param global_pmaskdict: A global dictionary of all the masks.
1755 - '''
1756 - is_stable = lambda kw: not kw.startswith("~") and not kw.startswith("-")
1757 - bad_stable_keywords = list(filter(is_stable, keywords))
1758 -
1759 - if bad_stable_keywords:
1760 - self.qatracker.add_error(
1761 - "LIVEVCS.stable", "%s/%s.ebuild with stable keywords:%s " % (
1762 - package, y_ebuild, bad_stable_keywords))
1763 -
1764 - good_keywords_exist = len(bad_stable_keywords) < len(keywords)
1765 - if good_keywords_exist and not has_global_mask(pkg, global_pmaskdict):
1766 - self.qatracker.add_error("LIVEVCS.unmasked", ebuild.relative_path)
1767
1768 diff --git a/pym/tbc/repoman/checks/ebuilds/eclasses/ruby.py b/pym/tbc/repoman/checks/ebuilds/eclasses/ruby.py
1769 deleted file mode 100644
1770 index e8d36ea..0000000
1771 --- a/pym/tbc/repoman/checks/ebuilds/eclasses/ruby.py
1772 +++ /dev/null
1773 @@ -1,32 +0,0 @@
1774 -
1775 -'''live.py
1776 -Performs Ruby eclass checks
1777 -'''
1778 -
1779 -from repoman.qa_data import ruby_deprecated
1780 -
1781 -
1782 -class RubyEclassChecks(object):
1783 - '''Performs checks for the usage of Ruby eclasses in ebuilds'''
1784 -
1785 - def __init__(self, qatracker):
1786 - '''
1787 - @param qatracker: QATracker instance
1788 - '''
1789 - self.qatracker = qatracker
1790 - self.old_ruby_eclasses = ["ruby-ng", "ruby-fakegem", "ruby"]
1791 -
1792 - def check(self, pkg, ebuild):
1793 - is_inherited = lambda eclass: eclass in pkg.inherited
1794 - is_old_ruby_eclass_inherited = filter(
1795 - is_inherited, self.old_ruby_eclasses)
1796 -
1797 - if is_old_ruby_eclass_inherited:
1798 - ruby_intersection = pkg.iuse.all.intersection(ruby_deprecated)
1799 -
1800 - if ruby_intersection:
1801 - for myruby in ruby_intersection:
1802 - self.qatracker.add_error(
1803 - "IUSE.rubydeprecated",
1804 - (ebuild.relative_path + ": Deprecated ruby target: %s")
1805 - % myruby)
1806
1807 diff --git a/pym/tbc/repoman/checks/ebuilds/errors.py b/pym/tbc/repoman/checks/ebuilds/errors.py
1808 deleted file mode 100644
1809 index 20ebc29..0000000
1810 --- a/pym/tbc/repoman/checks/ebuilds/errors.py
1811 +++ /dev/null
1812 @@ -1,48 +0,0 @@
1813 -# repoman: Error Messages
1814 -# Copyright 2007-2013 Gentoo Foundation
1815 -# Distributed under the terms of the GNU General Public License v2
1816 -
1817 -from __future__ import unicode_literals
1818 -
1819 -COPYRIGHT_ERROR = (
1820 - 'Invalid Gentoo Copyright on line: %d')
1821 -LICENSE_ERROR = (
1822 - 'Invalid Gentoo/GPL License on line: %d')
1823 -CVS_HEADER_ERROR = (
1824 - 'Malformed CVS Header on line: %d')
1825 -LEADING_SPACES_ERROR = (
1826 - 'Ebuild contains leading spaces on line: %d')
1827 -TRAILING_WHITESPACE_ERROR = (
1828 - 'Trailing whitespace error on line: %d')
1829 -READONLY_ASSIGNMENT_ERROR = (
1830 - 'Ebuild contains assignment to read-only variable on line: %d')
1831 -MISSING_QUOTES_ERROR = (
1832 - 'Unquoted Variable on line: %d')
1833 -NESTED_DIE_ERROR = (
1834 - 'Ebuild calls die in a subshell on line: %d')
1835 -PATCHES_ERROR = (
1836 - 'PATCHES is not a bash array on line: %d')
1837 -REDUNDANT_CD_S_ERROR = (
1838 - 'Ebuild has redundant cd ${S} statement on line: %d')
1839 -EMAKE_PARALLEL_DISABLED = (
1840 - 'Upstream parallel compilation bug (ebuild calls emake -j1 on line: %d)')
1841 -EMAKE_PARALLEL_DISABLED_VIA_MAKEOPTS = (
1842 - 'Upstream parallel compilation bug (MAKEOPTS=-j1 on line: %d)')
1843 -DEPRECATED_BINDNOW_FLAGS = (
1844 - 'Deprecated bindnow-flags call on line: %d')
1845 -EAPI_DEFINED_AFTER_INHERIT = (
1846 - 'EAPI defined after inherit on line: %d')
1847 -NO_AS_NEEDED = (
1848 - 'Upstream asneeded linking bug (no-as-needed on line: %d)')
1849 -PRESERVE_OLD_LIB = (
1850 - 'Ebuild calls deprecated preserve_old_lib on line: %d')
1851 -BUILT_WITH_USE = (
1852 - 'built_with_use on line: %d')
1853 -NO_OFFSET_WITH_HELPERS = (
1854 - "Helper function is used with D, ROOT, ED, EROOT or EPREFIX on line :%d")
1855 -SANDBOX_ADDPREDICT = (
1856 - 'Ebuild calls addpredict on line: %d')
1857 -USEQ_ERROR = (
1858 - 'Ebuild calls deprecated useq function on line: %d')
1859 -HASQ_ERROR = (
1860 - 'Ebuild calls deprecated hasq function on line: %d')
1861
1862 diff --git a/pym/tbc/repoman/checks/ebuilds/fetches.py b/pym/tbc/repoman/checks/ebuilds/fetches.py
1863 deleted file mode 100644
1864 index 95d88e8..0000000
1865 --- a/pym/tbc/repoman/checks/ebuilds/fetches.py
1866 +++ /dev/null
1867 @@ -1,138 +0,0 @@
1868 -
1869 -'''fetches.py
1870 -Performs the src_uri fetchlist and files checks
1871 -'''
1872 -
1873 -from stat import S_ISDIR
1874 -
1875 -# import our initialized portage instance
1876 -from tbc.repoman._portage import portage
1877 -
1878 -from portage import os
1879 -
1880 -from tbc.repoman.vcs.vcs import vcs_new_changed
1881 -
1882 -
1883 -class FetchChecks(object):
1884 - '''Performs checks on the files needed for the ebuild'''
1885 -
1886 - def __init__(
1887 - self, qatracker, repoman_settings, repo_settings, portdb, vcs_settings):
1888 - '''
1889 - @param qatracker: QATracker instance
1890 - @param repoman_settings: settings instance
1891 - @param repo_settings: repository settings instance
1892 - @param portdb: portdb instance
1893 - '''
1894 - self.portdb = portdb
1895 - self.qatracker = qatracker
1896 - self.repo_settings = repo_settings
1897 - self.repoman_settings = repoman_settings
1898 - self.vcs_settings = vcs_settings
1899 - self._digests = None
1900 -
1901 - def check(self, xpkg, checkdir, checkdir_relative, mychanged, mynew):
1902 - '''Checks the ebuild sources and files for errors
1903 -
1904 - @param xpkg: the pacakge being checked
1905 - @param checkdir: string, directory path
1906 - @param checkdir_relative: repolevel determined path
1907 - '''
1908 - self.checkdir = checkdir
1909 - fetchlist_dict = portage.FetchlistDict(
1910 - checkdir, self.repoman_settings, self.portdb)
1911 - myfiles_all = []
1912 - self.src_uri_error = False
1913 - for mykey in fetchlist_dict:
1914 - try:
1915 - myfiles_all.extend(fetchlist_dict[mykey])
1916 - except portage.exception.InvalidDependString as e:
1917 - self.src_uri_error = True
1918 - try:
1919 - self.portdb.aux_get(mykey, ["SRC_URI"])
1920 - except KeyError:
1921 - # This will be reported as an "ebuild.syntax" error.
1922 - pass
1923 - else:
1924 - self.qatracker.add_error(
1925 - "SRC_URI.syntax", "%s.ebuild SRC_URI: %s" % (mykey, e))
1926 - del fetchlist_dict
1927 - if not self.src_uri_error:
1928 - # This test can produce false positives if SRC_URI could not
1929 - # be parsed for one or more ebuilds. There's no point in
1930 - # producing a false error here since the root cause will
1931 - # produce a valid error elsewhere, such as "SRC_URI.syntax"
1932 - # or "ebuild.sytax".
1933 - myfiles_all = set(myfiles_all)
1934 - for entry in self.digests:
1935 - if entry not in myfiles_all:
1936 - self.qatracker.add_error("digest.unused", checkdir + "::" + entry)
1937 - for entry in myfiles_all:
1938 - if entry not in self.digests:
1939 - self.qatracker.add_error("digest.missing", checkdir + "::" + entry)
1940 - del myfiles_all
1941 -
1942 - if os.path.exists(checkdir + "/files"):
1943 - filesdirlist = os.listdir(checkdir + "/files")
1944 -
1945 - # Recurse through files directory, use filesdirlist as a stack;
1946 - # appending directories as needed,
1947 - # so people can't hide > 20k files in a subdirectory.
1948 - while filesdirlist:
1949 - y = filesdirlist.pop(0)
1950 - relative_path = os.path.join(xpkg, "files", y)
1951 - full_path = os.path.join(self.repo_settings.repodir, relative_path)
1952 - try:
1953 - mystat = os.stat(full_path)
1954 - except OSError as oe:
1955 - if oe.errno == 2:
1956 - # don't worry about it. it likely was removed via fix above.
1957 - continue
1958 - else:
1959 - raise oe
1960 - if S_ISDIR(mystat.st_mode):
1961 - # !!! VCS "portability" alert! Need some function isVcsDir() or alike !!!
1962 - if y == "CVS" or y == ".svn":
1963 - continue
1964 - for z in os.listdir(checkdir + "/files/" + y):
1965 - if z == "CVS" or z == ".svn":
1966 - continue
1967 - filesdirlist.append(y + "/" + z)
1968 - # Current policy is no files over 20 KiB, these are the checks.
1969 - # File size between 20 KiB and 60 KiB causes a warning,
1970 - # while file size over 60 KiB causes an error.
1971 - elif mystat.st_size > 61440:
1972 - self.qatracker.add_error(
1973 - "file.size.fatal", "(%d KiB) %s/files/%s" % (
1974 - mystat.st_size // 1024, xpkg, y))
1975 - elif mystat.st_size > 20480:
1976 - self.qatracker.add_error(
1977 - "file.size", "(%d KiB) %s/files/%s" % (
1978 - mystat.st_size // 1024, xpkg, y))
1979 -
1980 - index = self.repo_settings.repo_config.find_invalid_path_char(y)
1981 - if index != -1:
1982 - y_relative = os.path.join(checkdir_relative, "files", y)
1983 - if self.vcs_settings.vcs is not None \
1984 - and not vcs_new_changed(y_relative, mychanged, mynew):
1985 - # If the file isn't in the VCS new or changed set, then
1986 - # assume that it's an irrelevant temporary file (Manifest
1987 - # entries are not generated for file names containing
1988 - # prohibited characters). See bug #406877.
1989 - index = -1
1990 - if index != -1:
1991 - self.qatracker.add_error(
1992 - "file.name",
1993 - "%s/files/%s: char '%s'" % (checkdir, y, y[index]))
1994 -
1995 - @property
1996 - def digests(self):
1997 - '''Property function, returns the saved digests or
1998 - loads them for the test'''
1999 - if not self._digests:
2000 - mf = self.repoman_settings.repositories.get_repo_for_location(
2001 - os.path.dirname(os.path.dirname(self.checkdir)))
2002 - mf = mf.load_manifest(self.checkdir, self.repoman_settings["DISTDIR"])
2003 - self._digests = mf.getTypeDigests("DIST")
2004 - del mf
2005 - return self._digests
2006
2007 diff --git a/pym/tbc/repoman/checks/ebuilds/isebuild.py b/pym/tbc/repoman/checks/ebuilds/isebuild.py
2008 deleted file mode 100644
2009 index 42c69bd..0000000
2010 --- a/pym/tbc/repoman/checks/ebuilds/isebuild.py
2011 +++ /dev/null
2012 @@ -1,70 +0,0 @@
2013 -
2014 -import stat
2015 -
2016 -from _emerge.Package import Package
2017 -from _emerge.RootConfig import RootConfig
2018 -
2019 -# import our initialized portage instance
2020 -from tbc.repoman._portage import portage
2021 -
2022 -from portage import os
2023 -
2024 -from tbc.repoman.qa_data import no_exec, allvars
2025 -
2026 -
2027 -class IsEbuild(object):
2028 -
2029 - def __init__(self, repoman_settings, repo_settings, portdb, qatracker):
2030 - ''''''
2031 - self.portdb = portdb
2032 - self.qatracker = qatracker
2033 - self.root_config = RootConfig(
2034 - repoman_settings, repo_settings.trees[repo_settings.root], None)
2035 -
2036 - def check(self, checkdirlist, checkdir, xpkg):
2037 - self.continue_ = False
2038 - ebuildlist = []
2039 - pkgs = {}
2040 - allvalid = True
2041 - for y in checkdirlist:
2042 - file_is_ebuild = y.endswith(".ebuild")
2043 - file_should_be_non_executable = y in no_exec or file_is_ebuild
2044 -
2045 - if file_should_be_non_executable:
2046 - file_is_executable = stat.S_IMODE(
2047 - os.stat(os.path.join(checkdir, y)).st_mode) & 0o111
2048 -
2049 - if file_is_executable:
2050 - self.qatracker.add_error("file.executable", os.path.join(checkdir, y))
2051 - if file_is_ebuild:
2052 - pf = y[:-7]
2053 - ebuildlist.append(pf)
2054 - catdir = xpkg.split("/")[0]
2055 - cpv = "%s/%s" % (catdir, pf)
2056 - try:
2057 - myaux = dict(zip(allvars, self.portdb.aux_get(cpv, allvars)))
2058 - except KeyError:
2059 - allvalid = False
2060 - self.qatracker.add_error("ebuild.syntax", os.path.join(xpkg, y))
2061 - continue
2062 - except IOError:
2063 - allvalid = False
2064 - self.qatracker.add_error("ebuild.output", os.path.join(xpkg, y))
2065 - continue
2066 - if not portage.eapi_is_supported(myaux["EAPI"]):
2067 - allvalid = False
2068 - self.qatracker.add_error("EAPI.unsupported", os.path.join(xpkg, y))
2069 - continue
2070 - pkgs[pf] = Package(
2071 - cpv=cpv, metadata=myaux, root_config=self.root_config,
2072 - type_name="ebuild")
2073 -
2074 - if len(pkgs) != len(ebuildlist):
2075 - # If we can't access all the metadata then it's totally unsafe to
2076 - # commit since there's no way to generate a correct Manifest.
2077 - # Do not try to do any more QA checks on this package since missing
2078 - # metadata leads to false positives for several checks, and false
2079 - # positives confuse users.
2080 - self.continue_ = True
2081 -
2082 - return pkgs, allvalid
2083
2084 diff --git a/pym/tbc/repoman/checks/ebuilds/keywords.py b/pym/tbc/repoman/checks/ebuilds/keywords.py
2085 deleted file mode 100644
2086 index 235c751..0000000
2087 --- a/pym/tbc/repoman/checks/ebuilds/keywords.py
2088 +++ /dev/null
2089 @@ -1,121 +0,0 @@
2090 -
2091 -'''keywords.py
2092 -Perform KEYWORDS related checks
2093 -'''
2094 -
2095 -
2096 -class KeywordChecks(object):
2097 - '''Perform checks on the KEYWORDS of an ebuild'''
2098 -
2099 - def __init__(self, qatracker, options):
2100 - '''
2101 - @param qatracker: QATracker instance
2102 - '''
2103 - self.qatracker = qatracker
2104 - self.options = options
2105 - self.slot_keywords = {}
2106 -
2107 - def prepare(self):
2108 - '''Prepare the checks for the next package.'''
2109 - self.slot_keywords = {}
2110 -
2111 - def check(
2112 - self, pkg, package, ebuild, y_ebuild, keywords, ebuild_archs, changed,
2113 - live_ebuild, kwlist, profiles):
2114 - '''Perform the check.
2115 -
2116 - @param pkg: Package in which we check (object).
2117 - @param package: Package in which we check (string).
2118 - @param ebuild: Ebuild which we check (object).
2119 - @param y_ebuild: Ebuild which we check (string).
2120 - @param keywords: All the keywords (including -...) of the ebuild.
2121 - @param ebuild_archs: Just the architectures (no prefixes) of the ebuild.
2122 - @param changed: Changes instance
2123 - @param slot_keywords: A dictionary of keywords per slot.
2124 - @param live_ebuild: A boolean that determines if this is a live ebuild.
2125 - @param kwlist: A list of all global keywords.
2126 - @param profiles: A list of all profiles.
2127 - '''
2128 - if not self.options.straight_to_stable:
2129 - self._checkAddedWithStableKeywords(
2130 - package, ebuild, y_ebuild, keywords, changed)
2131 -
2132 - self._checkForDroppedKeywords(
2133 - pkg, ebuild, ebuild_archs, live_ebuild)
2134 -
2135 - self._checkForInvalidKeywords(
2136 - pkg, package, y_ebuild, kwlist, profiles)
2137 -
2138 - self._checkForMaskLikeKeywords(
2139 - package, y_ebuild, keywords, kwlist)
2140 -
2141 - self.slot_keywords[pkg.slot].update(ebuild_archs)
2142 -
2143 - def _isKeywordStable(self, keyword):
2144 - return not keyword.startswith("~") and not keyword.startswith("-")
2145 -
2146 - def _checkAddedWithStableKeywords(
2147 - self, package, ebuild, y_ebuild, keywords, changed):
2148 - catdir, pkgdir = package.split("/")
2149 -
2150 - stable_keywords = list(filter(self._isKeywordStable, keywords))
2151 - if stable_keywords:
2152 - if ebuild.ebuild_path in changed.new_ebuilds and catdir != "virtual":
2153 - stable_keywords.sort()
2154 - self.qatracker.add_error(
2155 - "KEYWORDS.stable",
2156 - "%s/%s.ebuild added with stable keywords: %s" %
2157 - (package, y_ebuild, " ".join(stable_keywords)))
2158 -
2159 - def _checkForDroppedKeywords(
2160 - self, pkg, ebuild, ebuild_archs, live_ebuild):
2161 - previous_keywords = self.slot_keywords.get(pkg.slot)
2162 - if previous_keywords is None:
2163 - self.slot_keywords[pkg.slot] = set()
2164 - elif ebuild_archs and "*" not in ebuild_archs and not live_ebuild:
2165 - dropped_keywords = previous_keywords.difference(ebuild_archs)
2166 - if dropped_keywords:
2167 - self.qatracker.add_error(
2168 - "KEYWORDS.dropped", "%s: %s" % (
2169 - ebuild.relative_path,
2170 - " ".join(sorted(dropped_keywords))))
2171 -
2172 - def _checkForInvalidKeywords(
2173 - self, pkg, package, y_ebuild, kwlist, profiles):
2174 - myuse = pkg._metadata["KEYWORDS"].split()
2175 -
2176 - for mykey in myuse:
2177 - if mykey not in ("-*", "*", "~*"):
2178 - myskey = mykey
2179 -
2180 - if not self._isKeywordStable(myskey[:1]):
2181 - myskey = myskey[1:]
2182 -
2183 - if myskey not in kwlist:
2184 - self.qatracker.add_error(
2185 - "KEYWORDS.invalid",
2186 - "%s/%s.ebuild: %s" % (
2187 - package, y_ebuild, mykey))
2188 - elif myskey not in profiles:
2189 - self.qatracker.add_error(
2190 - "KEYWORDS.invalid",
2191 - "%s/%s.ebuild: %s (profile invalid)" % (
2192 - package, y_ebuild, mykey))
2193 -
2194 - def _checkForMaskLikeKeywords(
2195 - self, package, y_ebuild, keywords, kwlist):
2196 -
2197 - # KEYWORDS="-*" is a stupid replacement for package.mask
2198 - # and screws general KEYWORDS semantics
2199 - if "-*" in keywords:
2200 - haskeyword = False
2201 -
2202 - for kw in keywords:
2203 - if kw[0] == "~":
2204 - kw = kw[1:]
2205 - if kw in kwlist:
2206 - haskeyword = True
2207 -
2208 - if not haskeyword:
2209 - self.qatracker.add_error(
2210 - "KEYWORDS.stupid", package + "/" + y_ebuild + ".ebuild")
2211
2212 diff --git a/pym/tbc/repoman/checks/ebuilds/manifests.py b/pym/tbc/repoman/checks/ebuilds/manifests.py
2213 deleted file mode 100644
2214 index 70030c2..0000000
2215 --- a/pym/tbc/repoman/checks/ebuilds/manifests.py
2216 +++ /dev/null
2217 @@ -1,101 +0,0 @@
2218 -
2219 -import logging
2220 -import sys
2221 -
2222 -# import our initialized portage instance
2223 -from tbc.repoman._portage import portage
2224 -
2225 -from portage import os
2226 -from portage.package.ebuild.digestgen import digestgen
2227 -from portage.util import writemsg_level
2228 -
2229 -
2230 -class Manifests(object):
2231 -
2232 - def __init__(self, options, qatracker=None, repoman_settings=None):
2233 - self.options = options
2234 - self.qatracker = qatracker
2235 - self.repoman_settings = repoman_settings
2236 - self.generated_manifest = False
2237 -
2238 - def run(self, checkdir, portdb):
2239 - self.generated_manifest = False
2240 - self.digest_only = self.options.mode != 'manifest-check' \
2241 - and self.options.digest == 'y'
2242 - if self.options.pretend:
2243 - return False
2244 - if self.options.mode in ("manifest", 'commit', 'fix') or self.digest_only:
2245 - failed = False
2246 - self.auto_assumed = set()
2247 - fetchlist_dict = portage.FetchlistDict(
2248 - checkdir, self.repoman_settings, portdb)
2249 - if self.options.mode == 'manifest' and self.options.force:
2250 - portage._doebuild_manifest_exempt_depend += 1
2251 - self.create_manifest(checkdir, fetchlist_dict)
2252 - self.repoman_settings["O"] = checkdir
2253 - try:
2254 - self.generated_manifest = digestgen(
2255 - mysettings=self.repoman_settings, myportdb=portdb)
2256 - except portage.exception.PermissionDenied as e:
2257 - self.generated_manifest = False
2258 - writemsg_level(
2259 - "!!! Permission denied: '%s'\n" % (e,),
2260 - level=logging.ERROR, noiselevel=-1)
2261 -
2262 - if not self.generated_manifest:
2263 - writemsg_level(
2264 - "Unable to generate manifest.",
2265 - level=logging.ERROR, noiselevel=-1)
2266 - failed = True
2267 -
2268 - if self.options.mode == "manifest":
2269 - if not failed and self.options.force and self.auto_assumed and \
2270 - 'assume-digests' in self.repoman_settings.features:
2271 - # Show which digests were assumed despite the --force option
2272 - # being given. This output will already have been shown by
2273 - # digestgen() if assume-digests is not enabled, so only show
2274 - # it here if assume-digests is enabled.
2275 - pkgs = list(fetchlist_dict)
2276 - pkgs.sort()
2277 - portage.writemsg_stdout(
2278 - " digest.assumed %s" %
2279 - portage.output.colorize(
2280 - "WARN", str(len(self.auto_assumed)).rjust(18)) + "\n")
2281 - for cpv in pkgs:
2282 - fetchmap = fetchlist_dict[cpv]
2283 - pf = portage.catsplit(cpv)[1]
2284 - for distfile in sorted(fetchmap):
2285 - if distfile in self.auto_assumed:
2286 - portage.writemsg_stdout(
2287 - " %s::%s\n" % (pf, distfile))
2288 - # continue, skip remaining main loop code
2289 - return True
2290 - elif failed:
2291 - sys.exit(1)
2292 - return False
2293 -
2294 - def create_manifest(self, checkdir, fetchlist_dict):
2295 - try:
2296 - distdir = self.repoman_settings['DISTDIR']
2297 - mf = self.repoman_settings.repositories.get_repo_for_location(
2298 - os.path.dirname(os.path.dirname(checkdir)))
2299 - mf = mf.load_manifest(
2300 - checkdir, distdir, fetchlist_dict=fetchlist_dict)
2301 - mf.create(
2302 - requiredDistfiles=None, assumeDistHashesAlways=True)
2303 - for distfiles in fetchlist_dict.values():
2304 - for distfile in distfiles:
2305 - if os.path.isfile(os.path.join(distdir, distfile)):
2306 - mf.fhashdict['DIST'].pop(distfile, None)
2307 - else:
2308 - self.auto_assumed.add(distfile)
2309 - mf.write()
2310 - finally:
2311 - portage._doebuild_manifest_exempt_depend -= 1
2312 -
2313 - def digest_check(self, xpkg, checkdir):
2314 - self.repoman_settings['O'] = checkdir
2315 - self.repoman_settings['PORTAGE_QUIET'] = '1'
2316 - if not portage.digestcheck([], self.repoman_settings, strict=1):
2317 - self.qatracker.add_error("manifest.bad", os.path.join(xpkg, 'Manifest'))
2318 - self.repoman_settings.pop('PORTAGE_QUIET', None)
2319
2320 diff --git a/pym/tbc/repoman/checks/ebuilds/misc.py b/pym/tbc/repoman/checks/ebuilds/misc.py
2321 deleted file mode 100644
2322 index 6c9a6ed..0000000
2323 --- a/pym/tbc/repoman/checks/ebuilds/misc.py
2324 +++ /dev/null
2325 @@ -1,54 +0,0 @@
2326 -
2327 -'''repoman/checks/ebuilds/misc.py
2328 -Miscelaneous ebuild check functions'''
2329 -
2330 -import re
2331 -
2332 -# import our initialized portage instance
2333 -from tbc.repoman._portage import portage
2334 -
2335 -
2336 -pv_toolong_re = re.compile(r'[0-9]{19,}')
2337 -
2338 -
2339 -def bad_split_check(xpkg, y_ebuild, pkgdir, qatracker):
2340 - '''Checks for bad category/package splits.
2341 -
2342 - @param xpkg: the pacakge being checked
2343 - @param y_ebuild: string of the ebuild name being tested
2344 - @param pkgdir: string: path
2345 - @param qatracker: QATracker instance
2346 - '''
2347 - myesplit = portage.pkgsplit(y_ebuild)
2348 -
2349 - is_bad_split = myesplit is None or myesplit[0] != xpkg.split("/")[-1]
2350 -
2351 - if is_bad_split:
2352 - is_pv_toolong = pv_toolong_re.search(myesplit[1])
2353 - is_pv_toolong2 = pv_toolong_re.search(myesplit[2])
2354 -
2355 - if is_pv_toolong or is_pv_toolong2:
2356 - qatracker.add_error(
2357 - "ebuild.invalidname", xpkg + "/" + y_ebuild + ".ebuild")
2358 - return True
2359 - elif myesplit[0] != pkgdir:
2360 - print(pkgdir, myesplit[0])
2361 - qatracker.add_error(
2362 - "ebuild.namenomatch", xpkg + "/" + y_ebuild + ".ebuild")
2363 - return True
2364 - return False
2365 -
2366 -
2367 -def pkg_invalid(pkg, qatracker, ebuild):
2368 - '''Checks for invalid packages
2369 -
2370 - @param pkg: _emerge.Package instance
2371 - @param qatracker: QATracker instance
2372 - @return boolean:
2373 - '''
2374 - if pkg.invalid:
2375 - for k, msgs in pkg.invalid.items():
2376 - for msg in msgs:
2377 - qatracker.add_error(k, "%s: %s" % (ebuild.relative_path, msg))
2378 - return True
2379 - return False
2380
2381 diff --git a/pym/tbc/repoman/checks/ebuilds/pkgmetadata.py b/pym/tbc/repoman/checks/ebuilds/pkgmetadata.py
2382 deleted file mode 100644
2383 index 5b0d250..0000000
2384 --- a/pym/tbc/repoman/checks/ebuilds/pkgmetadata.py
2385 +++ /dev/null
2386 @@ -1,174 +0,0 @@
2387 -
2388 -'''Package Metadata Checks operations'''
2389 -
2390 -import sys
2391 -
2392 -from itertools import chain
2393 -
2394 -try:
2395 - import xml.etree.ElementTree
2396 - from xml.parsers.expat import ExpatError
2397 -except (SystemExit, KeyboardInterrupt):
2398 - raise
2399 -except (ImportError, SystemError, RuntimeError, Exception):
2400 - # broken or missing xml support
2401 - # http://bugs.python.org/issue14988
2402 - msg = ["Please enable python's \"xml\" USE flag in order to use repoman."]
2403 - from portage.output import EOutput
2404 - out = EOutput()
2405 - for line in msg:
2406 - out.eerror(line)
2407 - sys.exit(1)
2408 -
2409 -# import our initialized portage instance
2410 -from tbc.repoman._portage import portage
2411 -
2412 -from portage.exception import InvalidAtom
2413 -from portage import os
2414 -from portage import _encodings, _unicode_encode
2415 -from portage.dep import Atom
2416 -
2417 -from tbc.repoman.metadata import (
2418 - metadata_xml_encoding, metadata_doctype_name,
2419 - metadata_dtd_uri, metadata_xml_declaration, parse_metadata_use)
2420 -from tbc.repoman.checks.herds.herdbase import get_herd_base
2421 -from tbc.repoman.checks.herds.metadata import check_metadata, UnknownHerdsError
2422 -from tbc.repoman._xml import _XMLParser, _MetadataTreeBuilder, XmlLint
2423 -
2424 -
2425 -class PkgMetadata(object):
2426 - '''Package metadata.xml checks'''
2427 -
2428 - def __init__(self, options, qatracker, repoman_settings):
2429 - '''PkgMetadata init function
2430 -
2431 - @param options: ArgumentParser.parse_known_args(argv[1:]) options
2432 - @param qatracker: QATracker instance
2433 - @param repoman_settings: settings instance
2434 - '''
2435 - self.options = options
2436 - self.qatracker = qatracker
2437 - self.repoman_settings = repoman_settings
2438 - self.musedict = {}
2439 - self.xmllint = XmlLint(self.options, self.repoman_settings)
2440 -
2441 - def check(self, xpkg, checkdir, checkdirlist, repolevel):
2442 - '''Performs the checks on the metadata.xml for the package
2443 -
2444 - @param xpkg: the pacakge being checked
2445 - @param checkdir: string, directory path
2446 - @param checkdirlist: list of checkdir's
2447 - @param repolevel: integer
2448 - '''
2449 -
2450 - self.musedict = {}
2451 - # metadata.xml file check
2452 - if "metadata.xml" not in checkdirlist:
2453 - self.qatracker.add_error("metadata.missing", xpkg + "/metadata.xml")
2454 - # metadata.xml parse check
2455 - else:
2456 - metadata_bad = False
2457 - xml_info = {}
2458 - xml_parser = _XMLParser(xml_info, target=_MetadataTreeBuilder())
2459 -
2460 - # read metadata.xml into memory
2461 - try:
2462 - _metadata_xml = xml.etree.ElementTree.parse(
2463 - _unicode_encode(
2464 - os.path.join(checkdir, "metadata.xml"),
2465 - encoding=_encodings['fs'], errors='strict'),
2466 - parser=xml_parser)
2467 - except (ExpatError, SyntaxError, EnvironmentError) as e:
2468 - metadata_bad = True
2469 - self.qatracker.add_error("metadata.bad", "%s/metadata.xml: %s" % (xpkg, e))
2470 - del e
2471 - else:
2472 - if not hasattr(xml_parser, 'parser') or \
2473 - sys.hexversion < 0x2070000 or \
2474 - (sys.hexversion > 0x3000000 and sys.hexversion < 0x3020000):
2475 - # doctype is not parsed with python 2.6 or 3.1
2476 - pass
2477 - else:
2478 - if "XML_DECLARATION" not in xml_info:
2479 - self.qatracker.add_error(
2480 - "metadata.bad", "%s/metadata.xml: "
2481 - "xml declaration is missing on first line, "
2482 - "should be '%s'" % (xpkg, metadata_xml_declaration))
2483 - else:
2484 - xml_version, xml_encoding, xml_standalone = \
2485 - xml_info["XML_DECLARATION"]
2486 - if xml_encoding is None or \
2487 - xml_encoding.upper() != metadata_xml_encoding:
2488 - if xml_encoding is None:
2489 - encoding_problem = "but it is undefined"
2490 - else:
2491 - encoding_problem = "not '%s'" % xml_encoding
2492 - self.qatracker.add_error(
2493 - "metadata.bad", "%s/metadata.xml: "
2494 - "xml declaration encoding should be '%s', %s" %
2495 - (xpkg, metadata_xml_encoding, encoding_problem))
2496 -
2497 - if "DOCTYPE" not in xml_info:
2498 - metadata_bad = True
2499 - self.qatracker.add_error(
2500 - "metadata.bad",
2501 - "%s/metadata.xml: %s" % (xpkg, "DOCTYPE is missing"))
2502 - else:
2503 - doctype_name, doctype_system, doctype_pubid = \
2504 - xml_info["DOCTYPE"]
2505 - if doctype_system != metadata_dtd_uri:
2506 - if doctype_system is None:
2507 - system_problem = "but it is undefined"
2508 - else:
2509 - system_problem = "not '%s'" % doctype_system
2510 - self.qatracker.add_error(
2511 - "metadata.bad", "%s/metadata.xml: "
2512 - "DOCTYPE: SYSTEM should refer to '%s', %s" %
2513 - (xpkg, metadata_dtd_uri, system_problem))
2514 -
2515 - if doctype_name != metadata_doctype_name:
2516 - self.qatracker.add_error(
2517 - "metadata.bad", "%s/metadata.xml: "
2518 - "DOCTYPE: name should be '%s', not '%s'" %
2519 - (xpkg, metadata_doctype_name, doctype_name))
2520 -
2521 - # load USE flags from metadata.xml
2522 - try:
2523 - self.musedict = parse_metadata_use(_metadata_xml)
2524 - except portage.exception.ParseError as e:
2525 - metadata_bad = True
2526 - self.qatracker.add_error(
2527 - "metadata.bad", "%s/metadata.xml: %s" % (xpkg, e))
2528 - else:
2529 - for atom in chain(*self.musedict.values()):
2530 - if atom is None:
2531 - continue
2532 - try:
2533 - atom = Atom(atom)
2534 - except InvalidAtom as e:
2535 - self.qatracker.add_error(
2536 - "metadata.bad",
2537 - "%s/metadata.xml: Invalid atom: %s" % (xpkg, e))
2538 - else:
2539 - if atom.cp != xpkg:
2540 - self.qatracker.add_error(
2541 - "metadata.bad",
2542 - "%s/metadata.xml: Atom contains "
2543 - "unexpected cat/pn: %s" % (xpkg, atom))
2544 -
2545 - # Run other metadata.xml checkers
2546 - try:
2547 - check_metadata(_metadata_xml, get_herd_base(
2548 - self.repoman_settings))
2549 - except (UnknownHerdsError, ) as e:
2550 - metadata_bad = True
2551 - self.qatracker.add_error(
2552 - "metadata.bad", "%s/metadata.xml: %s" % (xpkg, e))
2553 - del e
2554 -
2555 - # Only carry out if in package directory or check forced
2556 - if not metadata_bad:
2557 - if not self.xmllint.check(checkdir, repolevel):
2558 - self.qatracker.add_error("metadata.bad", xpkg + "/metadata.xml")
2559 - del metadata_bad
2560 - return
2561
2562 diff --git a/pym/tbc/repoman/checks/ebuilds/thirdpartymirrors.py b/pym/tbc/repoman/checks/ebuilds/thirdpartymirrors.py
2563 deleted file mode 100644
2564 index 39d0410..0000000
2565 --- a/pym/tbc/repoman/checks/ebuilds/thirdpartymirrors.py
2566 +++ /dev/null
2567 @@ -1,38 +0,0 @@
2568 -
2569 -# import our initialized portage instance
2570 -from tbc.repoman._portage import portage
2571 -
2572 -
2573 -class ThirdPartyMirrors(object):
2574 -
2575 - def __init__(self, repoman_settings, qatracker):
2576 - # TODO: Build a regex instead here, for the SRC_URI.mirror check.
2577 - self.thirdpartymirrors = {}
2578 - profile_thirdpartymirrors = repoman_settings.thirdpartymirrors().items()
2579 - for mirror_alias, mirrors in profile_thirdpartymirrors:
2580 - for mirror in mirrors:
2581 - if not mirror.endswith("/"):
2582 - mirror += "/"
2583 - self.thirdpartymirrors[mirror] = mirror_alias
2584 -
2585 - self.qatracker = qatracker
2586 -
2587 - def check(self, myaux, relative_path):
2588 - # Check that URIs don't reference a server from thirdpartymirrors.
2589 - for uri in portage.dep.use_reduce(
2590 - myaux["SRC_URI"], matchall=True, is_src_uri=True,
2591 - eapi=myaux["EAPI"], flat=True):
2592 - contains_mirror = False
2593 - for mirror, mirror_alias in self.thirdpartymirrors.items():
2594 - if uri.startswith(mirror):
2595 - contains_mirror = True
2596 - break
2597 - if not contains_mirror:
2598 - continue
2599 -
2600 - new_uri = "mirror://%s/%s" % (mirror_alias, uri[len(mirror):])
2601 - self.qatracker.add_error(
2602 - "SRC_URI.mirror",
2603 - "%s: '%s' found in thirdpartymirrors, use '%s'" % (
2604 - relative_path, mirror, new_uri))
2605 - return
2606
2607 diff --git a/pym/tbc/repoman/checks/ebuilds/use_flags.py b/pym/tbc/repoman/checks/ebuilds/use_flags.py
2608 deleted file mode 100644
2609 index 4fd72d8..0000000
2610 --- a/pym/tbc/repoman/checks/ebuilds/use_flags.py
2611 +++ /dev/null
2612 @@ -1,89 +0,0 @@
2613 -
2614 -'''use_flags.py
2615 -Performs USE flag related checks
2616 -'''
2617 -
2618 -# import our centrally initialized portage instance
2619 -from tbc.repoman._portage import portage
2620 -
2621 -from portage import eapi
2622 -from portage.eapi import eapi_has_iuse_defaults, eapi_has_required_use
2623 -
2624 -
2625 -class USEFlagChecks(object):
2626 - '''Performs checks on USE flags listed in the ebuilds and metadata.xml'''
2627 -
2628 - def __init__(self, qatracker, globalUseFlags):
2629 - '''
2630 - @param qatracker: QATracker instance
2631 - @param globalUseFlags: Global USE flags
2632 - '''
2633 - self.qatracker = qatracker
2634 - self.globalUseFlags = globalUseFlags
2635 - self.useFlags = []
2636 - self.defaultUseFlags = []
2637 - self.usedUseFlags = set()
2638 -
2639 - def check(self, pkg, package, ebuild, y_ebuild, localUseFlags):
2640 - '''Perform the check.
2641 -
2642 - @param pkg: Package in which we check (object).
2643 - @param package: Package in which we check (string).
2644 - @param ebuild: Ebuild which we check (object).
2645 - @param y_ebuild: Ebuild which we check (string).
2646 - @param localUseFlags: Local USE flags of the package
2647 - '''
2648 - # reset state variables for the run
2649 - self.useFlags = []
2650 - self.defaultUseFlags = []
2651 - self.usedUseFlags = set()
2652 - self._checkGlobal(pkg)
2653 - self._checkMetadata(package, ebuild, y_ebuild, localUseFlags)
2654 - self._checkRequiredUSE(pkg, ebuild)
2655 -
2656 - def getUsedUseFlags(self):
2657 - '''Get the USE flags that this check has seen'''
2658 - return self.usedUseFlags
2659 -
2660 - def _checkGlobal(self, pkg):
2661 - for myflag in pkg._metadata["IUSE"].split():
2662 - flag_name = myflag.lstrip("+-")
2663 - self.usedUseFlags.add(flag_name)
2664 - if myflag != flag_name:
2665 - self.defaultUseFlags.append(myflag)
2666 - if flag_name not in self.globalUseFlags:
2667 - self.useFlags.append(flag_name)
2668 -
2669 - def _checkMetadata(self, package, ebuild, y_ebuild, localUseFlags):
2670 - for mypos in range(len(self.useFlags) - 1, -1, -1):
2671 - if self.useFlags[mypos] and (self.useFlags[mypos] in localUseFlags):
2672 - del self.useFlags[mypos]
2673 -
2674 - if self.defaultUseFlags and not eapi_has_iuse_defaults(eapi):
2675 - for myflag in self.defaultUseFlags:
2676 - self.qatracker.add_error(
2677 - 'EAPI.incompatible', "%s: IUSE defaults"
2678 - " not supported with EAPI='%s': '%s'" % (
2679 - ebuild.relative_path, eapi, myflag))
2680 -
2681 - for mypos in range(len(self.useFlags)):
2682 - self.qatracker.add_error(
2683 - "IUSE.invalid",
2684 - "%s/%s.ebuild: %s" % (package, y_ebuild, self.useFlags[mypos]))
2685 -
2686 - def _checkRequiredUSE(self, pkg, ebuild):
2687 - required_use = pkg._metadata["REQUIRED_USE"]
2688 - if required_use:
2689 - if not eapi_has_required_use(eapi):
2690 - self.qatracker.add_error(
2691 - 'EAPI.incompatible', "%s: REQUIRED_USE"
2692 - " not supported with EAPI='%s'"
2693 - % (ebuild.relative_path, eapi,))
2694 - try:
2695 - portage.dep.check_required_use(
2696 - required_use, (), pkg.iuse.is_valid_flag, eapi=eapi)
2697 - except portage.exception.InvalidDependString as e:
2698 - self.qatracker.add_error(
2699 - "REQUIRED_USE.syntax",
2700 - "%s: REQUIRED_USE: %s" % (ebuild.relative_path, e))
2701 - del e
2702
2703 diff --git a/pym/tbc/repoman/checks/ebuilds/variables/__init__.py b/pym/tbc/repoman/checks/ebuilds/variables/__init__.py
2704 deleted file mode 100644
2705 index e69de29..0000000
2706
2707 diff --git a/pym/tbc/repoman/checks/ebuilds/variables/description.py b/pym/tbc/repoman/checks/ebuilds/variables/description.py
2708 deleted file mode 100644
2709 index a2b1057..0000000
2710 --- a/pym/tbc/repoman/checks/ebuilds/variables/description.py
2711 +++ /dev/null
2712 @@ -1,32 +0,0 @@
2713 -
2714 -'''description.py
2715 -Perform checks on the DESCRIPTION variable.
2716 -'''
2717 -
2718 -from repoman.qa_data import max_desc_len
2719 -
2720 -
2721 -class DescriptionChecks(object):
2722 - '''Perform checks on the DESCRIPTION variable.'''
2723 -
2724 - def __init__(self, qatracker):
2725 - '''
2726 - @param qatracker: QATracker instance
2727 - '''
2728 - self.qatracker = qatracker
2729 -
2730 - def check(self, pkg, ebuild):
2731 - '''
2732 - @param pkg: Package in which we check (object).
2733 - @param ebuild: Ebuild which we check (object).
2734 - '''
2735 - self._checkTooLong(pkg, ebuild)
2736 -
2737 - def _checkTooLong(self, pkg, ebuild):
2738 - # 14 is the length of DESCRIPTION=""
2739 - if len(pkg._metadata['DESCRIPTION']) > max_desc_len:
2740 - self.qatracker.add_error(
2741 - 'DESCRIPTION.toolong',
2742 - "%s: DESCRIPTION is %d characters (max %d)" %
2743 - (ebuild.relative_path, len(
2744 - pkg._metadata['DESCRIPTION']), max_desc_len))
2745
2746 diff --git a/pym/tbc/repoman/checks/ebuilds/variables/eapi.py b/pym/tbc/repoman/checks/ebuilds/variables/eapi.py
2747 deleted file mode 100644
2748 index 2f8b1cb..0000000
2749 --- a/pym/tbc/repoman/checks/ebuilds/variables/eapi.py
2750 +++ /dev/null
2751 @@ -1,44 +0,0 @@
2752 -
2753 -'''eapi.py
2754 -Perform checks on the EAPI variable.
2755 -'''
2756 -
2757 -
2758 -class EAPIChecks(object):
2759 - '''Perform checks on the EAPI variable.'''
2760 -
2761 - def __init__(self, qatracker, repo_settings):
2762 - '''
2763 - @param qatracker: QATracker instance
2764 - @param repo_settings: Repository settings
2765 - '''
2766 - self.qatracker = qatracker
2767 - self.repo_settings = repo_settings
2768 -
2769 - def check(self, pkg, ebuild):
2770 - '''
2771 - @param pkg: Package in which we check (object).
2772 - @param ebuild: Ebuild which we check (object).
2773 - '''
2774 - eapi = pkg._metadata["EAPI"]
2775 -
2776 - if not self._checkBanned(ebuild, eapi):
2777 - self._checkDeprecated(ebuild, eapi)
2778 -
2779 - def _checkBanned(self, ebuild, eapi):
2780 - if self.repo_settings.repo_config.eapi_is_banned(eapi):
2781 - self.qatracker.add_error(
2782 - "repo.eapi.banned", "%s: %s" % (ebuild.relative_path, eapi))
2783 -
2784 - return True
2785 -
2786 - return False
2787 -
2788 - def _checkDeprecated(self, ebuild, eapi):
2789 - if self.repo_settings.repo_config.eapi_is_deprecated(eapi):
2790 - self.qatracker.add_error(
2791 - "repo.eapi.deprecated", "%s: %s" % (ebuild.relative_path, eapi))
2792 -
2793 - return True
2794 -
2795 - return False
2796
2797 diff --git a/pym/tbc/repoman/checks/ebuilds/variables/license.py b/pym/tbc/repoman/checks/ebuilds/variables/license.py
2798 deleted file mode 100644
2799 index fbb0bfc..0000000
2800 --- a/pym/tbc/repoman/checks/ebuilds/variables/license.py
2801 +++ /dev/null
2802 @@ -1,47 +0,0 @@
2803 -
2804 -'''description.py
2805 -Perform checks on the LICENSE variable.
2806 -'''
2807 -
2808 -# import our initialized portage instance
2809 -from tbc.repoman._portage import portage
2810 -
2811 -
2812 -class LicenseChecks(object):
2813 - '''Perform checks on the LICENSE variable.'''
2814 -
2815 - def __init__(self, qatracker, liclist, liclist_deprecated):
2816 - '''
2817 - @param qatracker: QATracker instance
2818 - @param liclist: List of licenses.
2819 - @param liclist: List of deprecated licenses.
2820 - '''
2821 - self.qatracker = qatracker
2822 - self.liclist = liclist
2823 - self.liclist_deprecated = liclist_deprecated
2824 -
2825 - def check(
2826 - self, pkg, package, ebuild, y_ebuild):
2827 - '''
2828 - @param pkg: Package in which we check (object).
2829 - @param package: Package in which we check (string).
2830 - @param ebuild: Ebuild which we check (object).
2831 - @param y_ebuild: Ebuild which we check (string).
2832 - '''
2833 -
2834 - # Parse the LICENSE variable, remove USE conditions and flatten it.
2835 - licenses = portage.dep.use_reduce(
2836 - pkg._metadata["LICENSE"], matchall=1, flat=True)
2837 -
2838 - # Check each entry to ensure that it exists in ${PORTDIR}/licenses/.
2839 - for lic in licenses:
2840 - # Need to check for "||" manually as no portage
2841 - # function will remove it without removing values.
2842 - if lic not in self.liclist and lic != "||":
2843 - self.qatracker.add_error(
2844 - "LICENSE.invalid",
2845 - package + "/" + y_ebuild + ".ebuild: %s" % lic)
2846 - elif lic in self.liclist_deprecated:
2847 - self.qatracker.add_error(
2848 - "LICENSE.deprecated",
2849 - "%s: %s" % (ebuild.relative_path, lic))
2850
2851 diff --git a/pym/tbc/repoman/checks/ebuilds/variables/restrict.py b/pym/tbc/repoman/checks/ebuilds/variables/restrict.py
2852 deleted file mode 100644
2853 index 215b792..0000000
2854 --- a/pym/tbc/repoman/checks/ebuilds/variables/restrict.py
2855 +++ /dev/null
2856 @@ -1,41 +0,0 @@
2857 -
2858 -'''restrict.py
2859 -Perform checks on the RESTRICT variable.
2860 -'''
2861 -
2862 -# import our initialized portage instance
2863 -from repoman._portage import portage
2864 -
2865 -from repoman.qa_data import valid_restrict
2866 -
2867 -
2868 -class RestrictChecks(object):
2869 - '''Perform checks on the RESTRICT variable.'''
2870 -
2871 - def __init__(self, qatracker):
2872 - '''
2873 - @param qatracker: QATracker instance
2874 - '''
2875 - self.qatracker = qatracker
2876 -
2877 - def check(self, pkg, package, ebuild, y_ebuild):
2878 - myrestrict = None
2879 -
2880 - try:
2881 - myrestrict = portage.dep.use_reduce(
2882 - pkg._metadata["RESTRICT"], matchall=1, flat=True)
2883 - except portage.exception.InvalidDependString as e:
2884 - self. qatracker.add_error(
2885 - "RESTRICT.syntax",
2886 - "%s: RESTRICT: %s" % (ebuild.relative_path, e))
2887 - del e
2888 -
2889 - if myrestrict:
2890 - myrestrict = set(myrestrict)
2891 - mybadrestrict = myrestrict.difference(valid_restrict)
2892 -
2893 - if mybadrestrict:
2894 - for mybad in mybadrestrict:
2895 - self.qatracker.add_error(
2896 - "RESTRICT.invalid",
2897 - package + "/" + y_ebuild + ".ebuild: %s" % mybad)
2898
2899 diff --git a/pym/tbc/repoman/checks/herds/__init__.py b/pym/tbc/repoman/checks/herds/__init__.py
2900 deleted file mode 100644
2901 index e69de29..0000000
2902
2903 diff --git a/pym/tbc/repoman/checks/herds/herdbase.py b/pym/tbc/repoman/checks/herds/herdbase.py
2904 deleted file mode 100644
2905 index 5140acd..0000000
2906 --- a/pym/tbc/repoman/checks/herds/herdbase.py
2907 +++ /dev/null
2908 @@ -1,135 +0,0 @@
2909 -# -*- coding: utf-8 -*-
2910 -# repoman: Herd database analysis
2911 -# Copyright 2010-2013 Gentoo Foundation
2912 -# Distributed under the terms of the GNU General Public License v2 or later
2913 -
2914 -from __future__ import unicode_literals
2915 -
2916 -import errno
2917 -import xml.etree.ElementTree
2918 -try:
2919 - from xml.parsers.expat import ExpatError
2920 -except (SystemExit, KeyboardInterrupt):
2921 - raise
2922 -except (ImportError, SystemError, RuntimeError, Exception):
2923 - # broken or missing xml support
2924 - # http://bugs.python.org/issue14988
2925 - # This means that python is built without xml support.
2926 - # We tolerate global scope import failures for optional
2927 - # modules, so that ImportModulesTestCase can succeed (or
2928 - # possibly alert us about unexpected import failures).
2929 - pass
2930 -
2931 -from portage import _encodings, _unicode_encode
2932 -from portage.exception import FileNotFound, ParseError, PermissionDenied
2933 -from portage import os
2934 -
2935 -from tbc.repoman.errors import err
2936 -
2937 -__all__ = [
2938 - "make_herd_base", "get_herd_base"
2939 -]
2940 -
2941 -
2942 -def _make_email(nick_name):
2943 - if not nick_name.endswith('@gentoo.org'):
2944 - nick_name = nick_name + '@gentoo.org'
2945 - return nick_name
2946 -
2947 -
2948 -class HerdBase(object):
2949 - def __init__(self, herd_to_emails, all_emails):
2950 - self.herd_to_emails = herd_to_emails
2951 - self.all_emails = all_emails
2952 -
2953 - def known_herd(self, herd_name):
2954 - return herd_name in self.herd_to_emails
2955 -
2956 - def known_maintainer(self, nick_name):
2957 - return _make_email(nick_name) in self.all_emails
2958 -
2959 - def maintainer_in_herd(self, nick_name, herd_name):
2960 - return _make_email(nick_name) in self.herd_to_emails[herd_name]
2961 -
2962 -
2963 -class _HerdsTreeBuilder(xml.etree.ElementTree.TreeBuilder):
2964 - """
2965 - Implements doctype() as required to avoid deprecation warnings with
2966 - >=python-2.7.
2967 - """
2968 - def doctype(self, name, pubid, system):
2969 - pass
2970 -
2971 -
2972 -def make_herd_base(filename):
2973 - herd_to_emails = dict()
2974 - all_emails = set()
2975 -
2976 - try:
2977 - xml_tree = xml.etree.ElementTree.parse(
2978 - _unicode_encode(
2979 - filename, encoding=_encodings['fs'], errors='strict'),
2980 - parser=xml.etree.ElementTree.XMLParser(
2981 - target=_HerdsTreeBuilder()))
2982 - except ExpatError as e:
2983 - raise ParseError("metadata.xml: %s" % (e,))
2984 - except EnvironmentError as e:
2985 - func_call = "open('%s')" % filename
2986 - if e.errno == errno.EACCES:
2987 - raise PermissionDenied(func_call)
2988 - elif e.errno == errno.ENOENT:
2989 - raise FileNotFound(filename)
2990 - raise
2991 -
2992 - herds = xml_tree.findall('herd')
2993 - for h in herds:
2994 - _herd_name = h.find('name')
2995 - if _herd_name is None:
2996 - continue
2997 - herd_name = _herd_name.text.strip()
2998 - del _herd_name
2999 -
3000 - maintainers = h.findall('maintainer')
3001 - herd_emails = set()
3002 - for m in maintainers:
3003 - _m_email = m.find('email')
3004 - if _m_email is None:
3005 - continue
3006 - m_email = _m_email.text.strip()
3007 -
3008 - herd_emails.add(m_email)
3009 - all_emails.add(m_email)
3010 -
3011 - herd_to_emails[herd_name] = herd_emails
3012 -
3013 - return HerdBase(herd_to_emails, all_emails)
3014 -
3015 -
3016 -def get_herd_base(repoman_settings):
3017 - try:
3018 - herd_base = make_herd_base(
3019 - os.path.join(repoman_settings["PORTDIR"], "metadata/herds.xml"))
3020 - except (EnvironmentError, ParseError, PermissionDenied) as e:
3021 - err(str(e))
3022 - except FileNotFound:
3023 - # TODO: Download as we do for metadata.dtd, but add a way to
3024 - # disable for non-gentoo repoman users who may not have herds.
3025 - herd_base = None
3026 - return herd_base
3027 -
3028 -
3029 -if __name__ == '__main__':
3030 - h = make_herd_base('/usr/portage/metadata/herds.xml')
3031 -
3032 - assert(h.known_herd('sound'))
3033 - assert(not h.known_herd('media-sound'))
3034 -
3035 - assert(h.known_maintainer('sping'))
3036 - assert(h.known_maintainer('sping@g.o'))
3037 - assert(not h.known_maintainer('portage'))
3038 -
3039 - assert(h.maintainer_in_herd('zmedico@g.o', 'tools-portage'))
3040 - assert(not h.maintainer_in_herd('pva@g.o', 'tools-portage'))
3041 -
3042 - import pprint
3043 - pprint.pprint(h.herd_to_emails)
3044
3045 diff --git a/pym/tbc/repoman/checks/herds/metadata.py b/pym/tbc/repoman/checks/herds/metadata.py
3046 deleted file mode 100644
3047 index 3c67fcf..0000000
3048 --- a/pym/tbc/repoman/checks/herds/metadata.py
3049 +++ /dev/null
3050 @@ -1,25 +0,0 @@
3051 -
3052 -
3053 -class UnknownHerdsError(ValueError):
3054 - def __init__(self, herd_names):
3055 - _plural = len(herd_names) != 1
3056 - super(UnknownHerdsError, self).__init__(
3057 - 'Unknown %s %s' % (
3058 - _plural and 'herds' or 'herd',
3059 - ','.join('"%s"' % e for e in herd_names)))
3060 -
3061 -
3062 -def check_metadata_herds(xml_tree, herd_base):
3063 - herd_nodes = xml_tree.findall('herd')
3064 - unknown_herds = [
3065 - name for name in (
3066 - e.text.strip() for e in herd_nodes if e.text is not None)
3067 - if not herd_base.known_herd(name)]
3068 -
3069 - if unknown_herds:
3070 - raise UnknownHerdsError(unknown_herds)
3071 -
3072 -
3073 -def check_metadata(xml_tree, herd_base):
3074 - if herd_base is not None:
3075 - check_metadata_herds(xml_tree, herd_base)
3076
3077 diff --git a/pym/tbc/repoman/copyrights.py b/pym/tbc/repoman/copyrights.py
3078 deleted file mode 100644
3079 index 056cfda..0000000
3080 --- a/pym/tbc/repoman/copyrights.py
3081 +++ /dev/null
3082 @@ -1,119 +0,0 @@
3083 -
3084 -
3085 -import difflib
3086 -import io
3087 -import re
3088 -from tempfile import mkstemp
3089 -
3090 -from portage import _encodings
3091 -from portage import _unicode_decode
3092 -from portage import _unicode_encode
3093 -from portage import os
3094 -from portage import shutil
3095 -from portage import util
3096 -
3097 -
3098 -_copyright_re1 = re.compile(br'^(# Copyright \d\d\d\d)-\d\d\d\d ')
3099 -_copyright_re2 = re.compile(br'^(# Copyright )(\d\d\d\d) ')
3100 -
3101 -
3102 -class _copyright_repl(object):
3103 - __slots__ = ('year',)
3104 -
3105 - def __init__(self, year):
3106 - self.year = year
3107 -
3108 - def __call__(self, matchobj):
3109 - if matchobj.group(2) == self.year:
3110 - return matchobj.group(0)
3111 - else:
3112 - return matchobj.group(1) + matchobj.group(2) + \
3113 - b'-' + self.year + b' '
3114 -
3115 -
3116 -def update_copyright_year(year, line):
3117 - """
3118 - These two regexes are taken from echangelog
3119 - update_copyright(), except that we don't hardcode
3120 - 1999 here (in order to be more generic).
3121 - """
3122 - is_bytes = isinstance(line, bytes)
3123 - if is_bytes:
3124 - if not line.startswith(b'# Copyright '):
3125 - return line
3126 - else:
3127 - if not line.startswith('# Copyright '):
3128 - return line
3129 -
3130 - year = _unicode_encode(year)
3131 - line = _unicode_encode(line)
3132 -
3133 - line = _copyright_re1.sub(br'\1-' + year + b' ', line)
3134 - line = _copyright_re2.sub(_copyright_repl(year), line)
3135 - if not is_bytes:
3136 - line = _unicode_decode(line)
3137 - return line
3138 -
3139 -
3140 -def update_copyright(fn_path, year, pretend=False):
3141 - """
3142 - Check file for a Copyright statement, and update its year. The
3143 - patterns used for replacing copyrights are taken from echangelog.
3144 - Only the first lines of each file that start with a hash ('#') are
3145 - considered, until a line is found that doesn't start with a hash.
3146 - Files are read and written in binary mode, so that this function
3147 - will work correctly with files encoded in any character set, as
3148 - long as the copyright statements consist of plain ASCII.
3149 - """
3150 -
3151 - try:
3152 - fn_hdl = io.open(_unicode_encode(
3153 - fn_path, encoding=_encodings['fs'], errors='strict'),
3154 - mode='rb')
3155 - except EnvironmentError:
3156 - return
3157 -
3158 - orig_header = []
3159 - new_header = []
3160 -
3161 - for line in fn_hdl:
3162 - line_strip = line.strip()
3163 - orig_header.append(line)
3164 - if not line_strip or line_strip[:1] != b'#':
3165 - new_header.append(line)
3166 - break
3167 -
3168 - line = update_copyright_year(year, line)
3169 - new_header.append(line)
3170 -
3171 - difflines = 0
3172 - for diffline in difflib.unified_diff(
3173 - [_unicode_decode(diffline) for diffline in orig_header],
3174 - [_unicode_decode(diffline) for diffline in new_header],
3175 - fromfile=fn_path, tofile=fn_path, n=0):
3176 - util.writemsg_stdout(diffline, noiselevel=-1)
3177 - difflines += 1
3178 - util.writemsg_stdout("\n", noiselevel=-1)
3179 -
3180 - # unified diff has three lines to start with
3181 - if difflines > 3 and not pretend:
3182 - # write new file with changed header
3183 - f, fnnew_path = mkstemp()
3184 - f = io.open(f, mode='wb')
3185 - for line in new_header:
3186 - f.write(line)
3187 - for line in fn_hdl:
3188 - f.write(line)
3189 - f.close()
3190 - try:
3191 - fn_stat = os.stat(fn_path)
3192 - except OSError:
3193 - fn_stat = None
3194 -
3195 - shutil.move(fnnew_path, fn_path)
3196 -
3197 - if fn_stat is None:
3198 - util.apply_permissions(fn_path, mode=0o644)
3199 - else:
3200 - util.apply_stat_permissions(fn_path, fn_stat)
3201 - fn_hdl.close()
3202
3203 diff --git a/pym/tbc/repoman/ebuild.py b/pym/tbc/repoman/ebuild.py
3204 deleted file mode 100644
3205 index 1dddfb9..0000000
3206 --- a/pym/tbc/repoman/ebuild.py
3207 +++ /dev/null
3208 @@ -1,28 +0,0 @@
3209 -
3210 -
3211 -from portage import os
3212 -
3213 -
3214 -class Ebuild(object):
3215 - '''Class to run primary checks on ebuilds'''
3216 -
3217 - def __init__(
3218 - self, repo_settings, repolevel, pkgdir, catdir, vcs_settings, x, y):
3219 - self.vcs_settings = vcs_settings
3220 - self.relative_path = os.path.join(x, y + ".ebuild")
3221 - self.full_path = os.path.join(repo_settings.repodir, self.relative_path)
3222 - self.ebuild_path = y + ".ebuild"
3223 - if repolevel < 3:
3224 - self.ebuild_path = os.path.join(pkgdir, self.ebuild_path)
3225 - if repolevel < 2:
3226 - self.ebuild_path = os.path.join(catdir, self.ebuild_path)
3227 - self.ebuild_path = os.path.join(".", self.ebuild_path)
3228 -
3229 - def untracked(self, check_ebuild_notadded, y, eadded):
3230 - do_check = self.vcs_settings.vcs in ("cvs", "svn", "bzr")
3231 - really_notadded = check_ebuild_notadded and y not in eadded
3232 -
3233 - if do_check and really_notadded:
3234 - # ebuild not added to vcs
3235 - return True
3236 - return False
3237
3238 diff --git a/pym/tbc/repoman/errors.py b/pym/tbc/repoman/errors.py
3239 deleted file mode 100644
3240 index 305eece..0000000
3241 --- a/pym/tbc/repoman/errors.py
3242 +++ /dev/null
3243 @@ -1,19 +0,0 @@
3244 -
3245 -import sys
3246 -
3247 -
3248 -def warn(txt):
3249 - print("repoman: " + txt)
3250 -
3251 -
3252 -def err(txt):
3253 - warn(txt)
3254 - sys.exit(1)
3255 -
3256 -
3257 -def caterror(catdir, repodir):
3258 - err(
3259 - "%s is not an official category."
3260 - " Skipping QA checks in this directory.\n"
3261 - "Please ensure that you add %s to %s/profiles/categories\n"
3262 - "if it is a new category." % (catdir, catdir, repodir))
3263
3264 diff --git a/pym/tbc/repoman/main.py b/pym/tbc/repoman/main.py
3265 deleted file mode 100644
3266 index 10d508b..0000000
3267 --- a/pym/tbc/repoman/main.py
3268 +++ /dev/null
3269 @@ -1,1655 +0,0 @@
3270 -# Copyright 1999-2015 Gentoo Foundation
3271 -# Distributed under the terms of the GNU General Public License v2
3272 -
3273 -from __future__ import print_function, unicode_literals
3274 -
3275 -import copy
3276 -import errno
3277 -import io
3278 -import logging
3279 -import re
3280 -import signal
3281 -import subprocess
3282 -import sys
3283 -import tempfile
3284 -import platform
3285 -from itertools import chain
3286 -from pprint import pformat
3287 -
3288 -from os import path as osp
3289 -if osp.isfile(osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), ".portage_not_installed")):
3290 - pym_path = osp.join(osp.dirname(osp.dirname(osp.realpath(__file__)))) #, "pym")
3291 - sys.path.insert(0, pym_path)
3292 -# import our centrally initialized portage instance
3293 -from repoman._portage import portage
3294 -portage._internal_caller = True
3295 -portage._disable_legacy_globals()
3296 -
3297 -
3298 -from portage import os
3299 -from portage import _encodings
3300 -from portage import _unicode_encode
3301 -from _emerge.Package import Package
3302 -from _emerge.UserQuery import UserQuery
3303 -import portage.checksum
3304 -import portage.const
3305 -import portage.repository.config
3306 -from portage import cvstree, normalize_path
3307 -from portage import util
3308 -from portage.dep import Atom
3309 -from portage.exception import MissingParameter
3310 -from portage.process import find_binary, spawn
3311 -from portage.output import (
3312 - bold, create_color_func, green, nocolor, red)
3313 -from portage.output import ConsoleStyleFile, StyleWriter
3314 -from portage.util import formatter
3315 -from portage.util import writemsg_level
3316 -from portage.package.ebuild.digestgen import digestgen
3317 -
3318 -from repoman.argparser import parse_args
3319 -from repoman.checks.directories.files import FileChecks
3320 -from repoman.checks.ebuilds.checks import run_checks, checks_init
3321 -from repoman.checks.ebuilds.eclasses.live import LiveEclassChecks
3322 -from repoman.checks.ebuilds.eclasses.ruby import RubyEclassChecks
3323 -from repoman.checks.ebuilds.fetches import FetchChecks
3324 -from repoman.checks.ebuilds.keywords import KeywordChecks
3325 -from repoman.checks.ebuilds.isebuild import IsEbuild
3326 -from repoman.checks.ebuilds.thirdpartymirrors import ThirdPartyMirrors
3327 -from repoman.checks.ebuilds.manifests import Manifests
3328 -from repoman.check_missingslot import check_missingslot
3329 -from repoman.checks.ebuilds.misc import bad_split_check, pkg_invalid
3330 -from repoman.checks.ebuilds.pkgmetadata import PkgMetadata
3331 -from repoman.checks.ebuilds.use_flags import USEFlagChecks
3332 -from repoman.checks.ebuilds.variables.description import DescriptionChecks
3333 -from repoman.checks.ebuilds.variables.eapi import EAPIChecks
3334 -from repoman.checks.ebuilds.variables.license import LicenseChecks
3335 -from repoman.checks.ebuilds.variables.restrict import RestrictChecks
3336 -from repoman.ebuild import Ebuild
3337 -from repoman.errors import err
3338 -from repoman.modules.commit import repochecks
3339 -from repoman.profile import check_profiles, dev_keywords, setup_profile
3340 -from repoman.qa_data import (
3341 - format_qa_output, format_qa_output_column, qahelp,
3342 - qawarnings, qacats, missingvars,
3343 - suspect_virtual, suspect_rdepend)
3344 -from repoman.qa_tracker import QATracker
3345 -from repoman.repos import RepoSettings, repo_metadata
3346 -from repoman.scan import Changes, scan
3347 -from repoman._subprocess import repoman_popen, repoman_getstatusoutput
3348 -from repoman import utilities
3349 -from repoman.vcs.vcs import (
3350 - git_supports_gpg_sign, vcs_files_to_cps, VCSSettings)
3351 -from repoman.vcs.vcsstatus import VCSStatus
3352 -
3353 -
3354 -if sys.hexversion >= 0x3000000:
3355 - basestring = str
3356 -
3357 -util.initialize_logger()
3358 -
3359 -commitmessage = None
3360 -
3361 -bad = create_color_func("BAD")
3362 -
3363 -live_eclasses = portage.const.LIVE_ECLASSES
3364 -non_ascii_re = re.compile(r'[^\x00-\x7f]')
3365 -
3366 -# A sane umask is needed for files that portage creates.
3367 -os.umask(0o22)
3368 -
3369 -def sort_key(item):
3370 - return item[2].sub_path
3371 -
3372 -# Setup the GPG commands
3373 -def gpgsign(filename):
3374 - gpgcmd = repoman_settings.get("PORTAGE_GPG_SIGNING_COMMAND")
3375 - if gpgcmd in [None, '']:
3376 - raise MissingParameter("PORTAGE_GPG_SIGNING_COMMAND is unset!"
3377 - " Is make.globals missing?")
3378 - if "${PORTAGE_GPG_KEY}" in gpgcmd and \
3379 - "PORTAGE_GPG_KEY" not in repoman_settings:
3380 - raise MissingParameter("PORTAGE_GPG_KEY is unset!")
3381 - if "${PORTAGE_GPG_DIR}" in gpgcmd:
3382 - if "PORTAGE_GPG_DIR" not in repoman_settings:
3383 - repoman_settings["PORTAGE_GPG_DIR"] = \
3384 - os.path.expanduser("~/.gnupg")
3385 - logging.info(
3386 - "Automatically setting PORTAGE_GPG_DIR to '%s'" %
3387 - repoman_settings["PORTAGE_GPG_DIR"])
3388 - else:
3389 - repoman_settings["PORTAGE_GPG_DIR"] = \
3390 - os.path.expanduser(repoman_settings["PORTAGE_GPG_DIR"])
3391 - if not os.access(repoman_settings["PORTAGE_GPG_DIR"], os.X_OK):
3392 - raise portage.exception.InvalidLocation(
3393 - "Unable to access directory: PORTAGE_GPG_DIR='%s'" %
3394 - repoman_settings["PORTAGE_GPG_DIR"])
3395 - gpgvars = {"FILE": filename}
3396 - for k in ("PORTAGE_GPG_DIR", "PORTAGE_GPG_KEY"):
3397 - v = repoman_settings.get(k)
3398 - if v is not None:
3399 - gpgvars[k] = v
3400 - gpgcmd = portage.util.varexpand(gpgcmd, mydict=gpgvars)
3401 - if options.pretend:
3402 - print("(" + gpgcmd + ")")
3403 - else:
3404 - # Encode unicode manually for bug #310789.
3405 - gpgcmd = portage.util.shlex_split(gpgcmd)
3406 -
3407 - if sys.hexversion < 0x3020000 and sys.hexversion >= 0x3000000 and \
3408 - not os.path.isabs(gpgcmd[0]):
3409 - # Python 3.1 _execvp throws TypeError for non-absolute executable
3410 - # path passed as bytes (see http://bugs.python.org/issue8513).
3411 - fullname = find_binary(gpgcmd[0])
3412 - if fullname is None:
3413 - raise portage.exception.CommandNotFound(gpgcmd[0])
3414 - gpgcmd[0] = fullname
3415 -
3416 - gpgcmd = [
3417 - _unicode_encode(arg, encoding=_encodings['fs'], errors='strict')
3418 - for arg in gpgcmd]
3419 - rValue = subprocess.call(gpgcmd)
3420 - if rValue == os.EX_OK:
3421 - os.rename(filename + ".asc", filename)
3422 - else:
3423 - raise portage.exception.PortageException(
3424 - "!!! gpg exited with '" + str(rValue) + "' status")
3425 -
3426 -def need_signature(filename):
3427 - try:
3428 - with open(
3429 - _unicode_encode(
3430 - filename, encoding=_encodings['fs'], errors='strict'),
3431 - 'rb') as f:
3432 - return b"BEGIN PGP SIGNED MESSAGE" not in f.readline()
3433 - except IOError as e:
3434 - if e.errno in (errno.ENOENT, errno.ESTALE):
3435 - return False
3436 - raise
3437 -
3438 -def repoman_scan(repoman_settings, repo_settings, vcs_settings, portdb, options, myreporoot, mydir, check_changelog, config_root):
3439 - # Repoman sets it's own ACCEPT_KEYWORDS and we don't want it to
3440 - # behave incrementally.
3441 - repoman_incrementals = tuple(
3442 - x for x in portage.const.INCREMENTALS if x != 'ACCEPT_KEYWORDS')
3443 -
3444 - categories = repoman_settings.categories
3445 - reposplit = myreporoot.split(os.path.sep)
3446 - repolevel = len(reposplit)
3447 -
3448 - # It's confusing if these warnings are displayed without the user
3449 - # being told which profile they come from, so disable them.
3450 - env = os.environ.copy()
3451 - env['FEATURES'] = env.get('FEATURES', '') + ' -unknown-features-warn'
3452 -
3453 - ##################
3454 -
3455 - if options.mode == 'commit':
3456 - repochecks.commit_check(repolevel, reposplit)
3457 - repochecks.conflict_check(vcs_settings, options)
3458 -
3459 - ###################
3460 -
3461 - # Make startdir relative to the canonical repodir, so that we can pass
3462 - # it to digestgen and it won't have to be canonicalized again.
3463 - if repolevel == 1:
3464 - startdir = repo_settings.repodir
3465 - else:
3466 - startdir = normalize_path(mydir)
3467 - startdir = os.path.join(
3468 - repo_settings.repodir, *startdir.split(os.sep)[-2 - repolevel + 3:])
3469 - ###################
3470 -
3471 - # get lists of valid keywords, licenses, and use
3472 - new_data = repo_metadata(repo_settings.portdb, repoman_settings)
3473 - kwlist, liclist, uselist, profile_list, \
3474 - global_pmaskdict, liclist_deprecated = new_data
3475 -
3476 - repoman_settings['PORTAGE_ARCHLIST'] = ' '.join(sorted(kwlist))
3477 - repoman_settings.backup_changes('PORTAGE_ARCHLIST')
3478 -
3479 - ####################
3480 -
3481 - profiles = setup_profile(profile_list)
3482 -
3483 - ####################
3484 -
3485 - check_profiles(profiles, repoman_settings.archlist())
3486 -
3487 - ####################
3488 -
3489 - scanlist = scan(repolevel, reposplit, startdir, categories, repo_settings)
3490 -
3491 - ####################
3492 -
3493 - qatracker = QATracker()
3494 -
3495 - if options.mode == "manifest":
3496 - pass
3497 - elif options.pretend:
3498 - print(green("\nRepoMan does a once-over of the neighborhood..."))
3499 - else:
3500 - print(green("\nRepoMan scours the neighborhood..."))
3501 -
3502 - #####################
3503 -
3504 - changed = Changes(options)
3505 - changed.scan(vcs_settings)
3506 -
3507 - ######################
3508 -
3509 - have_pmasked = False
3510 - have_dev_keywords = False
3511 - dofail = 0
3512 -
3513 - # NOTE: match-all caches are not shared due to potential
3514 - # differences between profiles in _get_implicit_iuse.
3515 - arch_caches = {}
3516 - arch_xmatch_caches = {}
3517 - shared_xmatch_caches = {"cp-list": {}}
3518 -
3519 - include_arches = None
3520 - if options.include_arches:
3521 - include_arches = set()
3522 - include_arches.update(*[x.split() for x in options.include_arches])
3523 -
3524 - # Disable the "ebuild.notadded" check when not in commit mode and
3525 - # running `svn status` in every package dir will be too expensive.
3526 -
3527 - check_ebuild_notadded = not \
3528 - (vcs_settings.vcs == "svn" and repolevel < 3 and options.mode != "commit")
3529 -
3530 - effective_scanlist = scanlist
3531 - if options.if_modified == "y":
3532 - effective_scanlist = sorted(vcs_files_to_cps(
3533 - chain(changed.changed, changed.new, changed.removed),
3534 - repolevel, reposplit, categories))
3535 -
3536 - ######################
3537 - # initialize our checks classes here before the big xpkg loop
3538 - manifester = Manifests(options, qatracker, repoman_settings)
3539 - is_ebuild = IsEbuild(repoman_settings, repo_settings, portdb, qatracker)
3540 - filescheck = FileChecks(
3541 - qatracker, repoman_settings, repo_settings, portdb, vcs_settings)
3542 - status_check = VCSStatus(vcs_settings, qatracker)
3543 - fetchcheck = FetchChecks(
3544 - qatracker, repoman_settings, repo_settings, portdb, vcs_settings)
3545 - pkgmeta = PkgMetadata(options, qatracker, repoman_settings)
3546 - thirdparty = ThirdPartyMirrors(repoman_settings, qatracker)
3547 - use_flag_checks = USEFlagChecks(qatracker, uselist)
3548 - keywordcheck = KeywordChecks(qatracker, options)
3549 - liveeclasscheck = LiveEclassChecks(qatracker)
3550 - rubyeclasscheck = RubyEclassChecks(qatracker)
3551 - eapicheck = EAPIChecks(qatracker, repo_settings)
3552 - descriptioncheck = DescriptionChecks(qatracker)
3553 - licensecheck = LicenseChecks(qatracker, liclist, liclist_deprecated)
3554 - restrictcheck = RestrictChecks(qatracker)
3555 - ######################
3556 -
3557 - for xpkg in effective_scanlist:
3558 - # ebuilds and digests added to cvs respectively.
3559 - logging.info("checking package %s" % xpkg)
3560 - # save memory by discarding xmatch caches from previous package(s)
3561 - arch_xmatch_caches.clear()
3562 - eadded = []
3563 - catdir, pkgdir = xpkg.split("/")
3564 - checkdir = repo_settings.repodir + "/" + xpkg
3565 - checkdir_relative = ""
3566 - if repolevel < 3:
3567 - checkdir_relative = os.path.join(pkgdir, checkdir_relative)
3568 - if repolevel < 2:
3569 - checkdir_relative = os.path.join(catdir, checkdir_relative)
3570 - checkdir_relative = os.path.join(".", checkdir_relative)
3571 -
3572 - #####################
3573 - if manifester.run(checkdir, portdb):
3574 - continue
3575 - if not manifester.generated_manifest:
3576 - manifester.digest_check(xpkg, checkdir)
3577 - ######################
3578 -
3579 - if options.mode == 'manifest-check':
3580 - continue
3581 -
3582 - checkdirlist = os.listdir(checkdir)
3583 -
3584 - ######################
3585 - pkgs, allvalid = is_ebuild.check(checkdirlist, checkdir, xpkg)
3586 - if is_ebuild.continue_:
3587 - # If we can't access all the metadata then it's totally unsafe to
3588 - # commit since there's no way to generate a correct Manifest.
3589 - # Do not try to do any more QA checks on this package since missing
3590 - # metadata leads to false positives for several checks, and false
3591 - # positives confuse users.
3592 - can_force = False
3593 - continue
3594 - ######################
3595 -
3596 - keywordcheck.prepare()
3597 -
3598 - # Sort ebuilds in ascending order for the KEYWORDS.dropped check.
3599 - ebuildlist = sorted(pkgs.values())
3600 - ebuildlist = [pkg.pf for pkg in ebuildlist]
3601 - #######################
3602 - filescheck.check(
3603 - checkdir, checkdirlist, checkdir_relative, changed.changed, changed.new)
3604 - #######################
3605 - status_check.check(check_ebuild_notadded, checkdir, checkdir_relative, xpkg)
3606 - eadded.extend(status_check.eadded)
3607 -
3608 - #################
3609 - fetchcheck.check(
3610 - xpkg, checkdir, checkdir_relative, changed.changed, changed.new)
3611 - #################
3612 -
3613 - if check_changelog and "ChangeLog" not in checkdirlist:
3614 - qatracker.add_error("changelog.missing", xpkg + "/ChangeLog")
3615 - #################
3616 - pkgmeta.check(xpkg, checkdir, checkdirlist, repolevel)
3617 - muselist = frozenset(pkgmeta.musedict)
3618 - #################
3619 -
3620 - changelog_path = os.path.join(checkdir_relative, "ChangeLog")
3621 - changelog_modified = changelog_path in changed.changelogs
3622 -
3623 - # detect unused local USE-descriptions
3624 - used_useflags = set()
3625 -
3626 - for y_ebuild in ebuildlist:
3627 - ##################
3628 - ebuild = Ebuild(
3629 - repo_settings, repolevel, pkgdir, catdir, vcs_settings,
3630 - xpkg, y_ebuild)
3631 - ##################
3632 -
3633 - if check_changelog and not changelog_modified \
3634 - and ebuild.ebuild_path in changed.new_ebuilds:
3635 - qatracker.add_error('changelog.ebuildadded', ebuild.relative_path)
3636 -
3637 - if ebuild.untracked(check_ebuild_notadded, y_ebuild, eadded):
3638 - # ebuild not added to vcs
3639 - qatracker.add_error(
3640 - "ebuild.notadded", xpkg + "/" + y_ebuild + ".ebuild")
3641 -
3642 - ##################
3643 - if bad_split_check(xpkg, y_ebuild, pkgdir, qatracker):
3644 - continue
3645 - ###################
3646 - pkg = pkgs[y_ebuild]
3647 - if pkg_invalid(pkg, qatracker, ebuild):
3648 - allvalid = False
3649 - continue
3650 -
3651 - myaux = pkg._metadata
3652 - eapi = myaux["EAPI"]
3653 - inherited = pkg.inherited
3654 - live_ebuild = live_eclasses.intersection(inherited)
3655 -
3656 - #######################
3657 - eapicheck.check(pkg, ebuild)
3658 - #######################
3659 -
3660 - for k, v in myaux.items():
3661 - if not isinstance(v, basestring):
3662 - continue
3663 - m = non_ascii_re.search(v)
3664 - if m is not None:
3665 - qatracker.add_error(
3666 - "variable.invalidchar",
3667 - "%s: %s variable contains non-ASCII "
3668 - "character at position %s" %
3669 - (ebuild.relative_path, k, m.start() + 1))
3670 -
3671 - if not fetchcheck.src_uri_error:
3672 - #######################
3673 - thirdparty.check(myaux, ebuild.relative_path)
3674 - #######################
3675 - if myaux.get("PROVIDE"):
3676 - qatracker.add_error("virtual.oldstyle", ebuild.relative_path)
3677 -
3678 - for pos, missing_var in enumerate(missingvars):
3679 - if not myaux.get(missing_var):
3680 - if catdir == "virtual" and \
3681 - missing_var in ("HOMEPAGE", "LICENSE"):
3682 - continue
3683 - if live_ebuild and missing_var == "KEYWORDS":
3684 - continue
3685 - myqakey = missingvars[pos] + ".missing"
3686 - qatracker.add_error(myqakey, xpkg + "/" + y_ebuild + ".ebuild")
3687 -
3688 - if catdir == "virtual":
3689 - for var in ("HOMEPAGE", "LICENSE"):
3690 - if myaux.get(var):
3691 - myqakey = var + ".virtual"
3692 - qatracker.add_error(myqakey, ebuild.relative_path)
3693 -
3694 - #######################
3695 - descriptioncheck.check(pkg, ebuild)
3696 - #######################
3697 -
3698 - keywords = myaux["KEYWORDS"].split()
3699 -
3700 - ebuild_archs = set(
3701 - kw.lstrip("~") for kw in keywords if not kw.startswith("-"))
3702 -
3703 - #######################
3704 - keywordcheck.check(
3705 - pkg, xpkg, ebuild, y_ebuild, keywords, ebuild_archs, changed,
3706 - live_ebuild, kwlist, profiles)
3707 - #######################
3708 -
3709 - if live_ebuild and repo_settings.repo_config.name == "gentoo":
3710 - #######################
3711 - liveeclasscheck.check(
3712 - pkg, xpkg, ebuild, y_ebuild, keywords, global_pmaskdict)
3713 - #######################
3714 -
3715 - if options.ignore_arches:
3716 - arches = [[
3717 - repoman_settings["ARCH"], repoman_settings["ARCH"],
3718 - repoman_settings["ACCEPT_KEYWORDS"].split()]]
3719 - else:
3720 - arches = set()
3721 - for keyword in keywords:
3722 - if keyword[0] == "-":
3723 - continue
3724 - elif keyword[0] == "~":
3725 - arch = keyword[1:]
3726 - if arch == "*":
3727 - for expanded_arch in profiles:
3728 - if expanded_arch == "**":
3729 - continue
3730 - arches.add(
3731 - (keyword, expanded_arch, (
3732 - expanded_arch, "~" + expanded_arch)))
3733 - else:
3734 - arches.add((keyword, arch, (arch, keyword)))
3735 - else:
3736 - if keyword == "*":
3737 - for expanded_arch in profiles:
3738 - if expanded_arch == "**":
3739 - continue
3740 - arches.add(
3741 - (keyword, expanded_arch, (expanded_arch,)))
3742 - else:
3743 - arches.add((keyword, keyword, (keyword,)))
3744 - if not arches:
3745 - # Use an empty profile for checking dependencies of
3746 - # packages that have empty KEYWORDS.
3747 - arches.add(('**', '**', ('**',)))
3748 -
3749 - unknown_pkgs = set()
3750 - baddepsyntax = False
3751 - badlicsyntax = False
3752 - badprovsyntax = False
3753 - catpkg = catdir + "/" + y_ebuild
3754 -
3755 - inherited_java_eclass = "java-pkg-2" in inherited or \
3756 - "java-pkg-opt-2" in inherited
3757 - inherited_wxwidgets_eclass = "wxwidgets" in inherited
3758 - operator_tokens = set(["||", "(", ")"])
3759 - type_list, badsyntax = [], []
3760 - for mytype in Package._dep_keys + ("LICENSE", "PROPERTIES", "PROVIDE"):
3761 - mydepstr = myaux[mytype]
3762 -
3763 - buildtime = mytype in Package._buildtime_keys
3764 - runtime = mytype in Package._runtime_keys
3765 - token_class = None
3766 - if mytype.endswith("DEPEND"):
3767 - token_class = portage.dep.Atom
3768 -
3769 - try:
3770 - atoms = portage.dep.use_reduce(
3771 - mydepstr, matchall=1, flat=True,
3772 - is_valid_flag=pkg.iuse.is_valid_flag, token_class=token_class)
3773 - except portage.exception.InvalidDependString as e:
3774 - atoms = None
3775 - badsyntax.append(str(e))
3776 -
3777 - if atoms and mytype.endswith("DEPEND"):
3778 - if runtime and \
3779 - "test?" in mydepstr.split():
3780 - qatracker.add_error(
3781 - mytype + '.suspect',
3782 - "%s: 'test?' USE conditional in %s" %
3783 - (ebuild.relative_path, mytype))
3784 -
3785 - for atom in atoms:
3786 - if atom == "||":
3787 - continue
3788 -
3789 - is_blocker = atom.blocker
3790 -
3791 - # Skip dependency.unknown for blockers, so that we
3792 - # don't encourage people to remove necessary blockers,
3793 - # as discussed in bug 382407. We use atom.without_use
3794 - # due to bug 525376.
3795 - if not is_blocker and \
3796 - not portdb.xmatch("match-all", atom.without_use) and \
3797 - not atom.cp.startswith("virtual/"):
3798 - unknown_pkgs.add((mytype, atom.unevaluated_atom))
3799 -
3800 - if catdir != "virtual":
3801 - if not is_blocker and \
3802 - atom.cp in suspect_virtual:
3803 - qatracker.add_error(
3804 - 'virtual.suspect', ebuild.relative_path +
3805 - ": %s: consider using '%s' instead of '%s'" %
3806 - (mytype, suspect_virtual[atom.cp], atom))
3807 - if not is_blocker and \
3808 - atom.cp.startswith("perl-core/"):
3809 - qatracker.add_error('dependency.perlcore',
3810 - ebuild.relative_path +
3811 - ": %s: please use '%s' instead of '%s'" %
3812 - (mytype,
3813 - atom.replace("perl-core/","virtual/perl-"),
3814 - atom))
3815 -
3816 - if buildtime and \
3817 - not is_blocker and \
3818 - not inherited_java_eclass and \
3819 - atom.cp == "virtual/jdk":
3820 - qatracker.add_error(
3821 - 'java.eclassesnotused', ebuild.relative_path)
3822 - elif buildtime and \
3823 - not is_blocker and \
3824 - not inherited_wxwidgets_eclass and \
3825 - atom.cp == "x11-libs/wxGTK":
3826 - qatracker.add_error(
3827 - 'wxwidgets.eclassnotused',
3828 - "%s: %ss on x11-libs/wxGTK without inheriting"
3829 - " wxwidgets.eclass" % (ebuild.relative_path, mytype))
3830 - elif runtime:
3831 - if not is_blocker and \
3832 - atom.cp in suspect_rdepend:
3833 - qatracker.add_error(
3834 - mytype + '.suspect',
3835 - ebuild.relative_path + ": '%s'" % atom)
3836 -
3837 - if atom.operator == "~" and \
3838 - portage.versions.catpkgsplit(atom.cpv)[3] != "r0":
3839 - qacat = 'dependency.badtilde'
3840 - qatracker.add_error(
3841 - qacat, "%s: %s uses the ~ operator"
3842 - " with a non-zero revision: '%s'" %
3843 - (ebuild.relative_path, mytype, atom))
3844 -
3845 - check_missingslot(atom, mytype, eapi, portdb, qatracker,
3846 - ebuild.relative_path, myaux)
3847 -
3848 - type_list.extend([mytype] * (len(badsyntax) - len(type_list)))
3849 -
3850 - for m, b in zip(type_list, badsyntax):
3851 - if m.endswith("DEPEND"):
3852 - qacat = "dependency.syntax"
3853 - else:
3854 - qacat = m + ".syntax"
3855 - qatracker.add_error(
3856 - qacat, "%s: %s: %s" % (ebuild.relative_path, m, b))
3857 -
3858 - badlicsyntax = len([z for z in type_list if z == "LICENSE"])
3859 - badprovsyntax = len([z for z in type_list if z == "PROVIDE"])
3860 - baddepsyntax = len(type_list) != badlicsyntax + badprovsyntax
3861 - badlicsyntax = badlicsyntax > 0
3862 - badprovsyntax = badprovsyntax > 0
3863 -
3864 - #################
3865 - use_flag_checks.check(pkg, xpkg, ebuild, y_ebuild, muselist)
3866 -
3867 - ebuild_used_useflags = use_flag_checks.getUsedUseFlags()
3868 - used_useflags = used_useflags.union(ebuild_used_useflags)
3869 - #################
3870 - rubyeclasscheck.check(pkg, ebuild)
3871 - #################
3872 -
3873 - # license checks
3874 - if not badlicsyntax:
3875 - #################
3876 - licensecheck.check(pkg, xpkg, ebuild, y_ebuild)
3877 - #################
3878 -
3879 - #################
3880 - restrictcheck.check(pkg, xpkg, ebuild, y_ebuild)
3881 - #################
3882 -
3883 - # Syntax Checks
3884 -
3885 - if not vcs_settings.vcs_preserves_mtime:
3886 - if ebuild.ebuild_path not in changed.new_ebuilds and \
3887 - ebuild.ebuild_path not in changed.ebuilds:
3888 - pkg.mtime = None
3889 - try:
3890 - # All ebuilds should have utf_8 encoding.
3891 - f = io.open(
3892 - _unicode_encode(
3893 - ebuild.full_path, encoding=_encodings['fs'], errors='strict'),
3894 - mode='r', encoding=_encodings['repo.content'])
3895 - try:
3896 - for check_name, e in run_checks(f, pkg):
3897 - qatracker.add_error(
3898 - check_name, ebuild.relative_path + ': %s' % e)
3899 - finally:
3900 - f.close()
3901 - except UnicodeDecodeError:
3902 - # A file.UTF8 failure will have already been recorded above.
3903 - pass
3904 -
3905 - if options.force:
3906 - # The dep_check() calls are the most expensive QA test. If --force
3907 - # is enabled, there's no point in wasting time on these since the
3908 - # user is intent on forcing the commit anyway.
3909 - continue
3910 -
3911 - relevant_profiles = []
3912 - for keyword, arch, groups in arches:
3913 - if arch not in profiles:
3914 - # A missing profile will create an error further down
3915 - # during the KEYWORDS verification.
3916 - continue
3917 -
3918 - if include_arches is not None:
3919 - if arch not in include_arches:
3920 - continue
3921 -
3922 - relevant_profiles.extend(
3923 - (keyword, groups, prof) for prof in profiles[arch])
3924 -
3925 - relevant_profiles.sort(key=sort_key)
3926 -
3927 - for keyword, groups, prof in relevant_profiles:
3928 -
3929 - is_stable_profile = prof.status == "stable"
3930 - is_dev_profile = prof.status == "dev" and \
3931 - options.include_dev
3932 - is_exp_profile = prof.status == "exp" and \
3933 - options.include_exp_profiles == 'y'
3934 - if not (is_stable_profile or is_dev_profile or is_exp_profile):
3935 - continue
3936 -
3937 - dep_settings = arch_caches.get(prof.sub_path)
3938 - if dep_settings is None:
3939 - dep_settings = portage.config(
3940 - config_profile_path=prof.abs_path,
3941 - config_incrementals=repoman_incrementals,
3942 - config_root=config_root,
3943 - local_config=False,
3944 - _unmatched_removal=options.unmatched_removal,
3945 - env=env, repositories=repoman_settings.repositories)
3946 - dep_settings.categories = repoman_settings.categories
3947 - if options.without_mask:
3948 - dep_settings._mask_manager_obj = \
3949 - copy.deepcopy(dep_settings._mask_manager)
3950 - dep_settings._mask_manager._pmaskdict.clear()
3951 - arch_caches[prof.sub_path] = dep_settings
3952 -
3953 - xmatch_cache_key = (prof.sub_path, tuple(groups))
3954 - xcache = arch_xmatch_caches.get(xmatch_cache_key)
3955 - if xcache is None:
3956 - portdb.melt()
3957 - portdb.freeze()
3958 - xcache = portdb.xcache
3959 - xcache.update(shared_xmatch_caches)
3960 - arch_xmatch_caches[xmatch_cache_key] = xcache
3961 -
3962 - repo_settings.trees[repo_settings.root]["porttree"].settings = dep_settings
3963 - portdb.settings = dep_settings
3964 - portdb.xcache = xcache
3965 -
3966 - dep_settings["ACCEPT_KEYWORDS"] = " ".join(groups)
3967 - # just in case, prevent config.reset() from nuking these.
3968 - dep_settings.backup_changes("ACCEPT_KEYWORDS")
3969 -
3970 - # This attribute is used in dbapi._match_use() to apply
3971 - # use.stable.{mask,force} settings based on the stable
3972 - # status of the parent package. This is required in order
3973 - # for USE deps of unstable packages to be resolved correctly,
3974 - # since otherwise use.stable.{mask,force} settings of
3975 - # dependencies may conflict (see bug #456342).
3976 - dep_settings._parent_stable = dep_settings._isStable(pkg)
3977 -
3978 - # Handle package.use*.{force,mask) calculation, for use
3979 - # in dep_check.
3980 - dep_settings.useforce = dep_settings._use_manager.getUseForce(
3981 - pkg, stable=dep_settings._parent_stable)
3982 - dep_settings.usemask = dep_settings._use_manager.getUseMask(
3983 - pkg, stable=dep_settings._parent_stable)
3984 -
3985 - if not baddepsyntax:
3986 - ismasked = not ebuild_archs or \
3987 - pkg.cpv not in portdb.xmatch("match-visible",
3988 - Atom("%s::%s" % (pkg.cp, repo_settings.repo_config.name)))
3989 - if ismasked:
3990 - if not have_pmasked:
3991 - have_pmasked = bool(dep_settings._getMaskAtom(
3992 - pkg.cpv, pkg._metadata))
3993 - if options.ignore_masked:
3994 - continue
3995 - # we are testing deps for a masked package; give it some lee-way
3996 - suffix = "masked"
3997 - matchmode = "minimum-all"
3998 - else:
3999 - suffix = ""
4000 - matchmode = "minimum-visible"
4001 -
4002 - if not have_dev_keywords:
4003 - dev_keyword = dev_keywords(profiles)
4004 - have_dev_keywords = \
4005 - bool(dev_keyword.intersection(keywords))
4006 -
4007 - if prof.status == "dev":
4008 - suffix = suffix + "indev"
4009 -
4010 - for mytype in Package._dep_keys:
4011 -
4012 - mykey = "dependency.bad" + suffix
4013 - myvalue = myaux[mytype]
4014 - if not myvalue:
4015 - continue
4016 -
4017 - success, atoms = portage.dep_check(
4018 - myvalue, portdb, dep_settings,
4019 - use="all", mode=matchmode, trees=repo_settings.trees)
4020 -
4021 - if success:
4022 - if atoms:
4023 -
4024 - # Don't bother with dependency.unknown for
4025 - # cases in which *DEPEND.bad is triggered.
4026 - for atom in atoms:
4027 - # dep_check returns all blockers and they
4028 - # aren't counted for *DEPEND.bad, so we
4029 - # ignore them here.
4030 - if not atom.blocker:
4031 - unknown_pkgs.discard(
4032 - (mytype, atom.unevaluated_atom))
4033 -
4034 - if not prof.sub_path:
4035 - # old-style virtuals currently aren't
4036 - # resolvable with empty profile, since
4037 - # 'virtuals' mappings are unavailable
4038 - # (it would be expensive to search
4039 - # for PROVIDE in all ebuilds)
4040 - atoms = [
4041 - atom for atom in atoms if not (
4042 - atom.cp.startswith('virtual/')
4043 - and not portdb.cp_list(atom.cp))]
4044 -
4045 - # we have some unsolvable deps
4046 - # remove ! deps, which always show up as unsatisfiable
4047 - atoms = [
4048 - str(atom.unevaluated_atom)
4049 - for atom in atoms if not atom.blocker]
4050 -
4051 - # if we emptied out our list, continue:
4052 - if not atoms:
4053 - continue
4054 - qatracker.add_error(mykey,
4055 - "%s: %s: %s(%s)\n%s"
4056 - % (ebuild.relative_path, mytype, keyword, prof,
4057 - pformat(atoms, indent=6)))
4058 - else:
4059 - qatracker.add_error(mykey,
4060 - "%s: %s: %s(%s)\n%s"
4061 - % (ebuild.relative_path, mytype, keyword, prof,
4062 - pformat(atoms, indent=6)))
4063 -
4064 - if not baddepsyntax and unknown_pkgs:
4065 - type_map = {}
4066 - for mytype, atom in unknown_pkgs:
4067 - type_map.setdefault(mytype, set()).add(atom)
4068 - for mytype, atoms in type_map.items():
4069 - qatracker.add_error(
4070 - "dependency.unknown", "%s: %s: %s"
4071 - % (ebuild.relative_path, mytype, ", ".join(sorted(atoms))))
4072 -
4073 - # check if there are unused local USE-descriptions in metadata.xml
4074 - # (unless there are any invalids, to avoid noise)
4075 - if allvalid:
4076 - for myflag in muselist.difference(used_useflags):
4077 - qatracker.add_error(
4078 - "metadata.warning",
4079 - "%s/metadata.xml: unused local USE-description: '%s'"
4080 - % (xpkg, myflag))
4081 -
4082 - if options.if_modified == "y" and len(effective_scanlist) < 1:
4083 - logging.warning("--if-modified is enabled, but no modified packages were found!")
4084 -
4085 - suggest_ignore_masked = False
4086 - suggest_include_dev = False
4087 -
4088 - if have_pmasked and not (options.without_mask or options.ignore_masked):
4089 - suggest_ignore_masked = True
4090 - if have_dev_keywords and not options.include_dev:
4091 - suggest_include_dev = True
4092 -
4093 - if suggest_ignore_masked or suggest_include_dev:
4094 - print()
4095 - if suggest_ignore_masked:
4096 - print(bold(
4097 - "Note: use --without-mask to check "
4098 - "KEYWORDS on dependencies of masked packages"))
4099 -
4100 - if suggest_include_dev:
4101 - print(bold(
4102 - "Note: use --include-dev (-d) to check "
4103 - "dependencies for 'dev' profiles"))
4104 - print()
4105 - return qatracker
4106 -def repoman_main(argv):
4107 -
4108 - config_root = os.environ.get("PORTAGE_CONFIGROOT")
4109 - repoman_settings = portage.config(config_root=config_root, local_config=False)
4110 -
4111 - if repoman_settings.get("NOCOLOR", "").lower() in ("yes", "true") or \
4112 - repoman_settings.get('TERM') == 'dumb' or \
4113 - not sys.stdout.isatty():
4114 - nocolor()
4115 -
4116 - options, arguments = parse_args(
4117 - sys.argv, qahelp, repoman_settings.get("REPOMAN_DEFAULT_OPTS", ""))
4118 -
4119 - if options.version:
4120 - print("Portage", portage.VERSION)
4121 - sys.exit(0)
4122 -
4123 - if options.experimental_inherit == 'y':
4124 - # This is experimental, so it's non-fatal.
4125 - qawarnings.add("inherit.missing")
4126 - checks_init(experimental_inherit=True)
4127 -
4128 - # Set this to False when an extraordinary issue (generally
4129 - # something other than a QA issue) makes it impossible to
4130 - # commit (like if Manifest generation fails).
4131 - can_force = True
4132 -
4133 - portdir, portdir_overlay, mydir = utilities.FindPortdir(repoman_settings)
4134 - if portdir is None:
4135 - sys.exit(1)
4136 -
4137 - myreporoot = os.path.basename(portdir_overlay)
4138 - myreporoot += mydir[len(portdir_overlay):]
4139 -
4140 - ##################
4141 -
4142 - vcs_settings = VCSSettings(options, repoman_settings)
4143 -
4144 - repo_settings = RepoSettings(
4145 - config_root, portdir, portdir_overlay,
4146 - repoman_settings, vcs_settings, options, qawarnings)
4147 -
4148 - repoman_settings = repo_settings.repoman_settings
4149 -
4150 - portdb = repo_settings.portdb
4151 -
4152 - ##################
4153 -
4154 - if options.echangelog is None and repo_settings.repo_config.update_changelog:
4155 - options.echangelog = 'y'
4156 -
4157 - if vcs_settings.vcs is None:
4158 - options.echangelog = 'n'
4159 -
4160 - # The --echangelog option causes automatic ChangeLog generation,
4161 - # which invalidates changelog.ebuildadded and changelog.missing
4162 - # checks.
4163 - # Note: Some don't use ChangeLogs in distributed SCMs.
4164 - # It will be generated on server side from scm log,
4165 - # before package moves to the rsync server.
4166 - # This is needed because they try to avoid merge collisions.
4167 - # Gentoo's Council decided to always use the ChangeLog file.
4168 - # TODO: shouldn't this just be switched on the repo, iso the VCS?
4169 - is_echangelog_enabled = options.echangelog in ('y', 'force')
4170 - vcs_settings.vcs_is_cvs_or_svn = vcs_settings.vcs in ('cvs', 'svn')
4171 - check_changelog = not is_echangelog_enabled and vcs_settings.vcs_is_cvs_or_svn
4172 -
4173 - if 'digest' in repoman_settings.features and options.digest != 'n':
4174 - options.digest = 'y'
4175 -
4176 - logging.debug("vcs: %s" % (vcs_settings.vcs,))
4177 - logging.debug("repo config: %s" % (repo_settings.repo_config,))
4178 - logging.debug("options: %s" % (options,))
4179 -
4180 - categories = []
4181 - for path in repo_settings.repo_config.eclass_db.porttrees:
4182 - categories.extend(portage.util.grabfile(
4183 - os.path.join(path, 'profiles', 'categories')))
4184 - repoman_settings.categories = frozenset(
4185 - portage.util.stack_lists([categories], incremental=1))
4186 - categories = repoman_settings.categories
4187 -
4188 - portdb.settings = repoman_settings
4189 - # We really only need to cache the metadata that's necessary for visibility
4190 - # filtering. Anything else can be discarded to reduce memory consumption.
4191 - portdb._aux_cache_keys.clear()
4192 - portdb._aux_cache_keys.update(
4193 - ["EAPI", "IUSE", "KEYWORDS", "repository", "SLOT"])
4194 -
4195 - reposplit = myreporoot.split(os.path.sep)
4196 - repolevel = len(reposplit)
4197 -
4198 - # Call scan
4199 - qatracker = repoman_scan(repoman_settings, repo_settings, vcs_settings, portdb, options, myreporoot, mydir, check_changelog, config_root)
4200 -
4201 - if options.mode == "manifest":
4202 - sys.exit(dofail)
4203 -
4204 - # dofail will be true if we have failed in at least one non-warning category
4205 - dofail = 0
4206 - # dowarn will be true if we tripped any warnings
4207 - dowarn = 0
4208 - # dofull will be true if we should print a "repoman full" informational message
4209 - dofull = options.mode != 'full'
4210 -
4211 - for x in qacats:
4212 - if x not in qatracker.fails:
4213 - continue
4214 - dowarn = 1
4215 - if x not in qawarnings:
4216 - dofail = 1
4217 -
4218 - if dofail or \
4219 - (dowarn and not (options.quiet or options.mode == "scan")):
4220 - dofull = 0
4221 -
4222 - # Save QA output so that it can be conveniently displayed
4223 - # in $EDITOR while the user creates a commit message.
4224 - # Otherwise, the user would not be able to see this output
4225 - # once the editor has taken over the screen.
4226 - qa_output = io.StringIO()
4227 - style_file = ConsoleStyleFile(sys.stdout)
4228 - if options.mode == 'commit' and \
4229 - (not commitmessage or not commitmessage.strip()):
4230 - style_file.write_listener = qa_output
4231 - console_writer = StyleWriter(file=style_file, maxcol=9999)
4232 - console_writer.style_listener = style_file.new_styles
4233 -
4234 - f = formatter.AbstractFormatter(console_writer)
4235 -
4236 - format_outputs = {
4237 - 'column': format_qa_output_column,
4238 - 'default': format_qa_output
4239 - }
4240 -
4241 - format_output = format_outputs.get(
4242 - options.output_style, format_outputs['default'])
4243 - format_output(f, qatracker.fails, dofull, dofail, options, qawarnings)
4244 -
4245 - style_file.flush()
4246 - del console_writer, f, style_file
4247 - qa_output = qa_output.getvalue()
4248 - qa_output = qa_output.splitlines(True)
4249 -
4250 - if options.mode != 'commit':
4251 - if dofull:
4252 - print(bold("Note: type \"repoman full\" for a complete listing."))
4253 - if dowarn and not dofail:
4254 - utilities.repoman_sez(
4255 - "\"You're only giving me a partial QA payment?\n"
4256 - " I'll take it this time, but I'm not happy.\"")
4257 - elif not dofail:
4258 - utilities.repoman_sez(
4259 - "\"If everyone were like you, I'd be out of business!\"")
4260 - elif dofail:
4261 - print(bad("Please fix these important QA issues first."))
4262 - utilities.repoman_sez(
4263 - "\"Make your QA payment on time"
4264 - " and you'll never see the likes of me.\"\n")
4265 - sys.exit(1)
4266 - else:
4267 - if dofail and can_force and options.force and not options.pretend:
4268 - utilities.repoman_sez(
4269 - " \"You want to commit even with these QA issues?\n"
4270 - " I'll take it this time, but I'm not happy.\"\n")
4271 - elif dofail:
4272 - if options.force and not can_force:
4273 - print(bad(
4274 - "The --force option has been disabled"
4275 - " due to extraordinary issues."))
4276 - print(bad("Please fix these important QA issues first."))
4277 - utilities.repoman_sez(
4278 - "\"Make your QA payment on time"
4279 - " and you'll never see the likes of me.\"\n")
4280 - sys.exit(1)
4281 -
4282 - if options.pretend:
4283 - utilities.repoman_sez(
4284 - "\"So, you want to play it safe. Good call.\"\n")
4285 -
4286 - myunadded = []
4287 - if vcs_settings.vcs == "cvs":
4288 - try:
4289 - myvcstree = portage.cvstree.getentries("./", recursive=1)
4290 - myunadded = portage.cvstree.findunadded(
4291 - myvcstree, recursive=1, basedir="./")
4292 - except SystemExit as e:
4293 - raise # TODO propagate this
4294 - except:
4295 - err("Error retrieving CVS tree; exiting.")
4296 - if vcs_settings.vcs == "svn":
4297 - try:
4298 - with repoman_popen("svn status --no-ignore") as f:
4299 - svnstatus = f.readlines()
4300 - myunadded = [
4301 - "./" + elem.rstrip().split()[1]
4302 - for elem in svnstatus
4303 - if elem.startswith("?") or elem.startswith("I")]
4304 - except SystemExit as e:
4305 - raise # TODO propagate this
4306 - except:
4307 - err("Error retrieving SVN info; exiting.")
4308 - if vcs_settings.vcs == "git":
4309 - # get list of files not under version control or missing
4310 - myf = repoman_popen("git ls-files --others")
4311 - myunadded = ["./" + elem[:-1] for elem in myf]
4312 - myf.close()
4313 - if vcs_settings.vcs == "bzr":
4314 - try:
4315 - with repoman_popen("bzr status -S .") as f:
4316 - bzrstatus = f.readlines()
4317 - myunadded = [
4318 - "./" + elem.rstrip().split()[1].split('/')[-1:][0]
4319 - for elem in bzrstatus
4320 - if elem.startswith("?") or elem[0:2] == " D"]
4321 - except SystemExit as e:
4322 - raise # TODO propagate this
4323 - except:
4324 - err("Error retrieving bzr info; exiting.")
4325 - if vcs_settings.vcs == "hg":
4326 - with repoman_popen("hg status --no-status --unknown .") as f:
4327 - myunadded = f.readlines()
4328 - myunadded = ["./" + elem.rstrip() for elem in myunadded]
4329 -
4330 - # Mercurial doesn't handle manually deleted files as removed from
4331 - # the repository, so the user need to remove them before commit,
4332 - # using "hg remove [FILES]"
4333 - with repoman_popen("hg status --no-status --deleted .") as f:
4334 - mydeleted = f.readlines()
4335 - mydeleted = ["./" + elem.rstrip() for elem in mydeleted]
4336 -
4337 - myautoadd = []
4338 - if myunadded:
4339 - for x in range(len(myunadded) - 1, -1, -1):
4340 - xs = myunadded[x].split("/")
4341 - if xs[-1] == "files":
4342 - print("!!! files dir is not added! Please correct this.")
4343 - sys.exit(-1)
4344 - elif xs[-1] == "Manifest":
4345 - # It's a manifest... auto add
4346 - myautoadd += [myunadded[x]]
4347 - del myunadded[x]
4348 -
4349 - if myunadded:
4350 - print(red(
4351 - "!!! The following files are in your local tree"
4352 - " but are not added to the master"))
4353 - print(red(
4354 - "!!! tree. Please remove them from the local tree"
4355 - " or add them to the master tree."))
4356 - for x in myunadded:
4357 - print(" ", x)
4358 - print()
4359 - print()
4360 - sys.exit(1)
4361 -
4362 - if vcs_settings.vcs == "hg" and mydeleted:
4363 - print(red(
4364 - "!!! The following files are removed manually"
4365 - " from your local tree but are not"))
4366 - print(red(
4367 - "!!! removed from the repository."
4368 - " Please remove them, using \"hg remove [FILES]\"."))
4369 - for x in mydeleted:
4370 - print(" ", x)
4371 - print()
4372 - print()
4373 - sys.exit(1)
4374 -
4375 - if vcs_settings.vcs == "cvs":
4376 - mycvstree = cvstree.getentries("./", recursive=1)
4377 - mychanged = cvstree.findchanged(mycvstree, recursive=1, basedir="./")
4378 - mynew = cvstree.findnew(mycvstree, recursive=1, basedir="./")
4379 - myremoved = portage.cvstree.findremoved(mycvstree, recursive=1, basedir="./")
4380 - bin_blob_pattern = re.compile("^-kb$")
4381 - no_expansion = set(portage.cvstree.findoption(
4382 - mycvstree, bin_blob_pattern, recursive=1, basedir="./"))
4383 -
4384 - if vcs_settings.vcs == "svn":
4385 - with repoman_popen("svn status") as f:
4386 - svnstatus = f.readlines()
4387 - mychanged = [
4388 - "./" + elem.split()[-1:][0]
4389 - for elem in svnstatus
4390 - if (elem[:1] in "MR" or elem[1:2] in "M")]
4391 - mynew = [
4392 - "./" + elem.split()[-1:][0]
4393 - for elem in svnstatus
4394 - if elem.startswith("A")]
4395 - myremoved = [
4396 - "./" + elem.split()[-1:][0]
4397 - for elem in svnstatus
4398 - if elem.startswith("D")]
4399 -
4400 - # Subversion expands keywords specified in svn:keywords properties.
4401 - with repoman_popen("svn propget -R svn:keywords") as f:
4402 - props = f.readlines()
4403 - expansion = dict(
4404 - ("./" + prop.split(" - ")[0], prop.split(" - ")[1].split())
4405 - for prop in props if " - " in prop)
4406 -
4407 - elif vcs_settings.vcs == "git":
4408 - with repoman_popen(
4409 - "git diff-index --name-only "
4410 - "--relative --diff-filter=M HEAD") as f:
4411 - mychanged = f.readlines()
4412 - mychanged = ["./" + elem[:-1] for elem in mychanged]
4413 -
4414 - with repoman_popen(
4415 - "git diff-index --name-only "
4416 - "--relative --diff-filter=A HEAD") as f:
4417 - mynew = f.readlines()
4418 - mynew = ["./" + elem[:-1] for elem in mynew]
4419 -
4420 - with repoman_popen(
4421 - "git diff-index --name-only "
4422 - "--relative --diff-filter=D HEAD") as f:
4423 - myremoved = f.readlines()
4424 - myremoved = ["./" + elem[:-1] for elem in myremoved]
4425 -
4426 - if vcs_settings.vcs == "bzr":
4427 - with repoman_popen("bzr status -S .") as f:
4428 - bzrstatus = f.readlines()
4429 - mychanged = [
4430 - "./" + elem.split()[-1:][0].split('/')[-1:][0]
4431 - for elem in bzrstatus
4432 - if elem and elem[1:2] == "M"]
4433 - mynew = [
4434 - "./" + elem.split()[-1:][0].split('/')[-1:][0]
4435 - for elem in bzrstatus
4436 - if elem and (elem[1:2] in "NK" or elem[0:1] == "R")]
4437 - myremoved = [
4438 - "./" + elem.split()[-1:][0].split('/')[-1:][0]
4439 - for elem in bzrstatus
4440 - if elem.startswith("-")]
4441 - myremoved = [
4442 - "./" + elem.split()[-3:-2][0].split('/')[-1:][0]
4443 - for elem in bzrstatus
4444 - if elem and (elem[1:2] == "K" or elem[0:1] == "R")]
4445 - # Bazaar expands nothing.
4446 -
4447 - if vcs_settings.vcs == "hg":
4448 - with repoman_popen("hg status --no-status --modified .") as f:
4449 - mychanged = f.readlines()
4450 - mychanged = ["./" + elem.rstrip() for elem in mychanged]
4451 -
4452 - with repoman_popen("hg status --no-status --added .") as f:
4453 - mynew = f.readlines()
4454 - mynew = ["./" + elem.rstrip() for elem in mynew]
4455 -
4456 - with repoman_popen("hg status --no-status --removed .") as f:
4457 - myremoved = f.readlines()
4458 - myremoved = ["./" + elem.rstrip() for elem in myremoved]
4459 -
4460 - if vcs_settings.vcs:
4461 - a_file_is_changed = mychanged or mynew or myremoved
4462 - a_file_is_deleted_hg = vcs_settings.vcs == "hg" and mydeleted
4463 -
4464 - if not (a_file_is_changed or a_file_is_deleted_hg):
4465 - utilities.repoman_sez(
4466 - "\"Doing nothing is not always good for QA.\"")
4467 - print()
4468 - print("(Didn't find any changed files...)")
4469 - print()
4470 - sys.exit(1)
4471 -
4472 - # Manifests need to be regenerated after all other commits, so don't commit
4473 - # them now even if they have changed.
4474 - mymanifests = set()
4475 - myupdates = set()
4476 - for f in mychanged + mynew:
4477 - if "Manifest" == os.path.basename(f):
4478 - mymanifests.add(f)
4479 - else:
4480 - myupdates.add(f)
4481 - myupdates.difference_update(myremoved)
4482 - myupdates = list(myupdates)
4483 - mymanifests = list(mymanifests)
4484 - myheaders = []
4485 - mydirty = []
4486 -
4487 - commitmessage = options.commitmsg
4488 - if options.commitmsgfile:
4489 - try:
4490 - f = io.open(
4491 - _unicode_encode(
4492 - options.commitmsgfile,
4493 - encoding=_encodings['fs'], errors='strict'),
4494 - mode='r', encoding=_encodings['content'], errors='replace')
4495 - commitmessage = f.read()
4496 - f.close()
4497 - del f
4498 - except (IOError, OSError) as e:
4499 - if e.errno == errno.ENOENT:
4500 - portage.writemsg(
4501 - "!!! File Not Found:"
4502 - " --commitmsgfile='%s'\n" % options.commitmsgfile)
4503 - else:
4504 - raise
4505 - # We've read the content so the file is no longer needed.
4506 - commitmessagefile = None
4507 - if not commitmessage or not commitmessage.strip():
4508 - msg_prefix = ""
4509 - if repolevel > 1:
4510 - msg_prefix = "/".join(reposplit[1:]) + ": "
4511 -
4512 - try:
4513 - editor = os.environ.get("EDITOR")
4514 - if editor and utilities.editor_is_executable(editor):
4515 - commitmessage = utilities.get_commit_message_with_editor(
4516 - editor, message=qa_output, prefix=msg_prefix)
4517 - else:
4518 - commitmessage = utilities.get_commit_message_with_stdin()
4519 - except KeyboardInterrupt:
4520 - logging.fatal("Interrupted; exiting...")
4521 - sys.exit(1)
4522 - if (not commitmessage or not commitmessage.strip()
4523 - or commitmessage.strip() == msg_prefix):
4524 - print("* no commit message? aborting commit.")
4525 - sys.exit(1)
4526 - commitmessage = commitmessage.rstrip()
4527 - changelog_msg = commitmessage
4528 - portage_version = getattr(portage, "VERSION", None)
4529 - gpg_key = repoman_settings.get("PORTAGE_GPG_KEY", "")
4530 - dco_sob = repoman_settings.get("DCO_SIGNED_OFF_BY", "")
4531 - if portage_version is None:
4532 - sys.stderr.write("Failed to insert portage version in message!\n")
4533 - sys.stderr.flush()
4534 - portage_version = "Unknown"
4535 -
4536 - report_options = []
4537 - if options.force:
4538 - report_options.append("--force")
4539 - if options.ignore_arches:
4540 - report_options.append("--ignore-arches")
4541 - if include_arches is not None:
4542 - report_options.append(
4543 - "--include-arches=\"%s\"" %
4544 - " ".join(sorted(include_arches)))
4545 -
4546 - if vcs_settings.vcs == "git":
4547 - # Use new footer only for git (see bug #438364).
4548 - commit_footer = "\n\nPackage-Manager: portage-%s" % portage_version
4549 - if report_options:
4550 - commit_footer += "\nRepoMan-Options: " + " ".join(report_options)
4551 - if repo_settings.sign_manifests:
4552 - commit_footer += "\nManifest-Sign-Key: %s" % (gpg_key, )
4553 - if dco_sob:
4554 - commit_footer += "\nSigned-off-by: %s" % (dco_sob, )
4555 - else:
4556 - unameout = platform.system() + " "
4557 - if platform.system() in ["Darwin", "SunOS"]:
4558 - unameout += platform.processor()
4559 - else:
4560 - unameout += platform.machine()
4561 - commit_footer = "\n\n"
4562 - if dco_sob:
4563 - commit_footer += "Signed-off-by: %s\n" % (dco_sob, )
4564 - commit_footer += "(Portage version: %s/%s/%s" % \
4565 - (portage_version, vcs_settings.vcs, unameout)
4566 - if report_options:
4567 - commit_footer += ", RepoMan options: " + " ".join(report_options)
4568 - if repo_settings.sign_manifests:
4569 - commit_footer += ", signed Manifest commit with key %s" % \
4570 - (gpg_key, )
4571 - else:
4572 - commit_footer += ", unsigned Manifest commit"
4573 - commit_footer += ")"
4574 -
4575 - commitmessage += commit_footer
4576 -
4577 - broken_changelog_manifests = []
4578 - if options.echangelog in ('y', 'force'):
4579 - logging.info("checking for unmodified ChangeLog files")
4580 - committer_name = utilities.get_committer_name(env=repoman_settings)
4581 - for x in sorted(vcs_files_to_cps(
4582 - chain(myupdates, mymanifests, myremoved),
4583 - repolevel, reposplit, categories)):
4584 - catdir, pkgdir = x.split("/")
4585 - checkdir = repo_settings.repodir + "/" + x
4586 - checkdir_relative = ""
4587 - if repolevel < 3:
4588 - checkdir_relative = os.path.join(pkgdir, checkdir_relative)
4589 - if repolevel < 2:
4590 - checkdir_relative = os.path.join(catdir, checkdir_relative)
4591 - checkdir_relative = os.path.join(".", checkdir_relative)
4592 -
4593 - changelog_path = os.path.join(checkdir_relative, "ChangeLog")
4594 - changelog_modified = changelog_path in changed.changelogs
4595 - if changelog_modified and options.echangelog != 'force':
4596 - continue
4597 -
4598 - # get changes for this package
4599 - cdrlen = len(checkdir_relative)
4600 - check_relative = lambda e: e.startswith(checkdir_relative)
4601 - split_relative = lambda e: e[cdrlen:]
4602 - clnew = list(map(split_relative, filter(check_relative, mynew)))
4603 - clremoved = list(map(split_relative, filter(check_relative, myremoved)))
4604 - clchanged = list(map(split_relative, filter(check_relative, mychanged)))
4605 -
4606 - # Skip ChangeLog generation if only the Manifest was modified,
4607 - # as discussed in bug #398009.
4608 - nontrivial_cl_files = set()
4609 - nontrivial_cl_files.update(clnew, clremoved, clchanged)
4610 - nontrivial_cl_files.difference_update(['Manifest'])
4611 - if not nontrivial_cl_files and options.echangelog != 'force':
4612 - continue
4613 -
4614 - new_changelog = utilities.UpdateChangeLog(
4615 - checkdir_relative, committer_name, changelog_msg,
4616 - os.path.join(repo_settings.repodir, 'skel.ChangeLog'),
4617 - catdir, pkgdir,
4618 - new=clnew, removed=clremoved, changed=clchanged,
4619 - pretend=options.pretend)
4620 - if new_changelog is None:
4621 - writemsg_level(
4622 - "!!! Updating the ChangeLog failed\n",
4623 - level=logging.ERROR, noiselevel=-1)
4624 - sys.exit(1)
4625 -
4626 - # if the ChangeLog was just created, add it to vcs
4627 - if new_changelog:
4628 - myautoadd.append(changelog_path)
4629 - # myautoadd is appended to myupdates below
4630 - else:
4631 - myupdates.append(changelog_path)
4632 -
4633 - if options.ask and not options.pretend:
4634 - # regenerate Manifest for modified ChangeLog (bug #420735)
4635 - repoman_settings["O"] = checkdir
4636 - digestgen(mysettings=repoman_settings, myportdb=portdb)
4637 - else:
4638 - broken_changelog_manifests.append(x)
4639 -
4640 - if myautoadd:
4641 - print(">>> Auto-Adding missing Manifest/ChangeLog file(s)...")
4642 - add_cmd = [vcs_settings.vcs, "add"]
4643 - add_cmd += myautoadd
4644 - if options.pretend:
4645 - portage.writemsg_stdout(
4646 - "(%s)\n" % " ".join(add_cmd),
4647 - noiselevel=-1)
4648 - else:
4649 -
4650 - if sys.hexversion < 0x3020000 and sys.hexversion >= 0x3000000 and \
4651 - not os.path.isabs(add_cmd[0]):
4652 - # Python 3.1 _execvp throws TypeError for non-absolute executable
4653 - # path passed as bytes (see http://bugs.python.org/issue8513).
4654 - fullname = find_binary(add_cmd[0])
4655 - if fullname is None:
4656 - raise portage.exception.CommandNotFound(add_cmd[0])
4657 - add_cmd[0] = fullname
4658 -
4659 - add_cmd = [_unicode_encode(arg) for arg in add_cmd]
4660 - retcode = subprocess.call(add_cmd)
4661 - if retcode != os.EX_OK:
4662 - logging.error(
4663 - "Exiting on %s error code: %s\n" % (vcs_settings.vcs, retcode))
4664 - sys.exit(retcode)
4665 -
4666 - myupdates += myautoadd
4667 -
4668 - print("* %s files being committed..." % green(str(len(myupdates))), end=' ')
4669 -
4670 - if vcs_settings.vcs not in ('cvs', 'svn'):
4671 - # With git, bzr and hg, there's never any keyword expansion, so
4672 - # there's no need to regenerate manifests and all files will be
4673 - # committed in one big commit at the end.
4674 - print()
4675 - elif not repo_settings.repo_config.thin_manifest:
4676 - if vcs_settings.vcs == 'cvs':
4677 - headerstring = "'\$(Header|Id).*\$'"
4678 - elif vcs_settings.vcs == "svn":
4679 - svn_keywords = dict((k.lower(), k) for k in [
4680 - "Rev",
4681 - "Revision",
4682 - "LastChangedRevision",
4683 - "Date",
4684 - "LastChangedDate",
4685 - "Author",
4686 - "LastChangedBy",
4687 - "URL",
4688 - "HeadURL",
4689 - "Id",
4690 - "Header",
4691 - ])
4692 -
4693 - for myfile in myupdates:
4694 -
4695 - # for CVS, no_expansion contains files that are excluded from expansion
4696 - if vcs_settings.vcs == "cvs":
4697 - if myfile in no_expansion:
4698 - continue
4699 -
4700 - # for SVN, expansion contains files that are included in expansion
4701 - elif vcs_settings.vcs == "svn":
4702 - if myfile not in expansion:
4703 - continue
4704 -
4705 - # Subversion keywords are case-insensitive
4706 - # in svn:keywords properties,
4707 - # but case-sensitive in contents of files.
4708 - enabled_keywords = []
4709 - for k in expansion[myfile]:
4710 - keyword = svn_keywords.get(k.lower())
4711 - if keyword is not None:
4712 - enabled_keywords.append(keyword)
4713 -
4714 - headerstring = "'\$(%s).*\$'" % "|".join(enabled_keywords)
4715 -
4716 - myout = repoman_getstatusoutput(
4717 - "egrep -q %s %s" % (headerstring, portage._shell_quote(myfile)))
4718 - if myout[0] == 0:
4719 - myheaders.append(myfile)
4720 -
4721 - print("%s have headers that will change." % green(str(len(myheaders))))
4722 - print(
4723 - "* Files with headers will"
4724 - " cause the manifests to be changed and committed separately.")
4725 -
4726 - logging.info("myupdates: %s", myupdates)
4727 - logging.info("myheaders: %s", myheaders)
4728 -
4729 - uq = UserQuery(options)
4730 - if options.ask and uq.query('Commit changes?', True) != 'Yes':
4731 - print("* aborting commit.")
4732 - sys.exit(128 + signal.SIGINT)
4733 -
4734 - # Handle the case where committed files have keywords which
4735 - # will change and need a priming commit before the Manifest
4736 - # can be committed.
4737 - if (myupdates or myremoved) and myheaders:
4738 - myfiles = myupdates + myremoved
4739 - fd, commitmessagefile = tempfile.mkstemp(".repoman.msg")
4740 - mymsg = os.fdopen(fd, "wb")
4741 - mymsg.write(_unicode_encode(commitmessage))
4742 - mymsg.close()
4743 -
4744 - separator = '-' * 78
4745 -
4746 - print()
4747 - print(green("Using commit message:"))
4748 - print(green(separator))
4749 - print(commitmessage)
4750 - print(green(separator))
4751 - print()
4752 -
4753 - # Having a leading ./ prefix on file paths can trigger a bug in
4754 - # the cvs server when committing files to multiple directories,
4755 - # so strip the prefix.
4756 - myfiles = [f.lstrip("./") for f in myfiles]
4757 -
4758 - commit_cmd = [vcs_settings.vcs]
4759 - commit_cmd.extend(vcs_settings.vcs_global_opts)
4760 - commit_cmd.append("commit")
4761 - commit_cmd.extend(vcs_settings.vcs_local_opts)
4762 - commit_cmd.extend(["-F", commitmessagefile])
4763 - commit_cmd.extend(myfiles)
4764 -
4765 - try:
4766 - if options.pretend:
4767 - print("(%s)" % (" ".join(commit_cmd),))
4768 - else:
4769 - retval = spawn(commit_cmd, env=repo_settings.commit_env)
4770 - if retval != os.EX_OK:
4771 - writemsg_level(
4772 - "!!! Exiting on %s (shell) "
4773 - "error code: %s\n" % (vcs_settings.vcs, retval),
4774 - level=logging.ERROR, noiselevel=-1)
4775 - sys.exit(retval)
4776 - finally:
4777 - try:
4778 - os.unlink(commitmessagefile)
4779 - except OSError:
4780 - pass
4781 -
4782 - # When files are removed and re-added, the cvs server will put /Attic/
4783 - # inside the $Header path. This code detects the problem and corrects it
4784 - # so that the Manifest will generate correctly. See bug #169500.
4785 - # Use binary mode in order to avoid potential character encoding issues.
4786 - cvs_header_re = re.compile(br'^#\s*\$Header.*\$$')
4787 - attic_str = b'/Attic/'
4788 - attic_replace = b'/'
4789 - for x in myheaders:
4790 - f = open(
4791 - _unicode_encode(x, encoding=_encodings['fs'], errors='strict'),
4792 - mode='rb')
4793 - mylines = f.readlines()
4794 - f.close()
4795 - modified = False
4796 - for i, line in enumerate(mylines):
4797 - if cvs_header_re.match(line) is not None and \
4798 - attic_str in line:
4799 - mylines[i] = line.replace(attic_str, attic_replace)
4800 - modified = True
4801 - if modified:
4802 - portage.util.write_atomic(x, b''.join(mylines), mode='wb')
4803 -
4804 - if repolevel == 1:
4805 - utilities.repoman_sez(
4806 - "\"You're rather crazy... "
4807 - "doing the entire repository.\"\n")
4808 -
4809 - if vcs_settings.vcs in ('cvs', 'svn') and (myupdates or myremoved):
4810 - for x in sorted(vcs_files_to_cps(
4811 - chain(myupdates, myremoved, mymanifests),
4812 - repolevel, reposplit, categories)):
4813 - repoman_settings["O"] = os.path.join(repo_settings.repodir, x)
4814 - digestgen(mysettings=repoman_settings, myportdb=portdb)
4815 -
4816 - elif broken_changelog_manifests:
4817 - for x in broken_changelog_manifests:
4818 - repoman_settings["O"] = os.path.join(repo_settings.repodir, x)
4819 - digestgen(mysettings=repoman_settings, myportdb=portdb)
4820 -
4821 - signed = False
4822 - if repo_settings.sign_manifests:
4823 - signed = True
4824 - try:
4825 - for x in sorted(vcs_files_to_cps(
4826 - chain(myupdates, myremoved, mymanifests),
4827 - repolevel, reposplit, categories)):
4828 - repoman_settings["O"] = os.path.join(repo_settings.repodir, x)
4829 - manifest_path = os.path.join(repoman_settings["O"], "Manifest")
4830 - if not need_signature(manifest_path):
4831 - continue
4832 - gpgsign(manifest_path)
4833 - except portage.exception.PortageException as e:
4834 - portage.writemsg("!!! %s\n" % str(e))
4835 - portage.writemsg("!!! Disabled FEATURES='sign'\n")
4836 - signed = False
4837 -
4838 - if vcs_settings.vcs == 'git':
4839 - # It's not safe to use the git commit -a option since there might
4840 - # be some modified files elsewhere in the working tree that the
4841 - # user doesn't want to commit. Therefore, call git update-index
4842 - # in order to ensure that the index is updated with the latest
4843 - # versions of all new and modified files in the relevant portion
4844 - # of the working tree.
4845 - myfiles = mymanifests + myupdates
4846 - myfiles.sort()
4847 - update_index_cmd = ["git", "update-index"]
4848 - update_index_cmd.extend(f.lstrip("./") for f in myfiles)
4849 - if options.pretend:
4850 - print("(%s)" % (" ".join(update_index_cmd),))
4851 - else:
4852 - retval = spawn(update_index_cmd, env=os.environ)
4853 - if retval != os.EX_OK:
4854 - writemsg_level(
4855 - "!!! Exiting on %s (shell) "
4856 - "error code: %s\n" % (vcs_settings.vcs, retval),
4857 - level=logging.ERROR, noiselevel=-1)
4858 - sys.exit(retval)
4859 -
4860 - if True:
4861 - myfiles = mymanifests[:]
4862 - # If there are no header (SVN/CVS keywords) changes in
4863 - # the files, this Manifest commit must include the
4864 - # other (yet uncommitted) files.
4865 - if not myheaders:
4866 - myfiles += myupdates
4867 - myfiles += myremoved
4868 - myfiles.sort()
4869 -
4870 - fd, commitmessagefile = tempfile.mkstemp(".repoman.msg")
4871 - mymsg = os.fdopen(fd, "wb")
4872 - mymsg.write(_unicode_encode(commitmessage))
4873 - mymsg.close()
4874 -
4875 - commit_cmd = []
4876 - if options.pretend and vcs_settings.vcs is None:
4877 - # substitute a bogus value for pretend output
4878 - commit_cmd.append("cvs")
4879 - else:
4880 - commit_cmd.append(vcs_settings.vcs)
4881 - commit_cmd.extend(vcs_settings.vcs_global_opts)
4882 - commit_cmd.append("commit")
4883 - commit_cmd.extend(vcs_settings.vcs_local_opts)
4884 - if vcs_settings.vcs == "hg":
4885 - commit_cmd.extend(["--logfile", commitmessagefile])
4886 - commit_cmd.extend(myfiles)
4887 - else:
4888 - commit_cmd.extend(["-F", commitmessagefile])
4889 - commit_cmd.extend(f.lstrip("./") for f in myfiles)
4890 -
4891 - try:
4892 - if options.pretend:
4893 - print("(%s)" % (" ".join(commit_cmd),))
4894 - else:
4895 - retval = spawn(commit_cmd, env=repo_settings.commit_env)
4896 - if retval != os.EX_OK:
4897 - if repo_settings.repo_config.sign_commit and vcs_settings.vcs == 'git' and \
4898 - not git_supports_gpg_sign():
4899 - # Inform user that newer git is needed (bug #403323).
4900 - logging.error(
4901 - "Git >=1.7.9 is required for signed commits!")
4902 -
4903 - writemsg_level(
4904 - "!!! Exiting on %s (shell) "
4905 - "error code: %s\n" % (vcs_settings.vcs, retval),
4906 - level=logging.ERROR, noiselevel=-1)
4907 - sys.exit(retval)
4908 - finally:
4909 - try:
4910 - os.unlink(commitmessagefile)
4911 - except OSError:
4912 - pass
4913 -
4914 - print()
4915 - if vcs_settings.vcs:
4916 - print("Commit complete.")
4917 - else:
4918 - print(
4919 - "repoman was too scared"
4920 - " by not seeing any familiar version control file"
4921 - " that he forgot to commit anything")
4922 - utilities.repoman_sez(
4923 - "\"If everyone were like you, I'd be out of business!\"\n")
4924 - sys.exit(0)
4925
4926 diff --git a/pym/tbc/repoman/metadata.py b/pym/tbc/repoman/metadata.py
4927 deleted file mode 100644
4928 index f2b63a7..0000000
4929 --- a/pym/tbc/repoman/metadata.py
4930 +++ /dev/null
4931 @@ -1,150 +0,0 @@
4932 -
4933 -import errno
4934 -import logging
4935 -import sys
4936 -import tempfile
4937 -import time
4938 -
4939 -try:
4940 - from urllib.parse import urlparse
4941 -except ImportError:
4942 - from urlparse import urlparse
4943 -
4944 -
4945 -# import our initialized portage instance
4946 -from repoman._portage import portage
4947 -
4948 -from portage import exception
4949 -from portage import os
4950 -from portage.output import green
4951 -
4952 -if sys.hexversion >= 0x3000000:
4953 - basestring = str
4954 -
4955 -if sys.hexversion >= 0x3000000:
4956 - basestring = str
4957 -
4958 -metadata_xml_encoding = 'UTF-8'
4959 -metadata_xml_declaration = '<?xml version="1.0" encoding="%s"?>' \
4960 - % (metadata_xml_encoding,)
4961 -metadata_doctype_name = 'pkgmetadata'
4962 -metadata_dtd_uri = 'http://www.gentoo.org/dtd/metadata.dtd'
4963 -# force refetch if the local copy creation time is older than this
4964 -metadata_dtd_ctime_interval = 60 * 60 * 24 * 7 # 7 days
4965 -
4966 -
4967 -def parse_metadata_use(xml_tree):
4968 - """
4969 - Records are wrapped in XML as per GLEP 56
4970 - returns a dict with keys constisting of USE flag names and values
4971 - containing their respective descriptions
4972 - """
4973 - uselist = {}
4974 -
4975 - usetags = xml_tree.findall("use")
4976 - if not usetags:
4977 - return uselist
4978 -
4979 - # It's possible to have multiple 'use' elements.
4980 - for usetag in usetags:
4981 - flags = usetag.findall("flag")
4982 - if not flags:
4983 - # DTD allows use elements containing no flag elements.
4984 - continue
4985 -
4986 - for flag in flags:
4987 - pkg_flag = flag.get("name")
4988 - if pkg_flag is None:
4989 - raise exception.ParseError("missing 'name' attribute for 'flag' tag")
4990 - flag_restrict = flag.get("restrict")
4991 -
4992 - # emulate the Element.itertext() method from python-2.7
4993 - inner_text = []
4994 - stack = []
4995 - stack.append(flag)
4996 - while stack:
4997 - obj = stack.pop()
4998 - if isinstance(obj, basestring):
4999 - inner_text.append(obj)
5000 - continue
5001 - if isinstance(obj.text, basestring):
5002 - inner_text.append(obj.text)
5003 - if isinstance(obj.tail, basestring):
5004 - stack.append(obj.tail)
5005 - stack.extend(reversed(obj))
5006 -
5007 - if pkg_flag not in uselist:
5008 - uselist[pkg_flag] = {}
5009 -
5010 - # (flag_restrict can be None)
5011 - uselist[pkg_flag][flag_restrict] = " ".join("".join(inner_text).split())
5012 -
5013 - return uselist
5014 -
5015 -
5016 -def fetch_metadata_dtd(metadata_dtd, repoman_settings):
5017 - """
5018 - Fetch metadata.dtd if it doesn't exist or the ctime is older than
5019 - metadata_dtd_ctime_interval.
5020 - @rtype: bool
5021 - @return: True if successful, otherwise False
5022 - """
5023 -
5024 - must_fetch = True
5025 - metadata_dtd_st = None
5026 - current_time = int(time.time())
5027 - try:
5028 - metadata_dtd_st = os.stat(metadata_dtd)
5029 - except EnvironmentError as e:
5030 - if e.errno not in (errno.ENOENT, errno.ESTALE):
5031 - raise
5032 - del e
5033 - else:
5034 - # Trigger fetch if metadata.dtd mtime is old or clock is wrong.
5035 - if abs(current_time - metadata_dtd_st.st_ctime) \
5036 - < metadata_dtd_ctime_interval:
5037 - must_fetch = False
5038 -
5039 - if must_fetch:
5040 - print()
5041 - print(
5042 - "%s the local copy of metadata.dtd "
5043 - "needs to be refetched, doing that now" % green("***"))
5044 - print()
5045 - parsed_url = urlparse(metadata_dtd_uri)
5046 - setting = 'FETCHCOMMAND_' + parsed_url.scheme.upper()
5047 - fcmd = repoman_settings.get(setting)
5048 - if not fcmd:
5049 - fcmd = repoman_settings.get('FETCHCOMMAND')
5050 - if not fcmd:
5051 - logging.error("FETCHCOMMAND is unset")
5052 - return False
5053 -
5054 - destdir = repoman_settings["DISTDIR"]
5055 - fd, metadata_dtd_tmp = tempfile.mkstemp(
5056 - prefix='metadata.dtd.', dir=destdir)
5057 - os.close(fd)
5058 -
5059 - try:
5060 - if not portage.getbinpkg.file_get(
5061 - metadata_dtd_uri, destdir, fcmd=fcmd,
5062 - filename=os.path.basename(metadata_dtd_tmp)):
5063 - logging.error(
5064 - "failed to fetch metadata.dtd from '%s'" % metadata_dtd_uri)
5065 - return False
5066 -
5067 - try:
5068 - portage.util.apply_secpass_permissions(
5069 - metadata_dtd_tmp,
5070 - gid=portage.data.portage_gid, mode=0o664, mask=0o2)
5071 - except portage.exception.PortageException:
5072 - pass
5073 -
5074 - os.rename(metadata_dtd_tmp, metadata_dtd)
5075 - finally:
5076 - try:
5077 - os.unlink(metadata_dtd_tmp)
5078 - except OSError:
5079 - pass
5080 -
5081 - return True
5082
5083 diff --git a/pym/tbc/repoman/modules/__init__.py b/pym/tbc/repoman/modules/__init__.py
5084 deleted file mode 100644
5085 index e69de29..0000000
5086
5087 diff --git a/pym/tbc/repoman/modules/commit/__init__.py b/pym/tbc/repoman/modules/commit/__init__.py
5088 deleted file mode 100644
5089 index e69de29..0000000
5090
5091 diff --git a/pym/tbc/repoman/modules/commit/repochecks.py b/pym/tbc/repoman/modules/commit/repochecks.py
5092 deleted file mode 100644
5093 index 2839864..0000000
5094 --- a/pym/tbc/repoman/modules/commit/repochecks.py
5095 +++ /dev/null
5096 @@ -1,32 +0,0 @@
5097 -
5098 -from portage.output import red
5099 -
5100 -from repoman.errors import err
5101 -from repoman.vcs.vcs import detect_vcs_conflicts
5102 -
5103 -
5104 -def commit_check(repolevel, reposplit):
5105 - # Check if it's in $PORTDIR/$CATEGORY/$PN , otherwise bail if commiting.
5106 - # Reason for this is if they're trying to commit in just $FILESDIR/*,
5107 - # the Manifest needs updating.
5108 - # This check ensures that repoman knows where it is,
5109 - # and the manifest recommit is at least possible.
5110 - if repolevel not in [1, 2, 3]:
5111 - print(red("***") + (
5112 - " Commit attempts *must* be from within a vcs checkout,"
5113 - " category, or package directory."))
5114 - print(red("***") + (
5115 - " Attempting to commit from a packages files directory"
5116 - " will be blocked for instance."))
5117 - print(red("***") + (
5118 - " This is intended behaviour,"
5119 - " to ensure the manifest is recommitted for a package."))
5120 - print(red("***"))
5121 - err(
5122 - "Unable to identify level we're commiting from for %s" %
5123 - '/'.join(reposplit))
5124 -
5125 -
5126 -def conflict_check(vcs_settings, options):
5127 - if vcs_settings.vcs:
5128 - detect_vcs_conflicts(options, vcs_settings.vcs)
5129
5130 diff --git a/pym/tbc/repoman/modules/fix/__init__.py b/pym/tbc/repoman/modules/fix/__init__.py
5131 deleted file mode 100644
5132 index e69de29..0000000
5133
5134 diff --git a/pym/tbc/repoman/modules/full/__init__.py b/pym/tbc/repoman/modules/full/__init__.py
5135 deleted file mode 100644
5136 index e69de29..0000000
5137
5138 diff --git a/pym/tbc/repoman/modules/manifest/__init__.py b/pym/tbc/repoman/modules/manifest/__init__.py
5139 deleted file mode 100644
5140 index e69de29..0000000
5141
5142 diff --git a/pym/tbc/repoman/modules/scan/__init__.py b/pym/tbc/repoman/modules/scan/__init__.py
5143 deleted file mode 100644
5144 index e69de29..0000000
5145
5146 diff --git a/pym/tbc/repoman/profile.py b/pym/tbc/repoman/profile.py
5147 deleted file mode 100644
5148 index 11b93c7..0000000
5149 --- a/pym/tbc/repoman/profile.py
5150 +++ /dev/null
5151 @@ -1,84 +0,0 @@
5152 -
5153 -from portage import normalize_path
5154 -from portage import os
5155 -from portage.output import red
5156 -
5157 -
5158 -class ProfileDesc(object):
5159 - __slots__ = ('abs_path', 'arch', 'status', 'sub_path', 'tree_path',)
5160 -
5161 - def __init__(self, arch, status, sub_path, tree_path):
5162 - self.arch = arch
5163 - self.status = status
5164 - if sub_path:
5165 - sub_path = normalize_path(sub_path.lstrip(os.sep))
5166 - self.sub_path = sub_path
5167 - self.tree_path = tree_path
5168 - if tree_path:
5169 - self.abs_path = os.path.join(tree_path, 'profiles', self.sub_path)
5170 - else:
5171 - self.abs_path = tree_path
5172 -
5173 - def __str__(self):
5174 - if self.sub_path:
5175 - return self.sub_path
5176 - return 'empty profile'
5177 -
5178 -
5179 -valid_profile_types = frozenset(['dev', 'exp', 'stable'])
5180 -
5181 -
5182 -def dev_keywords(profiles):
5183 - """
5184 - Create a set of KEYWORDS values that exist in 'dev'
5185 - profiles. These are used
5186 - to trigger a message notifying the user when they might
5187 - want to add the --include-dev option.
5188 - """
5189 - type_arch_map = {}
5190 - for arch, arch_profiles in profiles.items():
5191 - for prof in arch_profiles:
5192 - arch_set = type_arch_map.get(prof.status)
5193 - if arch_set is None:
5194 - arch_set = set()
5195 - type_arch_map[prof.status] = arch_set
5196 - arch_set.add(arch)
5197 -
5198 - dev_keywords = type_arch_map.get('dev', set())
5199 - dev_keywords.update(['~' + arch for arch in dev_keywords])
5200 - return frozenset(dev_keywords)
5201 -
5202 -
5203 -def setup_profile(profile_list):
5204 - # Ensure that profile sub_path attributes are unique. Process in reverse order
5205 - # so that profiles with duplicate sub_path from overlays will override
5206 - # profiles with the same sub_path from parent repos.
5207 - profiles = {}
5208 - profile_list.reverse()
5209 - profile_sub_paths = set()
5210 - for prof in profile_list:
5211 - if prof.sub_path in profile_sub_paths:
5212 - continue
5213 - profile_sub_paths.add(prof.sub_path)
5214 - profiles.setdefault(prof.arch, []).append(prof)
5215 -
5216 - # Use an empty profile for checking dependencies of
5217 - # packages that have empty KEYWORDS.
5218 - prof = ProfileDesc('**', 'stable', '', '')
5219 - profiles.setdefault(prof.arch, []).append(prof)
5220 - return profiles
5221 -
5222 -
5223 -def check_profiles(profiles, archlist):
5224 - for x in archlist:
5225 - if x[0] == "~":
5226 - continue
5227 - if x not in profiles:
5228 - print(red(
5229 - "\"%s\" doesn't have a valid profile listed in profiles.desc." % x))
5230 - print(red(
5231 - "You need to either \"cvs update\" your profiles dir"
5232 - " or follow this"))
5233 - print(red(
5234 - "up with the " + x + " team."))
5235 - print()
5236
5237 diff --git a/pym/tbc/repoman/qa_data.py b/pym/tbc/repoman/qa_data.py
5238 deleted file mode 100644
5239 index b262992..0000000
5240 --- a/pym/tbc/repoman/qa_data.py
5241 +++ /dev/null
5242 @@ -1,430 +0,0 @@
5243 -
5244 -import logging
5245 -
5246 -from _emerge.Package import Package
5247 -
5248 -# import our initialized portage instance
5249 -from repoman._portage import portage
5250 -
5251 -# 14 is the length of DESCRIPTION=""
5252 -max_desc_len = 100
5253 -allowed_filename_chars = "a-zA-Z0-9._-+:"
5254 -
5255 -qahelp = {
5256 - "CVS/Entries.IO_error": (
5257 - "Attempting to commit, and an IO error was encountered access the"
5258 - " Entries file"),
5259 - "ebuild.invalidname": (
5260 - "Ebuild files with a non-parseable or syntactically incorrect name"
5261 - " (or using 2.1 versioning extensions)"),
5262 - "ebuild.namenomatch": (
5263 - "Ebuild files that do not have the same name as their parent"
5264 - " directory"),
5265 - "changelog.ebuildadded": (
5266 - "An ebuild was added but the ChangeLog was not modified"),
5267 - "changelog.missing": (
5268 - "Missing ChangeLog files"),
5269 - "ebuild.notadded": (
5270 - "Ebuilds that exist but have not been added to cvs"),
5271 - "ebuild.patches": (
5272 - "PATCHES variable should be a bash array to ensure white space safety"),
5273 - "changelog.notadded": (
5274 - "ChangeLogs that exist but have not been added to cvs"),
5275 - "dependency.bad": (
5276 - "User-visible ebuilds with unsatisfied dependencies"
5277 - " (matched against *visible* ebuilds)"),
5278 - "dependency.badmasked": (
5279 - "Masked ebuilds with unsatisfied dependencies"
5280 - " (matched against *all* ebuilds)"),
5281 - "dependency.badindev": (
5282 - "User-visible ebuilds with unsatisfied dependencies"
5283 - " (matched against *visible* ebuilds) in developing arch"),
5284 - "dependency.badmaskedindev": (
5285 - "Masked ebuilds with unsatisfied dependencies"
5286 - " (matched against *all* ebuilds) in developing arch"),
5287 - "dependency.badtilde": (
5288 - "Uses the ~ dep operator with a non-zero revision part,"
5289 - " which is useless (the revision is ignored)"),
5290 - "dependency.missingslot": (
5291 - "RDEPEND matches more than one SLOT but does not specify a "
5292 - "slot and/or use the := or :* slot operator"),
5293 - "dependency.perlcore": (
5294 - "This ebuild directly depends on a package in perl-core;"
5295 - " it should use the corresponding virtual instead."),
5296 - "dependency.syntax": (
5297 - "Syntax error in dependency string"
5298 - " (usually an extra/missing space/parenthesis)"),
5299 - "dependency.unknown": (
5300 - "Ebuild has a dependency that refers to an unknown package"
5301 - " (which may be valid if it is a blocker for a renamed/removed package,"
5302 - " or is an alternative choice provided by an overlay)"),
5303 - "file.executable": (
5304 - "Ebuilds, digests, metadata.xml, Manifest, and ChangeLog do not need"
5305 - " the executable bit"),
5306 - "file.size": (
5307 - "Files in the files directory must be under 20 KiB"),
5308 - "file.size.fatal": (
5309 - "Files in the files directory must be under 60 KiB"),
5310 - "file.name": (
5311 - "File/dir name must be composed"
5312 - " of only the following chars: %s " % allowed_filename_chars),
5313 - "file.UTF8": (
5314 - "File is not UTF8 compliant"),
5315 - "inherit.deprecated": (
5316 - "Ebuild inherits a deprecated eclass"),
5317 - "inherit.missing": (
5318 - "Ebuild uses functions from an eclass but does not inherit it"),
5319 - "inherit.unused": (
5320 - "Ebuild inherits an eclass but does not use it"),
5321 - "java.eclassesnotused": (
5322 - "With virtual/jdk in DEPEND you must inherit a java eclass"),
5323 - "wxwidgets.eclassnotused": (
5324 - "Ebuild DEPENDs on x11-libs/wxGTK without inheriting wxwidgets.eclass"),
5325 - "KEYWORDS.dropped": (
5326 - "Ebuilds that appear to have dropped KEYWORDS for some arch"),
5327 - "KEYWORDS.missing": (
5328 - "Ebuilds that have a missing or empty KEYWORDS variable"),
5329 - "KEYWORDS.stable": (
5330 - "Ebuilds that have been added directly with stable KEYWORDS"),
5331 - "KEYWORDS.stupid": (
5332 - "Ebuilds that use KEYWORDS=-* instead of package.mask"),
5333 - "LICENSE.missing": (
5334 - "Ebuilds that have a missing or empty LICENSE variable"),
5335 - "LICENSE.virtual": (
5336 - "Virtuals that have a non-empty LICENSE variable"),
5337 - "DESCRIPTION.missing": (
5338 - "Ebuilds that have a missing or empty DESCRIPTION variable"),
5339 - "DESCRIPTION.toolong": (
5340 - "DESCRIPTION is over %d characters" % max_desc_len),
5341 - "EAPI.definition": (
5342 - "EAPI definition does not conform to PMS section 7.3.1"
5343 - " (first non-comment, non-blank line)"),
5344 - "EAPI.deprecated": (
5345 - "Ebuilds that use features that are deprecated in the current EAPI"),
5346 - "EAPI.incompatible": (
5347 - "Ebuilds that use features that are only available with a different"
5348 - " EAPI"),
5349 - "EAPI.unsupported": (
5350 - "Ebuilds that have an unsupported EAPI version"
5351 - " (you must upgrade portage)"),
5352 - "SLOT.invalid": (
5353 - "Ebuilds that have a missing or invalid SLOT variable value"),
5354 - "HOMEPAGE.missing": (
5355 - "Ebuilds that have a missing or empty HOMEPAGE variable"),
5356 - "HOMEPAGE.virtual": (
5357 - "Virtuals that have a non-empty HOMEPAGE variable"),
5358 - "PDEPEND.suspect": (
5359 - "PDEPEND contains a package that usually only belongs in DEPEND."),
5360 - "LICENSE.syntax": (
5361 - "Syntax error in LICENSE"
5362 - " (usually an extra/missing space/parenthesis)"),
5363 - "PROVIDE.syntax": (
5364 - "Syntax error in PROVIDE"
5365 - " (usually an extra/missing space/parenthesis)"),
5366 - "PROPERTIES.syntax": (
5367 - "Syntax error in PROPERTIES"
5368 - " (usually an extra/missing space/parenthesis)"),
5369 - "RESTRICT.syntax": (
5370 - "Syntax error in RESTRICT"
5371 - " (usually an extra/missing space/parenthesis)"),
5372 - "REQUIRED_USE.syntax": (
5373 - "Syntax error in REQUIRED_USE"
5374 - " (usually an extra/missing space/parenthesis)"),
5375 - "SRC_URI.syntax": (
5376 - "Syntax error in SRC_URI"
5377 - " (usually an extra/missing space/parenthesis)"),
5378 - "SRC_URI.mirror": (
5379 - "A uri listed in profiles/thirdpartymirrors is found in SRC_URI"),
5380 - "ebuild.syntax": (
5381 - "Error generating cache entry for ebuild;"
5382 - " typically caused by ebuild syntax error"
5383 - " or digest verification failure"),
5384 - "ebuild.output": (
5385 - "A simple sourcing of the ebuild produces output;"
5386 - " this breaks ebuild policy."),
5387 - "ebuild.nesteddie": (
5388 - "Placing 'die' inside ( ) prints an error,"
5389 - " but doesn't stop the ebuild."),
5390 - "variable.invalidchar": (
5391 - "A variable contains an invalid character"
5392 - " that is not part of the ASCII character set"),
5393 - "variable.readonly": (
5394 - "Assigning a readonly variable"),
5395 - "variable.usedwithhelpers": (
5396 - "Ebuild uses D, ROOT, ED, EROOT or EPREFIX with helpers"),
5397 - "LIVEVCS.stable": (
5398 - "This ebuild is a live checkout from a VCS but has stable keywords."),
5399 - "LIVEVCS.unmasked": (
5400 - "This ebuild is a live checkout from a VCS but has keywords"
5401 - " and is not masked in the global package.mask."),
5402 - "IUSE.invalid": (
5403 - "This ebuild has a variable in IUSE"
5404 - " that is not in the use.desc or its metadata.xml file"),
5405 - "IUSE.missing": (
5406 - "This ebuild has a USE conditional"
5407 - " which references a flag that is not listed in IUSE"),
5408 - "IUSE.rubydeprecated": (
5409 - "The ebuild has set a ruby interpreter in USE_RUBY,"
5410 - " that is not available as a ruby target anymore"),
5411 - "LICENSE.invalid": (
5412 - "This ebuild is listing a license"
5413 - " that doesnt exist in portages license/ dir."),
5414 - "LICENSE.deprecated": (
5415 - "This ebuild is listing a deprecated license."),
5416 - "KEYWORDS.invalid": (
5417 - "This ebuild contains KEYWORDS"
5418 - " that are not listed in profiles/arch.list"
5419 - " or for which no valid profile was found"),
5420 - "RDEPEND.implicit": (
5421 - "RDEPEND is unset in the ebuild"
5422 - " which triggers implicit RDEPEND=$DEPEND assignment"
5423 - " (prior to EAPI 4)"),
5424 - "RDEPEND.suspect": (
5425 - "RDEPEND contains a package that usually only belongs in DEPEND."),
5426 - "RESTRICT.invalid": (
5427 - "This ebuild contains invalid RESTRICT values."),
5428 - "digest.assumed": (
5429 - "Existing digest must be assumed correct (Package level only)"),
5430 - "digest.missing": (
5431 - "Some files listed in SRC_URI aren't referenced in the Manifest"),
5432 - "digest.unused": (
5433 - "Some files listed in the Manifest aren't referenced in SRC_URI"),
5434 - "ebuild.majorsyn": (
5435 - "This ebuild has a major syntax error"
5436 - " that may cause the ebuild to fail partially or fully"),
5437 - "ebuild.minorsyn": (
5438 - "This ebuild has a minor syntax error"
5439 - " that contravenes gentoo coding style"),
5440 - "ebuild.badheader": (
5441 - "This ebuild has a malformed header"),
5442 - "manifest.bad": (
5443 - "Manifest has missing or incorrect digests"),
5444 - "metadata.missing": (
5445 - "Missing metadata.xml files"),
5446 - "metadata.bad": (
5447 - "Bad metadata.xml files"),
5448 - "metadata.warning": (
5449 - "Warnings in metadata.xml files"),
5450 - "portage.internal": (
5451 - "The ebuild uses an internal Portage function or variable"),
5452 - "repo.eapi.banned": (
5453 - "The ebuild uses an EAPI which is"
5454 - " banned by the repository's metadata/layout.conf settings"),
5455 - "repo.eapi.deprecated": (
5456 - "The ebuild uses an EAPI which is"
5457 - " deprecated by the repository's metadata/layout.conf settings"),
5458 - "virtual.oldstyle": (
5459 - "The ebuild PROVIDEs an old-style virtual (see GLEP 37)"),
5460 - "virtual.suspect": (
5461 - "Ebuild contains a package"
5462 - " that usually should be pulled via virtual/, not directly."),
5463 - "usage.obsolete": (
5464 - "The ebuild makes use of an obsolete construct"),
5465 - "upstream.workaround": (
5466 - "The ebuild works around an upstream bug,"
5467 - " an upstream bug should be filed and tracked in bugs.gentoo.org")
5468 -}
5469 -
5470 -qacats = list(qahelp)
5471 -qacats.sort()
5472 -
5473 -qawarnings = set((
5474 - "changelog.missing",
5475 - "changelog.notadded",
5476 - "dependency.unknown",
5477 - "digest.assumed",
5478 - "digest.unused",
5479 - "ebuild.notadded",
5480 - "ebuild.nesteddie",
5481 - "dependency.badmasked",
5482 - "dependency.badindev",
5483 - "dependency.badmaskedindev",
5484 - "dependency.badtilde",
5485 - "dependency.missingslot",
5486 - "dependency.perlcore",
5487 - "DESCRIPTION.toolong",
5488 - "EAPI.deprecated",
5489 - "HOMEPAGE.virtual",
5490 - "LICENSE.deprecated",
5491 - "LICENSE.virtual",
5492 - "KEYWORDS.dropped",
5493 - "KEYWORDS.stupid",
5494 - "KEYWORDS.missing",
5495 - "PDEPEND.suspect",
5496 - "RDEPEND.implicit",
5497 - "RDEPEND.suspect",
5498 - "virtual.suspect",
5499 - "RESTRICT.invalid",
5500 - "ebuild.minorsyn",
5501 - "ebuild.badheader",
5502 - "ebuild.patches",
5503 - "file.size",
5504 - "inherit.unused",
5505 - "inherit.deprecated",
5506 - "java.eclassesnotused",
5507 - "wxwidgets.eclassnotused",
5508 - "metadata.warning",
5509 - "portage.internal",
5510 - "repo.eapi.deprecated",
5511 - "usage.obsolete",
5512 - "upstream.workaround",
5513 - "LIVEVCS.stable",
5514 - "LIVEVCS.unmasked",
5515 - "IUSE.rubydeprecated",
5516 -))
5517 -
5518 -
5519 -missingvars = ["KEYWORDS", "LICENSE", "DESCRIPTION", "HOMEPAGE"]
5520 -allvars = set(x for x in portage.auxdbkeys if not x.startswith("UNUSED_"))
5521 -allvars.update(Package.metadata_keys)
5522 -allvars = sorted(allvars)
5523 -
5524 -for x in missingvars:
5525 - x += ".missing"
5526 - if x not in qacats:
5527 - logging.warning('* missingvars values need to be added to qahelp ("%s")' % x)
5528 - qacats.append(x)
5529 - qawarnings.add(x)
5530 -
5531 -valid_restrict = frozenset([
5532 - "binchecks", "bindist", "fetch", "installsources", "mirror",
5533 - "preserve-libs", "primaryuri", "splitdebug", "strip", "test", "userpriv"])
5534 -
5535 -
5536 -suspect_rdepend = frozenset([
5537 - "app-arch/cabextract",
5538 - "app-arch/rpm2targz",
5539 - "app-doc/doxygen",
5540 - "dev-lang/nasm",
5541 - "dev-lang/swig",
5542 - "dev-lang/yasm",
5543 - "dev-perl/extutils-pkgconfig",
5544 - "dev-util/byacc",
5545 - "dev-util/cmake",
5546 - "dev-util/ftjam",
5547 - "dev-util/gperf",
5548 - "dev-util/gtk-doc",
5549 - "dev-util/gtk-doc-am",
5550 - "dev-util/intltool",
5551 - "dev-util/jam",
5552 - "dev-util/pkg-config-lite",
5553 - "dev-util/pkgconf",
5554 - "dev-util/pkgconfig",
5555 - "dev-util/pkgconfig-openbsd",
5556 - "dev-util/scons",
5557 - "dev-util/unifdef",
5558 - "dev-util/yacc",
5559 - "media-gfx/ebdftopcf",
5560 - "sys-apps/help2man",
5561 - "sys-devel/autoconf",
5562 - "sys-devel/automake",
5563 - "sys-devel/bin86",
5564 - "sys-devel/bison",
5565 - "sys-devel/dev86",
5566 - "sys-devel/flex",
5567 - "sys-devel/m4",
5568 - "sys-devel/pmake",
5569 - "virtual/linux-sources",
5570 - "virtual/pkgconfig",
5571 - "x11-misc/bdftopcf",
5572 - "x11-misc/imake",
5573 -])
5574 -
5575 -suspect_virtual = {
5576 - "dev-util/pkg-config-lite": "virtual/pkgconfig",
5577 - "dev-util/pkgconf": "virtual/pkgconfig",
5578 - "dev-util/pkgconfig": "virtual/pkgconfig",
5579 - "dev-util/pkgconfig-openbsd": "virtual/pkgconfig",
5580 - "dev-libs/libusb": "virtual/libusb",
5581 - "dev-libs/libusbx": "virtual/libusb",
5582 - "dev-libs/libusb-compat": "virtual/libusb",
5583 -}
5584 -
5585 -ruby_deprecated = frozenset([
5586 - "ruby_targets_ree18",
5587 - "ruby_targets_ruby18",
5588 -])
5589 -
5590 -
5591 -# file.executable
5592 -no_exec = frozenset(["Manifest", "ChangeLog", "metadata.xml"])
5593 -
5594 -
5595 -def format_qa_output(
5596 - formatter, fails, dofull, dofail, options, qawarnings):
5597 - """Helper function that formats output properly
5598 -
5599 - Args:
5600 - formatter - a subclass of Formatter
5601 - fails - a dict of qa status failures
5602 - dofull - boolean to print full results or a summary
5603 - dofail - boolean to decide if failure was hard or soft
5604 -
5605 - Returns:
5606 - None (modifies formatter)
5607 - """
5608 - full = options.mode == 'full'
5609 - # we only want key value pairs where value > 0
5610 - for category in sorted(fails):
5611 - number = len(fails[category])
5612 - formatter.add_literal_data(" " + category.ljust(30))
5613 - if category in qawarnings:
5614 - formatter.push_style("WARN")
5615 - else:
5616 - formatter.push_style("BAD")
5617 - formatter.add_literal_data("%s" % number)
5618 - formatter.pop_style()
5619 - formatter.add_line_break()
5620 - if not dofull:
5621 - if not full and dofail and category in qawarnings:
5622 - # warnings are considered noise when there are failures
5623 - continue
5624 - fails_list = fails[category]
5625 - if not full and len(fails_list) > 12:
5626 - fails_list = fails_list[:12]
5627 - for failure in fails_list:
5628 - formatter.add_literal_data(" " + failure)
5629 - formatter.add_line_break()
5630 -
5631 -
5632 -def format_qa_output_column(
5633 - formatter, fails, dofull, dofail, options, qawarnings):
5634 - """Helper function that formats output in a machine-parseable column format
5635 -
5636 - @param formatter: an instance of Formatter
5637 - @type formatter: Formatter
5638 - @param path: dict of qa status items
5639 - @type path: dict
5640 - @param fails: dict of qa status failures
5641 - @type fails: dict
5642 - @param dofull: Whether to print full results or a summary
5643 - @type dofull: boolean
5644 - @param dofail: Whether failure was hard or soft
5645 - @type dofail: boolean
5646 - @param options: The command-line options provided to repoman
5647 - @type options: Namespace
5648 - @param qawarnings: the set of warning types
5649 - @type qawarnings: set
5650 - @return: None (modifies formatter)
5651 - """
5652 - full = options.mode == 'full'
5653 - for category in fails.items():
5654 - number = len(fails[category])
5655 - formatter.add_literal_data("NumberOf " + category + " ")
5656 - if category in qawarnings:
5657 - formatter.push_style("WARN")
5658 - else:
5659 - formatter.push_style("BAD")
5660 - formatter.add_literal_data("%s" % number)
5661 - formatter.pop_style()
5662 - formatter.add_line_break()
5663 - if not dofull:
5664 - if not full and dofail and category in qawarnings:
5665 - # warnings are considered noise when there are failures
5666 - continue
5667 - fails_list = fails[category]
5668 - if not full and len(fails_list) > 12:
5669 - fails_list = fails_list[:12]
5670 - for failure in fails_list:
5671 - formatter.add_literal_data(category + " " + failure)
5672 - formatter.add_line_break()
5673
5674 diff --git a/pym/tbc/repoman/qa_tracker.py b/pym/tbc/repoman/qa_tracker.py
5675 deleted file mode 100644
5676 index 9bfe0e2..0000000
5677 --- a/pym/tbc/repoman/qa_tracker.py
5678 +++ /dev/null
5679 @@ -1,45 +0,0 @@
5680 -
5681 -import logging
5682 -import sys
5683 -
5684 -from repoman.qa_data import qacats, qawarnings
5685 -
5686 -
5687 -class QATracker(object):
5688 - '''Track all occurrances of Q/A problems detected'''
5689 -
5690 - def __init__(self):
5691 - self.fails = {}
5692 - self.warns = {}
5693 -
5694 - def add_error(self, detected_qa, info):
5695 - '''Add the Q/A error to the database of detected problems
5696 -
5697 - @param detected_qa: string, member of qa_data.qacats list
5698 - @param info: string, details of the detected problem
5699 - '''
5700 - if detected_qa not in qacats:
5701 - logging.error(
5702 - 'QATracker: Exiting on error. Unknown detected_qa type passed '
5703 - 'in to add_error(): %s, %s' % (detected_qa, info))
5704 - sys.exit(1)
5705 - try:
5706 - self.fails[detected_qa].append(info)
5707 - except KeyError:
5708 - self.fails[detected_qa] = [info]
5709 -
5710 - def add_warning(self, detected_qa, info):
5711 - '''Add the Q/A warning to the database of detected problems
5712 -
5713 - @param detected_qa: string, member of qa_data.qawarnings list
5714 - @param info: string, details of the detected problem
5715 - '''
5716 - if detected_qa not in qawarnings:
5717 - logging.error(
5718 - 'QATracker: Exiting on error. Unknown detected_qa type passed '
5719 - 'in to add_warning(): %s, %s' % (detected_qa, info))
5720 - sys.exit(1)
5721 - try:
5722 - self.warns[detected_qa].append(info)
5723 - except KeyError:
5724 - self.warns[detected_qa] = [info]
5725
5726 diff --git a/pym/tbc/repoman/repos.py b/pym/tbc/repoman/repos.py
5727 deleted file mode 100644
5728 index e6accb1..0000000
5729 --- a/pym/tbc/repoman/repos.py
5730 +++ /dev/null
5731 @@ -1,303 +0,0 @@
5732 -
5733 -
5734 -import io
5735 -import logging
5736 -import re
5737 -import sys
5738 -import textwrap
5739 -
5740 -# import our initialized portage instance
5741 -from tbc.repoman._portage import portage
5742 -
5743 -from portage import os
5744 -from portage import _encodings
5745 -from portage import _unicode_encode
5746 -
5747 -from tbc.repoman.errors import err
5748 -from tbc.repoman.profile import ProfileDesc, valid_profile_types
5749 -
5750 -GPG_KEY_ID_REGEX = r'(0x)?([0-9a-fA-F]{8}){1,5}!?'
5751 -bad = portage.output.create_color_func("BAD")
5752 -
5753 -
5754 -class RepoSettings(object):
5755 - '''Holds out repo specific settings'''
5756 -
5757 - def __init__(
5758 - self, config_root, portdir, portdir_overlay,
5759 - repoman_settings=None, vcs_settings=None, options=None,
5760 - qawarnings=None):
5761 - self.repoman_settings = repoman_settings
5762 - self.vcs_settings = vcs_settings
5763 -
5764 - repoman_repos = self.repoman_settings.repositories
5765 -
5766 - # Ensure that current repository is in the list of enabled repositories.
5767 - self.repodir = os.path.realpath(portdir_overlay)
5768 - try:
5769 - repoman_repos.get_repo_for_location(self.repodir)
5770 - except KeyError:
5771 - self._add_repo(config_root, portdir_overlay)
5772 -
5773 - self.root = self.repoman_settings['EROOT']
5774 - self.trees = {
5775 - self.root: {'porttree': portage.portagetree(settings=self.repoman_settings)}
5776 - }
5777 - self.portdb = self.trees[self.root]['porttree'].dbapi
5778 -
5779 - # Constrain dependency resolution to the master(s)
5780 - # that are specified in layout.conf.
5781 - self.repo_config = repoman_repos.get_repo_for_location(self.repodir)
5782 - self.portdb.porttrees = list(self.repo_config.eclass_db.porttrees)
5783 - self.portdir = self.portdb.porttrees[0]
5784 - self.commit_env = os.environ.copy()
5785 - # list() is for iteration on a copy.
5786 - for repo in list(repoman_repos):
5787 - # all paths are canonical
5788 - if repo.location not in self.repo_config.eclass_db.porttrees:
5789 - del repoman_repos[repo.name]
5790 -
5791 - if self.repo_config.allow_provide_virtual:
5792 - qawarnings.add("virtual.oldstyle")
5793 -
5794 - if self.repo_config.sign_commit:
5795 - func = getattr(self, '_vcs_gpg_%s' % vcs_settings.vcs)
5796 - func()
5797 -
5798 - # In order to disable manifest signatures, repos may set
5799 - # "sign-manifests = false" in metadata/layout.conf. This
5800 - # can be used to prevent merge conflicts like those that
5801 - # thin-manifests is designed to prevent.
5802 - self.sign_manifests = "sign" in self.repoman_settings.features and \
5803 - self.repo_config.sign_manifest
5804 -
5805 - if self.repo_config.sign_manifest and self.repo_config.name == "gentoo" and \
5806 - options.mode in ("commit",) and not self.sign_manifests:
5807 - msg = (
5808 - "The '%s' repository has manifest signatures enabled, "
5809 - "but FEATURES=sign is currently disabled. In order to avoid this "
5810 - "warning, enable FEATURES=sign in make.conf. Alternatively, "
5811 - "repositories can disable manifest signatures by setting "
5812 - "'sign-manifests = false' in metadata/layout.conf.") % (
5813 - self.repo_config.name,)
5814 - for line in textwrap.wrap(msg, 60):
5815 - logging.warn(line)
5816 -
5817 - is_commit = options.mode in ("commit",)
5818 - valid_gpg_key = self.repoman_settings.get("PORTAGE_GPG_KEY") and re.match(
5819 - r'^%s$' % GPG_KEY_ID_REGEX, self.repoman_settings["PORTAGE_GPG_KEY"])
5820 -
5821 - if self.sign_manifests and is_commit and not valid_gpg_key:
5822 - logging.error(
5823 - "PORTAGE_GPG_KEY value is invalid: %s" %
5824 - self.repoman_settings["PORTAGE_GPG_KEY"])
5825 - sys.exit(1)
5826 -
5827 - manifest_hashes = self.repo_config.manifest_hashes
5828 - if manifest_hashes is None:
5829 - manifest_hashes = portage.const.MANIFEST2_HASH_DEFAULTS
5830 -
5831 - if options.mode in ("commit", "fix", "manifest"):
5832 - if portage.const.MANIFEST2_REQUIRED_HASH not in manifest_hashes:
5833 - msg = (
5834 - "The 'manifest-hashes' setting in the '%s' repository's "
5835 - "metadata/layout.conf does not contain the '%s' hash which "
5836 - "is required by this portage version. You will have to "
5837 - "upgrade portage if you want to generate valid manifests for "
5838 - "this repository.") % (
5839 - self.repo_config.name, portage.const.MANIFEST2_REQUIRED_HASH)
5840 - for line in textwrap.wrap(msg, 70):
5841 - logging.error(line)
5842 - sys.exit(1)
5843 -
5844 - unsupported_hashes = manifest_hashes.difference(
5845 - portage.const.MANIFEST2_HASH_FUNCTIONS)
5846 - if unsupported_hashes:
5847 - msg = (
5848 - "The 'manifest-hashes' setting in the '%s' repository's "
5849 - "metadata/layout.conf contains one or more hash types '%s' "
5850 - "which are not supported by this portage version. You will "
5851 - "have to upgrade portage if you want to generate valid "
5852 - "manifests for this repository.") % (
5853 - self.repo_config.name, " ".join(sorted(unsupported_hashes)))
5854 - for line in textwrap.wrap(msg, 70):
5855 - logging.error(line)
5856 - sys.exit(1)
5857 -
5858 - def _add_repo(self, config_root, portdir_overlay):
5859 - self.repo_conf = portage.repository.config
5860 - self.repo_name = self.repo_conf.RepoConfig._read_valid_repo_name(
5861 - portdir_overlay)[0]
5862 - self.layout_conf_data = self.repo_conf.parse_layout_conf(portdir_overlay)[0]
5863 - if self.layout_conf_data['repo-name']:
5864 - self.repo_name = self.layout_conf_data['repo-name']
5865 - tmp_conf_file = io.StringIO(textwrap.dedent("""
5866 - [%s]
5867 - location = %s
5868 - """) % (self.repo_name, portdir_overlay))
5869 - # Ensure that the repository corresponding to $PWD overrides a
5870 - # repository of the same name referenced by the existing PORTDIR
5871 - # or PORTDIR_OVERLAY settings.
5872 - self.repoman_settings['PORTDIR_OVERLAY'] = "%s %s" % (
5873 - self.repoman_settings.get('PORTDIR_OVERLAY', ''),
5874 - portage._shell_quote(portdir_overlay))
5875 - self.repositories = self.repo_conf.load_repository_config(
5876 - self.repoman_settings, extra_files=[tmp_conf_file])
5877 - # We have to call the config constructor again so that attributes
5878 - # dependent on config.repositories are initialized correctly.
5879 - self.repoman_settings = portage.config(
5880 - config_root=config_root, local_config=False,
5881 - repositories=self.repositories)
5882 -
5883 - ##########
5884 - # future vcs plugin functions
5885 - ##########
5886 -
5887 - def _vcs_gpg_bzr(self):
5888 - pass
5889 -
5890 - def _vcs_gpg_cvs(self):
5891 - pass
5892 -
5893 - def _vcs_gpg_git(self):
5894 - # NOTE: It's possible to use --gpg-sign=key_id to specify the key in
5895 - # the commit arguments. If key_id is unspecified, then it must be
5896 - # configured by `git config user.signingkey key_id`.
5897 - self.vcs_settings.vcs_local_opts.append("--gpg-sign")
5898 - if self.repoman_settings.get("PORTAGE_GPG_DIR"):
5899 - # Pass GNUPGHOME to git for bug #462362.
5900 - self.commit_env["GNUPGHOME"] = self.repoman_settings["PORTAGE_GPG_DIR"]
5901 -
5902 - # Pass GPG_TTY to git for bug #477728.
5903 - try:
5904 - self.commit_env["GPG_TTY"] = os.ttyname(sys.stdin.fileno())
5905 - except OSError:
5906 - pass
5907 -
5908 - def _vcs_gpg_hg(self):
5909 - pass
5910 -
5911 - def _vcs_gpg_svn(self):
5912 - pass
5913 -
5914 -
5915 -def list_checks(kwlist, liclist, uselist, repoman_settings):
5916 - liclist_deprecated = set()
5917 - if "DEPRECATED" in repoman_settings._license_manager._license_groups:
5918 - liclist_deprecated.update(
5919 - repoman_settings._license_manager.expandLicenseTokens(["@DEPRECATED"]))
5920 -
5921 - if not liclist:
5922 - logging.fatal("Couldn't find licenses?")
5923 - sys.exit(1)
5924 -
5925 - if not kwlist:
5926 - logging.fatal("Couldn't read KEYWORDS from arch.list")
5927 - sys.exit(1)
5928 -
5929 - if not uselist:
5930 - logging.fatal("Couldn't find use.desc?")
5931 - sys.exit(1)
5932 - return liclist_deprecated
5933 -
5934 -
5935 -def repo_metadata(portdb, repoman_settings):
5936 - # get lists of valid keywords, licenses, and use
5937 - kwlist = set()
5938 - liclist = set()
5939 - uselist = set()
5940 - profile_list = []
5941 - global_pmasklines = []
5942 -
5943 - for path in portdb.porttrees:
5944 - try:
5945 - liclist.update(os.listdir(os.path.join(path, "licenses")))
5946 - except OSError:
5947 - pass
5948 - kwlist.update(
5949 - portage.grabfile(os.path.join(path, "profiles", "arch.list")))
5950 -
5951 - use_desc = portage.grabfile(os.path.join(path, 'profiles', 'use.desc'))
5952 - for x in use_desc:
5953 - x = x.split()
5954 - if x:
5955 - uselist.add(x[0])
5956 -
5957 - expand_desc_dir = os.path.join(path, 'profiles', 'desc')
5958 - try:
5959 - expand_list = os.listdir(expand_desc_dir)
5960 - except OSError:
5961 - pass
5962 - else:
5963 - for fn in expand_list:
5964 - if not fn[-5:] == '.desc':
5965 - continue
5966 - use_prefix = fn[:-5].lower() + '_'
5967 - for x in portage.grabfile(os.path.join(expand_desc_dir, fn)):
5968 - x = x.split()
5969 - if x:
5970 - uselist.add(use_prefix + x[0])
5971 -
5972 - global_pmasklines.append(
5973 - portage.util.grabfile_package(
5974 - os.path.join(path, 'profiles', 'package.mask'),
5975 - recursive=1, verify_eapi=True))
5976 -
5977 - desc_path = os.path.join(path, 'profiles', 'profiles.desc')
5978 - try:
5979 - desc_file = io.open(
5980 - _unicode_encode(
5981 - desc_path, encoding=_encodings['fs'], errors='strict'),
5982 - mode='r', encoding=_encodings['repo.content'], errors='replace')
5983 - except EnvironmentError:
5984 - pass
5985 - else:
5986 - for i, x in enumerate(desc_file):
5987 - if x[0] == "#":
5988 - continue
5989 - arch = x.split()
5990 - if len(arch) == 0:
5991 - continue
5992 - if len(arch) != 3:
5993 - err(
5994 - "wrong format: \"%s\" in %s line %d" %
5995 - (bad(x.strip()), desc_path, i + 1, ))
5996 - elif arch[0] not in kwlist:
5997 - err(
5998 - "invalid arch: \"%s\" in %s line %d" %
5999 - (bad(arch[0]), desc_path, i + 1, ))
6000 - elif arch[2] not in valid_profile_types:
6001 - err(
6002 - "invalid profile type: \"%s\" in %s line %d" %
6003 - (bad(arch[2]), desc_path, i + 1, ))
6004 - profile_desc = ProfileDesc(arch[0], arch[2], arch[1], path)
6005 - if not os.path.isdir(profile_desc.abs_path):
6006 - logging.error(
6007 - "Invalid %s profile (%s) for arch %s in %s line %d",
6008 - arch[2], arch[1], arch[0], desc_path, i + 1)
6009 - continue
6010 - if os.path.exists(
6011 - os.path.join(profile_desc.abs_path, 'deprecated')):
6012 - continue
6013 - profile_list.append(profile_desc)
6014 - desc_file.close()
6015 -
6016 - global_pmasklines = portage.util.stack_lists(global_pmasklines, incremental=1)
6017 - global_pmaskdict = {}
6018 - for x in global_pmasklines:
6019 - global_pmaskdict.setdefault(x.cp, []).append(x)
6020 - del global_pmasklines
6021 -
6022 - return (
6023 - kwlist, liclist, uselist, profile_list, global_pmaskdict,
6024 - list_checks(kwlist, liclist, uselist, repoman_settings))
6025 -
6026 -
6027 -def has_global_mask(pkg, global_pmaskdict):
6028 - mask_atoms = global_pmaskdict.get(pkg.cp)
6029 - if mask_atoms:
6030 - pkg_list = [pkg]
6031 - for x in mask_atoms:
6032 - if portage.dep.match_from_list(x, pkg_list):
6033 - return x
6034 - return None
6035
6036 diff --git a/pym/tbc/repoman/scan.py b/pym/tbc/repoman/scan.py
6037 deleted file mode 100644
6038 index efa234d..0000000
6039 --- a/pym/tbc/repoman/scan.py
6040 +++ /dev/null
6041 @@ -1,170 +0,0 @@
6042 -
6043 -import logging
6044 -import os
6045 -import sys
6046 -from itertools import chain
6047 -
6048 -from portage import cvstree
6049 -
6050 -from tbc.repoman.errors import caterror
6051 -from tbc.repoman._subprocess import repoman_popen
6052 -
6053 -
6054 -def scan(repolevel, reposplit, startdir, categories, repo_settings):
6055 - scanlist = []
6056 - if repolevel == 2:
6057 - # we are inside a category directory
6058 - catdir = reposplit[-1]
6059 - if catdir not in categories:
6060 - caterror(catdir, repo_settings.repodir)
6061 - mydirlist = os.listdir(startdir)
6062 - for x in mydirlist:
6063 - if x == "CVS" or x.startswith("."):
6064 - continue
6065 - if os.path.isdir(startdir + "/" + x):
6066 - scanlist.append(catdir + "/" + x)
6067 - # repo_subdir = catdir + os.sep
6068 - elif repolevel == 1:
6069 - for x in categories:
6070 - if not os.path.isdir(startdir + "/" + x):
6071 - continue
6072 - for y in os.listdir(startdir + "/" + x):
6073 - if y == "CVS" or y.startswith("."):
6074 - continue
6075 - if os.path.isdir(startdir + "/" + x + "/" + y):
6076 - scanlist.append(x + "/" + y)
6077 - # repo_subdir = ""
6078 - elif repolevel == 3:
6079 - catdir = reposplit[-2]
6080 - if catdir not in categories:
6081 - caterror(catdir, repo_settings.repodir)
6082 - scanlist.append(catdir + "/" + reposplit[-1])
6083 - # repo_subdir = scanlist[-1] + os.sep
6084 - else:
6085 - msg = 'Repoman is unable to determine PORTDIR or PORTDIR_OVERLAY' + \
6086 - ' from the current working directory'
6087 - logging.critical(msg)
6088 - sys.exit(1)
6089 -
6090 - # repo_subdir_len = len(repo_subdir)
6091 - scanlist.sort()
6092 -
6093 - logging.debug(
6094 - "Found the following packages to scan:\n%s" % '\n'.join(scanlist))
6095 -
6096 - return scanlist
6097 -
6098 -
6099 -class Changes(object):
6100 - '''Class object to scan and hold the resultant data
6101 - for all changes to process.
6102 -
6103 - Basic plan is move the spaghetti code here, refactor the code
6104 - to split it into separate functions for each cvs type.
6105 - Later refactoring can then move the individual scan_ functions
6106 - to their respective VCS plugin module.
6107 - Leaving this class as the manager class which runs the correct VCS plugin.
6108 - This will ease future addition of new VCS types.
6109 - '''
6110 -
6111 - def __init__(self, options):
6112 - self.options = options
6113 - self._reset()
6114 -
6115 - def _reset(self):
6116 - self.new_ebuilds = set()
6117 - self.ebuilds = set()
6118 - self.changelogs = set()
6119 - self.changed = []
6120 - self.new = []
6121 - self.removed = []
6122 -
6123 - def scan(self, vcs_settings):
6124 - self._reset()
6125 -
6126 - if vcs_settings.vcs:
6127 - vcscheck = getattr(self, 'scan_%s' % vcs_settings.vcs)
6128 - vcscheck()
6129 -
6130 - if vcs_settings.vcs:
6131 - self.new_ebuilds.update(x for x in self.new if x.endswith(".ebuild"))
6132 - self.ebuilds.update(x for x in self.changed if x.endswith(".ebuild"))
6133 - self.changelogs.update(
6134 - x for x in chain(self.changed, self.new)
6135 - if os.path.basename(x) == "ChangeLog")
6136 -
6137 - def scan_cvs(self):
6138 - tree = cvstree.getentries("./", recursive=1)
6139 - self.changed = cvstree.findchanged(tree, recursive=1, basedir="./")
6140 - self.new = cvstree.findnew(tree, recursive=1, basedir="./")
6141 - if self.options.if_modified == "y":
6142 - self.removed = cvstree.findremoved(tree, recursive=1, basedir="./")
6143 - del tree
6144 -
6145 - def scan_svn(self):
6146 - with repoman_popen("svn status") as f:
6147 - svnstatus = f.readlines()
6148 - self.changed = [
6149 - "./" + elem.split()[-1:][0]
6150 - for elem in svnstatus
6151 - if elem and elem[:1] in "MR"]
6152 - self.new = [
6153 - "./" + elem.split()[-1:][0]
6154 - for elem in svnstatus
6155 - if elem.startswith("A")]
6156 - if self.options.if_modified == "y":
6157 - self.removed = [
6158 - "./" + elem.split()[-1:][0]
6159 - for elem in svnstatus
6160 - if elem.startswith("D")]
6161 -
6162 - def scan_git(self):
6163 - with repoman_popen(
6164 - "git diff-index --name-only "
6165 - "--relative --diff-filter=M HEAD") as f:
6166 - changed = f.readlines()
6167 - self.changed = ["./" + elem[:-1] for elem in changed]
6168 - del changed
6169 -
6170 - with repoman_popen(
6171 - "git diff-index --name-only "
6172 - "--relative --diff-filter=A HEAD") as f:
6173 - new = f.readlines()
6174 - self.new = ["./" + elem[:-1] for elem in new]
6175 - if self.options.if_modified == "y":
6176 - with repoman_popen(
6177 - "git diff-index --name-only "
6178 - "--relative --diff-filter=D HEAD") as f:
6179 - removed = f.readlines()
6180 - self.removed = ["./" + elem[:-1] for elem in removed]
6181 - del removed
6182 -
6183 - def scan_bzr(self):
6184 - with repoman_popen("bzr status -S .") as f:
6185 - bzrstatus = f.readlines()
6186 - self.changed = [
6187 - "./" + elem.split()[-1:][0].split('/')[-1:][0]
6188 - for elem in bzrstatus
6189 - if elem and elem[1:2] == "M"]
6190 - self.new = [
6191 - "./" + elem.split()[-1:][0].split('/')[-1:][0]
6192 - for elem in bzrstatus
6193 - if elem and (elem[1:2] == "NK" or elem[0:1] == "R")]
6194 - if self.options.if_modified == "y":
6195 - self.removed = [
6196 - "./" + elem.split()[-3:-2][0].split('/')[-1:][0]
6197 - for elem in bzrstatus
6198 - if elem and (elem[1:2] == "K" or elem[0:1] == "R")]
6199 -
6200 - def scan_hg(self):
6201 - with repoman_popen("hg status --no-status --modified .") as f:
6202 - changed = f.readlines()
6203 - self.changed = ["./" + elem.rstrip() for elem in changed]
6204 - with repoman_popen("hg status --no-status --added .") as f:
6205 - new = f.readlines()
6206 - self.new = ["./" + elem.rstrip() for elem in new]
6207 - if self.options.if_modified == "y":
6208 - with repoman_popen("hg status --no-status --removed .") as f:
6209 - removed = f.readlines()
6210 - self.removed = ["./" + elem.rstrip() for elem in removed]
6211 - del changed, new, removed
6212
6213 diff --git a/pym/tbc/repoman/utilities.py b/pym/tbc/repoman/utilities.py
6214 deleted file mode 100644
6215 index 2a1f4d9..0000000
6216 --- a/pym/tbc/repoman/utilities.py
6217 +++ /dev/null
6218 @@ -1,595 +0,0 @@
6219 -# repoman: Utilities
6220 -# Copyright 2007-2013 Gentoo Foundation
6221 -# Distributed under the terms of the GNU General Public License v2
6222 -
6223 -"""This module contains utility functions to help repoman find ebuilds to
6224 -scan"""
6225 -
6226 -from __future__ import print_function, unicode_literals
6227 -
6228 -__all__ = [
6229 - "editor_is_executable",
6230 - "FindPackagesToScan",
6231 - "FindPortdir",
6232 - "get_commit_message_with_editor",
6233 - "get_commit_message_with_stdin",
6234 - "get_committer_name",
6235 - "have_ebuild_dir",
6236 - "have_profile_dir",
6237 - "UpdateChangeLog"
6238 -]
6239 -
6240 -import errno
6241 -import io
6242 -from itertools import chain
6243 -import logging
6244 -import pwd
6245 -import stat
6246 -import sys
6247 -import time
6248 -import textwrap
6249 -import difflib
6250 -from tempfile import mkstemp
6251 -
6252 -# import our initialized portage instance
6253 -from repoman._portage import portage
6254 -
6255 -from portage import os
6256 -from portage import shutil
6257 -from portage import _encodings
6258 -from portage import _unicode_decode
6259 -from portage import _unicode_encode
6260 -from portage import util
6261 -from portage.localization import _
6262 -from portage.process import find_binary
6263 -from portage.output import green
6264 -
6265 -from repoman.copyrights import update_copyright, update_copyright_year
6266 -
6267 -
6268 -normalize_path = util.normalize_path
6269 -util.initialize_logger()
6270 -
6271 -if sys.hexversion >= 0x3000000:
6272 - basestring = str
6273 -
6274 -
6275 -def have_profile_dir(path, maxdepth=3, filename="profiles.desc"):
6276 - """
6277 - Try to figure out if 'path' has a profiles/
6278 - dir in it by checking for the given filename.
6279 - """
6280 - while path != "/" and maxdepth:
6281 - if os.path.exists(os.path.join(path, "profiles", filename)):
6282 - return normalize_path(path)
6283 - path = normalize_path(path + "/..")
6284 - maxdepth -= 1
6285 -
6286 -
6287 -def have_ebuild_dir(path, maxdepth=3):
6288 - """
6289 - Try to figure out if 'path' or a subdirectory contains one or more
6290 - ebuild files named appropriately for their parent directory.
6291 - """
6292 - stack = [(normalize_path(path), 1)]
6293 - while stack:
6294 - path, depth = stack.pop()
6295 - basename = os.path.basename(path)
6296 - try:
6297 - listdir = os.listdir(path)
6298 - except OSError:
6299 - continue
6300 - for filename in listdir:
6301 - abs_filename = os.path.join(path, filename)
6302 - try:
6303 - st = os.stat(abs_filename)
6304 - except OSError:
6305 - continue
6306 - if stat.S_ISDIR(st.st_mode):
6307 - if depth < maxdepth:
6308 - stack.append((abs_filename, depth + 1))
6309 - elif stat.S_ISREG(st.st_mode):
6310 - if filename.endswith(".ebuild") and \
6311 - filename.startswith(basename + "-"):
6312 - return os.path.dirname(os.path.dirname(path))
6313 -
6314 -
6315 -def FindPackagesToScan(settings, startdir, reposplit):
6316 - """ Try to find packages that need to be scanned
6317 -
6318 - Args:
6319 - settings - portage.config instance, preferably repoman_settings
6320 - startdir - directory that repoman was run in
6321 - reposplit - root of the repository
6322 - Returns:
6323 - A list of directories to scan
6324 - """
6325 -
6326 - def AddPackagesInDir(path):
6327 - """ Given a list of dirs, add any packages in it """
6328 - ret = []
6329 - pkgdirs = os.listdir(path)
6330 - for d in pkgdirs:
6331 - if d == 'CVS' or d.startswith('.'):
6332 - continue
6333 - p = os.path.join(path, d)
6334 -
6335 - if os.path.isdir(p):
6336 - cat_pkg_dir = os.path.join(*p.split(os.path.sep)[-2:])
6337 - logging.debug('adding %s to scanlist' % cat_pkg_dir)
6338 - ret.append(cat_pkg_dir)
6339 - return ret
6340 -
6341 - scanlist = []
6342 - repolevel = len(reposplit)
6343 - if repolevel == 1: # root of the tree, startdir = repodir
6344 - for cat in settings.categories:
6345 - path = os.path.join(startdir, cat)
6346 - if not os.path.isdir(path):
6347 - continue
6348 - scanlist.extend(AddPackagesInDir(path))
6349 - elif repolevel == 2: # category level, startdir = catdir
6350 - # We only want 1 segment of the directory,
6351 - # this is why we use catdir instead of startdir.
6352 - catdir = reposplit[-2]
6353 - if catdir not in settings.categories:
6354 - logging.warn(
6355 - '%s is not a valid category according to profiles/categories, '
6356 - 'skipping checks in %s' % (catdir, catdir))
6357 - else:
6358 - scanlist = AddPackagesInDir(catdir)
6359 - elif repolevel == 3: # pkgdir level, startdir = pkgdir
6360 - catdir = reposplit[-2]
6361 - pkgdir = reposplit[-1]
6362 - if catdir not in settings.categories:
6363 - logging.warn(
6364 - '%s is not a valid category according to profiles/categories, '
6365 - 'skipping checks in %s' % (catdir, catdir))
6366 - else:
6367 - path = os.path.join(catdir, pkgdir)
6368 - logging.debug('adding %s to scanlist' % path)
6369 - scanlist.append(path)
6370 - return scanlist
6371 -
6372 -
6373 -def editor_is_executable(editor):
6374 - """
6375 - Given an EDITOR string, validate that it refers to
6376 - an executable. This uses shlex_split() to split the
6377 - first component and do a PATH lookup if necessary.
6378 -
6379 - @param editor: An EDITOR value from the environment.
6380 - @type: string
6381 - @rtype: bool
6382 - @return: True if an executable is found, False otherwise.
6383 - """
6384 - editor_split = util.shlex_split(editor)
6385 - if not editor_split:
6386 - return False
6387 - filename = editor_split[0]
6388 - if not os.path.isabs(filename):
6389 - return find_binary(filename) is not None
6390 - return os.access(filename, os.X_OK) and os.path.isfile(filename)
6391 -
6392 -
6393 -def get_commit_message_with_editor(editor, message=None, prefix=""):
6394 - """
6395 - Execute editor with a temporary file as it's argument
6396 - and return the file content afterwards.
6397 -
6398 - @param editor: An EDITOR value from the environment
6399 - @type: string
6400 - @param message: An iterable of lines to show in the editor.
6401 - @type: iterable
6402 - @param prefix: Suggested prefix for the commit message summary line.
6403 - @type: string
6404 - @rtype: string or None
6405 - @return: A string on success or None if an error occurs.
6406 - """
6407 - fd, filename = mkstemp()
6408 - try:
6409 - os.write(
6410 - fd, _unicode_encode(_(
6411 - prefix +
6412 - "\n\n# Please enter the commit message "
6413 - "for your changes.\n# (Comment lines starting "
6414 - "with '#' will not be included)\n"),
6415 - encoding=_encodings['content'], errors='backslashreplace'))
6416 - if message:
6417 - os.write(fd, b"#\n")
6418 - for line in message:
6419 - os.write(
6420 - fd, _unicode_encode(
6421 - "#" + line, encoding=_encodings['content'],
6422 - errors='backslashreplace'))
6423 - os.close(fd)
6424 - retval = os.system(editor + " '%s'" % filename)
6425 - if not (os.WIFEXITED(retval) and os.WEXITSTATUS(retval) == os.EX_OK):
6426 - return None
6427 - try:
6428 - with io.open(_unicode_encode(
6429 - filename, encoding=_encodings['fs'], errors='strict'),
6430 - mode='r', encoding=_encodings['content'], errors='replace') as f:
6431 - mylines = f.readlines()
6432 - except OSError as e:
6433 - if e.errno != errno.ENOENT:
6434 - raise
6435 - del e
6436 - return None
6437 - return "".join(line for line in mylines if not line.startswith("#"))
6438 - finally:
6439 - try:
6440 - os.unlink(filename)
6441 - except OSError:
6442 - pass
6443 -
6444 -
6445 -def get_commit_message_with_stdin():
6446 - """
6447 - Read a commit message from the user and return it.
6448 -
6449 - @rtype: string or None
6450 - @return: A string on success or None if an error occurs.
6451 - """
6452 - print(
6453 - "Please enter a commit message."
6454 - " Use Ctrl-d to finish or Ctrl-c to abort.")
6455 - commitmessage = []
6456 - while True:
6457 - commitmessage.append(sys.stdin.readline())
6458 - if not commitmessage[-1]:
6459 - break
6460 - commitmessage = "".join(commitmessage)
6461 - return commitmessage
6462 -
6463 -
6464 -def FindPortdir(settings):
6465 - """ Try to figure out what repo we are in and whether we are in a regular
6466 - tree or an overlay.
6467 -
6468 - Basic logic is:
6469 -
6470 - 1. Determine what directory we are in (supports symlinks).
6471 - 2. Build a list of directories from / to our current location
6472 - 3. Iterate over PORTDIR_OVERLAY, if we find a match,
6473 - search for a profiles directory in the overlay. If it has one,
6474 - make it portdir, otherwise make it portdir_overlay.
6475 - 4. If we didn't find an overlay in PORTDIR_OVERLAY,
6476 - see if we are in PORTDIR; if so, set portdir_overlay to PORTDIR.
6477 - If we aren't in PORTDIR, see if PWD has a profiles dir, if so,
6478 - set portdir_overlay and portdir to PWD, else make them False.
6479 - 5. If we haven't found portdir_overlay yet,
6480 - it means the user is doing something odd, report an error.
6481 - 6. If we haven't found a portdir yet, set portdir to PORTDIR.
6482 -
6483 - Args:
6484 - settings - portage.config instance, preferably repoman_settings
6485 - Returns:
6486 - list(portdir, portdir_overlay, location)
6487 - """
6488 -
6489 - portdir = None
6490 - portdir_overlay = None
6491 - location = os.getcwd()
6492 - pwd = _unicode_decode(os.environ.get('PWD', ''), encoding=_encodings['fs'])
6493 - if pwd and pwd != location and os.path.realpath(pwd) == location:
6494 - # getcwd() returns the canonical path but that makes it hard for repoman to
6495 - # orient itself if the user has symlinks in their portage tree structure.
6496 - # We use os.environ["PWD"], if available, to get the non-canonical path of
6497 - # the current working directory (from the shell).
6498 - location = pwd
6499 -
6500 - location = normalize_path(location)
6501 -
6502 - path_ids = {}
6503 - p = location
6504 - s = None
6505 - while True:
6506 - s = os.stat(p)
6507 - path_ids[(s.st_dev, s.st_ino)] = p
6508 - if p == "/":
6509 - break
6510 - p = os.path.dirname(p)
6511 - if location[-1] != "/":
6512 - location += "/"
6513 -
6514 - for overlay in portage.util.shlex_split(settings["PORTDIR_OVERLAY"]):
6515 - overlay = os.path.realpath(overlay)
6516 - try:
6517 - s = os.stat(overlay)
6518 - except OSError:
6519 - continue
6520 - overlay = path_ids.get((s.st_dev, s.st_ino))
6521 - if overlay is None:
6522 - continue
6523 - if overlay[-1] != "/":
6524 - overlay += "/"
6525 - if True:
6526 - portdir_overlay = overlay
6527 - subdir = location[len(overlay):]
6528 - if subdir and subdir[-1] != "/":
6529 - subdir += "/"
6530 - if have_profile_dir(location, subdir.count("/")):
6531 - portdir = portdir_overlay
6532 - break
6533 -
6534 - # Couldn't match location with anything from PORTDIR_OVERLAY,
6535 - # so fall back to have_profile_dir() checks alone. Assume that
6536 - # an overlay will contain at least a "repo_name" file while a
6537 - # master repo (portdir) will contain at least a "profiles.desc"
6538 - # file.
6539 - if not portdir_overlay:
6540 - portdir_overlay = have_profile_dir(location, filename="repo_name")
6541 - if not portdir_overlay:
6542 - portdir_overlay = have_ebuild_dir(location)
6543 - if portdir_overlay:
6544 - subdir = location[len(portdir_overlay):]
6545 - if subdir and subdir[-1] != os.sep:
6546 - subdir += os.sep
6547 - if have_profile_dir(location, subdir.count(os.sep)):
6548 - portdir = portdir_overlay
6549 -
6550 - if not portdir_overlay:
6551 - if (settings["PORTDIR"] + os.path.sep).startswith(location):
6552 - portdir_overlay = settings["PORTDIR"]
6553 - else:
6554 - portdir_overlay = have_profile_dir(location)
6555 - portdir = portdir_overlay
6556 -
6557 - if not portdir_overlay:
6558 - msg = 'Repoman is unable to determine PORTDIR or PORTDIR_OVERLAY' + \
6559 - ' from the current working directory'
6560 - logging.critical(msg)
6561 - return (None, None, None)
6562 -
6563 - if not portdir:
6564 - portdir = settings["PORTDIR"]
6565 -
6566 - if not portdir_overlay.endswith('/'):
6567 - portdir_overlay += '/'
6568 -
6569 - if not portdir.endswith('/'):
6570 - portdir += '/'
6571 -
6572 - return [normalize_path(x) for x in (portdir, portdir_overlay, location)]
6573 -
6574 -
6575 -def get_committer_name(env=None):
6576 - """Generate a committer string like echangelog does."""
6577 - if env is None:
6578 - env = os.environ
6579 - if 'GENTOO_COMMITTER_NAME' in env and 'GENTOO_COMMITTER_EMAIL' in env:
6580 - user = '%s <%s>' % (
6581 - env['GENTOO_COMMITTER_NAME'],
6582 - env['GENTOO_COMMITTER_EMAIL'])
6583 - elif 'GENTOO_AUTHOR_NAME' in env and 'GENTOO_AUTHOR_EMAIL' in env:
6584 - user = '%s <%s>' % (
6585 - env['GENTOO_AUTHOR_NAME'],
6586 - env['GENTOO_AUTHOR_EMAIL'])
6587 - elif 'ECHANGELOG_USER' in env:
6588 - user = env['ECHANGELOG_USER']
6589 - else:
6590 - pwd_struct = pwd.getpwuid(os.getuid())
6591 - gecos = pwd_struct.pw_gecos.split(',')[0] # bug #80011
6592 - user = '%s <%s@g.o>' % (gecos, pwd_struct.pw_name)
6593 - return user
6594 -
6595 -
6596 -def UpdateChangeLog(
6597 - pkgdir, user, msg, skel_path, category, package,
6598 - new=(), removed=(), changed=(), pretend=False, quiet=False):
6599 - """
6600 - Write an entry to an existing ChangeLog, or create a new one.
6601 - Updates copyright year on changed files, and updates the header of
6602 - ChangeLog with the contents of skel.ChangeLog.
6603 - """
6604 -
6605 - if '<root@' in user:
6606 - if not quiet:
6607 - logging.critical('Please set ECHANGELOG_USER or run as non-root')
6608 - return None
6609 -
6610 - # ChangeLog times are in UTC
6611 - gmtime = time.gmtime()
6612 - year = time.strftime('%Y', gmtime)
6613 - date = time.strftime('%d %b %Y', gmtime)
6614 -
6615 - # check modified files and the ChangeLog for copyright updates
6616 - # patches and diffs (identified by .patch and .diff) are excluded
6617 - for fn in chain(new, changed):
6618 - if fn.endswith('.diff') or fn.endswith('.patch'):
6619 - continue
6620 - update_copyright(os.path.join(pkgdir, fn), year, pretend=pretend)
6621 -
6622 - cl_path = os.path.join(pkgdir, 'ChangeLog')
6623 - clold_lines = []
6624 - clnew_lines = []
6625 - old_header_lines = []
6626 - header_lines = []
6627 -
6628 - clold_file = None
6629 - try:
6630 - clold_file = io.open(_unicode_encode(
6631 - cl_path, encoding=_encodings['fs'], errors='strict'),
6632 - mode='r', encoding=_encodings['repo.content'], errors='replace')
6633 - except EnvironmentError:
6634 - pass
6635 -
6636 - f, clnew_path = mkstemp()
6637 -
6638 - # construct correct header first
6639 - try:
6640 - if clold_file is not None:
6641 - # retain header from old ChangeLog
6642 - first_line = True
6643 - for line in clold_file:
6644 - line_strip = line.strip()
6645 - if line_strip and line[:1] != "#":
6646 - clold_lines.append(line)
6647 - break
6648 - # always make sure cat/pkg is up-to-date in case we are
6649 - # moving packages around, or copied from another pkg, or ...
6650 - if first_line:
6651 - if line.startswith('# ChangeLog for'):
6652 - line = '# ChangeLog for %s/%s\n' % (category, package)
6653 - first_line = False
6654 - old_header_lines.append(line)
6655 - header_lines.append(update_copyright_year(year, line))
6656 - if not line_strip:
6657 - break
6658 -
6659 - clskel_file = None
6660 - if not header_lines:
6661 - # delay opening this until we find we need a header
6662 - try:
6663 - clskel_file = io.open(_unicode_encode(
6664 - skel_path, encoding=_encodings['fs'], errors='strict'),
6665 - mode='r', encoding=_encodings['repo.content'],
6666 - errors='replace')
6667 - except EnvironmentError:
6668 - pass
6669 -
6670 - if clskel_file is not None:
6671 - # read skel.ChangeLog up to first empty line
6672 - for line in clskel_file:
6673 - line_strip = line.strip()
6674 - if not line_strip:
6675 - break
6676 - line = line.replace('<CATEGORY>', category)
6677 - line = line.replace('<PACKAGE_NAME>', package)
6678 - line = update_copyright_year(year, line)
6679 - header_lines.append(line)
6680 - header_lines.append('\n')
6681 - clskel_file.close()
6682 -
6683 - # write new ChangeLog entry
6684 - clnew_lines.extend(header_lines)
6685 - newebuild = False
6686 - for fn in new:
6687 - if not fn.endswith('.ebuild'):
6688 - continue
6689 - ebuild = fn.split(os.sep)[-1][0:-7]
6690 - clnew_lines.append('*%s (%s)\n' % (ebuild, date))
6691 - newebuild = True
6692 - if newebuild:
6693 - clnew_lines.append('\n')
6694 - trivial_files = ('ChangeLog', 'Manifest')
6695 - display_new = [
6696 - '+' + elem
6697 - for elem in new
6698 - if elem not in trivial_files]
6699 - display_removed = [
6700 - '-' + elem
6701 - for elem in removed]
6702 - display_changed = [
6703 - elem for elem in changed
6704 - if elem not in trivial_files]
6705 - if not (display_new or display_removed or display_changed):
6706 - # If there's nothing else to display, show one of the
6707 - # trivial files.
6708 - for fn in trivial_files:
6709 - if fn in new:
6710 - display_new = ['+' + fn]
6711 - break
6712 - elif fn in changed:
6713 - display_changed = [fn]
6714 - break
6715 -
6716 - display_new.sort()
6717 - display_removed.sort()
6718 - display_changed.sort()
6719 -
6720 - mesg = '%s; %s %s:' % (date, user, ', '.join(chain(
6721 - display_new, display_removed, display_changed)))
6722 - for line in textwrap.wrap(
6723 - mesg, 80, initial_indent=' ', subsequent_indent=' ',
6724 - break_on_hyphens=False):
6725 - clnew_lines.append('%s\n' % line)
6726 - for line in textwrap.wrap(
6727 - msg, 80, initial_indent=' ', subsequent_indent=' '):
6728 - clnew_lines.append('%s\n' % line)
6729 - # Don't append a trailing newline if the file is new.
6730 - if clold_file is not None:
6731 - clnew_lines.append('\n')
6732 -
6733 - f = io.open(
6734 - f, mode='w', encoding=_encodings['repo.content'],
6735 - errors='backslashreplace')
6736 -
6737 - for line in clnew_lines:
6738 - f.write(line)
6739 -
6740 - # append stuff from old ChangeLog
6741 - if clold_file is not None:
6742 -
6743 - if clold_lines:
6744 - # clold_lines may contain a saved non-header line
6745 - # that we want to write first.
6746 - # Also, append this line to clnew_lines so that the
6747 - # unified_diff call doesn't show it as removed.
6748 - for line in clold_lines:
6749 - f.write(line)
6750 - clnew_lines.append(line)
6751 -
6752 - else:
6753 - # ensure that there is no more than one blank
6754 - # line after our new entry
6755 - for line in clold_file:
6756 - if line.strip():
6757 - f.write(line)
6758 - break
6759 -
6760 - # Now prepend old_header_lines to clold_lines, for use
6761 - # in the unified_diff call below.
6762 - clold_lines = old_header_lines + clold_lines
6763 -
6764 - # Trim any trailing newlines.
6765 - lines = clold_file.readlines()
6766 - clold_file.close()
6767 - while lines and lines[-1] == '\n':
6768 - del lines[-1]
6769 - f.writelines(lines)
6770 - f.close()
6771 -
6772 - # show diff
6773 - if not quiet:
6774 - for line in difflib.unified_diff(
6775 - clold_lines, clnew_lines,
6776 - fromfile=cl_path, tofile=cl_path, n=0):
6777 - util.writemsg_stdout(line, noiselevel=-1)
6778 - util.writemsg_stdout("\n", noiselevel=-1)
6779 -
6780 - if pretend:
6781 - # remove what we've done
6782 - os.remove(clnew_path)
6783 - else:
6784 - # rename to ChangeLog, and set permissions
6785 - try:
6786 - clold_stat = os.stat(cl_path)
6787 - except OSError:
6788 - clold_stat = None
6789 -
6790 - shutil.move(clnew_path, cl_path)
6791 -
6792 - if clold_stat is None:
6793 - util.apply_permissions(cl_path, mode=0o644)
6794 - else:
6795 - util.apply_stat_permissions(cl_path, clold_stat)
6796 -
6797 - if clold_file is None:
6798 - return True
6799 - else:
6800 - return False
6801 - except IOError as e:
6802 - err = 'Repoman is unable to create/write to Changelog.new file: %s' % (e,)
6803 - logging.critical(err)
6804 - # try to remove if possible
6805 - try:
6806 - os.remove(clnew_path)
6807 - except OSError:
6808 - pass
6809 - return None
6810 -
6811 -
6812 -def repoman_sez(msg):
6813 - print (green("RepoMan sez:"), msg)
6814
6815 diff --git a/pym/tbc/repoman/vcs/__init__.py b/pym/tbc/repoman/vcs/__init__.py
6816 deleted file mode 100644
6817 index e69de29..0000000
6818
6819 diff --git a/pym/tbc/repoman/vcs/vcs.py b/pym/tbc/repoman/vcs/vcs.py
6820 deleted file mode 100644
6821 index 3f7cbb5..0000000
6822 --- a/pym/tbc/repoman/vcs/vcs.py
6823 +++ /dev/null
6824 @@ -1,274 +0,0 @@
6825 -
6826 -import collections
6827 -import logging
6828 -import re
6829 -import subprocess
6830 -import sys
6831 -from itertools import chain
6832 -
6833 -from portage import os
6834 -from portage.const import BASH_BINARY
6835 -from portage.output import red, green
6836 -from portage import _unicode_encode, _unicode_decode
6837 -
6838 -from tbc.repoman._subprocess import repoman_getstatusoutput
6839 -
6840 -
6841 -_vcs_type = collections.namedtuple('_vcs_type', 'name dir_name')
6842 -
6843 -_FindVCS_data = (
6844 - _vcs_type(
6845 - name='git',
6846 - dir_name='.git'
6847 - ),
6848 - _vcs_type(
6849 - name='bzr',
6850 - dir_name='.bzr'
6851 - ),
6852 - _vcs_type(
6853 - name='hg',
6854 - dir_name='.hg'
6855 - ),
6856 - _vcs_type(
6857 - name='svn',
6858 - dir_name='.svn'
6859 - )
6860 -)
6861 -
6862 -
6863 -def FindVCS():
6864 - """ Try to figure out in what VCS' working tree we are. """
6865 -
6866 - outvcs = []
6867 -
6868 - def seek(depth=None):
6869 - """ Seek for VCSes that have a top-level data directory only. """
6870 - retvcs = []
6871 - pathprep = ''
6872 -
6873 - while depth is None or depth > 0:
6874 - for vcs_type in _FindVCS_data:
6875 - vcs_dir = os.path.join(pathprep, vcs_type.dir_name)
6876 - if os.path.isdir(vcs_dir):
6877 - logging.debug(
6878 - 'FindVCS: found %(name)s dir: %(vcs_dir)s' % {
6879 - 'name': vcs_type.name,
6880 - 'vcs_dir': os.path.abspath(vcs_dir)})
6881 - retvcs.append(vcs_type.name)
6882 -
6883 - if retvcs:
6884 - break
6885 - pathprep = os.path.join(pathprep, '..')
6886 - if os.path.realpath(pathprep).strip('/') == '':
6887 - break
6888 - if depth is not None:
6889 - depth = depth - 1
6890 -
6891 - return retvcs
6892 -
6893 - # Level zero VCS-es.
6894 - if os.path.isdir('CVS'):
6895 - outvcs.append('cvs')
6896 - if os.path.isdir('.svn'): # <1.7
6897 - outvcs.append('svn')
6898 -
6899 - # If we already found one of 'level zeros', just take a quick look
6900 - # at the current directory. Otherwise, seek parents till we get
6901 - # something or reach root.
6902 - if outvcs:
6903 - outvcs.extend(seek(1))
6904 - else:
6905 - outvcs = seek()
6906 -
6907 - if len(outvcs) > 1:
6908 - # eliminate duplicates, like for svn in bug #391199
6909 - outvcs = list(set(outvcs))
6910 -
6911 - return outvcs
6912 -
6913 -
6914 -def vcs_files_to_cps(vcs_file_iter, repolevel, reposplit, categories):
6915 - """
6916 - Iterate over the given modified file paths returned from the vcs,
6917 - and return a frozenset containing category/pn strings for each
6918 - modified package.
6919 - """
6920 -
6921 - modified_cps = []
6922 -
6923 - if repolevel == 3:
6924 - if reposplit[-2] in categories and \
6925 - next(vcs_file_iter, None) is not None:
6926 - modified_cps.append("/".join(reposplit[-2:]))
6927 -
6928 - elif repolevel == 2:
6929 - category = reposplit[-1]
6930 - if category in categories:
6931 - for filename in vcs_file_iter:
6932 - f_split = filename.split(os.sep)
6933 - # ['.', pn, ...]
6934 - if len(f_split) > 2:
6935 - modified_cps.append(category + "/" + f_split[1])
6936 -
6937 - else:
6938 - # repolevel == 1
6939 - for filename in vcs_file_iter:
6940 - f_split = filename.split(os.sep)
6941 - # ['.', category, pn, ...]
6942 - if len(f_split) > 3 and f_split[1] in categories:
6943 - modified_cps.append("/".join(f_split[1:3]))
6944 -
6945 - return frozenset(modified_cps)
6946 -
6947 -
6948 -def vcs_new_changed(relative_path, mychanged, mynew):
6949 - for x in chain(mychanged, mynew):
6950 - if x == relative_path:
6951 - return True
6952 - return False
6953 -
6954 -
6955 -def git_supports_gpg_sign():
6956 - status, cmd_output = \
6957 - repoman_getstatusoutput("git --version")
6958 - cmd_output = cmd_output.split()
6959 - if cmd_output:
6960 - version = re.match(r'^(\d+)\.(\d+)\.(\d+)', cmd_output[-1])
6961 - if version is not None:
6962 - version = [int(x) for x in version.groups()]
6963 - if version[0] > 1 or \
6964 - (version[0] == 1 and version[1] > 7) or \
6965 - (version[0] == 1 and version[1] == 7 and version[2] >= 9):
6966 - return True
6967 - return False
6968 -
6969 -
6970 -def detect_vcs_conflicts(options, vcs):
6971 - """Determine if the checkout has problems like cvs conflicts.
6972 -
6973 - If you want more vcs support here just keep adding if blocks...
6974 - This could be better.
6975 -
6976 - TODO(antarus): Also this should probably not call sys.exit() as
6977 - repoman is run on >1 packages and one failure should not cause
6978 - subsequent packages to fail.
6979 -
6980 - Args:
6981 - vcs - A string identifying the version control system in use
6982 - Returns:
6983 - None (calls sys.exit on fatal problems)
6984 - """
6985 -
6986 - cmd = None
6987 - if vcs == 'cvs':
6988 - logging.info(
6989 - "Performing a %s with a little magic grep to check for updates." %
6990 - green("cvs -n up"))
6991 - cmd = (
6992 - "cvs -n up 2>/dev/null | "
6993 - "egrep '^[^\?] .*' | "
6994 - "egrep -v '^. .*/digest-[^/]+|^cvs server: .* -- ignored$'")
6995 - if vcs == 'svn':
6996 - logging.info(
6997 - "Performing a %s with a little magic grep to check for updates." %
6998 - green("svn status -u"))
6999 - cmd = (
7000 - "svn status -u 2>&1 | "
7001 - "egrep -v '^. +.*/digest-[^/]+' | "
7002 - "head -n-1")
7003 -
7004 - if cmd is not None:
7005 - # Use Popen instead of getstatusoutput(), in order to avoid
7006 - # unicode handling problems (see bug #310789).
7007 - args = [BASH_BINARY, "-c", cmd]
7008 - args = [_unicode_encode(x) for x in args]
7009 - proc = subprocess.Popen(
7010 - args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
7011 - out = _unicode_decode(proc.communicate()[0])
7012 - proc.wait()
7013 - mylines = out.splitlines()
7014 - myupdates = []
7015 - for line in mylines:
7016 - if not line:
7017 - continue
7018 -
7019 - # [ ] Unmodified (SVN) [U] Updates [P] Patches
7020 - # [M] Modified [A] Added [R] Removed / Replaced
7021 - # [D] Deleted
7022 - if line[0] not in " UPMARD":
7023 - # Stray Manifest is fine, we will readd it anyway.
7024 - if line[0] == '?' and line[1:].lstrip() == 'Manifest':
7025 - continue
7026 - logging.error(red(
7027 - "!!! Please fix the following issues reported "
7028 - "from cvs: %s" % green("(U,P,M,A,R,D are ok)")))
7029 - logging.error(red(
7030 - "!!! Note: This is a pretend/no-modify pass..."))
7031 - logging.error(out)
7032 - sys.exit(1)
7033 - elif vcs == 'cvs' and line[0] in "UP":
7034 - myupdates.append(line[2:])
7035 - elif vcs == 'svn' and line[8] == '*':
7036 - myupdates.append(line[9:].lstrip(" 1234567890"))
7037 -
7038 - if myupdates:
7039 - logging.info(green("Fetching trivial updates..."))
7040 - if options.pretend:
7041 - logging.info("(" + vcs + " update " + " ".join(myupdates) + ")")
7042 - retval = os.EX_OK
7043 - else:
7044 - retval = os.system(vcs + " update " + " ".join(myupdates))
7045 - if retval != os.EX_OK:
7046 - logging.fatal("!!! " + vcs + " exited with an error. Terminating.")
7047 - sys.exit(retval)
7048 -
7049 -
7050 -class VCSSettings(object):
7051 - '''Holds various VCS settings'''
7052 -
7053 - def __init__(self, options=None, repoman_settings=None):
7054 - if options.vcs:
7055 - if options.vcs in ('cvs', 'svn', 'git', 'bzr', 'hg'):
7056 - self.vcs = options.vcs
7057 - else:
7058 - self.vcs = None
7059 - else:
7060 - vcses = FindVCS()
7061 - if len(vcses) > 1:
7062 - print(red(
7063 - '*** Ambiguous workdir -- more than one VCS found'
7064 - ' at the same depth: %s.' % ', '.join(vcses)))
7065 - print(red(
7066 - '*** Please either clean up your workdir'
7067 - ' or specify --vcs option.'))
7068 - sys.exit(1)
7069 - elif vcses:
7070 - self.vcs = vcses[0]
7071 - else:
7072 - self.vcs = None
7073 -
7074 - if options.if_modified == "y" and self.vcs is None:
7075 - logging.info(
7076 - "Not in a version controlled repository; "
7077 - "disabling --if-modified.")
7078 - options.if_modified = "n"
7079 -
7080 - # Disable copyright/mtime check if vcs does not preserve mtime (bug #324075).
7081 - self.vcs_preserves_mtime = self.vcs in ('cvs',)
7082 -
7083 - self.vcs_local_opts = repoman_settings.get(
7084 - "REPOMAN_VCS_LOCAL_OPTS", "").split()
7085 - self.vcs_global_opts = repoman_settings.get(
7086 - "REPOMAN_VCS_GLOBAL_OPTS")
7087 - if self.vcs_global_opts is None:
7088 - if self.vcs in ('cvs', 'svn'):
7089 - self.vcs_global_opts = "-q"
7090 - else:
7091 - self.vcs_global_opts = ""
7092 - self.vcs_global_opts = self.vcs_global_opts.split()
7093 -
7094 - if options.mode == 'commit' and not options.pretend and not self.vcs:
7095 - logging.info(
7096 - "Not in a version controlled repository; "
7097 - "enabling pretend mode.")
7098 - options.pretend = True
7099
7100 diff --git a/pym/tbc/repoman/vcs/vcsstatus.py b/pym/tbc/repoman/vcs/vcsstatus.py
7101 deleted file mode 100644
7102 index 13f2e83..0000000
7103 --- a/pym/tbc/repoman/vcs/vcsstatus.py
7104 +++ /dev/null
7105 @@ -1,113 +0,0 @@
7106 -
7107 -
7108 -# import our initialized portage instance
7109 -from tbc.repoman._portage import portage
7110 -
7111 -from portage import os
7112 -
7113 -from tbc.repoman._subprocess import repoman_popen
7114 -
7115 -
7116 -class VCSStatus(object):
7117 - '''Determines the status of the vcs repositories
7118 - to determine if files are not added'''
7119 -
7120 - def __init__(self, vcs_settings, qatracker):
7121 - self.vcs_settings = vcs_settings
7122 - self.vcs = vcs_settings.vcs
7123 - self.eadded = []
7124 - self.qatracker = qatracker
7125 -
7126 - def check(self, check_not_added, checkdir, checkdir_relative, xpkg):
7127 - if self.vcs and check_not_added:
7128 - vcscheck = getattr(self, 'check_%s' % self.vcs)
7129 - vcscheck(checkdir, checkdir_relative, xpkg)
7130 -
7131 - def post_git_hg(self, myf, xpkg):
7132 - for l in myf:
7133 - if l[:-1][-7:] == ".ebuild":
7134 - self.qatracker.add_error(
7135 - "ebuild.notadded",
7136 - os.path.join(xpkg, os.path.basename(l[:-1])))
7137 - myf.close()
7138 -
7139 - def check_git(self, checkdir, checkdir_relative, xpkg):
7140 - myf = repoman_popen(
7141 - "git ls-files --others %s" %
7142 - (portage._shell_quote(checkdir_relative),))
7143 - self.post_git_hg(myf, xpkg)
7144 -
7145 - def check_hg(self, checkdir, checkdir_relative, xpkg):
7146 - myf = repoman_popen(
7147 - "hg status --no-status --unknown %s" %
7148 - (portage._shell_quote(checkdir_relative),))
7149 - self.post_git_hg(myf, xpkg)
7150 -
7151 - def check_cvs(self, checkdir, checkdir_relative, xpkg):
7152 - try:
7153 - myf = open(checkdir + "/CVS/Entries", "r")
7154 - myl = myf.readlines()
7155 - myf.close()
7156 - except IOError:
7157 - self.qatracker.add_error(
7158 - "CVS/Entries.IO_error", checkdir + "/CVS/Entries")
7159 - return True
7160 - for l in myl:
7161 - if l[0] != "/":
7162 - continue
7163 - splitl = l[1:].split("/")
7164 - if not len(splitl):
7165 - continue
7166 - if splitl[0][-7:] == ".ebuild":
7167 - self.eadded.append(splitl[0][:-7])
7168 - return True
7169 -
7170 - def check_svn(self, checkdir, checkdir_relative, xpkg):
7171 - try:
7172 - myf = repoman_popen(
7173 - "svn status --depth=files --verbose " +
7174 - portage._shell_quote(self.checkdir))
7175 - myl = myf.readlines()
7176 - myf.close()
7177 - except IOError:
7178 - raise
7179 - for l in myl:
7180 - if l[:1] == "?":
7181 - continue
7182 - if l[:7] == ' >':
7183 - # tree conflict, new in subversion 1.6
7184 - continue
7185 - l = l.split()[-1]
7186 - if l[-7:] == ".ebuild":
7187 - self.eadded.append(os.path.basename(l[:-7]))
7188 - try:
7189 - myf = repoman_popen(
7190 - "svn status " +
7191 - portage._shell_quote(checkdir))
7192 - myl = myf.readlines()
7193 - myf.close()
7194 - except IOError:
7195 - raise
7196 - for l in myl:
7197 - if l[0] == "A":
7198 - l = l.rstrip().split(' ')[-1]
7199 - if l[-7:] == ".ebuild":
7200 - self.eadded.append(os.path.basename(l[:-7]))
7201 - return True
7202 -
7203 - def check_bzr(self, checkdir, checkdir_relative, xpkg):
7204 - try:
7205 - myf = repoman_popen(
7206 - "bzr ls -v --kind=file " +
7207 - portage._shell_quote(checkdir))
7208 - myl = myf.readlines()
7209 - myf.close()
7210 - except IOError:
7211 - raise
7212 - for l in myl:
7213 - if l[1:2] == "?":
7214 - continue
7215 - l = l.split()[-1]
7216 - if l[-7:] == ".ebuild":
7217 - self.eadded.append(os.path.basename(l[:-7]))
7218 - return True