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 |