diff options
Diffstat (limited to 'portage_with_autodep/pym/repoman/utilities.py')
-rw-r--r-- | portage_with_autodep/pym/repoman/utilities.py | 164 |
1 files changed, 105 insertions, 59 deletions
diff --git a/portage_with_autodep/pym/repoman/utilities.py b/portage_with_autodep/pym/repoman/utilities.py index bee67aa..3ec3a4a 100644 --- a/portage_with_autodep/pym/repoman/utilities.py +++ b/portage_with_autodep/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,7 +326,7 @@ 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() @@ -367,10 +379,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 +440,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 +462,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 +522,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 +555,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 @@ -681,7 +715,7 @@ def get_committer_name(env=None): return user def UpdateChangeLog(pkgdir, user, msg, skel_path, category, package, - new=(), removed=(), changed=(), pretend=False): + new=(), removed=(), changed=(), pretend=False, quiet=False): """ Write an entry to an existing ChangeLog, or create a new one. Updates copyright year on changed files, and updates the header of @@ -689,8 +723,8 @@ def UpdateChangeLog(pkgdir, user, msg, skel_path, category, package, """ if '<root@' in user: - err = 'Please set ECHANGELOG_USER or run as non-root' - logging.critical(err) + if not quiet: + logging.critical('Please set ECHANGELOG_USER or run as non-root') return None # ChangeLog times are in UTC @@ -711,24 +745,13 @@ def UpdateChangeLog(pkgdir, user, msg, skel_path, category, package, old_header_lines = [] header_lines = [] + clold_file = None try: clold_file = io.open(_unicode_encode(cl_path, encoding=_encodings['fs'], errors='strict'), mode='r', encoding=_encodings['repo.content'], errors='replace') except EnvironmentError: - clold_file = None - - clskel_file = None - if clold_file is None: - # we will only need the ChangeLog skeleton if there is no - # ChangeLog yet - try: - clskel_file = io.open(_unicode_encode(skel_path, - encoding=_encodings['fs'], errors='strict'), - mode='r', encoding=_encodings['repo.content'], - errors='replace') - except EnvironmentError: - pass + pass f, clnew_path = mkstemp() @@ -736,17 +759,35 @@ def UpdateChangeLog(pkgdir, user, msg, skel_path, category, package, try: if clold_file is not None: # retain header from old ChangeLog + first_line = True for line in clold_file: - line_strip = line.strip() + line_strip = line.strip() if line_strip and line[:1] != "#": clold_lines.append(line) break + # always make sure cat/pkg is up-to-date in case we are + # moving packages around, or copied from another pkg, or ... + if first_line: + if line.startswith('# ChangeLog for'): + line = '# ChangeLog for %s/%s\n' % (category, package) + first_line = False old_header_lines.append(line) header_lines.append(_update_copyright_year(year, line)) if not line_strip: break - elif clskel_file is not None: + clskel_file = None + if not header_lines: + # delay opening this until we find we need a header + try: + clskel_file = io.open(_unicode_encode(skel_path, + encoding=_encodings['fs'], errors='strict'), + mode='r', encoding=_encodings['repo.content'], + errors='replace') + except EnvironmentError: + pass + + if clskel_file is not None: # read skel.ChangeLog up to first empty line for line in clskel_file: line_strip = line.strip() @@ -756,7 +797,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 @@ -766,10 +807,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] @@ -796,11 +837,13 @@ 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(_unicode_decode('\n')) + 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('\n') f = io.open(f, mode='w', encoding=_encodings['repo.content'], errors='backslashreplace') @@ -832,17 +875,20 @@ def UpdateChangeLog(pkgdir, user, msg, skel_path, category, package, # in the unified_diff call below. clold_lines = old_header_lines + clold_lines - for line in clold_file: - f.write(line) + # Trim any trailing newlines. + lines = clold_file.readlines() clold_file.close() + while lines and lines[-1] == '\n': + del lines[-1] + f.writelines(lines) f.close() - # show diff (do we want to keep on doing this, or only when - # pretend?) - for line in difflib.unified_diff(clold_lines, clnew_lines, - fromfile=cl_path, tofile=cl_path, n=0): - util.writemsg_stdout(line, noiselevel=-1) - util.writemsg_stdout("\n", noiselevel=-1) + # show diff + if not quiet: + for line in difflib.unified_diff(clold_lines, clnew_lines, + fromfile=cl_path, tofile=cl_path, n=0): + util.writemsg_stdout(line, noiselevel=-1) + util.writemsg_stdout("\n", noiselevel=-1) if pretend: # remove what we've done |