Gentoo Archives: gentoo-commits

From: Magnus Granberg <zorry@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] proj/tinderbox-cluster:master commit in: tbc/pym/repoman/, tbc/pym/
Date: Tue, 28 Jul 2015 23:20:55
Message-Id: 1438125604.2bdca5ed5769380d7f839aa521f95afb51d7dbed.zorry@gentoo
1 commit: 2bdca5ed5769380d7f839aa521f95afb51d7dbed
2 Author: Magnus Granberg <zorry <AT> gentoo <DOT> org>
3 AuthorDate: Tue Jul 28 23:20:04 2015 +0000
4 Commit: Magnus Granberg <zorry <AT> gentoo <DOT> org>
5 CommitDate: Tue Jul 28 23:20:04 2015 +0000
6 URL: https://gitweb.gentoo.org/proj/tinderbox-cluster.git/commit/?id=2bdca5ed
7
8 add repoman_main()
9
10 tbc/pym/repoman/main.py | 2832 +++++++++++++++++++++++------------------------
11 tbc/pym/updatedb.py | 3 +-
12 2 files changed, 1418 insertions(+), 1417 deletions(-)
13
14 diff --git a/tbc/pym/repoman/main.py b/tbc/pym/repoman/main.py
15 index b346b66..c49bd2c 100755
16 --- a/tbc/pym/repoman/main.py
17 +++ b/tbc/pym/repoman/main.py
18 @@ -94,1543 +94,1543 @@ non_ascii_re = re.compile(r'[^\x00-\x7f]')
19
20 # A sane umask is needed for files that portage creates.
21 os.umask(0o22)
22 -# Repoman sets it's own ACCEPT_KEYWORDS and we don't want it to
23 -# behave incrementally.
24 -repoman_incrementals = tuple(
25 - x for x in portage.const.INCREMENTALS if x != 'ACCEPT_KEYWORDS')
26 -config_root = os.environ.get("PORTAGE_CONFIGROOT")
27 -repoman_settings = portage.config(config_root=config_root, local_config=False)
28 -
29 -if repoman_settings.get("NOCOLOR", "").lower() in ("yes", "true") or \
30 - repoman_settings.get('TERM') == 'dumb' or \
31 - not sys.stdout.isatty():
32 - nocolor()
33 -
34 -options, arguments = parse_args(
35 - sys.argv, qahelp, repoman_settings.get("REPOMAN_DEFAULT_OPTS", ""))
36 -
37 -if options.version:
38 - print("Portage", portage.VERSION)
39 - sys.exit(0)
40
41 -if options.experimental_inherit == 'y':
42 - # This is experimental, so it's non-fatal.
43 - qawarnings.add("inherit.missing")
44 - checks_init(experimental_inherit=True)
45 +def sort_key(item):
46 + return item[2].sub_path
47 +
48 +# Setup the GPG commands
49 +def gpgsign(filename):
50 + gpgcmd = repoman_settings.get("PORTAGE_GPG_SIGNING_COMMAND")
51 + if gpgcmd is None:
52 + raise MissingParameter(
53 + "PORTAGE_GPG_SIGNING_COMMAND is unset!"
54 + " Is make.globals missing?")
55 + if "${PORTAGE_GPG_KEY}" in gpgcmd and \
56 + "PORTAGE_GPG_KEY" not in repoman_settings:
57 + raise MissingParameter("PORTAGE_GPG_KEY is unset!")
58 + if "${PORTAGE_GPG_DIR}" in gpgcmd:
59 + if "PORTAGE_GPG_DIR" not in repoman_settings:
60 + repoman_settings["PORTAGE_GPG_DIR"] = \
61 + os.path.expanduser("~/.gnupg")
62 + logging.info(
63 + "Automatically setting PORTAGE_GPG_DIR to '%s'" %
64 + repoman_settings["PORTAGE_GPG_DIR"])
65 + else:
66 + repoman_settings["PORTAGE_GPG_DIR"] = \
67 + os.path.expanduser(repoman_settings["PORTAGE_GPG_DIR"])
68 + if not os.access(repoman_settings["PORTAGE_GPG_DIR"], os.X_OK):
69 + raise portage.exception.InvalidLocation(
70 + "Unable to access directory: PORTAGE_GPG_DIR='%s'" %
71 + repoman_settings["PORTAGE_GPG_DIR"])
72 + gpgvars = {"FILE": filename}
73 + for k in ("PORTAGE_GPG_DIR", "PORTAGE_GPG_KEY"):
74 + v = repoman_settings.get(k)
75 + if v is not None:
76 + gpgvars[k] = v
77 + gpgcmd = portage.util.varexpand(gpgcmd, mydict=gpgvars)
78 + if options.pretend:
79 + print("(" + gpgcmd + ")")
80 + else:
81 + # Encode unicode manually for bug #310789.
82 + gpgcmd = portage.util.shlex_split(gpgcmd)
83 +
84 + if sys.hexversion < 0x3020000 and sys.hexversion >= 0x3000000 and \
85 + not os.path.isabs(gpgcmd[0]):
86 + # Python 3.1 _execvp throws TypeError for non-absolute executable
87 + # path passed as bytes (see http://bugs.python.org/issue8513).
88 + fullname = find_binary(gpgcmd[0])
89 + if fullname is None:
90 + raise portage.exception.CommandNotFound(gpgcmd[0])
91 + gpgcmd[0] = fullname
92 +
93 + gpgcmd = [
94 + _unicode_encode(arg, encoding=_encodings['fs'], errors='strict')
95 + for arg in gpgcmd]
96 + rValue = subprocess.call(gpgcmd)
97 + if rValue == os.EX_OK:
98 + os.rename(filename + ".asc", filename)
99 + else:
100 + raise portage.exception.PortageException(
101 + "!!! gpg exited with '" + str(rValue) + "' status")
102 +
103 +def need_signature(filename):
104 + try:
105 + with open(
106 + _unicode_encode(
107 + filename, encoding=_encodings['fs'], errors='strict'),
108 + 'rb') as f:
109 + return b"BEGIN PGP SIGNED MESSAGE" not in f.readline()
110 + except IOError as e:
111 + if e.errno in (errno.ENOENT, errno.ESTALE):
112 + return False
113 + raise
114 +
115 +def repoman_main(argv):
116 + # Repoman sets it's own ACCEPT_KEYWORDS and we don't want it to
117 + # behave incrementally.
118 + repoman_incrementals = tuple(
119 + x for x in portage.const.INCREMENTALS if x != 'ACCEPT_KEYWORDS')
120 + config_root = os.environ.get("PORTAGE_CONFIGROOT")
121 + repoman_settings = portage.config(config_root=config_root, local_config=False)
122 +
123 + if repoman_settings.get("NOCOLOR", "").lower() in ("yes", "true") or \
124 + repoman_settings.get('TERM') == 'dumb' or \
125 + not sys.stdout.isatty():
126 + nocolor()
127 +
128 + options, arguments = parse_args(
129 + argv, qahelp, repoman_settings.get("REPOMAN_DEFAULT_OPTS", ""))
130 +
131 + if options.version:
132 + print("Portage", portage.VERSION)
133 + sys.exit(0)
134 +
135 + if options.experimental_inherit == 'y':
136 + # This is experimental, so it's non-fatal.
137 + qawarnings.add("inherit.missing")
138 + checks_init(experimental_inherit=True)
139 +
140 + # Set this to False when an extraordinary issue (generally
141 + # something other than a QA issue) makes it impossible to
142 + # commit (like if Manifest generation fails).
143 + can_force = True
144 +
145 + portdir, portdir_overlay, mydir = utilities.FindPortdir(repoman_settings)
146 + if portdir is None:
147 + sys.exit(1)
148
149 -# Set this to False when an extraordinary issue (generally
150 -# something other than a QA issue) makes it impossible to
151 -# commit (like if Manifest generation fails).
152 -can_force = True
153 + myreporoot = os.path.basename(portdir_overlay)
154 + myreporoot += mydir[len(portdir_overlay):]
155 + ##################
156
157 -portdir, portdir_overlay, mydir = utilities.FindPortdir(repoman_settings)
158 -if portdir is None:
159 - sys.exit(1)
160 + vcs_settings = VCSSettings(options, repoman_settings)
161
162 -myreporoot = os.path.basename(portdir_overlay)
163 -myreporoot += mydir[len(portdir_overlay):]
164 -##################
165 + ##################
166
167 -vcs_settings = VCSSettings(options, repoman_settings)
168 + repo_settings = RepoSettings(
169 + config_root, portdir, portdir_overlay,
170 + repoman_settings, vcs_settings, options, qawarnings)
171
172 + repoman_settings = repo_settings.repoman_settings
173
174 -##################
175 + portdb = repo_settings.portdb
176 + ##################
177
178 -repo_settings = RepoSettings(
179 - config_root, portdir, portdir_overlay,
180 - repoman_settings, vcs_settings, options, qawarnings)
181 + if options.echangelog is None and repo_settings.repo_config.update_changelog:
182 + options.echangelog = 'y'
183
184 -repoman_settings = repo_settings.repoman_settings
185 + if vcs_settings.vcs is None:
186 + options.echangelog = 'n'
187
188 -portdb = repo_settings.portdb
189 -##################
190 + # The --echangelog option causes automatic ChangeLog generation,
191 + # which invalidates changelog.ebuildadded and changelog.missing
192 + # checks.
193 + # Note: Some don't use ChangeLogs in distributed SCMs.
194 + # It will be generated on server side from scm log,
195 + # before package moves to the rsync server.
196 + # This is needed because they try to avoid merge collisions.
197 + # Gentoo's Council decided to always use the ChangeLog file.
198 + # TODO: shouldn't this just be switched on the repo, iso the VCS?
199 + is_echangelog_enabled = options.echangelog in ('y', 'force')
200 + vcs_settings.vcs_is_cvs_or_svn = vcs_settings.vcs in ('cvs', 'svn')
201 + check_changelog = not is_echangelog_enabled and vcs_settings.vcs_is_cvs_or_svn
202
203 + if 'digest' in repoman_settings.features and options.digest != 'n':
204 + options.digest = 'y'
205
206 -if options.echangelog is None and repo_settings.repo_config.update_changelog:
207 - options.echangelog = 'y'
208 + logging.debug("vcs: %s" % (vcs_settings.vcs,))
209 + logging.debug("repo config: %s" % (repo_settings.repo_config,))
210 + logging.debug("options: %s" % (options,))
211
212 -if vcs_settings.vcs is None:
213 - options.echangelog = 'n'
214 + # It's confusing if these warnings are displayed without the user
215 + # being told which profile they come from, so disable them.
216 + env = os.environ.copy()
217 + env['FEATURES'] = env.get('FEATURES', '') + ' -unknown-features-warn'
218
219 -# The --echangelog option causes automatic ChangeLog generation,
220 -# which invalidates changelog.ebuildadded and changelog.missing
221 -# checks.
222 -# Note: Some don't use ChangeLogs in distributed SCMs.
223 -# It will be generated on server side from scm log,
224 -# before package moves to the rsync server.
225 -# This is needed because they try to avoid merge collisions.
226 -# Gentoo's Council decided to always use the ChangeLog file.
227 -# TODO: shouldn't this just be switched on the repo, iso the VCS?
228 -is_echangelog_enabled = options.echangelog in ('y', 'force')
229 -vcs_settings.vcs_is_cvs_or_svn = vcs_settings.vcs in ('cvs', 'svn')
230 -check_changelog = not is_echangelog_enabled and vcs_settings.vcs_is_cvs_or_svn
231 + categories = []
232 + for path in repo_settings.repo_config.eclass_db.porttrees:
233 + categories.extend(portage.util.grabfile(
234 + os.path.join(path, 'profiles', 'categories')))
235 + repoman_settings.categories = frozenset(
236 + portage.util.stack_lists([categories], incremental=1))
237 + categories = repoman_settings.categories
238
239 -if 'digest' in repoman_settings.features and options.digest != 'n':
240 - options.digest = 'y'
241 + portdb.settings = repoman_settings
242 + # We really only need to cache the metadata that's necessary for visibility
243 + # filtering. Anything else can be discarded to reduce memory consumption.
244 + portdb._aux_cache_keys.clear()
245 + portdb._aux_cache_keys.update(
246 + ["EAPI", "IUSE", "KEYWORDS", "repository", "SLOT"])
247
248 -logging.debug("vcs: %s" % (vcs_settings.vcs,))
249 -logging.debug("repo config: %s" % (repo_settings.repo_config,))
250 -logging.debug("options: %s" % (options,))
251 + reposplit = myreporoot.split(os.path.sep)
252 + repolevel = len(reposplit)
253
254 -# It's confusing if these warnings are displayed without the user
255 -# being told which profile they come from, so disable them.
256 -env = os.environ.copy()
257 -env['FEATURES'] = env.get('FEATURES', '') + ' -unknown-features-warn'
258 + ###################
259
260 -categories = []
261 -for path in repo_settings.repo_config.eclass_db.porttrees:
262 - categories.extend(portage.util.grabfile(
263 - os.path.join(path, 'profiles', 'categories')))
264 -repoman_settings.categories = frozenset(
265 - portage.util.stack_lists([categories], incremental=1))
266 -categories = repoman_settings.categories
267 + if options.mode == 'commit':
268 + repochecks.commit_check(repolevel, reposplit)
269 + repochecks.conflict_check(vcs_settings, options)
270
271 -portdb.settings = repoman_settings
272 -# We really only need to cache the metadata that's necessary for visibility
273 -# filtering. Anything else can be discarded to reduce memory consumption.
274 -portdb._aux_cache_keys.clear()
275 -portdb._aux_cache_keys.update(
276 - ["EAPI", "IUSE", "KEYWORDS", "repository", "SLOT"])
277 + ###################
278
279 -reposplit = myreporoot.split(os.path.sep)
280 -repolevel = len(reposplit)
281 + # Make startdir relative to the canonical repodir, so that we can pass
282 + # it to digestgen and it won't have to be canonicalized again.
283 + if repolevel == 1:
284 + startdir = repo_settings.repodir
285 + else:
286 + startdir = normalize_path(mydir)
287 + startdir = os.path.join(
288 + repo_settings.repodir, *startdir.split(os.sep)[-2 - repolevel + 3:])
289 + ###################
290
291 -###################
292 + # get lists of valid keywords, licenses, and use
293 + new_data = repo_metadata(repo_settings.portdb, repoman_settings)
294 + kwlist, liclist, uselist, profile_list, \
295 + global_pmaskdict, liclist_deprecated = new_data
296
297 -if options.mode == 'commit':
298 - repochecks.commit_check(repolevel, reposplit)
299 - repochecks.conflict_check(vcs_settings, options)
300 + repoman_settings['PORTAGE_ARCHLIST'] = ' '.join(sorted(kwlist))
301 + repoman_settings.backup_changes('PORTAGE_ARCHLIST')
302
303 -###################
304 + ####################
305
306 -# Make startdir relative to the canonical repodir, so that we can pass
307 -# it to digestgen and it won't have to be canonicalized again.
308 -if repolevel == 1:
309 - startdir = repo_settings.repodir
310 -else:
311 - startdir = normalize_path(mydir)
312 - startdir = os.path.join(
313 - repo_settings.repodir, *startdir.split(os.sep)[-2 - repolevel + 3:])
314 -###################
315 -
316 -# get lists of valid keywords, licenses, and use
317 -new_data = repo_metadata(repo_settings.portdb, repoman_settings)
318 -kwlist, liclist, uselist, profile_list, \
319 - global_pmaskdict, liclist_deprecated = new_data
320 -
321 -repoman_settings['PORTAGE_ARCHLIST'] = ' '.join(sorted(kwlist))
322 -repoman_settings.backup_changes('PORTAGE_ARCHLIST')
323 -
324 -####################
325 -
326 -profiles = setup_profile(profile_list)
327 -
328 -####################
329 -
330 -check_profiles(profiles, repoman_settings.archlist())
331 -
332 -####################
333 -
334 -scanlist = scan(repolevel, reposplit, startdir, categories, repo_settings)
335 -
336 -####################
337 -
338 -dev_keywords = dev_keywords(profiles)
339 -
340 -qatracker = QATracker()
341 -
342 -
343 -if options.mode == "manifest":
344 - pass
345 -elif options.pretend:
346 - print(green("\nRepoMan does a once-over of the neighborhood..."))
347 -else:
348 - print(green("\nRepoMan scours the neighborhood..."))
349 -
350 -#####################
351 -
352 -changed = Changes(options)
353 -changed.scan(vcs_settings)
354 -
355 -######################
356 -
357 -have_pmasked = False
358 -have_dev_keywords = False
359 -dofail = 0
360 -
361 -# NOTE: match-all caches are not shared due to potential
362 -# differences between profiles in _get_implicit_iuse.
363 -arch_caches = {}
364 -arch_xmatch_caches = {}
365 -shared_xmatch_caches = {"cp-list": {}}
366 -
367 -include_arches = None
368 -if options.include_arches:
369 - include_arches = set()
370 - include_arches.update(*[x.split() for x in options.include_arches])
371 -
372 -# Disable the "ebuild.notadded" check when not in commit mode and
373 -# running `svn status` in every package dir will be too expensive.
374 -
375 -check_ebuild_notadded = not \
376 - (vcs_settings.vcs == "svn" and repolevel < 3 and options.mode != "commit")
377 -
378 -effective_scanlist = scanlist
379 -if options.if_modified == "y":
380 - effective_scanlist = sorted(vcs_files_to_cps(
381 - chain(changed.changed, changed.new, changed.removed),
382 - repolevel, reposplit, categories))
383 -
384 -######################
385 -# initialize our checks classes here before the big xpkg loop
386 -manifester = Manifests(options, qatracker, repoman_settings)
387 -is_ebuild = IsEbuild(repoman_settings, repo_settings, portdb, qatracker)
388 -filescheck = FileChecks(
389 - qatracker, repoman_settings, repo_settings, portdb, vcs_settings)
390 -status_check = VCSStatus(vcs_settings, qatracker)
391 -fetchcheck = FetchChecks(
392 - qatracker, repoman_settings, repo_settings, portdb, vcs_settings)
393 -pkgmeta = PkgMetadata(options, qatracker, repoman_settings)
394 -thirdparty = ThirdPartyMirrors(repoman_settings, qatracker)
395 -use_flag_checks = USEFlagChecks(qatracker, uselist)
396 -keywordcheck = KeywordChecks(qatracker)
397 -liveeclasscheck = LiveEclassChecks(qatracker)
398 -rubyeclasscheck = RubyEclassChecks(qatracker)
399 -eapicheck = EAPIChecks(qatracker, repo_settings)
400 -descriptioncheck = DescriptionChecks(qatracker)
401 -licensecheck = LicenseChecks(qatracker, liclist, liclist_deprecated)
402 -restrictcheck = RestrictChecks(qatracker)
403 -######################
404 -
405 -for xpkg in effective_scanlist:
406 - # ebuilds and digests added to cvs respectively.
407 - logging.info("checking package %s" % xpkg)
408 - # save memory by discarding xmatch caches from previous package(s)
409 - arch_xmatch_caches.clear()
410 - eadded = []
411 - catdir, pkgdir = xpkg.split("/")
412 - checkdir = repo_settings.repodir + "/" + xpkg
413 - checkdir_relative = ""
414 - if repolevel < 3:
415 - checkdir_relative = os.path.join(pkgdir, checkdir_relative)
416 - if repolevel < 2:
417 - checkdir_relative = os.path.join(catdir, checkdir_relative)
418 - checkdir_relative = os.path.join(".", checkdir_relative)
419 -
420 -#####################
421 - if manifester.run(checkdir, portdb):
422 - continue
423 - if not manifester.generated_manifest:
424 - manifester.digest_check(xpkg, checkdir)
425 -######################
426 -
427 - if options.mode == 'manifest-check':
428 - continue
429 -
430 - checkdirlist = os.listdir(checkdir)
431 -
432 -######################
433 - pkgs, allvalid = is_ebuild.check(checkdirlist, checkdir, xpkg)
434 - if is_ebuild.continue_:
435 - # If we can't access all the metadata then it's totally unsafe to
436 - # commit since there's no way to generate a correct Manifest.
437 - # Do not try to do any more QA checks on this package since missing
438 - # metadata leads to false positives for several checks, and false
439 - # positives confuse users.
440 - can_force = False
441 - continue
442 -######################
443 -
444 - keywordcheck.prepare()
445 -
446 - # Sort ebuilds in ascending order for the KEYWORDS.dropped check.
447 - ebuildlist = sorted(pkgs.values())
448 - ebuildlist = [pkg.pf for pkg in ebuildlist]
449 -#######################
450 - filescheck.check(
451 - checkdir, checkdirlist, checkdir_relative, changed.changed, changed.new)
452 -#######################
453 - status_check.check(check_ebuild_notadded, checkdir, checkdir_relative, xpkg)
454 - eadded.extend(status_check.eadded)
455 -
456 -#################
457 - fetchcheck.check(
458 - xpkg, checkdir, checkdir_relative, changed.changed, changed.new)
459 -#################
460 -
461 - if check_changelog and "ChangeLog" not in checkdirlist:
462 - qatracker.add_error("changelog.missing", xpkg + "/ChangeLog")
463 -#################
464 - pkgmeta.check(xpkg, checkdir, checkdirlist, repolevel)
465 - muselist = frozenset(pkgmeta.musedict)
466 -#################
467 -
468 - changelog_path = os.path.join(checkdir_relative, "ChangeLog")
469 - changelog_modified = changelog_path in changed.changelogs
470 -
471 - # detect unused local USE-descriptions
472 - used_useflags = set()
473 -
474 - for y_ebuild in ebuildlist:
475 - ##################
476 - ebuild = Ebuild(
477 - repo_settings, repolevel, pkgdir, catdir, vcs_settings,
478 - xpkg, y_ebuild)
479 - ##################
480 -
481 - if check_changelog and not changelog_modified \
482 - and ebuild.ebuild_path in changed.new_ebuilds:
483 - qatracker.add_error('changelog.ebuildadded', ebuild.relative_path)
484 -
485 - if ebuild.untracked(check_ebuild_notadded, y_ebuild, eadded):
486 - # ebuild not added to vcs
487 - qatracker.add_error(
488 - "ebuild.notadded", xpkg + "/" + y_ebuild + ".ebuild")
489 -
490 -##################
491 - if bad_split_check(xpkg, y_ebuild, pkgdir, qatracker):
492 - continue
493 -###################
494 - pkg = pkgs[y_ebuild]
495 - if pkg_invalid(pkg, qatracker, ebuild):
496 - allvalid = False
497 + profiles = setup_profile(profile_list)
498 +
499 + ####################
500 +
501 + check_profiles(profiles, repoman_settings.archlist())
502 +
503 + ####################
504 +
505 + scanlist = scan(repolevel, reposplit, startdir, categories, repo_settings)
506 +
507 + ####################
508 +
509 + dev_keywords = dev_keywords(profiles)
510 +
511 + qatracker = QATracker()
512 +
513 +
514 + if options.mode == "manifest":
515 + pass
516 + elif options.pretend:
517 + print(green("\nRepoMan does a once-over of the neighborhood..."))
518 + else:
519 + print(green("\nRepoMan scours the neighborhood..."))
520 +
521 + #####################
522 +
523 + changed = Changes(options)
524 + changed.scan(vcs_settings)
525 +
526 + ######################
527 +
528 + have_pmasked = False
529 + have_dev_keywords = False
530 + dofail = 0
531 +
532 + # NOTE: match-all caches are not shared due to potential
533 + # differences between profiles in _get_implicit_iuse.
534 + arch_caches = {}
535 + arch_xmatch_caches = {}
536 + shared_xmatch_caches = {"cp-list": {}}
537 +
538 + include_arches = None
539 + if options.include_arches:
540 + include_arches = set()
541 + include_arches.update(*[x.split() for x in options.include_arches])
542 +
543 + # Disable the "ebuild.notadded" check when not in commit mode and
544 + # running `svn status` in every package dir will be too expensive.
545 +
546 + check_ebuild_notadded = not \
547 + (vcs_settings.vcs == "svn" and repolevel < 3 and options.mode != "commit")
548 +
549 + effective_scanlist = scanlist
550 + if options.if_modified == "y":
551 + effective_scanlist = sorted(vcs_files_to_cps(
552 + chain(changed.changed, changed.new, changed.removed),
553 + repolevel, reposplit, categories))
554 +
555 + ######################
556 + # initialize our checks classes here before the big xpkg loop
557 + manifester = Manifests(options, qatracker, repoman_settings)
558 + is_ebuild = IsEbuild(repoman_settings, repo_settings, portdb, qatracker)
559 + filescheck = FileChecks(
560 + qatracker, repoman_settings, repo_settings, portdb, vcs_settings)
561 + status_check = VCSStatus(vcs_settings, qatracker)
562 + fetchcheck = FetchChecks(
563 + qatracker, repoman_settings, repo_settings, portdb, vcs_settings)
564 + pkgmeta = PkgMetadata(options, qatracker, repoman_settings)
565 + thirdparty = ThirdPartyMirrors(repoman_settings, qatracker)
566 + use_flag_checks = USEFlagChecks(qatracker, uselist)
567 + keywordcheck = KeywordChecks(qatracker)
568 + liveeclasscheck = LiveEclassChecks(qatracker)
569 + rubyeclasscheck = RubyEclassChecks(qatracker)
570 + eapicheck = EAPIChecks(qatracker, repo_settings)
571 + descriptioncheck = DescriptionChecks(qatracker)
572 + licensecheck = LicenseChecks(qatracker, liclist, liclist_deprecated)
573 + restrictcheck = RestrictChecks(qatracker)
574 + ######################
575 +
576 + for xpkg in effective_scanlist:
577 + # ebuilds and digests added to cvs respectively.
578 + logging.info("checking package %s" % xpkg)
579 + # save memory by discarding xmatch caches from previous package(s)
580 + arch_xmatch_caches.clear()
581 + eadded = []
582 + catdir, pkgdir = xpkg.split("/")
583 + checkdir = repo_settings.repodir + "/" + xpkg
584 + checkdir_relative = ""
585 + if repolevel < 3:
586 + checkdir_relative = os.path.join(pkgdir, checkdir_relative)
587 + if repolevel < 2:
588 + checkdir_relative = os.path.join(catdir, checkdir_relative)
589 + checkdir_relative = os.path.join(".", checkdir_relative)
590 +
591 + #####################
592 + if manifester.run(checkdir, portdb):
593 continue
594 + if not manifester.generated_manifest:
595 + manifester.digest_check(xpkg, checkdir)
596 + ######################
597
598 - myaux = pkg._metadata
599 - eapi = myaux["EAPI"]
600 - inherited = pkg.inherited
601 - live_ebuild = live_eclasses.intersection(inherited)
602 + if options.mode == 'manifest-check':
603 + continue
604
605 - #######################
606 - eapicheck.check(pkg, ebuild)
607 - #######################
608 + checkdirlist = os.listdir(checkdir)
609 +
610 + ######################
611 + pkgs, allvalid = is_ebuild.check(checkdirlist, checkdir, xpkg)
612 + if is_ebuild.continue_:
613 + # If we can't access all the metadata then it's totally unsafe to
614 + # commit since there's no way to generate a correct Manifest.
615 + # Do not try to do any more QA checks on this package since missing
616 + # metadata leads to false positives for several checks, and false
617 + # positives confuse users.
618 + can_force = False
619 + continue
620 + ######################
621 +
622 + keywordcheck.prepare()
623 +
624 + # Sort ebuilds in ascending order for the KEYWORDS.dropped check.
625 + ebuildlist = sorted(pkgs.values())
626 + ebuildlist = [pkg.pf for pkg in ebuildlist]
627 + #######################
628 + filescheck.check(
629 + checkdir, checkdirlist, checkdir_relative, changed.changed, changed.new)
630 + #######################
631 + status_check.check(check_ebuild_notadded, checkdir, checkdir_relative, xpkg)
632 + eadded.extend(status_check.eadded)
633 +
634 + #################
635 + fetchcheck.check(
636 + xpkg, checkdir, checkdir_relative, changed.changed, changed.new)
637 + #################
638 +
639 + if check_changelog and "ChangeLog" not in checkdirlist:
640 + qatracker.add_error("changelog.missing", xpkg + "/ChangeLog")
641 + #################
642 + pkgmeta.check(xpkg, checkdir, checkdirlist, repolevel)
643 + muselist = frozenset(pkgmeta.musedict)
644 + #################
645 +
646 + changelog_path = os.path.join(checkdir_relative, "ChangeLog")
647 + changelog_modified = changelog_path in changed.changelogs
648 +
649 + # detect unused local USE-descriptions
650 + used_useflags = set()
651 +
652 + for y_ebuild in ebuildlist:
653 + ##################
654 + ebuild = Ebuild(
655 + repo_settings, repolevel, pkgdir, catdir, vcs_settings,
656 + xpkg, y_ebuild)
657 + ##################
658 +
659 + if check_changelog and not changelog_modified \
660 + and ebuild.ebuild_path in changed.new_ebuilds:
661 + qatracker.add_error('changelog.ebuildadded', ebuild.relative_path)
662 +
663 + if ebuild.untracked(check_ebuild_notadded, y_ebuild, eadded):
664 + # ebuild not added to vcs
665 + qatracker.add_error(
666 + "ebuild.notadded", xpkg + "/" + y_ebuild + ".ebuild")
667
668 - for k, v in myaux.items():
669 - if not isinstance(v, basestring):
670 + ##################
671 + if bad_split_check(xpkg, y_ebuild, pkgdir, qatracker):
672 continue
673 - m = non_ascii_re.search(v)
674 - if m is not None:
675 - qatracker.add_error(
676 - "variable.invalidchar",
677 - "%s: %s variable contains non-ASCII "
678 - "character at position %s" %
679 - (ebuild.relative_path, k, m.start() + 1))
680 + ###################
681 + pkg = pkgs[y_ebuild]
682 + if pkg_invalid(pkg, qatracker, ebuild):
683 + allvalid = False
684 + continue
685 +
686 + myaux = pkg._metadata
687 + eapi = myaux["EAPI"]
688 + inherited = pkg.inherited
689 + live_ebuild = live_eclasses.intersection(inherited)
690
691 - if not fetchcheck.src_uri_error:
692 #######################
693 - thirdparty.check(myaux, ebuild.relative_path)
694 + eapicheck.check(pkg, ebuild)
695 #######################
696 - if myaux.get("PROVIDE"):
697 - qatracker.add_error("virtual.oldstyle", ebuild.relative_path)
698
699 - for pos, missing_var in enumerate(missingvars):
700 - if not myaux.get(missing_var):
701 - if catdir == "virtual" and \
702 - missing_var in ("HOMEPAGE", "LICENSE"):
703 + for k, v in myaux.items():
704 + if not isinstance(v, basestring):
705 continue
706 - if live_ebuild and missing_var == "KEYWORDS":
707 - continue
708 - myqakey = missingvars[pos] + ".missing"
709 - qatracker.add_error(myqakey, xpkg + "/" + y_ebuild + ".ebuild")
710 -
711 - if catdir == "virtual":
712 - for var in ("HOMEPAGE", "LICENSE"):
713 - if myaux.get(var):
714 - myqakey = var + ".virtual"
715 - qatracker.add_error(myqakey, ebuild.relative_path)
716 + m = non_ascii_re.search(v)
717 + if m is not None:
718 + qatracker.add_error(
719 + "variable.invalidchar",
720 + "%s: %s variable contains non-ASCII "
721 + "character at position %s" %
722 + (ebuild.relative_path, k, m.start() + 1))
723 +
724 + if not fetchcheck.src_uri_error:
725 + #######################
726 + thirdparty.check(myaux, ebuild.relative_path)
727 + #######################
728 + if myaux.get("PROVIDE"):
729 + qatracker.add_error("virtual.oldstyle", ebuild.relative_path)
730 +
731 + for pos, missing_var in enumerate(missingvars):
732 + if not myaux.get(missing_var):
733 + if catdir == "virtual" and \
734 + missing_var in ("HOMEPAGE", "LICENSE"):
735 + continue
736 + if live_ebuild and missing_var == "KEYWORDS":
737 + continue
738 + myqakey = missingvars[pos] + ".missing"
739 + qatracker.add_error(myqakey, xpkg + "/" + y_ebuild + ".ebuild")
740
741 - #######################
742 - descriptioncheck.check(pkg, ebuild)
743 - #######################
744 + if catdir == "virtual":
745 + for var in ("HOMEPAGE", "LICENSE"):
746 + if myaux.get(var):
747 + myqakey = var + ".virtual"
748 + qatracker.add_error(myqakey, ebuild.relative_path)
749
750 - keywords = myaux["KEYWORDS"].split()
751 + #######################
752 + descriptioncheck.check(pkg, ebuild)
753 + #######################
754
755 - ebuild_archs = set(
756 - kw.lstrip("~") for kw in keywords if not kw.startswith("-"))
757 + keywords = myaux["KEYWORDS"].split()
758
759 - #######################
760 - keywordcheck.check(
761 - pkg, xpkg, ebuild, y_ebuild, keywords, ebuild_archs, changed,
762 - live_ebuild, kwlist, profiles)
763 - #######################
764 + ebuild_archs = set(
765 + kw.lstrip("~") for kw in keywords if not kw.startswith("-"))
766
767 - if live_ebuild and repo_settings.repo_config.name == "gentoo":
768 #######################
769 - liveeclasscheck.check(
770 - pkg, xpkg, ebuild, y_ebuild, keywords, global_pmaskdict)
771 + keywordcheck.check(
772 + pkg, xpkg, ebuild, y_ebuild, keywords, ebuild_archs, changed,
773 + live_ebuild, kwlist, profiles)
774 #######################
775
776 - if options.ignore_arches:
777 - arches = [[
778 - repoman_settings["ARCH"], repoman_settings["ARCH"],
779 - repoman_settings["ACCEPT_KEYWORDS"].split()]]
780 - else:
781 - arches = set()
782 - for keyword in keywords:
783 - if keyword[0] == "-":
784 - continue
785 - elif keyword[0] == "~":
786 - arch = keyword[1:]
787 - if arch == "*":
788 - for expanded_arch in profiles:
789 - if expanded_arch == "**":
790 - continue
791 - arches.add(
792 - (keyword, expanded_arch, (
793 - expanded_arch, "~" + expanded_arch)))
794 - else:
795 - arches.add((keyword, arch, (arch, keyword)))
796 - else:
797 - if keyword == "*":
798 - for expanded_arch in profiles:
799 - if expanded_arch == "**":
800 - continue
801 - arches.add(
802 - (keyword, expanded_arch, (expanded_arch,)))
803 - else:
804 - arches.add((keyword, keyword, (keyword,)))
805 - if not arches:
806 - # Use an empty profile for checking dependencies of
807 - # packages that have empty KEYWORDS.
808 - arches.add(('**', '**', ('**',)))
809 -
810 - unknown_pkgs = set()
811 - baddepsyntax = False
812 - badlicsyntax = False
813 - badprovsyntax = False
814 - catpkg = catdir + "/" + y_ebuild
815 -
816 - inherited_java_eclass = "java-pkg-2" in inherited or \
817 - "java-pkg-opt-2" in inherited
818 - inherited_wxwidgets_eclass = "wxwidgets" in inherited
819 - operator_tokens = set(["||", "(", ")"])
820 - type_list, badsyntax = [], []
821 - for mytype in Package._dep_keys + ("LICENSE", "PROPERTIES", "PROVIDE"):
822 - mydepstr = myaux[mytype]
823 -
824 - buildtime = mytype in Package._buildtime_keys
825 - runtime = mytype in Package._runtime_keys
826 - token_class = None
827 - if mytype.endswith("DEPEND"):
828 - token_class = portage.dep.Atom
829 + if live_ebuild and repo_settings.repo_config.name == "gentoo":
830 + #######################
831 + liveeclasscheck.check(
832 + pkg, xpkg, ebuild, y_ebuild, keywords, global_pmaskdict)
833 + #######################
834
835 - try:
836 - atoms = portage.dep.use_reduce(
837 - mydepstr, matchall=1, flat=True,
838 - is_valid_flag=pkg.iuse.is_valid_flag, token_class=token_class)
839 - except portage.exception.InvalidDependString as e:
840 - atoms = None
841 - badsyntax.append(str(e))
842 -
843 - if atoms and mytype.endswith("DEPEND"):
844 - if runtime and \
845 - "test?" in mydepstr.split():
846 - qatracker.add_error(
847 - mytype + '.suspect',
848 - "%s: 'test?' USE conditional in %s" %
849 - (ebuild.relative_path, mytype))
850 -
851 - for atom in atoms:
852 - if atom == "||":
853 + if options.ignore_arches:
854 + arches = [[
855 + repoman_settings["ARCH"], repoman_settings["ARCH"],
856 + repoman_settings["ACCEPT_KEYWORDS"].split()]]
857 + else:
858 + arches = set()
859 + for keyword in keywords:
860 + if keyword[0] == "-":
861 continue
862 + elif keyword[0] == "~":
863 + arch = keyword[1:]
864 + if arch == "*":
865 + for expanded_arch in profiles:
866 + if expanded_arch == "**":
867 + continue
868 + arches.add(
869 + (keyword, expanded_arch, (
870 + expanded_arch, "~" + expanded_arch)))
871 + else:
872 + arches.add((keyword, arch, (arch, keyword)))
873 + else:
874 + if keyword == "*":
875 + for expanded_arch in profiles:
876 + if expanded_arch == "**":
877 + continue
878 + arches.add(
879 + (keyword, expanded_arch, (expanded_arch,)))
880 + else:
881 + arches.add((keyword, keyword, (keyword,)))
882 + if not arches:
883 + # Use an empty profile for checking dependencies of
884 + # packages that have empty KEYWORDS.
885 + arches.add(('**', '**', ('**',)))
886 +
887 + unknown_pkgs = set()
888 + baddepsyntax = False
889 + badlicsyntax = False
890 + badprovsyntax = False
891 + catpkg = catdir + "/" + y_ebuild
892 +
893 + inherited_java_eclass = "java-pkg-2" in inherited or \
894 + "java-pkg-opt-2" in inherited
895 + inherited_wxwidgets_eclass = "wxwidgets" in inherited
896 + operator_tokens = set(["||", "(", ")"])
897 + type_list, badsyntax = [], []
898 + for mytype in Package._dep_keys + ("LICENSE", "PROPERTIES", "PROVIDE"):
899 + mydepstr = myaux[mytype]
900 +
901 + buildtime = mytype in Package._buildtime_keys
902 + runtime = mytype in Package._runtime_keys
903 + token_class = None
904 + if mytype.endswith("DEPEND"):
905 + token_class = portage.dep.Atom
906 +
907 + try:
908 + atoms = portage.dep.use_reduce(
909 + mydepstr, matchall=1, flat=True,
910 + is_valid_flag=pkg.iuse.is_valid_flag, token_class=token_class)
911 + except portage.exception.InvalidDependString as e:
912 + atoms = None
913 + badsyntax.append(str(e))
914 +
915 + if atoms and mytype.endswith("DEPEND"):
916 + if runtime and \
917 + "test?" in mydepstr.split():
918 + qatracker.add_error(
919 + mytype + '.suspect',
920 + "%s: 'test?' USE conditional in %s" %
921 + (ebuild.relative_path, mytype))
922
923 - is_blocker = atom.blocker
924 + for atom in atoms:
925 + if atom == "||":
926 + continue
927
928 - # Skip dependency.unknown for blockers, so that we
929 - # don't encourage people to remove necessary blockers,
930 - # as discussed in bug #382407.
931 - if not is_blocker and \
932 - not portdb.xmatch("match-all", atom) and \
933 - not atom.cp.startswith("virtual/"):
934 - unknown_pkgs.add((mytype, atom.unevaluated_atom))
935 + is_blocker = atom.blocker
936
937 - if catdir != "virtual":
938 + # Skip dependency.unknown for blockers, so that we
939 + # don't encourage people to remove necessary blockers,
940 + # as discussed in bug #382407.
941 if not is_blocker and \
942 - atom.cp in suspect_virtual:
943 + not portdb.xmatch("match-all", atom) and \
944 + not atom.cp.startswith("virtual/"):
945 + unknown_pkgs.add((mytype, atom.unevaluated_atom))
946 +
947 + if catdir != "virtual":
948 + if not is_blocker and \
949 + atom.cp in suspect_virtual:
950 + qatracker.add_error(
951 + 'virtual.suspect', ebuild.relative_path +
952 + ": %s: consider using '%s' instead of '%s'" %
953 + (mytype, suspect_virtual[atom.cp], atom))
954 + if not is_blocker and \
955 + atom.cp.startswith("perl-core/"):
956 + qatracker.add_error('dependency.perlcore',
957 + ebuild.relative_path +
958 + ": %s: please use '%s' instead of '%s'" %
959 + (mytype,
960 + atom.replace("perl-core/","virtual/perl-"),
961 + atom))
962 +
963 + if buildtime and \
964 + not is_blocker and \
965 + not inherited_java_eclass and \
966 + atom.cp == "virtual/jdk":
967 qatracker.add_error(
968 - 'virtual.suspect', ebuild.relative_path +
969 - ": %s: consider using '%s' instead of '%s'" %
970 - (mytype, suspect_virtual[atom.cp], atom))
971 - if not is_blocker and \
972 - atom.cp.startswith("perl-core/"):
973 - qatracker.add_error('dependency.perlcore',
974 - ebuild.relative_path +
975 - ": %s: please use '%s' instead of '%s'" %
976 - (mytype,
977 - atom.replace("perl-core/","virtual/perl-"),
978 - atom))
979 -
980 - if buildtime and \
981 - not is_blocker and \
982 - not inherited_java_eclass and \
983 - atom.cp == "virtual/jdk":
984 - qatracker.add_error(
985 - 'java.eclassesnotused', ebuild.relative_path)
986 - elif buildtime and \
987 - not is_blocker and \
988 - not inherited_wxwidgets_eclass and \
989 - atom.cp == "x11-libs/wxGTK":
990 - qatracker.add_error(
991 - 'wxwidgets.eclassnotused',
992 - "%s: %ss on x11-libs/wxGTK without inheriting"
993 - " wxwidgets.eclass" % (ebuild.relative_path, mytype))
994 - elif runtime:
995 - if not is_blocker and \
996 - atom.cp in suspect_rdepend:
997 + 'java.eclassesnotused', ebuild.relative_path)
998 + elif buildtime and \
999 + not is_blocker and \
1000 + not inherited_wxwidgets_eclass and \
1001 + atom.cp == "x11-libs/wxGTK":
1002 + qatracker.add_error(
1003 + 'wxwidgets.eclassnotused',
1004 + "%s: %ss on x11-libs/wxGTK without inheriting"
1005 + " wxwidgets.eclass" % (ebuild.relative_path, mytype))
1006 + elif runtime:
1007 + if not is_blocker and \
1008 + atom.cp in suspect_rdepend:
1009 + qatracker.add_error(
1010 + mytype + '.suspect',
1011 + ebuild.relative_path + ": '%s'" % atom)
1012 +
1013 + if atom.operator == "~" and \
1014 + portage.versions.catpkgsplit(atom.cpv)[3] != "r0":
1015 + qacat = 'dependency.badtilde'
1016 qatracker.add_error(
1017 - mytype + '.suspect',
1018 - ebuild.relative_path + ": '%s'" % atom)
1019 + qacat, "%s: %s uses the ~ operator"
1020 + " with a non-zero revision: '%s'" %
1021 + (ebuild.relative_path, mytype, atom))
1022
1023 - if atom.operator == "~" and \
1024 - portage.versions.catpkgsplit(atom.cpv)[3] != "r0":
1025 - qacat = 'dependency.badtilde'
1026 - qatracker.add_error(
1027 - qacat, "%s: %s uses the ~ operator"
1028 - " with a non-zero revision: '%s'" %
1029 - (ebuild.relative_path, mytype, atom))
1030 + type_list.extend([mytype] * (len(badsyntax) - len(type_list)))
1031 +
1032 + for m, b in zip(type_list, badsyntax):
1033 + if m.endswith("DEPEND"):
1034 + qacat = "dependency.syntax"
1035 + else:
1036 + qacat = m + ".syntax"
1037 + qatracker.add_error(
1038 + qacat, "%s: %s: %s" % (ebuild.relative_path, m, b))
1039
1040 - type_list.extend([mytype] * (len(badsyntax) - len(type_list)))
1041 + badlicsyntax = len([z for z in type_list if z == "LICENSE"])
1042 + badprovsyntax = len([z for z in type_list if z == "PROVIDE"])
1043 + baddepsyntax = len(type_list) != badlicsyntax + badprovsyntax
1044 + badlicsyntax = badlicsyntax > 0
1045 + badprovsyntax = badprovsyntax > 0
1046
1047 - for m, b in zip(type_list, badsyntax):
1048 - if m.endswith("DEPEND"):
1049 - qacat = "dependency.syntax"
1050 - else:
1051 - qacat = m + ".syntax"
1052 - qatracker.add_error(
1053 - qacat, "%s: %s: %s" % (ebuild.relative_path, m, b))
1054 -
1055 - badlicsyntax = len([z for z in type_list if z == "LICENSE"])
1056 - badprovsyntax = len([z for z in type_list if z == "PROVIDE"])
1057 - baddepsyntax = len(type_list) != badlicsyntax + badprovsyntax
1058 - badlicsyntax = badlicsyntax > 0
1059 - badprovsyntax = badprovsyntax > 0
1060 -
1061 - #################
1062 - use_flag_checks.check(pkg, xpkg, ebuild, y_ebuild, muselist)
1063 -
1064 - ebuild_used_useflags = use_flag_checks.getUsedUseFlags()
1065 - used_useflags = used_useflags.union(ebuild_used_useflags)
1066 - #################
1067 - rubyeclasscheck.check(pkg, ebuild)
1068 - #################
1069 -
1070 - # license checks
1071 - if not badlicsyntax:
1072 #################
1073 - licensecheck.check(pkg, xpkg, ebuild, y_ebuild)
1074 + use_flag_checks.check(pkg, xpkg, ebuild, y_ebuild, muselist)
1075 +
1076 + ebuild_used_useflags = use_flag_checks.getUsedUseFlags()
1077 + used_useflags = used_useflags.union(ebuild_used_useflags)
1078 + #################
1079 + rubyeclasscheck.check(pkg, ebuild)
1080 #################
1081
1082 - #################
1083 - restrictcheck.check(pkg, xpkg, ebuild, y_ebuild)
1084 - #################
1085 + # license checks
1086 + if not badlicsyntax:
1087 + #################
1088 + licensecheck.check(pkg, xpkg, ebuild, y_ebuild)
1089 + #################
1090
1091 - # Syntax Checks
1092 + #################
1093 + restrictcheck.check(pkg, xpkg, ebuild, y_ebuild)
1094 + #################
1095
1096 - if not vcs_settings.vcs_preserves_mtime:
1097 - if ebuild.ebuild_path not in changed.new_ebuilds and \
1098 - ebuild.ebuild_path not in changed.ebuilds:
1099 - pkg.mtime = None
1100 - try:
1101 - # All ebuilds should have utf_8 encoding.
1102 - f = io.open(
1103 - _unicode_encode(
1104 - ebuild.full_path, encoding=_encodings['fs'], errors='strict'),
1105 - mode='r', encoding=_encodings['repo.content'])
1106 - try:
1107 - for check_name, e in run_checks(f, pkg):
1108 - qatracker.add_error(
1109 - check_name, ebuild.relative_path + ': %s' % e)
1110 - finally:
1111 - f.close()
1112 - except UnicodeDecodeError:
1113 - # A file.UTF8 failure will have already been recorded above.
1114 - pass
1115 + # Syntax Checks
1116
1117 - if options.force:
1118 - # The dep_check() calls are the most expensive QA test. If --force
1119 - # is enabled, there's no point in wasting time on these since the
1120 - # user is intent on forcing the commit anyway.
1121 - continue
1122 + if not vcs_settings.vcs_preserves_mtime:
1123 + if ebuild.ebuild_path not in changed.new_ebuilds and \
1124 + ebuild.ebuild_path not in changed.ebuilds:
1125 + pkg.mtime = None
1126 + try:
1127 + # All ebuilds should have utf_8 encoding.
1128 + f = io.open(
1129 + _unicode_encode(
1130 + ebuild.full_path, encoding=_encodings['fs'], errors='strict'),
1131 + mode='r', encoding=_encodings['repo.content'])
1132 + try:
1133 + for check_name, e in run_checks(f, pkg):
1134 + qatracker.add_error(
1135 + check_name, ebuild.relative_path + ': %s' % e)
1136 + finally:
1137 + f.close()
1138 + except UnicodeDecodeError:
1139 + # A file.UTF8 failure will have already been recorded above.
1140 + pass
1141
1142 - relevant_profiles = []
1143 - for keyword, arch, groups in arches:
1144 - if arch not in profiles:
1145 - # A missing profile will create an error further down
1146 - # during the KEYWORDS verification.
1147 + if options.force:
1148 + # The dep_check() calls are the most expensive QA test. If --force
1149 + # is enabled, there's no point in wasting time on these since the
1150 + # user is intent on forcing the commit anyway.
1151 continue
1152
1153 - if include_arches is not None:
1154 - if arch not in include_arches:
1155 + relevant_profiles = []
1156 + for keyword, arch, groups in arches:
1157 + if arch not in profiles:
1158 + # A missing profile will create an error further down
1159 + # during the KEYWORDS verification.
1160 continue
1161
1162 - relevant_profiles.extend(
1163 - (keyword, groups, prof) for prof in profiles[arch])
1164 -
1165 - def sort_key(item):
1166 - return item[2].sub_path
1167 -
1168 - relevant_profiles.sort(key=sort_key)
1169 -
1170 - for keyword, groups, prof in relevant_profiles:
1171 -
1172 - is_stable_profile = prof.status == "stable"
1173 - is_dev_profile = prof.status == "dev" and \
1174 - options.include_dev
1175 - is_exp_profile = prof.status == "exp" and \
1176 - options.include_exp_profiles == 'y'
1177 - if not (is_stable_profile or is_dev_profile or is_exp_profile):
1178 - continue
1179 -
1180 - dep_settings = arch_caches.get(prof.sub_path)
1181 - if dep_settings is None:
1182 - dep_settings = portage.config(
1183 - config_profile_path=prof.abs_path,
1184 - config_incrementals=repoman_incrementals,
1185 - config_root=config_root,
1186 - local_config=False,
1187 - _unmatched_removal=options.unmatched_removal,
1188 - env=env, repositories=repoman_settings.repositories)
1189 - dep_settings.categories = repoman_settings.categories
1190 - if options.without_mask:
1191 - dep_settings._mask_manager_obj = \
1192 - copy.deepcopy(dep_settings._mask_manager)
1193 - dep_settings._mask_manager._pmaskdict.clear()
1194 - arch_caches[prof.sub_path] = dep_settings
1195 -
1196 - xmatch_cache_key = (prof.sub_path, tuple(groups))
1197 - xcache = arch_xmatch_caches.get(xmatch_cache_key)
1198 - if xcache is None:
1199 - portdb.melt()
1200 - portdb.freeze()
1201 - xcache = portdb.xcache
1202 - xcache.update(shared_xmatch_caches)
1203 - arch_xmatch_caches[xmatch_cache_key] = xcache
1204 -
1205 - repo_settings.trees[repo_settings.root]["porttree"].settings = dep_settings
1206 - portdb.settings = dep_settings
1207 - portdb.xcache = xcache
1208 -
1209 - dep_settings["ACCEPT_KEYWORDS"] = " ".join(groups)
1210 - # just in case, prevent config.reset() from nuking these.
1211 - dep_settings.backup_changes("ACCEPT_KEYWORDS")
1212 -
1213 - # This attribute is used in dbapi._match_use() to apply
1214 - # use.stable.{mask,force} settings based on the stable
1215 - # status of the parent package. This is required in order
1216 - # for USE deps of unstable packages to be resolved correctly,
1217 - # since otherwise use.stable.{mask,force} settings of
1218 - # dependencies may conflict (see bug #456342).
1219 - dep_settings._parent_stable = dep_settings._isStable(pkg)
1220 -
1221 - # Handle package.use*.{force,mask) calculation, for use
1222 - # in dep_check.
1223 - dep_settings.useforce = dep_settings._use_manager.getUseForce(
1224 - pkg, stable=dep_settings._parent_stable)
1225 - dep_settings.usemask = dep_settings._use_manager.getUseMask(
1226 - pkg, stable=dep_settings._parent_stable)
1227 -
1228 - if not baddepsyntax:
1229 - ismasked = not ebuild_archs or \
1230 - pkg.cpv not in portdb.xmatch("match-visible", pkg.cp)
1231 - if ismasked:
1232 - if not have_pmasked:
1233 - have_pmasked = bool(dep_settings._getMaskAtom(
1234 - pkg.cpv, pkg._metadata))
1235 - if options.ignore_masked:
1236 + if include_arches is not None:
1237 + if arch not in include_arches:
1238 continue
1239 - # we are testing deps for a masked package; give it some lee-way
1240 - suffix = "masked"
1241 - matchmode = "minimum-all"
1242 - else:
1243 - suffix = ""
1244 - matchmode = "minimum-visible"
1245
1246 - if not have_dev_keywords:
1247 - have_dev_keywords = \
1248 - bool(dev_keywords.intersection(keywords))
1249 + relevant_profiles.extend(
1250 + (keyword, groups, prof) for prof in profiles[arch])
1251
1252 - if prof.status == "dev":
1253 - suffix = suffix + "indev"
1254 + relevant_profiles.sort(key=sort_key)
1255
1256 - for mytype in Package._dep_keys:
1257 + for keyword, groups, prof in relevant_profiles:
1258
1259 - mykey = "dependency.bad" + suffix
1260 - myvalue = myaux[mytype]
1261 - if not myvalue:
1262 - continue
1263 + is_stable_profile = prof.status == "stable"
1264 + is_dev_profile = prof.status == "dev" and \
1265 + options.include_dev
1266 + is_exp_profile = prof.status == "exp" and \
1267 + options.include_exp_profiles == 'y'
1268 + if not (is_stable_profile or is_dev_profile or is_exp_profile):
1269 + continue
1270
1271 - success, atoms = portage.dep_check(
1272 - myvalue, portdb, dep_settings,
1273 - use="all", mode=matchmode, trees=repo_settings.trees)
1274 -
1275 - if success:
1276 - if atoms:
1277 -
1278 - # Don't bother with dependency.unknown for
1279 - # cases in which *DEPEND.bad is triggered.
1280 - for atom in atoms:
1281 - # dep_check returns all blockers and they
1282 - # aren't counted for *DEPEND.bad, so we
1283 - # ignore them here.
1284 - if not atom.blocker:
1285 - unknown_pkgs.discard(
1286 - (mytype, atom.unevaluated_atom))
1287 -
1288 - if not prof.sub_path:
1289 - # old-style virtuals currently aren't
1290 - # resolvable with empty profile, since
1291 - # 'virtuals' mappings are unavailable
1292 - # (it would be expensive to search
1293 - # for PROVIDE in all ebuilds)
1294 + dep_settings = arch_caches.get(prof.sub_path)
1295 + if dep_settings is None:
1296 + dep_settings = portage.config(
1297 + config_profile_path=prof.abs_path,
1298 + config_incrementals=repoman_incrementals,
1299 + config_root=config_root,
1300 + local_config=False,
1301 + _unmatched_removal=options.unmatched_removal,
1302 + env=env, repositories=repoman_settings.repositories)
1303 + dep_settings.categories = repoman_settings.categories
1304 + if options.without_mask:
1305 + dep_settings._mask_manager_obj = \
1306 + copy.deepcopy(dep_settings._mask_manager)
1307 + dep_settings._mask_manager._pmaskdict.clear()
1308 + arch_caches[prof.sub_path] = dep_settings
1309 +
1310 + xmatch_cache_key = (prof.sub_path, tuple(groups))
1311 + xcache = arch_xmatch_caches.get(xmatch_cache_key)
1312 + if xcache is None:
1313 + portdb.melt()
1314 + portdb.freeze()
1315 + xcache = portdb.xcache
1316 + xcache.update(shared_xmatch_caches)
1317 + arch_xmatch_caches[xmatch_cache_key] = xcache
1318 +
1319 + repo_settings.trees[repo_settings.root]["porttree"].settings = dep_settings
1320 + portdb.settings = dep_settings
1321 + portdb.xcache = xcache
1322 +
1323 + dep_settings["ACCEPT_KEYWORDS"] = " ".join(groups)
1324 + # just in case, prevent config.reset() from nuking these.
1325 + dep_settings.backup_changes("ACCEPT_KEYWORDS")
1326 +
1327 + # This attribute is used in dbapi._match_use() to apply
1328 + # use.stable.{mask,force} settings based on the stable
1329 + # status of the parent package. This is required in order
1330 + # for USE deps of unstable packages to be resolved correctly,
1331 + # since otherwise use.stable.{mask,force} settings of
1332 + # dependencies may conflict (see bug #456342).
1333 + dep_settings._parent_stable = dep_settings._isStable(pkg)
1334 +
1335 + # Handle package.use*.{force,mask) calculation, for use
1336 + # in dep_check.
1337 + dep_settings.useforce = dep_settings._use_manager.getUseForce(
1338 + pkg, stable=dep_settings._parent_stable)
1339 + dep_settings.usemask = dep_settings._use_manager.getUseMask(
1340 + pkg, stable=dep_settings._parent_stable)
1341 +
1342 + if not baddepsyntax:
1343 + ismasked = not ebuild_archs or \
1344 + pkg.cpv not in portdb.xmatch("match-visible", pkg.cp)
1345 + if ismasked:
1346 + if not have_pmasked:
1347 + have_pmasked = bool(dep_settings._getMaskAtom(
1348 + pkg.cpv, pkg._metadata))
1349 + if options.ignore_masked:
1350 + continue
1351 + # we are testing deps for a masked package; give it some lee-way
1352 + suffix = "masked"
1353 + matchmode = "minimum-all"
1354 + else:
1355 + suffix = ""
1356 + matchmode = "minimum-visible"
1357 +
1358 + if not have_dev_keywords:
1359 + have_dev_keywords = \
1360 + bool(dev_keywords.intersection(keywords))
1361 +
1362 + if prof.status == "dev":
1363 + suffix = suffix + "indev"
1364 +
1365 + for mytype in Package._dep_keys:
1366 +
1367 + mykey = "dependency.bad" + suffix
1368 + myvalue = myaux[mytype]
1369 + if not myvalue:
1370 + continue
1371 +
1372 + success, atoms = portage.dep_check(
1373 + myvalue, portdb, dep_settings,
1374 + use="all", mode=matchmode, trees=repo_settings.trees)
1375 +
1376 + if success:
1377 + if atoms:
1378 +
1379 + # Don't bother with dependency.unknown for
1380 + # cases in which *DEPEND.bad is triggered.
1381 + for atom in atoms:
1382 + # dep_check returns all blockers and they
1383 + # aren't counted for *DEPEND.bad, so we
1384 + # ignore them here.
1385 + if not atom.blocker:
1386 + unknown_pkgs.discard(
1387 + (mytype, atom.unevaluated_atom))
1388 +
1389 + if not prof.sub_path:
1390 + # old-style virtuals currently aren't
1391 + # resolvable with empty profile, since
1392 + # 'virtuals' mappings are unavailable
1393 + # (it would be expensive to search
1394 + # for PROVIDE in all ebuilds)
1395 + atoms = [
1396 + atom for atom in atoms if not (
1397 + atom.cp.startswith('virtual/')
1398 + and not portdb.cp_list(atom.cp))]
1399 +
1400 + # we have some unsolvable deps
1401 + # remove ! deps, which always show up as unsatisfiable
1402 atoms = [
1403 - atom for atom in atoms if not (
1404 - atom.cp.startswith('virtual/')
1405 - and not portdb.cp_list(atom.cp))]
1406 -
1407 - # we have some unsolvable deps
1408 - # remove ! deps, which always show up as unsatisfiable
1409 - atoms = [
1410 - str(atom.unevaluated_atom)
1411 - for atom in atoms if not atom.blocker]
1412 -
1413 - # if we emptied out our list, continue:
1414 - if not atoms:
1415 - continue
1416 + str(atom.unevaluated_atom)
1417 + for atom in atoms if not atom.blocker]
1418 +
1419 + # if we emptied out our list, continue:
1420 + if not atoms:
1421 + continue
1422 + qatracker.add_error(
1423 + mykey, "%s: %s: %s(%s) %s" % (
1424 + ebuild.relative_path, mytype, keyword, prof,
1425 + repr(atoms)))
1426 + else:
1427 qatracker.add_error(
1428 mykey, "%s: %s: %s(%s) %s" % (
1429 ebuild.relative_path, mytype, keyword, prof,
1430 repr(atoms)))
1431 - else:
1432 - qatracker.add_error(
1433 - mykey, "%s: %s: %s(%s) %s" % (
1434 - ebuild.relative_path, mytype, keyword, prof,
1435 - repr(atoms)))
1436 -
1437 - if not baddepsyntax and unknown_pkgs:
1438 - type_map = {}
1439 - for mytype, atom in unknown_pkgs:
1440 - type_map.setdefault(mytype, set()).add(atom)
1441 - for mytype, atoms in type_map.items():
1442 +
1443 + if not baddepsyntax and unknown_pkgs:
1444 + type_map = {}
1445 + for mytype, atom in unknown_pkgs:
1446 + type_map.setdefault(mytype, set()).add(atom)
1447 + for mytype, atoms in type_map.items():
1448 + qatracker.add_error(
1449 + "dependency.unknown", "%s: %s: %s"
1450 + % (ebuild.relative_path, mytype, ", ".join(sorted(atoms))))
1451 +
1452 + # check if there are unused local USE-descriptions in metadata.xml
1453 + # (unless there are any invalids, to avoid noise)
1454 + if allvalid:
1455 + for myflag in muselist.difference(used_useflags):
1456 qatracker.add_error(
1457 - "dependency.unknown", "%s: %s: %s"
1458 - % (ebuild.relative_path, mytype, ", ".join(sorted(atoms))))
1459 -
1460 - # check if there are unused local USE-descriptions in metadata.xml
1461 - # (unless there are any invalids, to avoid noise)
1462 - if allvalid:
1463 - for myflag in muselist.difference(used_useflags):
1464 - qatracker.add_error(
1465 - "metadata.warning",
1466 - "%s/metadata.xml: unused local USE-description: '%s'"
1467 - % (xpkg, myflag))
1468 -
1469 -if options.if_modified == "y" and len(effective_scanlist) < 1:
1470 - logging.warn("--if-modified is enabled, but no modified packages were found!")
1471 -
1472 -if options.mode == "manifest":
1473 - sys.exit(dofail)
1474 -
1475 -# dofail will be true if we have failed in at least one non-warning category
1476 -dofail = 0
1477 -# dowarn will be true if we tripped any warnings
1478 -dowarn = 0
1479 -# dofull will be true if we should print a "repoman full" informational message
1480 -dofull = options.mode != 'full'
1481 -
1482 -for x in qacats:
1483 - if x not in qatracker.fails:
1484 - continue
1485 - dowarn = 1
1486 - if x not in qawarnings:
1487 - dofail = 1
1488 -
1489 -if dofail or \
1490 - (dowarn and not (options.quiet or options.mode == "scan")):
1491 - dofull = 0
1492 -
1493 -# Save QA output so that it can be conveniently displayed
1494 -# in $EDITOR while the user creates a commit message.
1495 -# Otherwise, the user would not be able to see this output
1496 -# once the editor has taken over the screen.
1497 -qa_output = io.StringIO()
1498 -style_file = ConsoleStyleFile(sys.stdout)
1499 -if options.mode == 'commit' and \
1500 - (not commitmessage or not commitmessage.strip()):
1501 - style_file.write_listener = qa_output
1502 -console_writer = StyleWriter(file=style_file, maxcol=9999)
1503 -console_writer.style_listener = style_file.new_styles
1504 -
1505 -f = formatter.AbstractFormatter(console_writer)
1506 -
1507 -format_outputs = {
1508 - 'column': format_qa_output_column,
1509 - 'default': format_qa_output
1510 -}
1511 -
1512 -format_output = format_outputs.get(
1513 - options.output_style, format_outputs['default'])
1514 -format_output(f, qatracker.fails, dofull, dofail, options, qawarnings)
1515 -
1516 -style_file.flush()
1517 -del console_writer, f, style_file
1518 -qa_output = qa_output.getvalue()
1519 -qa_output = qa_output.splitlines(True)
1520 -
1521 -suggest_ignore_masked = False
1522 -suggest_include_dev = False
1523 -
1524 -if have_pmasked and not (options.without_mask or options.ignore_masked):
1525 - suggest_ignore_masked = True
1526 -if have_dev_keywords and not options.include_dev:
1527 - suggest_include_dev = True
1528 -
1529 -if suggest_ignore_masked or suggest_include_dev:
1530 - print()
1531 - if suggest_ignore_masked:
1532 - print(bold(
1533 - "Note: use --without-mask to check "
1534 - "KEYWORDS on dependencies of masked packages"))
1535 -
1536 - if suggest_include_dev:
1537 - print(bold(
1538 - "Note: use --include-dev (-d) to check "
1539 - "dependencies for 'dev' profiles"))
1540 - print()
1541 -
1542 -if options.mode != 'commit':
1543 - if dofull:
1544 - print(bold("Note: type \"repoman full\" for a complete listing."))
1545 - if dowarn and not dofail:
1546 - utilities.repoman_sez(
1547 - "\"You're only giving me a partial QA payment?\n"
1548 - " I'll take it this time, but I'm not happy.\"")
1549 - elif not dofail:
1550 - utilities.repoman_sez(
1551 - "\"If everyone were like you, I'd be out of business!\"")
1552 - elif dofail:
1553 - print(bad("Please fix these important QA issues first."))
1554 - utilities.repoman_sez(
1555 - "\"Make your QA payment on time"
1556 - " and you'll never see the likes of me.\"\n")
1557 - sys.exit(1)
1558 -else:
1559 - if dofail and can_force and options.force and not options.pretend:
1560 - utilities.repoman_sez(
1561 - " \"You want to commit even with these QA issues?\n"
1562 - " I'll take it this time, but I'm not happy.\"\n")
1563 - elif dofail:
1564 - if options.force and not can_force:
1565 - print(bad(
1566 - "The --force option has been disabled"
1567 - " due to extraordinary issues."))
1568 - print(bad("Please fix these important QA issues first."))
1569 - utilities.repoman_sez(
1570 - "\"Make your QA payment on time"
1571 - " and you'll never see the likes of me.\"\n")
1572 - sys.exit(1)
1573 + "metadata.warning",
1574 + "%s/metadata.xml: unused local USE-description: '%s'"
1575 + % (xpkg, myflag))
1576
1577 - if options.pretend:
1578 - utilities.repoman_sez(
1579 - "\"So, you want to play it safe. Good call.\"\n")
1580 + if options.if_modified == "y" and len(effective_scanlist) < 1:
1581 + logging.warn("--if-modified is enabled, but no modified packages were found!")
1582
1583 - myunadded = []
1584 - if vcs_settings.vcs == "cvs":
1585 - try:
1586 - myvcstree = portage.cvstree.getentries("./", recursive=1)
1587 - myunadded = portage.cvstree.findunadded(
1588 - myvcstree, recursive=1, basedir="./")
1589 - except SystemExit as e:
1590 - raise # TODO propagate this
1591 - except:
1592 - err("Error retrieving CVS tree; exiting.")
1593 - if vcs_settings.vcs == "svn":
1594 - try:
1595 - with repoman_popen("svn status --no-ignore") as f:
1596 - svnstatus = f.readlines()
1597 - myunadded = [
1598 - "./" + elem.rstrip().split()[1]
1599 - for elem in svnstatus
1600 - if elem.startswith("?") or elem.startswith("I")]
1601 - except SystemExit as e:
1602 - raise # TODO propagate this
1603 - except:
1604 - err("Error retrieving SVN info; exiting.")
1605 - if vcs_settings.vcs == "git":
1606 - # get list of files not under version control or missing
1607 - myf = repoman_popen("git ls-files --others")
1608 - myunadded = ["./" + elem[:-1] for elem in myf]
1609 - myf.close()
1610 - if vcs_settings.vcs == "bzr":
1611 - try:
1612 - with repoman_popen("bzr status -S .") as f:
1613 - bzrstatus = f.readlines()
1614 - myunadded = [
1615 - "./" + elem.rstrip().split()[1].split('/')[-1:][0]
1616 - for elem in bzrstatus
1617 - if elem.startswith("?") or elem[0:2] == " D"]
1618 - except SystemExit as e:
1619 - raise # TODO propagate this
1620 - except:
1621 - err("Error retrieving bzr info; exiting.")
1622 - if vcs_settings.vcs == "hg":
1623 - with repoman_popen("hg status --no-status --unknown .") as f:
1624 - myunadded = f.readlines()
1625 - myunadded = ["./" + elem.rstrip() for elem in myunadded]
1626 -
1627 - # Mercurial doesn't handle manually deleted files as removed from
1628 - # the repository, so the user need to remove them before commit,
1629 - # using "hg remove [FILES]"
1630 - with repoman_popen("hg status --no-status --deleted .") as f:
1631 - mydeleted = f.readlines()
1632 - mydeleted = ["./" + elem.rstrip() for elem in mydeleted]
1633 -
1634 - myautoadd = []
1635 - if myunadded:
1636 - for x in range(len(myunadded) - 1, -1, -1):
1637 - xs = myunadded[x].split("/")
1638 - if xs[-1] == "files":
1639 - print("!!! files dir is not added! Please correct this.")
1640 - sys.exit(-1)
1641 - elif xs[-1] == "Manifest":
1642 - # It's a manifest... auto add
1643 - myautoadd += [myunadded[x]]
1644 - del myunadded[x]
1645 -
1646 - if myunadded:
1647 - print(red(
1648 - "!!! The following files are in your local tree"
1649 - " but are not added to the master"))
1650 - print(red(
1651 - "!!! tree. Please remove them from the local tree"
1652 - " or add them to the master tree."))
1653 - for x in myunadded:
1654 - print(" ", x)
1655 - print()
1656 - print()
1657 - sys.exit(1)
1658 + if options.mode == "manifest":
1659 + sys.exit(dofail)
1660 +
1661 + # dofail will be true if we have failed in at least one non-warning category
1662 + dofail = 0
1663 + # dowarn will be true if we tripped any warnings
1664 + dowarn = 0
1665 + # dofull will be true if we should print a "repoman full" informational message
1666 + dofull = options.mode != 'full'
1667
1668 - if vcs_settings.vcs == "hg" and mydeleted:
1669 - print(red(
1670 - "!!! The following files are removed manually"
1671 - " from your local tree but are not"))
1672 - print(red(
1673 - "!!! removed from the repository."
1674 - " Please remove them, using \"hg remove [FILES]\"."))
1675 - for x in mydeleted:
1676 - print(" ", x)
1677 + for x in qacats:
1678 + if x not in qatracker.fails:
1679 + continue
1680 + dowarn = 1
1681 + if x not in qawarnings:
1682 + dofail = 1
1683 +
1684 + if dofail or \
1685 + (dowarn and not (options.quiet or options.mode == "scan")):
1686 + dofull = 0
1687 +
1688 + # Save QA output so that it can be conveniently displayed
1689 + # in $EDITOR while the user creates a commit message.
1690 + # Otherwise, the user would not be able to see this output
1691 + # once the editor has taken over the screen.
1692 + qa_output = io.StringIO()
1693 + style_file = ConsoleStyleFile(sys.stdout)
1694 + if options.mode == 'commit' and \
1695 + (not commitmessage or not commitmessage.strip()):
1696 + style_file.write_listener = qa_output
1697 + console_writer = StyleWriter(file=style_file, maxcol=9999)
1698 + console_writer.style_listener = style_file.new_styles
1699 +
1700 + f = formatter.AbstractFormatter(console_writer)
1701 +
1702 + format_outputs = {
1703 + 'column': format_qa_output_column,
1704 + 'default': format_qa_output
1705 + }
1706 +
1707 + format_output = format_outputs.get(
1708 + options.output_style, format_outputs['default'])
1709 + format_output(f, qatracker.fails, dofull, dofail, options, qawarnings)
1710 +
1711 + style_file.flush()
1712 + del console_writer, f, style_file
1713 + qa_output = qa_output.getvalue()
1714 + qa_output = qa_output.splitlines(True)
1715 +
1716 + suggest_ignore_masked = False
1717 + suggest_include_dev = False
1718 +
1719 + if have_pmasked and not (options.without_mask or options.ignore_masked):
1720 + suggest_ignore_masked = True
1721 + if have_dev_keywords and not options.include_dev:
1722 + suggest_include_dev = True
1723 +
1724 + if suggest_ignore_masked or suggest_include_dev:
1725 print()
1726 + if suggest_ignore_masked:
1727 + print(bold(
1728 + "Note: use --without-mask to check "
1729 + "KEYWORDS on dependencies of masked packages"))
1730 +
1731 + if suggest_include_dev:
1732 + print(bold(
1733 + "Note: use --include-dev (-d) to check "
1734 + "dependencies for 'dev' profiles"))
1735 print()
1736 - sys.exit(1)
1737
1738 - if vcs_settings.vcs == "cvs":
1739 - mycvstree = cvstree.getentries("./", recursive=1)
1740 - mychanged = cvstree.findchanged(mycvstree, recursive=1, basedir="./")
1741 - mynew = cvstree.findnew(mycvstree, recursive=1, basedir="./")
1742 - myremoved = portage.cvstree.findremoved(mycvstree, recursive=1, basedir="./")
1743 - bin_blob_pattern = re.compile("^-kb$")
1744 - no_expansion = set(portage.cvstree.findoption(
1745 - mycvstree, bin_blob_pattern, recursive=1, basedir="./"))
1746 -
1747 - if vcs_settings.vcs == "svn":
1748 - with repoman_popen("svn status") as f:
1749 - svnstatus = f.readlines()
1750 - mychanged = [
1751 - "./" + elem.split()[-1:][0]
1752 - for elem in svnstatus
1753 - if (elem[:1] in "MR" or elem[1:2] in "M")]
1754 - mynew = [
1755 - "./" + elem.split()[-1:][0]
1756 - for elem in svnstatus
1757 - if elem.startswith("A")]
1758 - myremoved = [
1759 - "./" + elem.split()[-1:][0]
1760 - for elem in svnstatus
1761 - if elem.startswith("D")]
1762 -
1763 - # Subversion expands keywords specified in svn:keywords properties.
1764 - with repoman_popen("svn propget -R svn:keywords") as f:
1765 - props = f.readlines()
1766 - expansion = dict(
1767 - ("./" + prop.split(" - ")[0], prop.split(" - ")[1].split())
1768 - for prop in props if " - " in prop)
1769 -
1770 - elif vcs_settings.vcs == "git":
1771 - with repoman_popen(
1772 - "git diff-index --name-only "
1773 - "--relative --diff-filter=M HEAD") as f:
1774 - mychanged = f.readlines()
1775 - mychanged = ["./" + elem[:-1] for elem in mychanged]
1776 -
1777 - with repoman_popen(
1778 - "git diff-index --name-only "
1779 - "--relative --diff-filter=A HEAD") as f:
1780 - mynew = f.readlines()
1781 - mynew = ["./" + elem[:-1] for elem in mynew]
1782 -
1783 - with repoman_popen(
1784 - "git diff-index --name-only "
1785 - "--relative --diff-filter=D HEAD") as f:
1786 - myremoved = f.readlines()
1787 - myremoved = ["./" + elem[:-1] for elem in myremoved]
1788 -
1789 - if vcs_settings.vcs == "bzr":
1790 - with repoman_popen("bzr status -S .") as f:
1791 - bzrstatus = f.readlines()
1792 - mychanged = [
1793 - "./" + elem.split()[-1:][0].split('/')[-1:][0]
1794 - for elem in bzrstatus
1795 - if elem and elem[1:2] == "M"]
1796 - mynew = [
1797 - "./" + elem.split()[-1:][0].split('/')[-1:][0]
1798 - for elem in bzrstatus
1799 - if elem and (elem[1:2] in "NK" or elem[0:1] == "R")]
1800 - myremoved = [
1801 - "./" + elem.split()[-1:][0].split('/')[-1:][0]
1802 - for elem in bzrstatus
1803 - if elem.startswith("-")]
1804 - myremoved = [
1805 - "./" + elem.split()[-3:-2][0].split('/')[-1:][0]
1806 - for elem in bzrstatus
1807 - if elem and (elem[1:2] == "K" or elem[0:1] == "R")]
1808 - # Bazaar expands nothing.
1809 -
1810 - if vcs_settings.vcs == "hg":
1811 - with repoman_popen("hg status --no-status --modified .") as f:
1812 - mychanged = f.readlines()
1813 - mychanged = ["./" + elem.rstrip() for elem in mychanged]
1814 -
1815 - with repoman_popen("hg status --no-status --added .") as f:
1816 - mynew = f.readlines()
1817 - mynew = ["./" + elem.rstrip() for elem in mynew]
1818 -
1819 - with repoman_popen("hg status --no-status --removed .") as f:
1820 - myremoved = f.readlines()
1821 - myremoved = ["./" + elem.rstrip() for elem in myremoved]
1822 -
1823 - if vcs_settings.vcs:
1824 - a_file_is_changed = mychanged or mynew or myremoved
1825 - a_file_is_deleted_hg = vcs_settings.vcs == "hg" and mydeleted
1826 -
1827 - if not (a_file_is_changed or a_file_is_deleted_hg):
1828 + if options.mode != 'commit':
1829 + if dofull:
1830 + print(bold("Note: type \"repoman full\" for a complete listing."))
1831 + if dowarn and not dofail:
1832 + utilities.repoman_sez(
1833 + "\"You're only giving me a partial QA payment?\n"
1834 + " I'll take it this time, but I'm not happy.\"")
1835 + elif not dofail:
1836 + utilities.repoman_sez(
1837 + "\"If everyone were like you, I'd be out of business!\"")
1838 + elif dofail:
1839 + print(bad("Please fix these important QA issues first."))
1840 + utilities.repoman_sez(
1841 + "\"Make your QA payment on time"
1842 + " and you'll never see the likes of me.\"\n")
1843 + sys.exit(1)
1844 + else:
1845 + if dofail and can_force and options.force and not options.pretend:
1846 + utilities.repoman_sez(
1847 + " \"You want to commit even with these QA issues?\n"
1848 + " I'll take it this time, but I'm not happy.\"\n")
1849 + elif dofail:
1850 + if options.force and not can_force:
1851 + print(bad(
1852 + "The --force option has been disabled"
1853 + " due to extraordinary issues."))
1854 + print(bad("Please fix these important QA issues first."))
1855 + utilities.repoman_sez(
1856 + "\"Make your QA payment on time"
1857 + " and you'll never see the likes of me.\"\n")
1858 + sys.exit(1)
1859 +
1860 + if options.pretend:
1861 utilities.repoman_sez(
1862 - "\"Doing nothing is not always good for QA.\"")
1863 + "\"So, you want to play it safe. Good call.\"\n")
1864 +
1865 + myunadded = []
1866 + if vcs_settings.vcs == "cvs":
1867 + try:
1868 + myvcstree = portage.cvstree.getentries("./", recursive=1)
1869 + myunadded = portage.cvstree.findunadded(
1870 + myvcstree, recursive=1, basedir="./")
1871 + except SystemExit as e:
1872 + raise # TODO propagate this
1873 + except:
1874 + err("Error retrieving CVS tree; exiting.")
1875 + if vcs_settings.vcs == "svn":
1876 + try:
1877 + with repoman_popen("svn status --no-ignore") as f:
1878 + svnstatus = f.readlines()
1879 + myunadded = [
1880 + "./" + elem.rstrip().split()[1]
1881 + for elem in svnstatus
1882 + if elem.startswith("?") or elem.startswith("I")]
1883 + except SystemExit as e:
1884 + raise # TODO propagate this
1885 + except:
1886 + err("Error retrieving SVN info; exiting.")
1887 + if vcs_settings.vcs == "git":
1888 + # get list of files not under version control or missing
1889 + myf = repoman_popen("git ls-files --others")
1890 + myunadded = ["./" + elem[:-1] for elem in myf]
1891 + myf.close()
1892 + if vcs_settings.vcs == "bzr":
1893 + try:
1894 + with repoman_popen("bzr status -S .") as f:
1895 + bzrstatus = f.readlines()
1896 + myunadded = [
1897 + "./" + elem.rstrip().split()[1].split('/')[-1:][0]
1898 + for elem in bzrstatus
1899 + if elem.startswith("?") or elem[0:2] == " D"]
1900 + except SystemExit as e:
1901 + raise # TODO propagate this
1902 + except:
1903 + err("Error retrieving bzr info; exiting.")
1904 + if vcs_settings.vcs == "hg":
1905 + with repoman_popen("hg status --no-status --unknown .") as f:
1906 + myunadded = f.readlines()
1907 + myunadded = ["./" + elem.rstrip() for elem in myunadded]
1908 +
1909 + # Mercurial doesn't handle manually deleted files as removed from
1910 + # the repository, so the user need to remove them before commit,
1911 + # using "hg remove [FILES]"
1912 + with repoman_popen("hg status --no-status --deleted .") as f:
1913 + mydeleted = f.readlines()
1914 + mydeleted = ["./" + elem.rstrip() for elem in mydeleted]
1915 +
1916 + myautoadd = []
1917 + if myunadded:
1918 + for x in range(len(myunadded) - 1, -1, -1):
1919 + xs = myunadded[x].split("/")
1920 + if xs[-1] == "files":
1921 + print("!!! files dir is not added! Please correct this.")
1922 + sys.exit(-1)
1923 + elif xs[-1] == "Manifest":
1924 + # It's a manifest... auto add
1925 + myautoadd += [myunadded[x]]
1926 + del myunadded[x]
1927 +
1928 + if myunadded:
1929 + print(red(
1930 + "!!! The following files are in your local tree"
1931 + " but are not added to the master"))
1932 + print(red(
1933 + "!!! tree. Please remove them from the local tree"
1934 + " or add them to the master tree."))
1935 + for x in myunadded:
1936 + print(" ", x)
1937 print()
1938 - print("(Didn't find any changed files...)")
1939 print()
1940 sys.exit(1)
1941
1942 - # Manifests need to be regenerated after all other commits, so don't commit
1943 - # them now even if they have changed.
1944 - mymanifests = set()
1945 - myupdates = set()
1946 - for f in mychanged + mynew:
1947 - if "Manifest" == os.path.basename(f):
1948 - mymanifests.add(f)
1949 - else:
1950 - myupdates.add(f)
1951 - myupdates.difference_update(myremoved)
1952 - myupdates = list(myupdates)
1953 - mymanifests = list(mymanifests)
1954 - myheaders = []
1955 - mydirty = []
1956 -
1957 - commitmessage = options.commitmsg
1958 - if options.commitmsgfile:
1959 - try:
1960 - f = io.open(
1961 - _unicode_encode(
1962 - options.commitmsgfile,
1963 - encoding=_encodings['fs'], errors='strict'),
1964 - mode='r', encoding=_encodings['content'], errors='replace')
1965 - commitmessage = f.read()
1966 - f.close()
1967 - del f
1968 - except (IOError, OSError) as e:
1969 - if e.errno == errno.ENOENT:
1970 - portage.writemsg(
1971 - "!!! File Not Found:"
1972 - " --commitmsgfile='%s'\n" % options.commitmsgfile)
1973 - else:
1974 - raise
1975 - # We've read the content so the file is no longer needed.
1976 - commitmessagefile = None
1977 - if not commitmessage or not commitmessage.strip():
1978 - try:
1979 - editor = os.environ.get("EDITOR")
1980 - if editor and utilities.editor_is_executable(editor):
1981 - commitmessage = utilities.get_commit_message_with_editor(
1982 - editor, message=qa_output)
1983 - else:
1984 - commitmessage = utilities.get_commit_message_with_stdin()
1985 - except KeyboardInterrupt:
1986 - logging.fatal("Interrupted; exiting...")
1987 - sys.exit(1)
1988 - if not commitmessage or not commitmessage.strip():
1989 - print("* no commit message? aborting commit.")
1990 + if vcs_settings.vcs == "hg" and mydeleted:
1991 + print(red(
1992 + "!!! The following files are removed manually"
1993 + " from your local tree but are not"))
1994 + print(red(
1995 + "!!! removed from the repository."
1996 + " Please remove them, using \"hg remove [FILES]\"."))
1997 + for x in mydeleted:
1998 + print(" ", x)
1999 + print()
2000 + print()
2001 sys.exit(1)
2002 - commitmessage = commitmessage.rstrip()
2003 - changelog_msg = commitmessage
2004 - portage_version = getattr(portage, "VERSION", None)
2005 - gpg_key = repoman_settings.get("PORTAGE_GPG_KEY", "")
2006 - dco_sob = repoman_settings.get("DCO_SIGNED_OFF_BY", "")
2007 - if portage_version is None:
2008 - sys.stderr.write("Failed to insert portage version in message!\n")
2009 - sys.stderr.flush()
2010 - portage_version = "Unknown"
2011 -
2012 - report_options = []
2013 - if options.force:
2014 - report_options.append("--force")
2015 - if options.ignore_arches:
2016 - report_options.append("--ignore-arches")
2017 - if include_arches is not None:
2018 - report_options.append(
2019 - "--include-arches=\"%s\"" %
2020 - " ".join(sorted(include_arches)))
2021 -
2022 - if vcs_settings.vcs == "git":
2023 - # Use new footer only for git (see bug #438364).
2024 - commit_footer = "\n\nPackage-Manager: portage-%s" % portage_version
2025 - if report_options:
2026 - commit_footer += "\nRepoMan-Options: " + " ".join(report_options)
2027 - if repo_settings.sign_manifests:
2028 - commit_footer += "\nManifest-Sign-Key: %s" % (gpg_key, )
2029 - if dco_sob:
2030 - commit_footer += "\nSigned-off-by: %s" % (dco_sob, )
2031 - else:
2032 - unameout = platform.system() + " "
2033 - if platform.system() in ["Darwin", "SunOS"]:
2034 - unameout += platform.processor()
2035 - else:
2036 - unameout += platform.machine()
2037 - commit_footer = "\n\n"
2038 - if dco_sob:
2039 - commit_footer += "Signed-off-by: %s\n" % (dco_sob, )
2040 - commit_footer += "(Portage version: %s/%s/%s" % \
2041 - (portage_version, vcs_settings.vcs, unameout)
2042 - if report_options:
2043 - commit_footer += ", RepoMan options: " + " ".join(report_options)
2044 - if repo_settings.sign_manifests:
2045 - commit_footer += ", signed Manifest commit with key %s" % \
2046 - (gpg_key, )
2047 - else:
2048 - commit_footer += ", unsigned Manifest commit"
2049 - commit_footer += ")"
2050 -
2051 - commitmessage += commit_footer
2052 -
2053 - broken_changelog_manifests = []
2054 - if options.echangelog in ('y', 'force'):
2055 - logging.info("checking for unmodified ChangeLog files")
2056 - committer_name = utilities.get_committer_name(env=repoman_settings)
2057 - for x in sorted(vcs_files_to_cps(
2058 - chain(myupdates, mymanifests, myremoved),
2059 - repolevel, reposplit, categories)):
2060 - catdir, pkgdir = x.split("/")
2061 - checkdir = repo_settings.repodir + "/" + x
2062 - checkdir_relative = ""
2063 - if repolevel < 3:
2064 - checkdir_relative = os.path.join(pkgdir, checkdir_relative)
2065 - if repolevel < 2:
2066 - checkdir_relative = os.path.join(catdir, checkdir_relative)
2067 - checkdir_relative = os.path.join(".", checkdir_relative)
2068 -
2069 - changelog_path = os.path.join(checkdir_relative, "ChangeLog")
2070 - changelog_modified = changelog_path in changed.changelogs
2071 - if changelog_modified and options.echangelog != 'force':
2072 - continue
2073
2074 - # get changes for this package
2075 - cdrlen = len(checkdir_relative)
2076 - check_relative = lambda e: e.startswith(checkdir_relative)
2077 - split_relative = lambda e: e[cdrlen:]
2078 - clnew = list(map(split_relative, filter(check_relative, mynew)))
2079 - clremoved = list(map(split_relative, filter(check_relative, myremoved)))
2080 - clchanged = list(map(split_relative, filter(check_relative, mychanged)))
2081 -
2082 - # Skip ChangeLog generation if only the Manifest was modified,
2083 - # as discussed in bug #398009.
2084 - nontrivial_cl_files = set()
2085 - nontrivial_cl_files.update(clnew, clremoved, clchanged)
2086 - nontrivial_cl_files.difference_update(['Manifest'])
2087 - if not nontrivial_cl_files and options.echangelog != 'force':
2088 - continue
2089 + if vcs_settings.vcs == "cvs":
2090 + mycvstree = cvstree.getentries("./", recursive=1)
2091 + mychanged = cvstree.findchanged(mycvstree, recursive=1, basedir="./")
2092 + mynew = cvstree.findnew(mycvstree, recursive=1, basedir="./")
2093 + myremoved = portage.cvstree.findremoved(mycvstree, recursive=1, basedir="./")
2094 + bin_blob_pattern = re.compile("^-kb$")
2095 + no_expansion = set(portage.cvstree.findoption(
2096 + mycvstree, bin_blob_pattern, recursive=1, basedir="./"))
2097 +
2098 + if vcs_settings.vcs == "svn":
2099 + with repoman_popen("svn status") as f:
2100 + svnstatus = f.readlines()
2101 + mychanged = [
2102 + "./" + elem.split()[-1:][0]
2103 + for elem in svnstatus
2104 + if (elem[:1] in "MR" or elem[1:2] in "M")]
2105 + mynew = [
2106 + "./" + elem.split()[-1:][0]
2107 + for elem in svnstatus
2108 + if elem.startswith("A")]
2109 + myremoved = [
2110 + "./" + elem.split()[-1:][0]
2111 + for elem in svnstatus
2112 + if elem.startswith("D")]
2113 +
2114 + # Subversion expands keywords specified in svn:keywords properties.
2115 + with repoman_popen("svn propget -R svn:keywords") as f:
2116 + props = f.readlines()
2117 + expansion = dict(
2118 + ("./" + prop.split(" - ")[0], prop.split(" - ")[1].split())
2119 + for prop in props if " - " in prop)
2120 +
2121 + elif vcs_settings.vcs == "git":
2122 + with repoman_popen(
2123 + "git diff-index --name-only "
2124 + "--relative --diff-filter=M HEAD") as f:
2125 + mychanged = f.readlines()
2126 + mychanged = ["./" + elem[:-1] for elem in mychanged]
2127 +
2128 + with repoman_popen(
2129 + "git diff-index --name-only "
2130 + "--relative --diff-filter=A HEAD") as f:
2131 + mynew = f.readlines()
2132 + mynew = ["./" + elem[:-1] for elem in mynew]
2133 +
2134 + with repoman_popen(
2135 + "git diff-index --name-only "
2136 + "--relative --diff-filter=D HEAD") as f:
2137 + myremoved = f.readlines()
2138 + myremoved = ["./" + elem[:-1] for elem in myremoved]
2139 +
2140 + if vcs_settings.vcs == "bzr":
2141 + with repoman_popen("bzr status -S .") as f:
2142 + bzrstatus = f.readlines()
2143 + mychanged = [
2144 + "./" + elem.split()[-1:][0].split('/')[-1:][0]
2145 + for elem in bzrstatus
2146 + if elem and elem[1:2] == "M"]
2147 + mynew = [
2148 + "./" + elem.split()[-1:][0].split('/')[-1:][0]
2149 + for elem in bzrstatus
2150 + if elem and (elem[1:2] in "NK" or elem[0:1] == "R")]
2151 + myremoved = [
2152 + "./" + elem.split()[-1:][0].split('/')[-1:][0]
2153 + for elem in bzrstatus
2154 + if elem.startswith("-")]
2155 + myremoved = [
2156 + "./" + elem.split()[-3:-2][0].split('/')[-1:][0]
2157 + for elem in bzrstatus
2158 + if elem and (elem[1:2] == "K" or elem[0:1] == "R")]
2159 + # Bazaar expands nothing.
2160
2161 - new_changelog = utilities.UpdateChangeLog(
2162 - checkdir_relative, committer_name, changelog_msg,
2163 - os.path.join(repo_settings.repodir, 'skel.ChangeLog'),
2164 - catdir, pkgdir,
2165 - new=clnew, removed=clremoved, changed=clchanged,
2166 - pretend=options.pretend)
2167 - if new_changelog is None:
2168 - writemsg_level(
2169 - "!!! Updating the ChangeLog failed\n",
2170 - level=logging.ERROR, noiselevel=-1)
2171 + if vcs_settings.vcs == "hg":
2172 + with repoman_popen("hg status --no-status --modified .") as f:
2173 + mychanged = f.readlines()
2174 + mychanged = ["./" + elem.rstrip() for elem in mychanged]
2175 +
2176 + with repoman_popen("hg status --no-status --added .") as f:
2177 + mynew = f.readlines()
2178 + mynew = ["./" + elem.rstrip() for elem in mynew]
2179 +
2180 + with repoman_popen("hg status --no-status --removed .") as f:
2181 + myremoved = f.readlines()
2182 + myremoved = ["./" + elem.rstrip() for elem in myremoved]
2183 +
2184 + if vcs_settings.vcs:
2185 + a_file_is_changed = mychanged or mynew or myremoved
2186 + a_file_is_deleted_hg = vcs_settings.vcs == "hg" and mydeleted
2187 +
2188 + if not (a_file_is_changed or a_file_is_deleted_hg):
2189 + utilities.repoman_sez(
2190 + "\"Doing nothing is not always good for QA.\"")
2191 + print()
2192 + print("(Didn't find any changed files...)")
2193 + print()
2194 sys.exit(1)
2195
2196 - # if the ChangeLog was just created, add it to vcs
2197 - if new_changelog:
2198 - myautoadd.append(changelog_path)
2199 - # myautoadd is appended to myupdates below
2200 + # Manifests need to be regenerated after all other commits, so don't commit
2201 + # them now even if they have changed.
2202 + mymanifests = set()
2203 + myupdates = set()
2204 + for f in mychanged + mynew:
2205 + if "Manifest" == os.path.basename(f):
2206 + mymanifests.add(f)
2207 else:
2208 - myupdates.append(changelog_path)
2209 -
2210 - if options.ask and not options.pretend:
2211 - # regenerate Manifest for modified ChangeLog (bug #420735)
2212 - repoman_settings["O"] = checkdir
2213 - digestgen(mysettings=repoman_settings, myportdb=portdb)
2214 + myupdates.add(f)
2215 + myupdates.difference_update(myremoved)
2216 + myupdates = list(myupdates)
2217 + mymanifests = list(mymanifests)
2218 + myheaders = []
2219 + mydirty = []
2220 +
2221 + commitmessage = options.commitmsg
2222 + if options.commitmsgfile:
2223 + try:
2224 + f = io.open(
2225 + _unicode_encode(
2226 + options.commitmsgfile,
2227 + encoding=_encodings['fs'], errors='strict'),
2228 + mode='r', encoding=_encodings['content'], errors='replace')
2229 + commitmessage = f.read()
2230 + f.close()
2231 + del f
2232 + except (IOError, OSError) as e:
2233 + if e.errno == errno.ENOENT:
2234 + portage.writemsg(
2235 + "!!! File Not Found:"
2236 + " --commitmsgfile='%s'\n" % options.commitmsgfile)
2237 + else:
2238 + raise
2239 + # We've read the content so the file is no longer needed.
2240 + commitmessagefile = None
2241 + if not commitmessage or not commitmessage.strip():
2242 + try:
2243 + editor = os.environ.get("EDITOR")
2244 + if editor and utilities.editor_is_executable(editor):
2245 + commitmessage = utilities.get_commit_message_with_editor(
2246 + editor, message=qa_output)
2247 + else:
2248 + commitmessage = utilities.get_commit_message_with_stdin()
2249 + except KeyboardInterrupt:
2250 + logging.fatal("Interrupted; exiting...")
2251 + sys.exit(1)
2252 + if not commitmessage or not commitmessage.strip():
2253 + print("* no commit message? aborting commit.")
2254 + sys.exit(1)
2255 + commitmessage = commitmessage.rstrip()
2256 + changelog_msg = commitmessage
2257 + portage_version = getattr(portage, "VERSION", None)
2258 + gpg_key = repoman_settings.get("PORTAGE_GPG_KEY", "")
2259 + dco_sob = repoman_settings.get("DCO_SIGNED_OFF_BY", "")
2260 + if portage_version is None:
2261 + sys.stderr.write("Failed to insert portage version in message!\n")
2262 + sys.stderr.flush()
2263 + portage_version = "Unknown"
2264 +
2265 + report_options = []
2266 + if options.force:
2267 + report_options.append("--force")
2268 + if options.ignore_arches:
2269 + report_options.append("--ignore-arches")
2270 + if include_arches is not None:
2271 + report_options.append(
2272 + "--include-arches=\"%s\"" %
2273 + " ".join(sorted(include_arches)))
2274 +
2275 + if vcs_settings.vcs == "git":
2276 + # Use new footer only for git (see bug #438364).
2277 + commit_footer = "\n\nPackage-Manager: portage-%s" % portage_version
2278 + if report_options:
2279 + commit_footer += "\nRepoMan-Options: " + " ".join(report_options)
2280 + if repo_settings.sign_manifests:
2281 + commit_footer += "\nManifest-Sign-Key: %s" % (gpg_key, )
2282 + if dco_sob:
2283 + commit_footer += "\nSigned-off-by: %s" % (dco_sob, )
2284 + else:
2285 + unameout = platform.system() + " "
2286 + if platform.system() in ["Darwin", "SunOS"]:
2287 + unameout += platform.processor()
2288 else:
2289 - broken_changelog_manifests.append(x)
2290 + unameout += platform.machine()
2291 + commit_footer = "\n\n"
2292 + if dco_sob:
2293 + commit_footer += "Signed-off-by: %s\n" % (dco_sob, )
2294 + commit_footer += "(Portage version: %s/%s/%s" % \
2295 + (portage_version, vcs_settings.vcs, unameout)
2296 + if report_options:
2297 + commit_footer += ", RepoMan options: " + " ".join(report_options)
2298 + if repo_settings.sign_manifests:
2299 + commit_footer += ", signed Manifest commit with key %s" % \
2300 + (gpg_key, )
2301 + else:
2302 + commit_footer += ", unsigned Manifest commit"
2303 + commit_footer += ")"
2304
2305 - if myautoadd:
2306 - print(">>> Auto-Adding missing Manifest/ChangeLog file(s)...")
2307 - add_cmd = [vcs_settings.vcs, "add"]
2308 - add_cmd += myautoadd
2309 - if options.pretend:
2310 - portage.writemsg_stdout(
2311 - "(%s)\n" % " ".join(add_cmd),
2312 - noiselevel=-1)
2313 - else:
2314 + commitmessage += commit_footer
2315
2316 - if sys.hexversion < 0x3020000 and sys.hexversion >= 0x3000000 and \
2317 - not os.path.isabs(add_cmd[0]):
2318 - # Python 3.1 _execvp throws TypeError for non-absolute executable
2319 - # path passed as bytes (see http://bugs.python.org/issue8513).
2320 - fullname = find_binary(add_cmd[0])
2321 - if fullname is None:
2322 - raise portage.exception.CommandNotFound(add_cmd[0])
2323 - add_cmd[0] = fullname
2324 -
2325 - add_cmd = [_unicode_encode(arg) for arg in add_cmd]
2326 - retcode = subprocess.call(add_cmd)
2327 - if retcode != os.EX_OK:
2328 - logging.error(
2329 - "Exiting on %s error code: %s\n" % (vcs_settings.vcs, retcode))
2330 - sys.exit(retcode)
2331 -
2332 - myupdates += myautoadd
2333 -
2334 - print("* %s files being committed..." % green(str(len(myupdates))), end=' ')
2335 -
2336 - if vcs_settings.vcs not in ('cvs', 'svn'):
2337 - # With git, bzr and hg, there's never any keyword expansion, so
2338 - # there's no need to regenerate manifests and all files will be
2339 - # committed in one big commit at the end.
2340 - print()
2341 - elif not repo_settings.repo_config.thin_manifest:
2342 - if vcs_settings.vcs == 'cvs':
2343 - headerstring = "'\$(Header|Id).*\$'"
2344 - elif vcs_settings.vcs == "svn":
2345 - svn_keywords = dict((k.lower(), k) for k in [
2346 - "Rev",
2347 - "Revision",
2348 - "LastChangedRevision",
2349 - "Date",
2350 - "LastChangedDate",
2351 - "Author",
2352 - "LastChangedBy",
2353 - "URL",
2354 - "HeadURL",
2355 - "Id",
2356 - "Header",
2357 - ])
2358 -
2359 - for myfile in myupdates:
2360 -
2361 - # for CVS, no_expansion contains files that are excluded from expansion
2362 - if vcs_settings.vcs == "cvs":
2363 - if myfile in no_expansion:
2364 + broken_changelog_manifests = []
2365 + if options.echangelog in ('y', 'force'):
2366 + logging.info("checking for unmodified ChangeLog files")
2367 + committer_name = utilities.get_committer_name(env=repoman_settings)
2368 + for x in sorted(vcs_files_to_cps(
2369 + chain(myupdates, mymanifests, myremoved),
2370 + repolevel, reposplit, categories)):
2371 + catdir, pkgdir = x.split("/")
2372 + checkdir = repo_settings.repodir + "/" + x
2373 + checkdir_relative = ""
2374 + if repolevel < 3:
2375 + checkdir_relative = os.path.join(pkgdir, checkdir_relative)
2376 + if repolevel < 2:
2377 + checkdir_relative = os.path.join(catdir, checkdir_relative)
2378 + checkdir_relative = os.path.join(".", checkdir_relative)
2379 +
2380 + changelog_path = os.path.join(checkdir_relative, "ChangeLog")
2381 + changelog_modified = changelog_path in changed.changelogs
2382 + if changelog_modified and options.echangelog != 'force':
2383 continue
2384
2385 - # for SVN, expansion contains files that are included in expansion
2386 - elif vcs_settings.vcs == "svn":
2387 - if myfile not in expansion:
2388 + # get changes for this package
2389 + cdrlen = len(checkdir_relative)
2390 + check_relative = lambda e: e.startswith(checkdir_relative)
2391 + split_relative = lambda e: e[cdrlen:]
2392 + clnew = list(map(split_relative, filter(check_relative, mynew)))
2393 + clremoved = list(map(split_relative, filter(check_relative, myremoved)))
2394 + clchanged = list(map(split_relative, filter(check_relative, mychanged)))
2395 +
2396 + # Skip ChangeLog generation if only the Manifest was modified,
2397 + # as discussed in bug #398009.
2398 + nontrivial_cl_files = set()
2399 + nontrivial_cl_files.update(clnew, clremoved, clchanged)
2400 + nontrivial_cl_files.difference_update(['Manifest'])
2401 + if not nontrivial_cl_files and options.echangelog != 'force':
2402 continue
2403
2404 - # Subversion keywords are case-insensitive
2405 - # in svn:keywords properties,
2406 - # but case-sensitive in contents of files.
2407 - enabled_keywords = []
2408 - for k in expansion[myfile]:
2409 - keyword = svn_keywords.get(k.lower())
2410 - if keyword is not None:
2411 - enabled_keywords.append(keyword)
2412 -
2413 - headerstring = "'\$(%s).*\$'" % "|".join(enabled_keywords)
2414 -
2415 - myout = repoman_getstatusoutput(
2416 - "egrep -q %s %s" % (headerstring, portage._shell_quote(myfile)))
2417 - if myout[0] == 0:
2418 - myheaders.append(myfile)
2419 -
2420 - print("%s have headers that will change." % green(str(len(myheaders))))
2421 - print(
2422 - "* Files with headers will"
2423 - " cause the manifests to be changed and committed separately.")
2424 -
2425 - logging.info("myupdates: %s", myupdates)
2426 - logging.info("myheaders: %s", myheaders)
2427 -
2428 - uq = UserQuery(options)
2429 - if options.ask and uq.query('Commit changes?', True) != 'Yes':
2430 - print("* aborting commit.")
2431 - sys.exit(128 + signal.SIGINT)
2432 -
2433 - # Handle the case where committed files have keywords which
2434 - # will change and need a priming commit before the Manifest
2435 - # can be committed.
2436 - if (myupdates or myremoved) and myheaders:
2437 - myfiles = myupdates + myremoved
2438 - fd, commitmessagefile = tempfile.mkstemp(".repoman.msg")
2439 - mymsg = os.fdopen(fd, "wb")
2440 - mymsg.write(_unicode_encode(commitmessage))
2441 - mymsg.close()
2442 -
2443 - separator = '-' * 78
2444 -
2445 - print()
2446 - print(green("Using commit message:"))
2447 - print(green(separator))
2448 - print(commitmessage)
2449 - print(green(separator))
2450 - print()
2451 + new_changelog = utilities.UpdateChangeLog(
2452 + checkdir_relative, committer_name, changelog_msg,
2453 + os.path.join(repo_settings.repodir, 'skel.ChangeLog'),
2454 + catdir, pkgdir,
2455 + new=clnew, removed=clremoved, changed=clchanged,
2456 + pretend=options.pretend)
2457 + if new_changelog is None:
2458 + writemsg_level(
2459 + "!!! Updating the ChangeLog failed\n",
2460 + level=logging.ERROR, noiselevel=-1)
2461 + sys.exit(1)
2462
2463 - # Having a leading ./ prefix on file paths can trigger a bug in
2464 - # the cvs server when committing files to multiple directories,
2465 - # so strip the prefix.
2466 - myfiles = [f.lstrip("./") for f in myfiles]
2467 + # if the ChangeLog was just created, add it to vcs
2468 + if new_changelog:
2469 + myautoadd.append(changelog_path)
2470 + # myautoadd is appended to myupdates below
2471 + else:
2472 + myupdates.append(changelog_path)
2473
2474 - commit_cmd = [vcs_settings.vcs]
2475 - commit_cmd.extend(vcs_settings.vcs_global_opts)
2476 - commit_cmd.append("commit")
2477 - commit_cmd.extend(vcs_settings.vcs_local_opts)
2478 - commit_cmd.extend(["-F", commitmessagefile])
2479 - commit_cmd.extend(myfiles)
2480 + if options.ask and not options.pretend:
2481 + # regenerate Manifest for modified ChangeLog (bug #420735)
2482 + repoman_settings["O"] = checkdir
2483 + digestgen(mysettings=repoman_settings, myportdb=portdb)
2484 + else:
2485 + broken_changelog_manifests.append(x)
2486
2487 - try:
2488 + if myautoadd:
2489 + print(">>> Auto-Adding missing Manifest/ChangeLog file(s)...")
2490 + add_cmd = [vcs_settings.vcs, "add"]
2491 + add_cmd += myautoadd
2492 if options.pretend:
2493 - print("(%s)" % (" ".join(commit_cmd),))
2494 + portage.writemsg_stdout(
2495 + "(%s)\n" % " ".join(add_cmd),
2496 + noiselevel=-1)
2497 else:
2498 - retval = spawn(commit_cmd, env=repo_settings.commit_env)
2499 - if retval != os.EX_OK:
2500 - writemsg_level(
2501 - "!!! Exiting on %s (shell) "
2502 - "error code: %s\n" % (vcs_settings.vcs, retval),
2503 - level=logging.ERROR, noiselevel=-1)
2504 - sys.exit(retval)
2505 - finally:
2506 - try:
2507 - os.unlink(commitmessagefile)
2508 - except OSError:
2509 - pass
2510
2511 - # Setup the GPG commands
2512 - def gpgsign(filename):
2513 - gpgcmd = repoman_settings.get("PORTAGE_GPG_SIGNING_COMMAND")
2514 - if gpgcmd is None:
2515 - raise MissingParameter(
2516 - "PORTAGE_GPG_SIGNING_COMMAND is unset!"
2517 - " Is make.globals missing?")
2518 - if "${PORTAGE_GPG_KEY}" in gpgcmd and \
2519 - "PORTAGE_GPG_KEY" not in repoman_settings:
2520 - raise MissingParameter("PORTAGE_GPG_KEY is unset!")
2521 - if "${PORTAGE_GPG_DIR}" in gpgcmd:
2522 - if "PORTAGE_GPG_DIR" not in repoman_settings:
2523 - repoman_settings["PORTAGE_GPG_DIR"] = \
2524 - os.path.expanduser("~/.gnupg")
2525 - logging.info(
2526 - "Automatically setting PORTAGE_GPG_DIR to '%s'" %
2527 - repoman_settings["PORTAGE_GPG_DIR"])
2528 - else:
2529 - repoman_settings["PORTAGE_GPG_DIR"] = \
2530 - os.path.expanduser(repoman_settings["PORTAGE_GPG_DIR"])
2531 - if not os.access(repoman_settings["PORTAGE_GPG_DIR"], os.X_OK):
2532 - raise portage.exception.InvalidLocation(
2533 - "Unable to access directory: PORTAGE_GPG_DIR='%s'" %
2534 - repoman_settings["PORTAGE_GPG_DIR"])
2535 - gpgvars = {"FILE": filename}
2536 - for k in ("PORTAGE_GPG_DIR", "PORTAGE_GPG_KEY"):
2537 - v = repoman_settings.get(k)
2538 - if v is not None:
2539 - gpgvars[k] = v
2540 - gpgcmd = portage.util.varexpand(gpgcmd, mydict=gpgvars)
2541 - if options.pretend:
2542 - print("(" + gpgcmd + ")")
2543 - else:
2544 - # Encode unicode manually for bug #310789.
2545 - gpgcmd = portage.util.shlex_split(gpgcmd)
2546 -
2547 - if sys.hexversion < 0x3020000 and sys.hexversion >= 0x3000000 and \
2548 - not os.path.isabs(gpgcmd[0]):
2549 - # Python 3.1 _execvp throws TypeError for non-absolute executable
2550 - # path passed as bytes (see http://bugs.python.org/issue8513).
2551 - fullname = find_binary(gpgcmd[0])
2552 - if fullname is None:
2553 - raise portage.exception.CommandNotFound(gpgcmd[0])
2554 - gpgcmd[0] = fullname
2555 -
2556 - gpgcmd = [
2557 - _unicode_encode(arg, encoding=_encodings['fs'], errors='strict')
2558 - for arg in gpgcmd]
2559 - rValue = subprocess.call(gpgcmd)
2560 - if rValue == os.EX_OK:
2561 - os.rename(filename + ".asc", filename)
2562 - else:
2563 - raise portage.exception.PortageException(
2564 - "!!! gpg exited with '" + str(rValue) + "' status")
2565 + if sys.hexversion < 0x3020000 and sys.hexversion >= 0x3000000 and \
2566 + not os.path.isabs(add_cmd[0]):
2567 + # Python 3.1 _execvp throws TypeError for non-absolute executable
2568 + # path passed as bytes (see http://bugs.python.org/issue8513).
2569 + fullname = find_binary(add_cmd[0])
2570 + if fullname is None:
2571 + raise portage.exception.CommandNotFound(add_cmd[0])
2572 + add_cmd[0] = fullname
2573 +
2574 + add_cmd = [_unicode_encode(arg) for arg in add_cmd]
2575 + retcode = subprocess.call(add_cmd)
2576 + if retcode != os.EX_OK:
2577 + logging.error(
2578 + "Exiting on %s error code: %s\n" % (vcs_settings.vcs, retcode))
2579 + sys.exit(retcode)
2580 +
2581 + myupdates += myautoadd
2582 +
2583 + print("* %s files being committed..." % green(str(len(myupdates))), end=' ')
2584 +
2585 + if vcs_settings.vcs not in ('cvs', 'svn'):
2586 + # With git, bzr and hg, there's never any keyword expansion, so
2587 + # there's no need to regenerate manifests and all files will be
2588 + # committed in one big commit at the end.
2589 + print()
2590 + elif not repo_settings.repo_config.thin_manifest:
2591 + if vcs_settings.vcs == 'cvs':
2592 + headerstring = "'\$(Header|Id).*\$'"
2593 + elif vcs_settings.vcs == "svn":
2594 + svn_keywords = dict((k.lower(), k) for k in [
2595 + "Rev",
2596 + "Revision",
2597 + "LastChangedRevision",
2598 + "Date",
2599 + "LastChangedDate",
2600 + "Author",
2601 + "LastChangedBy",
2602 + "URL",
2603 + "HeadURL",
2604 + "Id",
2605 + "Header",
2606 + ])
2607 +
2608 + for myfile in myupdates:
2609 +
2610 + # for CVS, no_expansion contains files that are excluded from expansion
2611 + if vcs_settings.vcs == "cvs":
2612 + if myfile in no_expansion:
2613 + continue
2614
2615 - def need_signature(filename):
2616 - try:
2617 - with open(
2618 - _unicode_encode(
2619 - filename, encoding=_encodings['fs'], errors='strict'),
2620 - 'rb') as f:
2621 - return b"BEGIN PGP SIGNED MESSAGE" not in f.readline()
2622 - except IOError as e:
2623 - if e.errno in (errno.ENOENT, errno.ESTALE):
2624 - return False
2625 - raise
2626 + # for SVN, expansion contains files that are included in expansion
2627 + elif vcs_settings.vcs == "svn":
2628 + if myfile not in expansion:
2629 + continue
2630
2631 - # When files are removed and re-added, the cvs server will put /Attic/
2632 - # inside the $Header path. This code detects the problem and corrects it
2633 - # so that the Manifest will generate correctly. See bug #169500.
2634 - # Use binary mode in order to avoid potential character encoding issues.
2635 - cvs_header_re = re.compile(br'^#\s*\$Header.*\$$')
2636 - attic_str = b'/Attic/'
2637 - attic_replace = b'/'
2638 - for x in myheaders:
2639 - f = open(
2640 - _unicode_encode(x, encoding=_encodings['fs'], errors='strict'),
2641 - mode='rb')
2642 - mylines = f.readlines()
2643 - f.close()
2644 - modified = False
2645 - for i, line in enumerate(mylines):
2646 - if cvs_header_re.match(line) is not None and \
2647 - attic_str in line:
2648 - mylines[i] = line.replace(attic_str, attic_replace)
2649 - modified = True
2650 - if modified:
2651 - portage.util.write_atomic(x, b''.join(mylines), mode='wb')
2652 + # Subversion keywords are case-insensitive
2653 + # in svn:keywords properties,
2654 + # but case-sensitive in contents of files.
2655 + enabled_keywords = []
2656 + for k in expansion[myfile]:
2657 + keyword = svn_keywords.get(k.lower())
2658 + if keyword is not None:
2659 + enabled_keywords.append(keyword)
2660 +
2661 + headerstring = "'\$(%s).*\$'" % "|".join(enabled_keywords)
2662 +
2663 + myout = repoman_getstatusoutput(
2664 + "egrep -q %s %s" % (headerstring, portage._shell_quote(myfile)))
2665 + if myout[0] == 0:
2666 + myheaders.append(myfile)
2667 +
2668 + print("%s have headers that will change." % green(str(len(myheaders))))
2669 + print(
2670 + "* Files with headers will"
2671 + " cause the manifests to be changed and committed separately.")
2672 +
2673 + logging.info("myupdates: %s", myupdates)
2674 + logging.info("myheaders: %s", myheaders)
2675 +
2676 + uq = UserQuery(options)
2677 + if options.ask and uq.query('Commit changes?', True) != 'Yes':
2678 + print("* aborting commit.")
2679 + sys.exit(128 + signal.SIGINT)
2680 +
2681 + # Handle the case where committed files have keywords which
2682 + # will change and need a priming commit before the Manifest
2683 + # can be committed.
2684 + if (myupdates or myremoved) and myheaders:
2685 + myfiles = myupdates + myremoved
2686 + fd, commitmessagefile = tempfile.mkstemp(".repoman.msg")
2687 + mymsg = os.fdopen(fd, "wb")
2688 + mymsg.write(_unicode_encode(commitmessage))
2689 + mymsg.close()
2690 +
2691 + separator = '-' * 78
2692
2693 - if repolevel == 1:
2694 - utilities.repoman_sez(
2695 - "\"You're rather crazy... "
2696 - "doing the entire repository.\"\n")
2697 -
2698 - if vcs_settings.vcs in ('cvs', 'svn') and (myupdates or myremoved):
2699 - for x in sorted(vcs_files_to_cps(
2700 - chain(myupdates, myremoved, mymanifests),
2701 - repolevel, reposplit, categories)):
2702 - repoman_settings["O"] = os.path.join(repo_settings.repodir, x)
2703 - digestgen(mysettings=repoman_settings, myportdb=portdb)
2704 -
2705 - elif broken_changelog_manifests:
2706 - for x in broken_changelog_manifests:
2707 - repoman_settings["O"] = os.path.join(repo_settings.repodir, x)
2708 - digestgen(mysettings=repoman_settings, myportdb=portdb)
2709 -
2710 - signed = False
2711 - if repo_settings.sign_manifests:
2712 - signed = True
2713 - try:
2714 + print()
2715 + print(green("Using commit message:"))
2716 + print(green(separator))
2717 + print(commitmessage)
2718 + print(green(separator))
2719 + print()
2720 +
2721 + # Having a leading ./ prefix on file paths can trigger a bug in
2722 + # the cvs server when committing files to multiple directories,
2723 + # so strip the prefix.
2724 + myfiles = [f.lstrip("./") for f in myfiles]
2725 +
2726 + commit_cmd = [vcs_settings.vcs]
2727 + commit_cmd.extend(vcs_settings.vcs_global_opts)
2728 + commit_cmd.append("commit")
2729 + commit_cmd.extend(vcs_settings.vcs_local_opts)
2730 + commit_cmd.extend(["-F", commitmessagefile])
2731 + commit_cmd.extend(myfiles)
2732 +
2733 + try:
2734 + if options.pretend:
2735 + print("(%s)" % (" ".join(commit_cmd),))
2736 + else:
2737 + retval = spawn(commit_cmd, env=repo_settings.commit_env)
2738 + if retval != os.EX_OK:
2739 + writemsg_level(
2740 + "!!! Exiting on %s (shell) "
2741 + "error code: %s\n" % (vcs_settings.vcs, retval),
2742 + level=logging.ERROR, noiselevel=-1)
2743 + sys.exit(retval)
2744 + finally:
2745 + try:
2746 + os.unlink(commitmessagefile)
2747 + except OSError:
2748 + pass
2749 +
2750 + # When files are removed and re-added, the cvs server will put /Attic/
2751 + # inside the $Header path. This code detects the problem and corrects it
2752 + # so that the Manifest will generate correctly. See bug #169500.
2753 + # Use binary mode in order to avoid potential character encoding issues.
2754 + cvs_header_re = re.compile(br'^#\s*\$Header.*\$$')
2755 + attic_str = b'/Attic/'
2756 + attic_replace = b'/'
2757 + for x in myheaders:
2758 + f = open(
2759 + _unicode_encode(x, encoding=_encodings['fs'], errors='strict'),
2760 + mode='rb')
2761 + mylines = f.readlines()
2762 + f.close()
2763 + modified = False
2764 + for i, line in enumerate(mylines):
2765 + if cvs_header_re.match(line) is not None and \
2766 + attic_str in line:
2767 + mylines[i] = line.replace(attic_str, attic_replace)
2768 + modified = True
2769 + if modified:
2770 + portage.util.write_atomic(x, b''.join(mylines), mode='wb')
2771 +
2772 + if repolevel == 1:
2773 + utilities.repoman_sez(
2774 + "\"You're rather crazy... "
2775 + "doing the entire repository.\"\n")
2776 +
2777 + if vcs_settings.vcs in ('cvs', 'svn') and (myupdates or myremoved):
2778 for x in sorted(vcs_files_to_cps(
2779 chain(myupdates, myremoved, mymanifests),
2780 repolevel, reposplit, categories)):
2781 repoman_settings["O"] = os.path.join(repo_settings.repodir, x)
2782 - manifest_path = os.path.join(repoman_settings["O"], "Manifest")
2783 - if not need_signature(manifest_path):
2784 - continue
2785 - gpgsign(manifest_path)
2786 - except portage.exception.PortageException as e:
2787 - portage.writemsg("!!! %s\n" % str(e))
2788 - portage.writemsg("!!! Disabled FEATURES='sign'\n")
2789 - signed = False
2790 -
2791 - if vcs_settings.vcs == 'git':
2792 - # It's not safe to use the git commit -a option since there might
2793 - # be some modified files elsewhere in the working tree that the
2794 - # user doesn't want to commit. Therefore, call git update-index
2795 - # in order to ensure that the index is updated with the latest
2796 - # versions of all new and modified files in the relevant portion
2797 - # of the working tree.
2798 - myfiles = mymanifests + myupdates
2799 - myfiles.sort()
2800 - update_index_cmd = ["git", "update-index"]
2801 - update_index_cmd.extend(f.lstrip("./") for f in myfiles)
2802 - if options.pretend:
2803 - print("(%s)" % (" ".join(update_index_cmd),))
2804 - else:
2805 - retval = spawn(update_index_cmd, env=os.environ)
2806 - if retval != os.EX_OK:
2807 - writemsg_level(
2808 - "!!! Exiting on %s (shell) "
2809 - "error code: %s\n" % (vcs_settings.vcs, retval),
2810 - level=logging.ERROR, noiselevel=-1)
2811 - sys.exit(retval)
2812 -
2813 - if True:
2814 - myfiles = mymanifests[:]
2815 - # If there are no header (SVN/CVS keywords) changes in
2816 - # the files, this Manifest commit must include the
2817 - # other (yet uncommitted) files.
2818 - if not myheaders:
2819 - myfiles += myupdates
2820 - myfiles += myremoved
2821 - myfiles.sort()
2822 -
2823 - fd, commitmessagefile = tempfile.mkstemp(".repoman.msg")
2824 - mymsg = os.fdopen(fd, "wb")
2825 - mymsg.write(_unicode_encode(commitmessage))
2826 - mymsg.close()
2827 -
2828 - commit_cmd = []
2829 - if options.pretend and vcs_settings.vcs is None:
2830 - # substitute a bogus value for pretend output
2831 - commit_cmd.append("cvs")
2832 - else:
2833 - commit_cmd.append(vcs_settings.vcs)
2834 - commit_cmd.extend(vcs_settings.vcs_global_opts)
2835 - commit_cmd.append("commit")
2836 - commit_cmd.extend(vcs_settings.vcs_local_opts)
2837 - if vcs_settings.vcs == "hg":
2838 - commit_cmd.extend(["--logfile", commitmessagefile])
2839 - commit_cmd.extend(myfiles)
2840 - else:
2841 - commit_cmd.extend(["-F", commitmessagefile])
2842 - commit_cmd.extend(f.lstrip("./") for f in myfiles)
2843 + digestgen(mysettings=repoman_settings, myportdb=portdb)
2844
2845 - try:
2846 + elif broken_changelog_manifests:
2847 + for x in broken_changelog_manifests:
2848 + repoman_settings["O"] = os.path.join(repo_settings.repodir, x)
2849 + digestgen(mysettings=repoman_settings, myportdb=portdb)
2850 +
2851 + signed = False
2852 + if repo_settings.sign_manifests:
2853 + signed = True
2854 + try:
2855 + for x in sorted(vcs_files_to_cps(
2856 + chain(myupdates, myremoved, mymanifests),
2857 + repolevel, reposplit, categories)):
2858 + repoman_settings["O"] = os.path.join(repo_settings.repodir, x)
2859 + manifest_path = os.path.join(repoman_settings["O"], "Manifest")
2860 + if not need_signature(manifest_path):
2861 + continue
2862 + gpgsign(manifest_path)
2863 + except portage.exception.PortageException as e:
2864 + portage.writemsg("!!! %s\n" % str(e))
2865 + portage.writemsg("!!! Disabled FEATURES='sign'\n")
2866 + signed = False
2867 +
2868 + if vcs_settings.vcs == 'git':
2869 + # It's not safe to use the git commit -a option since there might
2870 + # be some modified files elsewhere in the working tree that the
2871 + # user doesn't want to commit. Therefore, call git update-index
2872 + # in order to ensure that the index is updated with the latest
2873 + # versions of all new and modified files in the relevant portion
2874 + # of the working tree.
2875 + myfiles = mymanifests + myupdates
2876 + myfiles.sort()
2877 + update_index_cmd = ["git", "update-index"]
2878 + update_index_cmd.extend(f.lstrip("./") for f in myfiles)
2879 if options.pretend:
2880 - print("(%s)" % (" ".join(commit_cmd),))
2881 + print("(%s)" % (" ".join(update_index_cmd),))
2882 else:
2883 - retval = spawn(commit_cmd, env=repo_settings.commit_env)
2884 + retval = spawn(update_index_cmd, env=os.environ)
2885 if retval != os.EX_OK:
2886 - if repo_settings.repo_config.sign_commit and vcs_settings.vcs == 'git' and \
2887 - not git_supports_gpg_sign():
2888 - # Inform user that newer git is needed (bug #403323).
2889 - logging.error(
2890 - "Git >=1.7.9 is required for signed commits!")
2891 -
2892 writemsg_level(
2893 "!!! Exiting on %s (shell) "
2894 "error code: %s\n" % (vcs_settings.vcs, retval),
2895 level=logging.ERROR, noiselevel=-1)
2896 sys.exit(retval)
2897 - finally:
2898 +
2899 + if True:
2900 + myfiles = mymanifests[:]
2901 + # If there are no header (SVN/CVS keywords) changes in
2902 + # the files, this Manifest commit must include the
2903 + # other (yet uncommitted) files.
2904 + if not myheaders:
2905 + myfiles += myupdates
2906 + myfiles += myremoved
2907 + myfiles.sort()
2908 +
2909 + fd, commitmessagefile = tempfile.mkstemp(".repoman.msg")
2910 + mymsg = os.fdopen(fd, "wb")
2911 + mymsg.write(_unicode_encode(commitmessage))
2912 + mymsg.close()
2913 +
2914 + commit_cmd = []
2915 + if options.pretend and vcs_settings.vcs is None:
2916 + # substitute a bogus value for pretend output
2917 + commit_cmd.append("cvs")
2918 + else:
2919 + commit_cmd.append(vcs_settings.vcs)
2920 + commit_cmd.extend(vcs_settings.vcs_global_opts)
2921 + commit_cmd.append("commit")
2922 + commit_cmd.extend(vcs_settings.vcs_local_opts)
2923 + if vcs_settings.vcs == "hg":
2924 + commit_cmd.extend(["--logfile", commitmessagefile])
2925 + commit_cmd.extend(myfiles)
2926 + else:
2927 + commit_cmd.extend(["-F", commitmessagefile])
2928 + commit_cmd.extend(f.lstrip("./") for f in myfiles)
2929 +
2930 try:
2931 - os.unlink(commitmessagefile)
2932 - except OSError:
2933 - pass
2934 + if options.pretend:
2935 + print("(%s)" % (" ".join(commit_cmd),))
2936 + else:
2937 + retval = spawn(commit_cmd, env=repo_settings.commit_env)
2938 + if retval != os.EX_OK:
2939 + if repo_settings.repo_config.sign_commit and vcs_settings.vcs == 'git' and \
2940 + not git_supports_gpg_sign():
2941 + # Inform user that newer git is needed (bug #403323).
2942 + logging.error(
2943 + "Git >=1.7.9 is required for signed commits!")
2944 +
2945 + writemsg_level(
2946 + "!!! Exiting on %s (shell) "
2947 + "error code: %s\n" % (vcs_settings.vcs, retval),
2948 + level=logging.ERROR, noiselevel=-1)
2949 + sys.exit(retval)
2950 + finally:
2951 + try:
2952 + os.unlink(commitmessagefile)
2953 + except OSError:
2954 + pass
2955
2956 - print()
2957 - if vcs_settings.vcs:
2958 - print("Commit complete.")
2959 - else:
2960 - print(
2961 - "repoman was too scared"
2962 - " by not seeing any familiar version control file"
2963 - " that he forgot to commit anything")
2964 - utilities.repoman_sez(
2965 - "\"If everyone were like you, I'd be out of business!\"\n")
2966 -sys.exit(0)
2967 + print()
2968 + if vcs_settings.vcs:
2969 + print("Commit complete.")
2970 + else:
2971 + print(
2972 + "repoman was too scared"
2973 + " by not seeing any familiar version control file"
2974 + " that he forgot to commit anything")
2975 + utilities.repoman_sez(
2976 + "\"If everyone were like you, I'd be out of business!\"\n")
2977 + sys.exit(0)
2978
2979 diff --git a/tbc/pym/updatedb.py b/tbc/pym/updatedb.py
2980 index fb96e13..b860f51 100644
2981 --- a/tbc/pym/updatedb.py
2982 +++ b/tbc/pym/updatedb.py
2983 @@ -6,6 +6,7 @@ import sys
2984 import os
2985 import multiprocessing
2986 import time
2987 +import re
2988 import portage
2989 from portage.xml.metadata import MetaDataXML
2990 from sqlalchemy.orm import scoped_session, sessionmaker
2991 @@ -58,7 +59,7 @@ def update_cpv_db_pool(mysettings, myportdb, cp, repo, tbc_settings, config_id):
2992 package = element[1]
2993
2994 # update the categories table
2995 - repodir = self._myportdb.getRepositoryPath('gentoo')
2996 + repodir = myportdb.getRepositoryPath('gentoo')
2997 pkgdir = repodir + "/" + categories
2998 categories_metadataDict = get_categories_metadataDict(pkgdir)
2999 update_categories_db(session2, categories, categories_metadataDict)