diff options
author | Brian Dolbec <dolsen@gentoo.org> | 2014-03-26 06:52:42 -0700 |
---|---|---|
committer | Brian Dolbec <dolsen@gentoo.org> | 2014-03-26 06:52:42 -0700 |
commit | 276611668673967d8dd76caebb1e427dd10b3ff2 (patch) | |
tree | 479b3b5dccbc0dfd96c617908eb21946e6785eeb /pym/repoman/utilities.py | |
parent | Merge branch 'master' of git+ssh://git.overlays.gentoo.org/proj/portage into ... (diff) | |
download | portage-276611668673967d8dd76caebb1e427dd10b3ff2.tar.gz portage-276611668673967d8dd76caebb1e427dd10b3ff2.tar.bz2 portage-276611668673967d8dd76caebb1e427dd10b3ff2.zip |
Merge branch 'master' of git+ssh://git.overlays.gentoo.org/proj/portage into public_apipublic_api
Diffstat (limited to 'pym/repoman/utilities.py')
-rw-r--r-- | pym/repoman/utilities.py | 146 |
1 files changed, 112 insertions, 34 deletions
diff --git a/pym/repoman/utilities.py b/pym/repoman/utilities.py index 013858a6d..aec61fe2f 100644 --- a/pym/repoman/utilities.py +++ b/pym/repoman/utilities.py @@ -1,11 +1,11 @@ # repoman: Utilities -# Copyright 2007-2012 Gentoo Foundation +# Copyright 2007-2013 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 """This module contains utility functions to help repoman find ebuilds to scan""" -from __future__ import print_function +from __future__ import print_function, unicode_literals __all__ = [ "detect_vcs_conflicts", @@ -25,6 +25,7 @@ __all__ = [ "UpdateChangeLog" ] +import collections import errno import io from itertools import chain @@ -33,18 +34,20 @@ import pwd import re import stat import sys +import subprocess import time import textwrap import difflib from tempfile import mkstemp +import portage from portage import os from portage import shutil -from portage import subprocess_getstatusoutput from portage import _encodings from portage import _unicode_decode from portage import _unicode_encode from portage import output +from portage.const import BASH_BINARY from portage.localization import _ from portage.output import red, green from portage.process import find_binary @@ -71,22 +74,31 @@ def detect_vcs_conflicts(options, vcs): Returns: None (calls sys.exit on fatal problems) """ - retval = ("","") + + cmd = None if vcs == 'cvs': logging.info("Performing a " + output.green("cvs -n up") + \ " with a little magic grep to check for updates.") - retval = subprocess_getstatusoutput("cvs -n up 2>/dev/null | " + \ + cmd = "cvs -n up 2>/dev/null | " + \ "egrep '^[^\?] .*' | " + \ - "egrep -v '^. .*/digest-[^/]+|^cvs server: .* -- ignored$'") + "egrep -v '^. .*/digest-[^/]+|^cvs server: .* -- ignored$'" if vcs == 'svn': logging.info("Performing a " + output.green("svn status -u") + \ " with a little magic grep to check for updates.") - retval = subprocess_getstatusoutput("svn status -u 2>&1 | " + \ + cmd = "svn status -u 2>&1 | " + \ "egrep -v '^. +.*/digest-[^/]+' | " + \ - "head -n-1") - - if vcs in ['cvs', 'svn']: - mylines = retval[1].splitlines() + "head -n-1" + + if cmd is not None: + # Use Popen instead of getstatusoutput(), in order to avoid + # unicode handling problems (see bug #310789). + args = [BASH_BINARY, "-c", cmd] + args = [_unicode_encode(x) for x in args] + proc = subprocess.Popen(args, stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + out = _unicode_decode(proc.communicate()[0]) + proc.wait() + mylines = out.splitlines() myupdates = [] for line in mylines: if not line: @@ -98,7 +110,7 @@ def detect_vcs_conflicts(options, vcs): logging.error(red("!!! Please fix the following issues reported " + \ "from cvs: ")+green("(U,P,M,A,R,D are ok)")) logging.error(red("!!! Note: This is a pretend/no-modify pass...")) - logging.error(retval[1]) + logging.error(out) sys.exit(1) elif vcs == 'cvs' and line[0] in "UP": myupdates.append(line[2:]) @@ -298,12 +310,12 @@ def format_qa_output(formatter, stats, fails, dofull, dofail, options, qawarning # we only want key value pairs where value > 0 for category, number in \ filter(lambda myitem: myitem[1] > 0, iter(stats.items())): - formatter.add_literal_data(_unicode_decode(" " + category.ljust(30))) + formatter.add_literal_data(" " + category.ljust(30)) if category in qawarnings: formatter.push_style("WARN") else: formatter.push_style("BAD") - formatter.add_literal_data(_unicode_decode(str(number))) + formatter.add_literal_data("%s" % number) formatter.pop_style() formatter.add_line_break() if not dofull: @@ -314,10 +326,54 @@ def format_qa_output(formatter, stats, fails, dofull, dofail, options, qawarning if not full and len(fails_list) > 12: fails_list = fails_list[:12] for failure in fails_list: - formatter.add_literal_data(_unicode_decode(" " + failure)) + formatter.add_literal_data(" " + failure) formatter.add_line_break() +def format_qa_output_column(formatter, stats, fails, dofull, dofail, options, qawarnings): + """Helper function that formats output in a machine-parseable column format + + @param formatter: an instance of Formatter + @type formatter: Formatter + @param path: dict of qa status items + @type path: dict + @param fails: dict of qa status failures + @type fails: dict + @param dofull: Whether to print full results or a summary + @type dofull: boolean + @param dofail: Whether failure was hard or soft + @type dofail: boolean + @param options: The command-line options provided to repoman + @type options: Namespace + @param qawarnings: the set of warning types + @type qawarnings: set + @return: None (modifies formatter) + """ + full = options.mode == 'full' + for category, number in stats.items(): + # we only want key value pairs where value > 0 + if number < 1: + continue + + formatter.add_literal_data("NumberOf " + category + " ") + if category in qawarnings: + formatter.push_style("WARN") + else: + formatter.push_style("BAD") + formatter.add_literal_data("%s" % number) + formatter.pop_style() + formatter.add_line_break() + if not dofull: + if not full and dofail and category in qawarnings: + # warnings are considered noise when there are failures + continue + fails_list = fails[category] + if not full and len(fails_list) > 12: + fails_list = fails_list[:12] + for failure in fails_list: + formatter.add_literal_data(category + " " + failure) + formatter.add_line_break() + def editor_is_executable(editor): """ Given an EDITOR string, validate that it refers to @@ -367,10 +423,11 @@ def get_commit_message_with_editor(editor, message=None): if not (os.WIFEXITED(retval) and os.WEXITSTATUS(retval) == os.EX_OK): return None try: - mylines = io.open(_unicode_encode(filename, + with io.open(_unicode_encode(filename, encoding=_encodings['fs'], errors='strict'), mode='r', encoding=_encodings['content'], errors='replace' - ).readlines() + ) as f: + mylines = f.readlines() except OSError as e: if e.errno != errno.ENOENT: raise @@ -427,7 +484,7 @@ def FindPortdir(settings): portdir = None portdir_overlay = None location = os.getcwd() - pwd = os.environ.get('PWD', '') + pwd = _unicode_decode(os.environ.get('PWD', ''), encoding=_encodings['fs']) if pwd and pwd != location and os.path.realpath(pwd) == location: # getcwd() returns the canonical path but that makes it hard for repoman to # orient itself if the user has symlinks in their portage tree structure. @@ -449,7 +506,7 @@ def FindPortdir(settings): if location[-1] != "/": location += "/" - for overlay in settings["PORTDIR_OVERLAY"].split(): + for overlay in portage.util.shlex_split(settings["PORTDIR_OVERLAY"]): overlay = os.path.realpath(overlay) try: s = os.stat(overlay) @@ -509,6 +566,28 @@ def FindPortdir(settings): return [normalize_path(x) for x in (portdir, portdir_overlay, location)] +_vcs_type = collections.namedtuple('_vcs_type', + 'name dir_name') + +_FindVCS_data = ( + _vcs_type( + name = 'git', + dir_name = '.git' + ), + _vcs_type( + name = 'bzr', + dir_name = '.bzr' + ), + _vcs_type( + name = 'hg', + dir_name = '.hg' + ), + _vcs_type( + name = 'svn', + dir_name = '.svn' + ) +) + def FindVCS(): """ Try to figure out in what VCS' working tree we are. """ @@ -520,14 +599,13 @@ def FindVCS(): pathprep = '' while depth is None or depth > 0: - if os.path.isdir(os.path.join(pathprep, '.git')): - retvcs.append('git') - if os.path.isdir(os.path.join(pathprep, '.bzr')): - retvcs.append('bzr') - if os.path.isdir(os.path.join(pathprep, '.hg')): - retvcs.append('hg') - if os.path.isdir(os.path.join(pathprep, '.svn')): # >=1.7 - retvcs.append('svn') + for vcs_type in _FindVCS_data: + vcs_dir = os.path.join(pathprep, vcs_type.dir_name) + if os.path.isdir(vcs_dir): + logging.debug('FindVCS: found %(name)s dir: %(vcs_dir)s' % + {'name': vcs_type.name, + 'vcs_dir': os.path.abspath(vcs_dir)}) + retvcs.append(vcs_type.name) if retvcs: break @@ -763,7 +841,7 @@ def UpdateChangeLog(pkgdir, user, msg, skel_path, category, package, line = line.replace('<PACKAGE_NAME>', package) line = _update_copyright_year(year, line) header_lines.append(line) - header_lines.append(_unicode_decode('\n')) + header_lines.append('\n') clskel_file.close() # write new ChangeLog entry @@ -773,10 +851,10 @@ def UpdateChangeLog(pkgdir, user, msg, skel_path, category, package, if not fn.endswith('.ebuild'): continue ebuild = fn.split(os.sep)[-1][0:-7] - clnew_lines.append(_unicode_decode('*%s (%s)\n' % (ebuild, date))) + clnew_lines.append('*%s (%s)\n' % (ebuild, date)) newebuild = True if newebuild: - clnew_lines.append(_unicode_decode('\n')) + clnew_lines.append('\n') trivial_files = ('ChangeLog', 'Manifest') display_new = ['+' + elem for elem in new if elem not in trivial_files] @@ -803,19 +881,19 @@ def UpdateChangeLog(pkgdir, user, msg, skel_path, category, package, for line in textwrap.wrap(mesg, 80, \ initial_indent=' ', subsequent_indent=' ', \ break_on_hyphens=False): - clnew_lines.append(_unicode_decode('%s\n' % line)) + clnew_lines.append('%s\n' % line) for line in textwrap.wrap(msg, 80, \ initial_indent=' ', subsequent_indent=' '): - clnew_lines.append(_unicode_decode('%s\n' % line)) + clnew_lines.append('%s\n' % line) # Don't append a trailing newline if the file is new. if clold_file is not None: - clnew_lines.append(_unicode_decode('\n')) + clnew_lines.append('\n') f = io.open(f, mode='w', encoding=_encodings['repo.content'], errors='backslashreplace') for line in clnew_lines: - f.write(_unicode_decode(line)) + f.write(line) # append stuff from old ChangeLog if clold_file is not None: |