Gentoo Archives: gentoo-commits

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