Gentoo Archives: gentoo-commits

From: Brian Dolbec <dolsen@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] proj/portage:master commit in: pym/repoman/
Date: Mon, 21 Sep 2015 23:51:47
Message-Id: 1442878966.8553e18d54009d5fb804a7a9d65ae0d8f7de2cba.dolsen@gentoo
1 commit: 8553e18d54009d5fb804a7a9d65ae0d8f7de2cba
2 Author: Brian Dolbec <dolsen <AT> gentoo <DOT> org>
3 AuthorDate: Sat Sep 19 00:48:05 2015 +0000
4 Commit: Brian Dolbec <dolsen <AT> gentoo <DOT> org>
5 CommitDate: Mon Sep 21 23:42:46 2015 +0000
6 URL: https://gitweb.gentoo.org/proj/portage.git/commit/?id=8553e18d
7
8 repoman: Move the remaining actions to an Actions class
9
10 Fix regression from which always runs commit mode.
11 Error found by Mike Gilbert
12 actions.py: Assign repoman_settings from the repo_settings variable
13 Add a return to the end perform(), it just didn't seem right to leave it hanging.
14
15 pym/repoman/{main.py => actions.py} | 662 +++++++++++++------------------
16 pym/repoman/main.py | 756 ++----------------------------------
17 2 files changed, 302 insertions(+), 1116 deletions(-)
18
19 diff --git a/pym/repoman/main.py b/pym/repoman/actions.py
20 old mode 100755
21 new mode 100644
22 similarity index 66%
23 copy from pym/repoman/main.py
24 copy to pym/repoman/actions.py
25 index 2b2f91d..611c0dd
26 --- a/pym/repoman/main.py
27 +++ b/pym/repoman/actions.py
28 @@ -1,337 +1,80 @@
29 -#!/usr/bin/python -bO
30 -# Copyright 1999-2015 Gentoo Foundation
31 -# Distributed under the terms of the GNU General Public License v2
32 -
33 -from __future__ import print_function, unicode_literals
34
35 import errno
36 import io
37 import logging
38 +import platform
39 import re
40 import signal
41 import subprocess
42 import sys
43 import tempfile
44 -import platform
45 from itertools import chain
46
47 -from os import path as osp
48 -if osp.isfile(osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), ".portage_not_installed")):
49 - pym_path = osp.join(osp.dirname(osp.dirname(osp.realpath(__file__)))) #, "pym")
50 - sys.path.insert(0, pym_path)
51 -# import our centrally initialized portage instance
52 -from repoman._portage import portage
53 -portage._internal_caller = True
54 -portage._disable_legacy_globals()
55 -
56 +from _emerge.UserQuery import UserQuery
57
58 +import portage
59 +from portage import cvstree
60 from portage import os
61 from portage import _encodings
62 from portage import _unicode_encode
63 -from _emerge.UserQuery import UserQuery
64 -import portage.checksum
65 -import portage.const
66 -import portage.repository.config
67 -from portage import cvstree
68 -from portage import util
69 -from portage.process import find_binary, spawn
70 from portage.output import (
71 - bold, create_color_func, green, nocolor, red)
72 -from portage.output import ConsoleStyleFile, StyleWriter
73 -from portage.util import formatter
74 -from portage.util import writemsg_level
75 + bold, create_color_func, green, red)
76 from portage.package.ebuild.digestgen import digestgen
77 +from portage.process import find_binary, spawn
78 +from portage.util import writemsg_level
79
80 -from repoman.argparser import parse_args
81 -from repoman.checks.ebuilds.checks import checks_init
82 +from repoman._subprocess import repoman_popen, repoman_getstatusoutput
83 from repoman.errors import err
84 from repoman.gpg import gpgsign, need_signature
85 -from repoman.qa_data import (
86 - format_qa_output, format_qa_output_column, qahelp,
87 - qawarnings, qacats)
88 -from repoman.repos import RepoSettings
89 -from repoman.scanner import Scanner
90 -from repoman._subprocess import repoman_popen, repoman_getstatusoutput
91 from repoman import utilities
92 -from repoman.vcs.vcs import (
93 - git_supports_gpg_sign, vcs_files_to_cps, VCSSettings)
94 -
95 -
96 -if sys.hexversion >= 0x3000000:
97 - basestring = str
98 -
99 -util.initialize_logger()
100 +from repoman.vcs.vcs import git_supports_gpg_sign, vcs_files_to_cps
101
102 bad = create_color_func("BAD")
103
104 -# A sane umask is needed for files that portage creates.
105 -os.umask(0o22)
106 -
107 -
108 -def repoman_main(argv):
109 - config_root = os.environ.get("PORTAGE_CONFIGROOT")
110 - repoman_settings = portage.config(config_root=config_root, local_config=False)
111 -
112 - if repoman_settings.get("NOCOLOR", "").lower() in ("yes", "true") or \
113 - repoman_settings.get('TERM') == 'dumb' or \
114 - not sys.stdout.isatty():
115 - nocolor()
116 -
117 - options, arguments = parse_args(
118 - sys.argv, qahelp, repoman_settings.get("REPOMAN_DEFAULT_OPTS", ""))
119 -
120 - if options.version:
121 - print("Portage", portage.VERSION)
122 - sys.exit(0)
123 -
124 - if options.experimental_inherit == 'y':
125 - # This is experimental, so it's non-fatal.
126 - qawarnings.add("inherit.missing")
127 - checks_init(experimental_inherit=True)
128 -
129 - # Set this to False when an extraordinary issue (generally
130 - # something other than a QA issue) makes it impossible to
131 - # commit (like if Manifest generation fails).
132 - can_force = True
133 -
134 - portdir, portdir_overlay, mydir = utilities.FindPortdir(repoman_settings)
135 - if portdir is None:
136 - sys.exit(1)
137 -
138 - myreporoot = os.path.basename(portdir_overlay)
139 - myreporoot += mydir[len(portdir_overlay):]
140 -
141 - vcs_settings = VCSSettings(options, repoman_settings)
142 -
143 - repo_settings = RepoSettings(
144 - config_root, portdir, portdir_overlay,
145 - repoman_settings, vcs_settings, options, qawarnings)
146 - repoman_settings = repo_settings.repoman_settings
147 - portdb = repo_settings.portdb
148 -
149 - if 'digest' in repoman_settings.features and options.digest != 'n':
150 - options.digest = 'y'
151 -
152 - logging.debug("vcs: %s" % (vcs_settings.vcs,))
153 - logging.debug("repo config: %s" % (repo_settings.repo_config,))
154 - logging.debug("options: %s" % (options,))
155 -
156 - # It's confusing if these warnings are displayed without the user
157 - # being told which profile they come from, so disable them.
158 - env = os.environ.copy()
159 - env['FEATURES'] = env.get('FEATURES', '') + ' -unknown-features-warn'
160 -
161 - # Perform the main checks
162 - scanner = Scanner(repo_settings, myreporoot, config_root, options,
163 - vcs_settings, mydir, env)
164 - qatracker, can_force = scanner.scan_pkgs(can_force)
165 -
166 - commitmessage = None
167 -
168 - if options.if_modified == "y" and len(scanner.effective_scanlist) < 1:
169 - logging.warning("--if-modified is enabled, but no modified packages were found!")
170 -
171 - # dofail will be true if we have failed in at least one non-warning category
172 - dofail = 0
173 - # dowarn will be true if we tripped any warnings
174 - dowarn = 0
175 - # dofull will be true if we should print a "repoman full" informational message
176 - dofull = options.mode != 'full'
177 -
178 - # early out for manifest generation
179 - if options.mode == "manifest":
180 - sys.exit(dofail)
181 -
182 - for x in qacats:
183 - if x not in qatracker.fails:
184 - continue
185 - dowarn = 1
186 - if x not in qawarnings:
187 - dofail = 1
188 -
189 - if dofail or \
190 - (dowarn and not (options.quiet or options.mode == "scan")):
191 - dofull = 0
192 -
193 - # Save QA output so that it can be conveniently displayed
194 - # in $EDITOR while the user creates a commit message.
195 - # Otherwise, the user would not be able to see this output
196 - # once the editor has taken over the screen.
197 - qa_output = io.StringIO()
198 - style_file = ConsoleStyleFile(sys.stdout)
199 - if options.mode == 'commit' and \
200 - (not commitmessage or not commitmessage.strip()):
201 - style_file.write_listener = qa_output
202 - console_writer = StyleWriter(file=style_file, maxcol=9999)
203 - console_writer.style_listener = style_file.new_styles
204 -
205 - f = formatter.AbstractFormatter(console_writer)
206 -
207 - format_outputs = {
208 - 'column': format_qa_output_column,
209 - 'default': format_qa_output
210 - }
211 -
212 - format_output = format_outputs.get(
213 - options.output_style, format_outputs['default'])
214 - format_output(f, qatracker.fails, dofull, dofail, options, qawarnings)
215 -
216 - style_file.flush()
217 - del console_writer, f, style_file
218 - qa_output = qa_output.getvalue()
219 - qa_output = qa_output.splitlines(True)
220 -
221 - suggest_ignore_masked = False
222 - suggest_include_dev = False
223 -
224 - if scanner.have['pmasked'] and not (options.without_mask or options.ignore_masked):
225 - suggest_ignore_masked = True
226 - if scanner.have['dev_keywords'] and not options.include_dev:
227 - suggest_include_dev = True
228 -
229 - if suggest_ignore_masked or suggest_include_dev:
230 - print()
231 - if suggest_ignore_masked:
232 - print(bold(
233 - "Note: use --without-mask to check "
234 - "KEYWORDS on dependencies of masked packages"))
235
236 - if suggest_include_dev:
237 - print(bold(
238 - "Note: use --include-dev (-d) to check "
239 - "dependencies for 'dev' profiles"))
240 - print()
241 +class Actions(object):
242 + '''Handles post check result output and performs
243 + the various vcs activities for committing the results'''
244 +
245 + def __init__(self, repo_settings, options, scanner, vcs_settings):
246 + self.repo_settings = repo_settings
247 + self.options = options
248 + self.scanner = scanner
249 + self.vcs_settings = vcs_settings
250 + self.repoman_settings = repo_settings.repoman_settings
251 + self.suggest = {
252 + 'ignore_masked': False,
253 + 'include_dev': False,
254 + }
255 + if scanner.have['pmasked'] and not (options.without_mask or options.ignore_masked):
256 + self.suggest['ignore_masked'] = True
257 + if scanner.have['dev_keywords'] and not options.include_dev:
258 + self.suggest['include_dev'] = True
259 +
260 +
261 + def inform(self, can_force, result):
262 + '''Inform the user of all the problems found'''
263 + if self.suggest['ignore_masked'] or self.suggest['include_dev']:
264 + self._suggest()
265 + if self.options.mode != 'commit':
266 + self._non_commit(result)
267 + return False
268 + else:
269 + self._fail(result, can_force)
270 + if self.options.pretend:
271 + utilities.repoman_sez(
272 + "\"So, you want to play it safe. Good call.\"\n")
273 + return True
274
275 - if options.mode != 'commit':
276 - if dofull:
277 - print(bold("Note: type \"repoman full\" for a complete listing."))
278 - if dowarn and not dofail:
279 - utilities.repoman_sez(
280 - "\"You're only giving me a partial QA payment?\n"
281 - " I'll take it this time, but I'm not happy.\"")
282 - elif not dofail:
283 - utilities.repoman_sez(
284 - "\"If everyone were like you, I'd be out of business!\"")
285 - elif dofail:
286 - print(bad("Please fix these important QA issues first."))
287 - utilities.repoman_sez(
288 - "\"Make your QA payment on time"
289 - " and you'll never see the likes of me.\"\n")
290 - sys.exit(1)
291 - else:
292 - if dofail and can_force and options.force and not options.pretend:
293 - utilities.repoman_sez(
294 - " \"You want to commit even with these QA issues?\n"
295 - " I'll take it this time, but I'm not happy.\"\n")
296 - elif dofail:
297 - if options.force and not can_force:
298 - print(bad(
299 - "The --force option has been disabled"
300 - " due to extraordinary issues."))
301 - print(bad("Please fix these important QA issues first."))
302 - utilities.repoman_sez(
303 - "\"Make your QA payment on time"
304 - " and you'll never see the likes of me.\"\n")
305 - sys.exit(1)
306
307 - if options.pretend:
308 - utilities.repoman_sez(
309 - "\"So, you want to play it safe. Good call.\"\n")
310 + def perform(self, qa_output):
311 + myunadded, mydeleted = self._vcs_unadded()
312
313 - myunadded = []
314 - if vcs_settings.vcs == "cvs":
315 - try:
316 - myvcstree = portage.cvstree.getentries("./", recursive=1)
317 - myunadded = portage.cvstree.findunadded(
318 - myvcstree, recursive=1, basedir="./")
319 - except SystemExit as e:
320 - raise # TODO propagate this
321 - except:
322 - err("Error retrieving CVS tree; exiting.")
323 - if vcs_settings.vcs == "svn":
324 - try:
325 - with repoman_popen("svn status --no-ignore") as f:
326 - svnstatus = f.readlines()
327 - myunadded = [
328 - "./" + elem.rstrip().split()[1]
329 - for elem in svnstatus
330 - if elem.startswith("?") or elem.startswith("I")]
331 - except SystemExit as e:
332 - raise # TODO propagate this
333 - except:
334 - err("Error retrieving SVN info; exiting.")
335 - if vcs_settings.vcs == "git":
336 - # get list of files not under version control or missing
337 - myf = repoman_popen("git ls-files --others")
338 - myunadded = ["./" + elem[:-1] for elem in myf]
339 - myf.close()
340 - if vcs_settings.vcs == "bzr":
341 - try:
342 - with repoman_popen("bzr status -S .") as f:
343 - bzrstatus = f.readlines()
344 - myunadded = [
345 - "./" + elem.rstrip().split()[1].split('/')[-1:][0]
346 - for elem in bzrstatus
347 - if elem.startswith("?") or elem[0:2] == " D"]
348 - except SystemExit as e:
349 - raise # TODO propagate this
350 - except:
351 - err("Error retrieving bzr info; exiting.")
352 - if vcs_settings.vcs == "hg":
353 - with repoman_popen("hg status --no-status --unknown .") as f:
354 - myunadded = f.readlines()
355 - myunadded = ["./" + elem.rstrip() for elem in myunadded]
356 + myautoadd = self._vcs_autoadd(myunadded)
357
358 - # Mercurial doesn't handle manually deleted files as removed from
359 - # the repository, so the user need to remove them before commit,
360 - # using "hg remove [FILES]"
361 - with repoman_popen("hg status --no-status --deleted .") as f:
362 - mydeleted = f.readlines()
363 - mydeleted = ["./" + elem.rstrip() for elem in mydeleted]
364 + self._vcs_deleted(mydeleted)
365
366 - myautoadd = []
367 - if myunadded:
368 - for x in range(len(myunadded) - 1, -1, -1):
369 - xs = myunadded[x].split("/")
370 - if repo_settings.repo_config.find_invalid_path_char(myunadded[x]) != -1:
371 - # The Manifest excludes this file,
372 - # so it's safe to ignore.
373 - del myunadded[x]
374 - elif xs[-1] == "files":
375 - print("!!! files dir is not added! Please correct this.")
376 - sys.exit(-1)
377 - elif xs[-1] == "Manifest":
378 - # It's a manifest... auto add
379 - myautoadd += [myunadded[x]]
380 - del myunadded[x]
381 -
382 - if myunadded:
383 - print(red(
384 - "!!! The following files are in your local tree"
385 - " but are not added to the master"))
386 - print(red(
387 - "!!! tree. Please remove them from the local tree"
388 - " or add them to the master tree."))
389 - for x in myunadded:
390 - print(" ", x)
391 - print()
392 - print()
393 - sys.exit(1)
394 -
395 - if vcs_settings.vcs == "hg" and mydeleted:
396 - print(red(
397 - "!!! The following files are removed manually"
398 - " from your local tree but are not"))
399 - print(red(
400 - "!!! removed from the repository."
401 - " Please remove them, using \"hg remove [FILES]\"."))
402 - for x in mydeleted:
403 - print(" ", x)
404 - print()
405 - print()
406 - sys.exit(1)
407 -
408 - if vcs_settings.vcs == "cvs":
409 + if self.vcs_settings.vcs == "cvs":
410 mycvstree = cvstree.getentries("./", recursive=1)
411 mychanged = cvstree.findchanged(mycvstree, recursive=1, basedir="./")
412 mynew = cvstree.findnew(mycvstree, recursive=1, basedir="./")
413 @@ -340,7 +83,7 @@ def repoman_main(argv):
414 no_expansion = set(portage.cvstree.findoption(
415 mycvstree, bin_blob_pattern, recursive=1, basedir="./"))
416
417 - if vcs_settings.vcs == "svn":
418 + if self.vcs_settings.vcs == "svn":
419 with repoman_popen("svn status") as f:
420 svnstatus = f.readlines()
421 mychanged = [
422 @@ -363,7 +106,7 @@ def repoman_main(argv):
423 ("./" + prop.split(" - ")[0], prop.split(" - ")[1].split())
424 for prop in props if " - " in prop)
425
426 - elif vcs_settings.vcs == "git":
427 + elif self.vcs_settings.vcs == "git":
428 with repoman_popen(
429 "git diff-index --name-only "
430 "--relative --diff-filter=M HEAD") as f:
431 @@ -382,7 +125,7 @@ def repoman_main(argv):
432 myremoved = f.readlines()
433 myremoved = ["./" + elem[:-1] for elem in myremoved]
434
435 - if vcs_settings.vcs == "bzr":
436 + if self.vcs_settings.vcs == "bzr":
437 with repoman_popen("bzr status -S .") as f:
438 bzrstatus = f.readlines()
439 mychanged = [
440 @@ -403,7 +146,7 @@ def repoman_main(argv):
441 if elem and (elem[1:2] == "K" or elem[0:1] == "R")]
442 # Bazaar expands nothing.
443
444 - if vcs_settings.vcs == "hg":
445 + if self.vcs_settings.vcs == "hg":
446 with repoman_popen("hg status --no-status --modified .") as f:
447 mychanged = f.readlines()
448 mychanged = ["./" + elem.rstrip() for elem in mychanged]
449 @@ -416,9 +159,9 @@ def repoman_main(argv):
450 myremoved = f.readlines()
451 myremoved = ["./" + elem.rstrip() for elem in myremoved]
452
453 - if vcs_settings.vcs:
454 + if self.vcs_settings.vcs:
455 a_file_is_changed = mychanged or mynew or myremoved
456 - a_file_is_deleted_hg = vcs_settings.vcs == "hg" and mydeleted
457 + a_file_is_deleted_hg = self.vcs_settings.vcs == "hg" and mydeleted
458
459 if not (a_file_is_changed or a_file_is_deleted_hg):
460 utilities.repoman_sez(
461 @@ -442,12 +185,12 @@ def repoman_main(argv):
462 mymanifests = list(mymanifests)
463 myheaders = []
464
465 - commitmessage = options.commitmsg
466 - if options.commitmsgfile:
467 + commitmessage = self.options.commitmsg
468 + if self.options.commitmsgfile:
469 try:
470 f = io.open(
471 _unicode_encode(
472 - options.commitmsgfile,
473 + self.options.commitmsgfile,
474 encoding=_encodings['fs'], errors='strict'),
475 mode='r', encoding=_encodings['content'], errors='replace')
476 commitmessage = f.read()
477 @@ -457,15 +200,15 @@ def repoman_main(argv):
478 if e.errno == errno.ENOENT:
479 portage.writemsg(
480 "!!! File Not Found:"
481 - " --commitmsgfile='%s'\n" % options.commitmsgfile)
482 + " --commitmsgfile='%s'\n" % self.options.commitmsgfile)
483 else:
484 raise
485 # We've read the content so the file is no longer needed.
486 commitmessagefile = None
487 if not commitmessage or not commitmessage.strip():
488 msg_prefix = ""
489 - if scanner.repolevel > 1:
490 - msg_prefix = "/".join(scanner.reposplit[1:]) + ": "
491 + if self.scanner.repolevel > 1:
492 + msg_prefix = "/".join(self.scanner.reposplit[1:]) + ": "
493
494 try:
495 editor = os.environ.get("EDITOR")
496 @@ -484,29 +227,29 @@ def repoman_main(argv):
497 commitmessage = commitmessage.rstrip()
498 changelog_msg = commitmessage
499 portage_version = getattr(portage, "VERSION", None)
500 - gpg_key = repoman_settings.get("PORTAGE_GPG_KEY", "")
501 - dco_sob = repoman_settings.get("DCO_SIGNED_OFF_BY", "")
502 + gpg_key = self.repoman_settings.get("PORTAGE_GPG_KEY", "")
503 + dco_sob = self.repoman_settings.get("DCO_SIGNED_OFF_BY", "")
504 if portage_version is None:
505 sys.stderr.write("Failed to insert portage version in message!\n")
506 sys.stderr.flush()
507 portage_version = "Unknown"
508
509 report_options = []
510 - if options.force:
511 + if self.options.force:
512 report_options.append("--force")
513 - if options.ignore_arches:
514 + if self.options.ignore_arches:
515 report_options.append("--ignore-arches")
516 - if scanner.include_arches is not None:
517 + if self.scanner.include_arches is not None:
518 report_options.append(
519 "--include-arches=\"%s\"" %
520 - " ".join(sorted(scanner.include_arches)))
521 + " ".join(sorted(self.scanner.include_arches)))
522
523 - if vcs_settings.vcs == "git":
524 + if self.vcs_settings.vcs == "git":
525 # Use new footer only for git (see bug #438364).
526 commit_footer = "\n\nPackage-Manager: portage-%s" % portage_version
527 if report_options:
528 commit_footer += "\nRepoMan-Options: " + " ".join(report_options)
529 - if repo_settings.sign_manifests:
530 + if self.repo_settings.sign_manifests:
531 commit_footer += "\nManifest-Sign-Key: %s" % (gpg_key, )
532 if dco_sob:
533 commit_footer += "\nSigned-off-by: %s" % (dco_sob, )
534 @@ -520,10 +263,10 @@ def repoman_main(argv):
535 if dco_sob:
536 commit_footer += "Signed-off-by: %s\n" % (dco_sob, )
537 commit_footer += "(Portage version: %s/%s/%s" % \
538 - (portage_version, vcs_settings.vcs, unameout)
539 + (portage_version, self.vcs_settings.vcs, unameout)
540 if report_options:
541 commit_footer += ", RepoMan options: " + " ".join(report_options)
542 - if repo_settings.sign_manifests:
543 + if self.repo_settings.sign_manifests:
544 commit_footer += ", signed Manifest commit with key %s" % \
545 (gpg_key, )
546 else:
547 @@ -533,24 +276,24 @@ def repoman_main(argv):
548 commitmessage += commit_footer
549
550 broken_changelog_manifests = []
551 - if options.echangelog in ('y', 'force'):
552 + if self.options.echangelog in ('y', 'force'):
553 logging.info("checking for unmodified ChangeLog files")
554 - committer_name = utilities.get_committer_name(env=repoman_settings)
555 + committer_name = utilities.get_committer_name(env=self.repoman_settings)
556 for x in sorted(vcs_files_to_cps(
557 chain(myupdates, mymanifests, myremoved),
558 - scanner.repolevel, scanner.reposplit, scanner.categories)):
559 + self.scanner.repolevel, self.scanner.reposplit, self.scanner.categories)):
560 catdir, pkgdir = x.split("/")
561 - checkdir = repo_settings.repodir + "/" + x
562 + checkdir = self.repo_settings.repodir + "/" + x
563 checkdir_relative = ""
564 - if scanner.repolevel < 3:
565 + if self.scanner.repolevel < 3:
566 checkdir_relative = os.path.join(pkgdir, checkdir_relative)
567 - if scanner.repolevel < 2:
568 + if self.scanner.repolevel < 2:
569 checkdir_relative = os.path.join(catdir, checkdir_relative)
570 checkdir_relative = os.path.join(".", checkdir_relative)
571
572 changelog_path = os.path.join(checkdir_relative, "ChangeLog")
573 - changelog_modified = changelog_path in scanner.changed.changelogs
574 - if changelog_modified and options.echangelog != 'force':
575 + changelog_modified = changelog_path in self.scanner.changed.changelogs
576 + if changelog_modified and self.options.echangelog != 'force':
577 continue
578
579 # get changes for this package
580 @@ -566,15 +309,15 @@ def repoman_main(argv):
581 nontrivial_cl_files = set()
582 nontrivial_cl_files.update(clnew, clremoved, clchanged)
583 nontrivial_cl_files.difference_update(['Manifest'])
584 - if not nontrivial_cl_files and options.echangelog != 'force':
585 + if not nontrivial_cl_files and self.options.echangelog != 'force':
586 continue
587
588 new_changelog = utilities.UpdateChangeLog(
589 checkdir_relative, committer_name, changelog_msg,
590 - os.path.join(repo_settings.repodir, 'skel.ChangeLog'),
591 + os.path.join(self.repo_settings.repodir, 'skel.ChangeLog'),
592 catdir, pkgdir,
593 new=clnew, removed=clremoved, changed=clchanged,
594 - pretend=options.pretend)
595 + pretend=self.options.pretend)
596 if new_changelog is None:
597 writemsg_level(
598 "!!! Updating the ChangeLog failed\n",
599 @@ -588,18 +331,18 @@ def repoman_main(argv):
600 else:
601 myupdates.append(changelog_path)
602
603 - if options.ask and not options.pretend:
604 + if self.options.ask and not self.options.pretend:
605 # regenerate Manifest for modified ChangeLog (bug #420735)
606 - repoman_settings["O"] = checkdir
607 - digestgen(mysettings=repoman_settings, myportdb=portdb)
608 + self.repoman_settings["O"] = checkdir
609 + digestgen(mysettings=self.repoman_settings, myportdb=self.repo_settings.portdb)
610 else:
611 broken_changelog_manifests.append(x)
612
613 if myautoadd:
614 print(">>> Auto-Adding missing Manifest/ChangeLog file(s)...")
615 - add_cmd = [vcs_settings.vcs, "add"]
616 + add_cmd = [self.vcs_settings.vcs, "add"]
617 add_cmd += myautoadd
618 - if options.pretend:
619 + if self.options.pretend:
620 portage.writemsg_stdout(
621 "(%s)\n" % " ".join(add_cmd),
622 noiselevel=-1)
623 @@ -618,22 +361,22 @@ def repoman_main(argv):
624 retcode = subprocess.call(add_cmd)
625 if retcode != os.EX_OK:
626 logging.error(
627 - "Exiting on %s error code: %s\n" % (vcs_settings.vcs, retcode))
628 + "Exiting on %s error code: %s\n" % (self.vcs_settings.vcs, retcode))
629 sys.exit(retcode)
630
631 myupdates += myautoadd
632
633 print("* %s files being committed..." % green(str(len(myupdates))), end=' ')
634
635 - if vcs_settings.vcs not in ('cvs', 'svn'):
636 + if self.vcs_settings.vcs not in ('cvs', 'svn'):
637 # With git, bzr and hg, there's never any keyword expansion, so
638 # there's no need to regenerate manifests and all files will be
639 # committed in one big commit at the end.
640 print()
641 - elif not repo_settings.repo_config.thin_manifest:
642 - if vcs_settings.vcs == 'cvs':
643 + elif not self.repo_settings.repo_config.thin_manifest:
644 + if self.vcs_settings.vcs == 'cvs':
645 headerstring = "'\$(Header|Id).*\$'"
646 - elif vcs_settings.vcs == "svn":
647 + elif self.vcs_settings.vcs == "svn":
648 svn_keywords = dict((k.lower(), k) for k in [
649 "Rev",
650 "Revision",
651 @@ -651,12 +394,12 @@ def repoman_main(argv):
652 for myfile in myupdates:
653
654 # for CVS, no_expansion contains files that are excluded from expansion
655 - if vcs_settings.vcs == "cvs":
656 + if self.vcs_settings.vcs == "cvs":
657 if myfile in no_expansion:
658 continue
659
660 # for SVN, expansion contains files that are included in expansion
661 - elif vcs_settings.vcs == "svn":
662 + elif self.vcs_settings.vcs == "svn":
663 if myfile not in expansion:
664 continue
665
666 @@ -684,8 +427,8 @@ def repoman_main(argv):
667 logging.info("myupdates: %s", myupdates)
668 logging.info("myheaders: %s", myheaders)
669
670 - uq = UserQuery(options)
671 - if options.ask and uq.query('Commit changes?', True) != 'Yes':
672 + uq = UserQuery(self.options)
673 + if self.options.ask and uq.query('Commit changes?', True) != 'Yes':
674 print("* aborting commit.")
675 sys.exit(128 + signal.SIGINT)
676
677 @@ -713,22 +456,22 @@ def repoman_main(argv):
678 # so strip the prefix.
679 myfiles = [f.lstrip("./") for f in myfiles]
680
681 - commit_cmd = [vcs_settings.vcs]
682 - commit_cmd.extend(vcs_settings.vcs_global_opts)
683 + commit_cmd = [self.vcs_settings.vcs]
684 + commit_cmd.extend(self.vcs_settings.vcs_global_opts)
685 commit_cmd.append("commit")
686 - commit_cmd.extend(vcs_settings.vcs_local_opts)
687 + commit_cmd.extend(self.vcs_settings.vcs_local_opts)
688 commit_cmd.extend(["-F", commitmessagefile])
689 commit_cmd.extend(myfiles)
690
691 try:
692 - if options.pretend:
693 + if self.options.pretend:
694 print("(%s)" % (" ".join(commit_cmd),))
695 else:
696 - retval = spawn(commit_cmd, env=repo_settings.commit_env)
697 + retval = spawn(commit_cmd, env=self.repo_settings.commit_env)
698 if retval != os.EX_OK:
699 writemsg_level(
700 "!!! Exiting on %s (shell) "
701 - "error code: %s\n" % (vcs_settings.vcs, retval),
702 + "error code: %s\n" % (self.vcs_settings.vcs, retval),
703 level=logging.ERROR, noiselevel=-1)
704 sys.exit(retval)
705 finally:
706 @@ -759,39 +502,39 @@ def repoman_main(argv):
707 if modified:
708 portage.util.write_atomic(x, b''.join(mylines), mode='wb')
709
710 - if scanner.repolevel == 1:
711 + if self.scanner.repolevel == 1:
712 utilities.repoman_sez(
713 "\"You're rather crazy... "
714 "doing the entire repository.\"\n")
715
716 - if vcs_settings.vcs in ('cvs', 'svn') and (myupdates or myremoved):
717 + if self.vcs_settings.vcs in ('cvs', 'svn') and (myupdates or myremoved):
718 for x in sorted(vcs_files_to_cps(
719 chain(myupdates, myremoved, mymanifests),
720 - scanner.repolevel, scanner.reposplit, scanner.categories)):
721 - repoman_settings["O"] = os.path.join(repo_settings.repodir, x)
722 - digestgen(mysettings=repoman_settings, myportdb=portdb)
723 + self.scanner.repolevel, self.scanner.reposplit, self.scanner.categories)):
724 + self.repoman_settings["O"] = os.path.join(self.repo_settings.repodir, x)
725 + digestgen(mysettings=self.repoman_settings, myportdb=self.repo_settings.portdb)
726
727 elif broken_changelog_manifests:
728 for x in broken_changelog_manifests:
729 - repoman_settings["O"] = os.path.join(repo_settings.repodir, x)
730 - digestgen(mysettings=repoman_settings, myportdb=portdb)
731 + self.repoman_settings["O"] = os.path.join(self.repo_settings.repodir, x)
732 + digestgen(mysettings=self.repoman_settings, myportdb=self.repo_settings.portdb)
733
734 - if repo_settings.sign_manifests:
735 + if self.repo_settings.sign_manifests:
736 try:
737 for x in sorted(vcs_files_to_cps(
738 chain(myupdates, myremoved, mymanifests),
739 - scanner.repolevel, scanner.reposplit, scanner.categories)):
740 - repoman_settings["O"] = os.path.join(repo_settings.repodir, x)
741 - manifest_path = os.path.join(repoman_settings["O"], "Manifest")
742 + self.scanner.repolevel, self.scanner.reposplit, self.scanner.categories)):
743 + self.repoman_settings["O"] = os.path.join(self.repo_settings.repodir, x)
744 + manifest_path = os.path.join(self.repoman_settings["O"], "Manifest")
745 if not need_signature(manifest_path):
746 continue
747 - gpgsign(manifest_path, repoman_settings, options)
748 + gpgsign(manifest_path, self.repoman_settings, self.options)
749 except portage.exception.PortageException as e:
750 portage.writemsg("!!! %s\n" % str(e))
751 portage.writemsg("!!! Disabled FEATURES='sign'\n")
752 - repo_settings.sign_manifests = False
753 + self.repo_settings.sign_manifests = False
754
755 - if vcs_settings.vcs == 'git':
756 + if self.vcs_settings.vcs == 'git':
757 # It's not safe to use the git commit -a option since there might
758 # be some modified files elsewhere in the working tree that the
759 # user doesn't want to commit. Therefore, call git update-index
760 @@ -802,14 +545,14 @@ def repoman_main(argv):
761 myfiles.sort()
762 update_index_cmd = ["git", "update-index"]
763 update_index_cmd.extend(f.lstrip("./") for f in myfiles)
764 - if options.pretend:
765 + if self.options.pretend:
766 print("(%s)" % (" ".join(update_index_cmd),))
767 else:
768 retval = spawn(update_index_cmd, env=os.environ)
769 if retval != os.EX_OK:
770 writemsg_level(
771 "!!! Exiting on %s (shell) "
772 - "error code: %s\n" % (vcs_settings.vcs, retval),
773 + "error code: %s\n" % (self.vcs_settings.vcs, retval),
774 level=logging.ERROR, noiselevel=-1)
775 sys.exit(retval)
776
777 @@ -829,15 +572,15 @@ def repoman_main(argv):
778 mymsg.close()
779
780 commit_cmd = []
781 - if options.pretend and vcs_settings.vcs is None:
782 + if self.options.pretend and self.vcs_settings.vcs is None:
783 # substitute a bogus value for pretend output
784 commit_cmd.append("cvs")
785 else:
786 - commit_cmd.append(vcs_settings.vcs)
787 - commit_cmd.extend(vcs_settings.vcs_global_opts)
788 + commit_cmd.append(self.vcs_settings.vcs)
789 + commit_cmd.extend(self.vcs_settings.vcs_global_opts)
790 commit_cmd.append("commit")
791 - commit_cmd.extend(vcs_settings.vcs_local_opts)
792 - if vcs_settings.vcs == "hg":
793 + commit_cmd.extend(self.vcs_settings.vcs_local_opts)
794 + if self.vcs_settings.vcs == "hg":
795 commit_cmd.extend(["--logfile", commitmessagefile])
796 commit_cmd.extend(myfiles)
797 else:
798 @@ -845,12 +588,12 @@ def repoman_main(argv):
799 commit_cmd.extend(f.lstrip("./") for f in myfiles)
800
801 try:
802 - if options.pretend:
803 + if self.options.pretend:
804 print("(%s)" % (" ".join(commit_cmd),))
805 else:
806 - retval = spawn(commit_cmd, env=repo_settings.commit_env)
807 + retval = spawn(commit_cmd, env=self.repo_settings.commit_env)
808 if retval != os.EX_OK:
809 - if repo_settings.repo_config.sign_commit and vcs_settings.vcs == 'git' and \
810 + if self.repo_settings.repo_config.sign_commit and self.vcs_settings.vcs == 'git' and \
811 not git_supports_gpg_sign():
812 # Inform user that newer git is needed (bug #403323).
813 logging.error(
814 @@ -858,7 +601,7 @@ def repoman_main(argv):
815
816 writemsg_level(
817 "!!! Exiting on %s (shell) "
818 - "error code: %s\n" % (vcs_settings.vcs, retval),
819 + "error code: %s\n" % (self.vcs_settings.vcs, retval),
820 level=logging.ERROR, noiselevel=-1)
821 sys.exit(retval)
822 finally:
823 @@ -868,7 +611,7 @@ def repoman_main(argv):
824 pass
825
826 print()
827 - if vcs_settings.vcs:
828 + if self.vcs_settings.vcs:
829 print("Commit complete.")
830 else:
831 print(
832 @@ -877,4 +620,155 @@ def repoman_main(argv):
833 " that he forgot to commit anything")
834 utilities.repoman_sez(
835 "\"If everyone were like you, I'd be out of business!\"\n")
836 - sys.exit(0)
837 + return
838 +
839 +
840 + def _suggest(self):
841 + print()
842 + if self.suggest['ignore_masked']:
843 + print(bold(
844 + "Note: use --without-mask to check "
845 + "KEYWORDS on dependencies of masked packages"))
846 +
847 + if self.suggest['include_dev']:
848 + print(bold(
849 + "Note: use --include-dev (-d) to check "
850 + "dependencies for 'dev' profiles"))
851 + print()
852 +
853 +
854 + def _non_commit(self, result):
855 + if result['full']:
856 + print(bold("Note: type \"repoman full\" for a complete listing."))
857 + if result['warn'] and not result['fail']:
858 + utilities.repoman_sez(
859 + "\"You're only giving me a partial QA payment?\n"
860 + " I'll take it this time, but I'm not happy.\"")
861 + elif not result['fail']:
862 + utilities.repoman_sez(
863 + "\"If everyone were like you, I'd be out of business!\"")
864 + elif result['fail']:
865 + print(bad("Please fix these important QA issues first."))
866 + utilities.repoman_sez(
867 + "\"Make your QA payment on time"
868 + " and you'll never see the likes of me.\"\n")
869 + sys.exit(1)
870 +
871 +
872 + def _fail(self, result, can_force):
873 + if result['fail'] and can_force and self.options.force and not self.options.pretend:
874 + utilities.repoman_sez(
875 + " \"You want to commit even with these QA issues?\n"
876 + " I'll take it this time, but I'm not happy.\"\n")
877 + elif result['fail']:
878 + if self.options.force and not can_force:
879 + print(bad(
880 + "The --force option has been disabled"
881 + " due to extraordinary issues."))
882 + print(bad("Please fix these important QA issues first."))
883 + utilities.repoman_sez(
884 + "\"Make your QA payment on time"
885 + " and you'll never see the likes of me.\"\n")
886 + sys.exit(1)
887 +
888 +
889 + def _vcs_unadded(self):
890 + myunadded = []
891 + mydeleted = []
892 + if self.vcs_settings.vcs == "cvs":
893 + try:
894 + myvcstree = portage.cvstree.getentries("./", recursive=1)
895 + myunadded = portage.cvstree.findunadded(
896 + myvcstree, recursive=1, basedir="./")
897 + except SystemExit:
898 + raise # TODO propagate this
899 + except:
900 + err("Error retrieving CVS tree; exiting.")
901 + if self.vcs_settings.vcs == "svn":
902 + try:
903 + with repoman_popen("svn status --no-ignore") as f:
904 + svnstatus = f.readlines()
905 + myunadded = [
906 + "./" + elem.rstrip().split()[1]
907 + for elem in svnstatus
908 + if elem.startswith("?") or elem.startswith("I")]
909 + except SystemExit:
910 + raise # TODO propagate this
911 + except:
912 + err("Error retrieving SVN info; exiting.")
913 + if self.vcs_settings.vcs == "git":
914 + # get list of files not under version control or missing
915 + myf = repoman_popen("git ls-files --others")
916 + myunadded = ["./" + elem[:-1] for elem in myf]
917 + myf.close()
918 + if self.vcs_settings.vcs == "bzr":
919 + try:
920 + with repoman_popen("bzr status -S .") as f:
921 + bzrstatus = f.readlines()
922 + myunadded = [
923 + "./" + elem.rstrip().split()[1].split('/')[-1:][0]
924 + for elem in bzrstatus
925 + if elem.startswith("?") or elem[0:2] == " D"]
926 + except SystemExit:
927 + raise # TODO propagate this
928 + except:
929 + err("Error retrieving bzr info; exiting.")
930 + if self.vcs_settings.vcs == "hg":
931 + with repoman_popen("hg status --no-status --unknown .") as f:
932 + myunadded = f.readlines()
933 + myunadded = ["./" + elem.rstrip() for elem in myunadded]
934 +
935 + # Mercurial doesn't handle manually deleted files as removed from
936 + # the repository, so the user need to remove them before commit,
937 + # using "hg remove [FILES]"
938 + with repoman_popen("hg status --no-status --deleted .") as f:
939 + mydeleted = f.readlines()
940 + mydeleted = ["./" + elem.rstrip() for elem in mydeleted]
941 + return myunadded, mydeleted
942 +
943 +
944 + def _vcs_autoadd(self, myunadded):
945 + myautoadd = []
946 + if myunadded:
947 + for x in range(len(myunadded) - 1, -1, -1):
948 + xs = myunadded[x].split("/")
949 + if self.repo_settings.repo_config.find_invalid_path_char(myunadded[x]) != -1:
950 + # The Manifest excludes this file,
951 + # so it's safe to ignore.
952 + del myunadded[x]
953 + elif xs[-1] == "files":
954 + print("!!! files dir is not added! Please correct this.")
955 + sys.exit(-1)
956 + elif xs[-1] == "Manifest":
957 + # It's a manifest... auto add
958 + myautoadd += [myunadded[x]]
959 + del myunadded[x]
960 +
961 + if myunadded:
962 + print(red(
963 + "!!! The following files are in your local tree"
964 + " but are not added to the master"))
965 + print(red(
966 + "!!! tree. Please remove them from the local tree"
967 + " or add them to the master tree."))
968 + for x in myunadded:
969 + print(" ", x)
970 + print()
971 + print()
972 + sys.exit(1)
973 + return myautoadd
974 +
975 +
976 + def _vcs_deleted(self, mydeleted):
977 + if self.vcs_settings.vcs == "hg" and mydeleted:
978 + print(red(
979 + "!!! The following files are removed manually"
980 + " from your local tree but are not"))
981 + print(red(
982 + "!!! removed from the repository."
983 + " Please remove them, using \"hg remove [FILES]\"."))
984 + for x in mydeleted:
985 + print(" ", x)
986 + print()
987 + print()
988 + sys.exit(1)
989
990 diff --git a/pym/repoman/main.py b/pym/repoman/main.py
991 index 2b2f91d..808c55e 100755
992 --- a/pym/repoman/main.py
993 +++ b/pym/repoman/main.py
994 @@ -4,16 +4,9 @@
995
996 from __future__ import print_function, unicode_literals
997
998 -import errno
999 import io
1000 import logging
1001 -import re
1002 -import signal
1003 -import subprocess
1004 import sys
1005 -import tempfile
1006 -import platform
1007 -from itertools import chain
1008
1009 from os import path as osp
1010 if osp.isfile(osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), ".portage_not_installed")):
1011 @@ -26,36 +19,24 @@ portage._disable_legacy_globals()
1012
1013
1014 from portage import os
1015 -from portage import _encodings
1016 -from portage import _unicode_encode
1017 -from _emerge.UserQuery import UserQuery
1018 import portage.checksum
1019 import portage.const
1020 import portage.repository.config
1021 -from portage import cvstree
1022 from portage import util
1023 -from portage.process import find_binary, spawn
1024 -from portage.output import (
1025 - bold, create_color_func, green, nocolor, red)
1026 +from portage.output import create_color_func, nocolor
1027 from portage.output import ConsoleStyleFile, StyleWriter
1028 from portage.util import formatter
1029 -from portage.util import writemsg_level
1030 -from portage.package.ebuild.digestgen import digestgen
1031
1032 +from repoman.actions import Actions
1033 from repoman.argparser import parse_args
1034 from repoman.checks.ebuilds.checks import checks_init
1035 -from repoman.errors import err
1036 -from repoman.gpg import gpgsign, need_signature
1037 from repoman.qa_data import (
1038 format_qa_output, format_qa_output_column, qahelp,
1039 qawarnings, qacats)
1040 from repoman.repos import RepoSettings
1041 from repoman.scanner import Scanner
1042 -from repoman._subprocess import repoman_popen, repoman_getstatusoutput
1043 from repoman import utilities
1044 -from repoman.vcs.vcs import (
1045 - git_supports_gpg_sign, vcs_files_to_cps, VCSSettings)
1046 -
1047 +from repoman.vcs.vcs import VCSSettings
1048
1049 if sys.hexversion >= 0x3000000:
1050 basestring = str
1051 @@ -107,7 +88,6 @@ def repoman_main(argv):
1052 config_root, portdir, portdir_overlay,
1053 repoman_settings, vcs_settings, options, qawarnings)
1054 repoman_settings = repo_settings.repoman_settings
1055 - portdb = repo_settings.portdb
1056
1057 if 'digest' in repoman_settings.features and options.digest != 'n':
1058 options.digest = 'y'
1059 @@ -131,27 +111,29 @@ def repoman_main(argv):
1060 if options.if_modified == "y" and len(scanner.effective_scanlist) < 1:
1061 logging.warning("--if-modified is enabled, but no modified packages were found!")
1062
1063 - # dofail will be true if we have failed in at least one non-warning category
1064 - dofail = 0
1065 - # dowarn will be true if we tripped any warnings
1066 - dowarn = 0
1067 - # dofull will be true if we should print a "repoman full" informational message
1068 - dofull = options.mode != 'full'
1069 + result = {
1070 + # fail will be true if we have failed in at least one non-warning category
1071 + 'fail': 0,
1072 + # warn will be true if we tripped any warnings
1073 + 'warn': 0,
1074 + # full will be true if we should print a "repoman full" informational message
1075 + 'full': options.mode != 'full',
1076 + }
1077
1078 # early out for manifest generation
1079 if options.mode == "manifest":
1080 - sys.exit(dofail)
1081 + sys.exit(result['fail'])
1082
1083 for x in qacats:
1084 if x not in qatracker.fails:
1085 continue
1086 - dowarn = 1
1087 + result['warn'] = 1
1088 if x not in qawarnings:
1089 - dofail = 1
1090 + result['fail'] = 1
1091
1092 - if dofail or \
1093 - (dowarn and not (options.quiet or options.mode == "scan")):
1094 - dofull = 0
1095 + if result['fail'] or \
1096 + (result['warn'] and not (options.quiet or options.mode == "scan")):
1097 + result['full'] = 0
1098
1099 # Save QA output so that it can be conveniently displayed
1100 # in $EDITOR while the user creates a commit message.
1101 @@ -174,707 +156,17 @@ def repoman_main(argv):
1102
1103 format_output = format_outputs.get(
1104 options.output_style, format_outputs['default'])
1105 - format_output(f, qatracker.fails, dofull, dofail, options, qawarnings)
1106 + format_output(f, qatracker.fails, result['full'], result['fail'], options, qawarnings)
1107
1108 style_file.flush()
1109 del console_writer, f, style_file
1110 qa_output = qa_output.getvalue()
1111 qa_output = qa_output.splitlines(True)
1112
1113 - suggest_ignore_masked = False
1114 - suggest_include_dev = False
1115 -
1116 - if scanner.have['pmasked'] and not (options.without_mask or options.ignore_masked):
1117 - suggest_ignore_masked = True
1118 - if scanner.have['dev_keywords'] and not options.include_dev:
1119 - suggest_include_dev = True
1120 -
1121 - if suggest_ignore_masked or suggest_include_dev:
1122 - print()
1123 - if suggest_ignore_masked:
1124 - print(bold(
1125 - "Note: use --without-mask to check "
1126 - "KEYWORDS on dependencies of masked packages"))
1127 -
1128 - if suggest_include_dev:
1129 - print(bold(
1130 - "Note: use --include-dev (-d) to check "
1131 - "dependencies for 'dev' profiles"))
1132 - print()
1133 -
1134 - if options.mode != 'commit':
1135 - if dofull:
1136 - print(bold("Note: type \"repoman full\" for a complete listing."))
1137 - if dowarn and not dofail:
1138 - utilities.repoman_sez(
1139 - "\"You're only giving me a partial QA payment?\n"
1140 - " I'll take it this time, but I'm not happy.\"")
1141 - elif not dofail:
1142 - utilities.repoman_sez(
1143 - "\"If everyone were like you, I'd be out of business!\"")
1144 - elif dofail:
1145 - print(bad("Please fix these important QA issues first."))
1146 - utilities.repoman_sez(
1147 - "\"Make your QA payment on time"
1148 - " and you'll never see the likes of me.\"\n")
1149 - sys.exit(1)
1150 - else:
1151 - if dofail and can_force and options.force and not options.pretend:
1152 - utilities.repoman_sez(
1153 - " \"You want to commit even with these QA issues?\n"
1154 - " I'll take it this time, but I'm not happy.\"\n")
1155 - elif dofail:
1156 - if options.force and not can_force:
1157 - print(bad(
1158 - "The --force option has been disabled"
1159 - " due to extraordinary issues."))
1160 - print(bad("Please fix these important QA issues first."))
1161 - utilities.repoman_sez(
1162 - "\"Make your QA payment on time"
1163 - " and you'll never see the likes of me.\"\n")
1164 - sys.exit(1)
1165 -
1166 - if options.pretend:
1167 - utilities.repoman_sez(
1168 - "\"So, you want to play it safe. Good call.\"\n")
1169 -
1170 - myunadded = []
1171 - if vcs_settings.vcs == "cvs":
1172 - try:
1173 - myvcstree = portage.cvstree.getentries("./", recursive=1)
1174 - myunadded = portage.cvstree.findunadded(
1175 - myvcstree, recursive=1, basedir="./")
1176 - except SystemExit as e:
1177 - raise # TODO propagate this
1178 - except:
1179 - err("Error retrieving CVS tree; exiting.")
1180 - if vcs_settings.vcs == "svn":
1181 - try:
1182 - with repoman_popen("svn status --no-ignore") as f:
1183 - svnstatus = f.readlines()
1184 - myunadded = [
1185 - "./" + elem.rstrip().split()[1]
1186 - for elem in svnstatus
1187 - if elem.startswith("?") or elem.startswith("I")]
1188 - except SystemExit as e:
1189 - raise # TODO propagate this
1190 - except:
1191 - err("Error retrieving SVN info; exiting.")
1192 - if vcs_settings.vcs == "git":
1193 - # get list of files not under version control or missing
1194 - myf = repoman_popen("git ls-files --others")
1195 - myunadded = ["./" + elem[:-1] for elem in myf]
1196 - myf.close()
1197 - if vcs_settings.vcs == "bzr":
1198 - try:
1199 - with repoman_popen("bzr status -S .") as f:
1200 - bzrstatus = f.readlines()
1201 - myunadded = [
1202 - "./" + elem.rstrip().split()[1].split('/')[-1:][0]
1203 - for elem in bzrstatus
1204 - if elem.startswith("?") or elem[0:2] == " D"]
1205 - except SystemExit as e:
1206 - raise # TODO propagate this
1207 - except:
1208 - err("Error retrieving bzr info; exiting.")
1209 - if vcs_settings.vcs == "hg":
1210 - with repoman_popen("hg status --no-status --unknown .") as f:
1211 - myunadded = f.readlines()
1212 - myunadded = ["./" + elem.rstrip() for elem in myunadded]
1213 -
1214 - # Mercurial doesn't handle manually deleted files as removed from
1215 - # the repository, so the user need to remove them before commit,
1216 - # using "hg remove [FILES]"
1217 - with repoman_popen("hg status --no-status --deleted .") as f:
1218 - mydeleted = f.readlines()
1219 - mydeleted = ["./" + elem.rstrip() for elem in mydeleted]
1220 -
1221 - myautoadd = []
1222 - if myunadded:
1223 - for x in range(len(myunadded) - 1, -1, -1):
1224 - xs = myunadded[x].split("/")
1225 - if repo_settings.repo_config.find_invalid_path_char(myunadded[x]) != -1:
1226 - # The Manifest excludes this file,
1227 - # so it's safe to ignore.
1228 - del myunadded[x]
1229 - elif xs[-1] == "files":
1230 - print("!!! files dir is not added! Please correct this.")
1231 - sys.exit(-1)
1232 - elif xs[-1] == "Manifest":
1233 - # It's a manifest... auto add
1234 - myautoadd += [myunadded[x]]
1235 - del myunadded[x]
1236 -
1237 - if myunadded:
1238 - print(red(
1239 - "!!! The following files are in your local tree"
1240 - " but are not added to the master"))
1241 - print(red(
1242 - "!!! tree. Please remove them from the local tree"
1243 - " or add them to the master tree."))
1244 - for x in myunadded:
1245 - print(" ", x)
1246 - print()
1247 - print()
1248 - sys.exit(1)
1249 -
1250 - if vcs_settings.vcs == "hg" and mydeleted:
1251 - print(red(
1252 - "!!! The following files are removed manually"
1253 - " from your local tree but are not"))
1254 - print(red(
1255 - "!!! removed from the repository."
1256 - " Please remove them, using \"hg remove [FILES]\"."))
1257 - for x in mydeleted:
1258 - print(" ", x)
1259 - print()
1260 - print()
1261 - sys.exit(1)
1262 -
1263 - if vcs_settings.vcs == "cvs":
1264 - mycvstree = cvstree.getentries("./", recursive=1)
1265 - mychanged = cvstree.findchanged(mycvstree, recursive=1, basedir="./")
1266 - mynew = cvstree.findnew(mycvstree, recursive=1, basedir="./")
1267 - myremoved = portage.cvstree.findremoved(mycvstree, recursive=1, basedir="./")
1268 - bin_blob_pattern = re.compile("^-kb$")
1269 - no_expansion = set(portage.cvstree.findoption(
1270 - mycvstree, bin_blob_pattern, recursive=1, basedir="./"))
1271 -
1272 - if vcs_settings.vcs == "svn":
1273 - with repoman_popen("svn status") as f:
1274 - svnstatus = f.readlines()
1275 - mychanged = [
1276 - "./" + elem.split()[-1:][0]
1277 - for elem in svnstatus
1278 - if (elem[:1] in "MR" or elem[1:2] in "M")]
1279 - mynew = [
1280 - "./" + elem.split()[-1:][0]
1281 - for elem in svnstatus
1282 - if elem.startswith("A")]
1283 - myremoved = [
1284 - "./" + elem.split()[-1:][0]
1285 - for elem in svnstatus
1286 - if elem.startswith("D")]
1287 -
1288 - # Subversion expands keywords specified in svn:keywords properties.
1289 - with repoman_popen("svn propget -R svn:keywords") as f:
1290 - props = f.readlines()
1291 - expansion = dict(
1292 - ("./" + prop.split(" - ")[0], prop.split(" - ")[1].split())
1293 - for prop in props if " - " in prop)
1294 -
1295 - elif vcs_settings.vcs == "git":
1296 - with repoman_popen(
1297 - "git diff-index --name-only "
1298 - "--relative --diff-filter=M HEAD") as f:
1299 - mychanged = f.readlines()
1300 - mychanged = ["./" + elem[:-1] for elem in mychanged]
1301 -
1302 - with repoman_popen(
1303 - "git diff-index --name-only "
1304 - "--relative --diff-filter=A HEAD") as f:
1305 - mynew = f.readlines()
1306 - mynew = ["./" + elem[:-1] for elem in mynew]
1307 -
1308 - with repoman_popen(
1309 - "git diff-index --name-only "
1310 - "--relative --diff-filter=D HEAD") as f:
1311 - myremoved = f.readlines()
1312 - myremoved = ["./" + elem[:-1] for elem in myremoved]
1313 -
1314 - if vcs_settings.vcs == "bzr":
1315 - with repoman_popen("bzr status -S .") as f:
1316 - bzrstatus = f.readlines()
1317 - mychanged = [
1318 - "./" + elem.split()[-1:][0].split('/')[-1:][0]
1319 - for elem in bzrstatus
1320 - if elem and elem[1:2] == "M"]
1321 - mynew = [
1322 - "./" + elem.split()[-1:][0].split('/')[-1:][0]
1323 - for elem in bzrstatus
1324 - if elem and (elem[1:2] in "NK" or elem[0:1] == "R")]
1325 - myremoved = [
1326 - "./" + elem.split()[-1:][0].split('/')[-1:][0]
1327 - for elem in bzrstatus
1328 - if elem.startswith("-")]
1329 - myremoved = [
1330 - "./" + elem.split()[-3:-2][0].split('/')[-1:][0]
1331 - for elem in bzrstatus
1332 - if elem and (elem[1:2] == "K" or elem[0:1] == "R")]
1333 - # Bazaar expands nothing.
1334 -
1335 - if vcs_settings.vcs == "hg":
1336 - with repoman_popen("hg status --no-status --modified .") as f:
1337 - mychanged = f.readlines()
1338 - mychanged = ["./" + elem.rstrip() for elem in mychanged]
1339 -
1340 - with repoman_popen("hg status --no-status --added .") as f:
1341 - mynew = f.readlines()
1342 - mynew = ["./" + elem.rstrip() for elem in mynew]
1343 -
1344 - with repoman_popen("hg status --no-status --removed .") as f:
1345 - myremoved = f.readlines()
1346 - myremoved = ["./" + elem.rstrip() for elem in myremoved]
1347 -
1348 - if vcs_settings.vcs:
1349 - a_file_is_changed = mychanged or mynew or myremoved
1350 - a_file_is_deleted_hg = vcs_settings.vcs == "hg" and mydeleted
1351 -
1352 - if not (a_file_is_changed or a_file_is_deleted_hg):
1353 - utilities.repoman_sez(
1354 - "\"Doing nothing is not always good for QA.\"")
1355 - print()
1356 - print("(Didn't find any changed files...)")
1357 - print()
1358 - sys.exit(1)
1359 -
1360 - # Manifests need to be regenerated after all other commits, so don't commit
1361 - # them now even if they have changed.
1362 - mymanifests = set()
1363 - myupdates = set()
1364 - for f in mychanged + mynew:
1365 - if "Manifest" == os.path.basename(f):
1366 - mymanifests.add(f)
1367 - else:
1368 - myupdates.add(f)
1369 - myupdates.difference_update(myremoved)
1370 - myupdates = list(myupdates)
1371 - mymanifests = list(mymanifests)
1372 - myheaders = []
1373 -
1374 - commitmessage = options.commitmsg
1375 - if options.commitmsgfile:
1376 - try:
1377 - f = io.open(
1378 - _unicode_encode(
1379 - options.commitmsgfile,
1380 - encoding=_encodings['fs'], errors='strict'),
1381 - mode='r', encoding=_encodings['content'], errors='replace')
1382 - commitmessage = f.read()
1383 - f.close()
1384 - del f
1385 - except (IOError, OSError) as e:
1386 - if e.errno == errno.ENOENT:
1387 - portage.writemsg(
1388 - "!!! File Not Found:"
1389 - " --commitmsgfile='%s'\n" % options.commitmsgfile)
1390 - else:
1391 - raise
1392 - # We've read the content so the file is no longer needed.
1393 - commitmessagefile = None
1394 - if not commitmessage or not commitmessage.strip():
1395 - msg_prefix = ""
1396 - if scanner.repolevel > 1:
1397 - msg_prefix = "/".join(scanner.reposplit[1:]) + ": "
1398 -
1399 - try:
1400 - editor = os.environ.get("EDITOR")
1401 - if editor and utilities.editor_is_executable(editor):
1402 - commitmessage = utilities.get_commit_message_with_editor(
1403 - editor, message=qa_output, prefix=msg_prefix)
1404 - else:
1405 - commitmessage = utilities.get_commit_message_with_stdin()
1406 - except KeyboardInterrupt:
1407 - logging.fatal("Interrupted; exiting...")
1408 - sys.exit(1)
1409 - if (not commitmessage or not commitmessage.strip()
1410 - or commitmessage.strip() == msg_prefix):
1411 - print("* no commit message? aborting commit.")
1412 - sys.exit(1)
1413 - commitmessage = commitmessage.rstrip()
1414 - changelog_msg = commitmessage
1415 - portage_version = getattr(portage, "VERSION", None)
1416 - gpg_key = repoman_settings.get("PORTAGE_GPG_KEY", "")
1417 - dco_sob = repoman_settings.get("DCO_SIGNED_OFF_BY", "")
1418 - if portage_version is None:
1419 - sys.stderr.write("Failed to insert portage version in message!\n")
1420 - sys.stderr.flush()
1421 - portage_version = "Unknown"
1422 -
1423 - report_options = []
1424 - if options.force:
1425 - report_options.append("--force")
1426 - if options.ignore_arches:
1427 - report_options.append("--ignore-arches")
1428 - if scanner.include_arches is not None:
1429 - report_options.append(
1430 - "--include-arches=\"%s\"" %
1431 - " ".join(sorted(scanner.include_arches)))
1432 -
1433 - if vcs_settings.vcs == "git":
1434 - # Use new footer only for git (see bug #438364).
1435 - commit_footer = "\n\nPackage-Manager: portage-%s" % portage_version
1436 - if report_options:
1437 - commit_footer += "\nRepoMan-Options: " + " ".join(report_options)
1438 - if repo_settings.sign_manifests:
1439 - commit_footer += "\nManifest-Sign-Key: %s" % (gpg_key, )
1440 - if dco_sob:
1441 - commit_footer += "\nSigned-off-by: %s" % (dco_sob, )
1442 - else:
1443 - unameout = platform.system() + " "
1444 - if platform.system() in ["Darwin", "SunOS"]:
1445 - unameout += platform.processor()
1446 - else:
1447 - unameout += platform.machine()
1448 - commit_footer = "\n\n"
1449 - if dco_sob:
1450 - commit_footer += "Signed-off-by: %s\n" % (dco_sob, )
1451 - commit_footer += "(Portage version: %s/%s/%s" % \
1452 - (portage_version, vcs_settings.vcs, unameout)
1453 - if report_options:
1454 - commit_footer += ", RepoMan options: " + " ".join(report_options)
1455 - if repo_settings.sign_manifests:
1456 - commit_footer += ", signed Manifest commit with key %s" % \
1457 - (gpg_key, )
1458 - else:
1459 - commit_footer += ", unsigned Manifest commit"
1460 - commit_footer += ")"
1461 -
1462 - commitmessage += commit_footer
1463 -
1464 - broken_changelog_manifests = []
1465 - if options.echangelog in ('y', 'force'):
1466 - logging.info("checking for unmodified ChangeLog files")
1467 - committer_name = utilities.get_committer_name(env=repoman_settings)
1468 - for x in sorted(vcs_files_to_cps(
1469 - chain(myupdates, mymanifests, myremoved),
1470 - scanner.repolevel, scanner.reposplit, scanner.categories)):
1471 - catdir, pkgdir = x.split("/")
1472 - checkdir = repo_settings.repodir + "/" + x
1473 - checkdir_relative = ""
1474 - if scanner.repolevel < 3:
1475 - checkdir_relative = os.path.join(pkgdir, checkdir_relative)
1476 - if scanner.repolevel < 2:
1477 - checkdir_relative = os.path.join(catdir, checkdir_relative)
1478 - checkdir_relative = os.path.join(".", checkdir_relative)
1479 -
1480 - changelog_path = os.path.join(checkdir_relative, "ChangeLog")
1481 - changelog_modified = changelog_path in scanner.changed.changelogs
1482 - if changelog_modified and options.echangelog != 'force':
1483 - continue
1484 -
1485 - # get changes for this package
1486 - cdrlen = len(checkdir_relative)
1487 - check_relative = lambda e: e.startswith(checkdir_relative)
1488 - split_relative = lambda e: e[cdrlen:]
1489 - clnew = list(map(split_relative, filter(check_relative, mynew)))
1490 - clremoved = list(map(split_relative, filter(check_relative, myremoved)))
1491 - clchanged = list(map(split_relative, filter(check_relative, mychanged)))
1492 -
1493 - # Skip ChangeLog generation if only the Manifest was modified,
1494 - # as discussed in bug #398009.
1495 - nontrivial_cl_files = set()
1496 - nontrivial_cl_files.update(clnew, clremoved, clchanged)
1497 - nontrivial_cl_files.difference_update(['Manifest'])
1498 - if not nontrivial_cl_files and options.echangelog != 'force':
1499 - continue
1500 -
1501 - new_changelog = utilities.UpdateChangeLog(
1502 - checkdir_relative, committer_name, changelog_msg,
1503 - os.path.join(repo_settings.repodir, 'skel.ChangeLog'),
1504 - catdir, pkgdir,
1505 - new=clnew, removed=clremoved, changed=clchanged,
1506 - pretend=options.pretend)
1507 - if new_changelog is None:
1508 - writemsg_level(
1509 - "!!! Updating the ChangeLog failed\n",
1510 - level=logging.ERROR, noiselevel=-1)
1511 - sys.exit(1)
1512 -
1513 - # if the ChangeLog was just created, add it to vcs
1514 - if new_changelog:
1515 - myautoadd.append(changelog_path)
1516 - # myautoadd is appended to myupdates below
1517 - else:
1518 - myupdates.append(changelog_path)
1519 -
1520 - if options.ask and not options.pretend:
1521 - # regenerate Manifest for modified ChangeLog (bug #420735)
1522 - repoman_settings["O"] = checkdir
1523 - digestgen(mysettings=repoman_settings, myportdb=portdb)
1524 - else:
1525 - broken_changelog_manifests.append(x)
1526 -
1527 - if myautoadd:
1528 - print(">>> Auto-Adding missing Manifest/ChangeLog file(s)...")
1529 - add_cmd = [vcs_settings.vcs, "add"]
1530 - add_cmd += myautoadd
1531 - if options.pretend:
1532 - portage.writemsg_stdout(
1533 - "(%s)\n" % " ".join(add_cmd),
1534 - noiselevel=-1)
1535 - else:
1536 -
1537 - if sys.hexversion < 0x3020000 and sys.hexversion >= 0x3000000 and \
1538 - not os.path.isabs(add_cmd[0]):
1539 - # Python 3.1 _execvp throws TypeError for non-absolute executable
1540 - # path passed as bytes (see http://bugs.python.org/issue8513).
1541 - fullname = find_binary(add_cmd[0])
1542 - if fullname is None:
1543 - raise portage.exception.CommandNotFound(add_cmd[0])
1544 - add_cmd[0] = fullname
1545 -
1546 - add_cmd = [_unicode_encode(arg) for arg in add_cmd]
1547 - retcode = subprocess.call(add_cmd)
1548 - if retcode != os.EX_OK:
1549 - logging.error(
1550 - "Exiting on %s error code: %s\n" % (vcs_settings.vcs, retcode))
1551 - sys.exit(retcode)
1552 -
1553 - myupdates += myautoadd
1554 -
1555 - print("* %s files being committed..." % green(str(len(myupdates))), end=' ')
1556 -
1557 - if vcs_settings.vcs not in ('cvs', 'svn'):
1558 - # With git, bzr and hg, there's never any keyword expansion, so
1559 - # there's no need to regenerate manifests and all files will be
1560 - # committed in one big commit at the end.
1561 - print()
1562 - elif not repo_settings.repo_config.thin_manifest:
1563 - if vcs_settings.vcs == 'cvs':
1564 - headerstring = "'\$(Header|Id).*\$'"
1565 - elif vcs_settings.vcs == "svn":
1566 - svn_keywords = dict((k.lower(), k) for k in [
1567 - "Rev",
1568 - "Revision",
1569 - "LastChangedRevision",
1570 - "Date",
1571 - "LastChangedDate",
1572 - "Author",
1573 - "LastChangedBy",
1574 - "URL",
1575 - "HeadURL",
1576 - "Id",
1577 - "Header",
1578 - ])
1579 -
1580 - for myfile in myupdates:
1581 -
1582 - # for CVS, no_expansion contains files that are excluded from expansion
1583 - if vcs_settings.vcs == "cvs":
1584 - if myfile in no_expansion:
1585 - continue
1586 -
1587 - # for SVN, expansion contains files that are included in expansion
1588 - elif vcs_settings.vcs == "svn":
1589 - if myfile not in expansion:
1590 - continue
1591 -
1592 - # Subversion keywords are case-insensitive
1593 - # in svn:keywords properties,
1594 - # but case-sensitive in contents of files.
1595 - enabled_keywords = []
1596 - for k in expansion[myfile]:
1597 - keyword = svn_keywords.get(k.lower())
1598 - if keyword is not None:
1599 - enabled_keywords.append(keyword)
1600 -
1601 - headerstring = "'\$(%s).*\$'" % "|".join(enabled_keywords)
1602 -
1603 - myout = repoman_getstatusoutput(
1604 - "egrep -q %s %s" % (headerstring, portage._shell_quote(myfile)))
1605 - if myout[0] == 0:
1606 - myheaders.append(myfile)
1607 -
1608 - print("%s have headers that will change." % green(str(len(myheaders))))
1609 - print(
1610 - "* Files with headers will"
1611 - " cause the manifests to be changed and committed separately.")
1612 -
1613 - logging.info("myupdates: %s", myupdates)
1614 - logging.info("myheaders: %s", myheaders)
1615 -
1616 - uq = UserQuery(options)
1617 - if options.ask and uq.query('Commit changes?', True) != 'Yes':
1618 - print("* aborting commit.")
1619 - sys.exit(128 + signal.SIGINT)
1620 -
1621 - # Handle the case where committed files have keywords which
1622 - # will change and need a priming commit before the Manifest
1623 - # can be committed.
1624 - if (myupdates or myremoved) and myheaders:
1625 - myfiles = myupdates + myremoved
1626 - fd, commitmessagefile = tempfile.mkstemp(".repoman.msg")
1627 - mymsg = os.fdopen(fd, "wb")
1628 - mymsg.write(_unicode_encode(commitmessage))
1629 - mymsg.close()
1630 -
1631 - separator = '-' * 78
1632 -
1633 - print()
1634 - print(green("Using commit message:"))
1635 - print(green(separator))
1636 - print(commitmessage)
1637 - print(green(separator))
1638 - print()
1639 -
1640 - # Having a leading ./ prefix on file paths can trigger a bug in
1641 - # the cvs server when committing files to multiple directories,
1642 - # so strip the prefix.
1643 - myfiles = [f.lstrip("./") for f in myfiles]
1644 -
1645 - commit_cmd = [vcs_settings.vcs]
1646 - commit_cmd.extend(vcs_settings.vcs_global_opts)
1647 - commit_cmd.append("commit")
1648 - commit_cmd.extend(vcs_settings.vcs_local_opts)
1649 - commit_cmd.extend(["-F", commitmessagefile])
1650 - commit_cmd.extend(myfiles)
1651 -
1652 - try:
1653 - if options.pretend:
1654 - print("(%s)" % (" ".join(commit_cmd),))
1655 - else:
1656 - retval = spawn(commit_cmd, env=repo_settings.commit_env)
1657 - if retval != os.EX_OK:
1658 - writemsg_level(
1659 - "!!! Exiting on %s (shell) "
1660 - "error code: %s\n" % (vcs_settings.vcs, retval),
1661 - level=logging.ERROR, noiselevel=-1)
1662 - sys.exit(retval)
1663 - finally:
1664 - try:
1665 - os.unlink(commitmessagefile)
1666 - except OSError:
1667 - pass
1668 -
1669 - # When files are removed and re-added, the cvs server will put /Attic/
1670 - # inside the $Header path. This code detects the problem and corrects it
1671 - # so that the Manifest will generate correctly. See bug #169500.
1672 - # Use binary mode in order to avoid potential character encoding issues.
1673 - cvs_header_re = re.compile(br'^#\s*\$Header.*\$$')
1674 - attic_str = b'/Attic/'
1675 - attic_replace = b'/'
1676 - for x in myheaders:
1677 - f = open(
1678 - _unicode_encode(x, encoding=_encodings['fs'], errors='strict'),
1679 - mode='rb')
1680 - mylines = f.readlines()
1681 - f.close()
1682 - modified = False
1683 - for i, line in enumerate(mylines):
1684 - if cvs_header_re.match(line) is not None and \
1685 - attic_str in line:
1686 - mylines[i] = line.replace(attic_str, attic_replace)
1687 - modified = True
1688 - if modified:
1689 - portage.util.write_atomic(x, b''.join(mylines), mode='wb')
1690 -
1691 - if scanner.repolevel == 1:
1692 - utilities.repoman_sez(
1693 - "\"You're rather crazy... "
1694 - "doing the entire repository.\"\n")
1695 -
1696 - if vcs_settings.vcs in ('cvs', 'svn') and (myupdates or myremoved):
1697 - for x in sorted(vcs_files_to_cps(
1698 - chain(myupdates, myremoved, mymanifests),
1699 - scanner.repolevel, scanner.reposplit, scanner.categories)):
1700 - repoman_settings["O"] = os.path.join(repo_settings.repodir, x)
1701 - digestgen(mysettings=repoman_settings, myportdb=portdb)
1702 -
1703 - elif broken_changelog_manifests:
1704 - for x in broken_changelog_manifests:
1705 - repoman_settings["O"] = os.path.join(repo_settings.repodir, x)
1706 - digestgen(mysettings=repoman_settings, myportdb=portdb)
1707 -
1708 - if repo_settings.sign_manifests:
1709 - try:
1710 - for x in sorted(vcs_files_to_cps(
1711 - chain(myupdates, myremoved, mymanifests),
1712 - scanner.repolevel, scanner.reposplit, scanner.categories)):
1713 - repoman_settings["O"] = os.path.join(repo_settings.repodir, x)
1714 - manifest_path = os.path.join(repoman_settings["O"], "Manifest")
1715 - if not need_signature(manifest_path):
1716 - continue
1717 - gpgsign(manifest_path, repoman_settings, options)
1718 - except portage.exception.PortageException as e:
1719 - portage.writemsg("!!! %s\n" % str(e))
1720 - portage.writemsg("!!! Disabled FEATURES='sign'\n")
1721 - repo_settings.sign_manifests = False
1722 -
1723 - if vcs_settings.vcs == 'git':
1724 - # It's not safe to use the git commit -a option since there might
1725 - # be some modified files elsewhere in the working tree that the
1726 - # user doesn't want to commit. Therefore, call git update-index
1727 - # in order to ensure that the index is updated with the latest
1728 - # versions of all new and modified files in the relevant portion
1729 - # of the working tree.
1730 - myfiles = mymanifests + myupdates
1731 - myfiles.sort()
1732 - update_index_cmd = ["git", "update-index"]
1733 - update_index_cmd.extend(f.lstrip("./") for f in myfiles)
1734 - if options.pretend:
1735 - print("(%s)" % (" ".join(update_index_cmd),))
1736 - else:
1737 - retval = spawn(update_index_cmd, env=os.environ)
1738 - if retval != os.EX_OK:
1739 - writemsg_level(
1740 - "!!! Exiting on %s (shell) "
1741 - "error code: %s\n" % (vcs_settings.vcs, retval),
1742 - level=logging.ERROR, noiselevel=-1)
1743 - sys.exit(retval)
1744 -
1745 - if True:
1746 - myfiles = mymanifests[:]
1747 - # If there are no header (SVN/CVS keywords) changes in
1748 - # the files, this Manifest commit must include the
1749 - # other (yet uncommitted) files.
1750 - if not myheaders:
1751 - myfiles += myupdates
1752 - myfiles += myremoved
1753 - myfiles.sort()
1754 -
1755 - fd, commitmessagefile = tempfile.mkstemp(".repoman.msg")
1756 - mymsg = os.fdopen(fd, "wb")
1757 - mymsg.write(_unicode_encode(commitmessage))
1758 - mymsg.close()
1759 -
1760 - commit_cmd = []
1761 - if options.pretend and vcs_settings.vcs is None:
1762 - # substitute a bogus value for pretend output
1763 - commit_cmd.append("cvs")
1764 - else:
1765 - commit_cmd.append(vcs_settings.vcs)
1766 - commit_cmd.extend(vcs_settings.vcs_global_opts)
1767 - commit_cmd.append("commit")
1768 - commit_cmd.extend(vcs_settings.vcs_local_opts)
1769 - if vcs_settings.vcs == "hg":
1770 - commit_cmd.extend(["--logfile", commitmessagefile])
1771 - commit_cmd.extend(myfiles)
1772 - else:
1773 - commit_cmd.extend(["-F", commitmessagefile])
1774 - commit_cmd.extend(f.lstrip("./") for f in myfiles)
1775 -
1776 - try:
1777 - if options.pretend:
1778 - print("(%s)" % (" ".join(commit_cmd),))
1779 - else:
1780 - retval = spawn(commit_cmd, env=repo_settings.commit_env)
1781 - if retval != os.EX_OK:
1782 - if repo_settings.repo_config.sign_commit and vcs_settings.vcs == 'git' and \
1783 - not git_supports_gpg_sign():
1784 - # Inform user that newer git is needed (bug #403323).
1785 - logging.error(
1786 - "Git >=1.7.9 is required for signed commits!")
1787 -
1788 - writemsg_level(
1789 - "!!! Exiting on %s (shell) "
1790 - "error code: %s\n" % (vcs_settings.vcs, retval),
1791 - level=logging.ERROR, noiselevel=-1)
1792 - sys.exit(retval)
1793 - finally:
1794 - try:
1795 - os.unlink(commitmessagefile)
1796 - except OSError:
1797 - pass
1798 -
1799 - print()
1800 - if vcs_settings.vcs:
1801 - print("Commit complete.")
1802 - else:
1803 - print(
1804 - "repoman was too scared"
1805 - " by not seeing any familiar version control file"
1806 - " that he forgot to commit anything")
1807 - utilities.repoman_sez(
1808 - "\"If everyone were like you, I'd be out of business!\"\n")
1809 + # output the results
1810 + actions = Actions(repo_settings, options, scanner, vcs_settings)
1811 + if actions.inform(can_force, result):
1812 + # perform any other actions
1813 + actions.perform(qa_output)
1814 +
1815 sys.exit(0)