summaryrefslogtreecommitdiffstats
path: root/pym/repoman/utilities.py
diff options
context:
space:
mode:
authorFabian Groffen <grobian@gentoo.org>2011-10-16 15:31:07 -0700
committerZac Medico <zmedico@gentoo.org>2011-10-16 15:31:07 -0700
commitf757cd2a4dd2d3634743c207a4aadb3f217bfce1 (patch)
tree333fa169fdb594ed7f25fa457200974b1604f00c /pym/repoman/utilities.py
parent5b8fdc7d3e4c64ce79d0218fd101f8292602d10b (diff)
downloadportage-f757cd2a4dd2d3634743c207a4aadb3f217bfce1.tar.gz
portage-f757cd2a4dd2d3634743c207a4aadb3f217bfce1.tar.bz2
portage-f757cd2a4dd2d3634743c207a4aadb3f217bfce1.zip
repoman: implemented echangelog functionality
Instead of calling echangelog, which on its turn has to query the VCS again, use the existing information on changes made to the current directory, and update the ChangeLog from Python itself. This avoids a call to echangelog, and avoids again retrieving the same VCS information as repoman already did. It makes repoman independent from external tools it didn't install itself, and should be faster in general.
Diffstat (limited to 'pym/repoman/utilities.py')
-rw-r--r--pym/repoman/utilities.py122
1 files changed, 120 insertions, 2 deletions
diff --git a/pym/repoman/utilities.py b/pym/repoman/utilities.py
index 79137036c..8f7d5d54c 100644
--- a/pym/repoman/utilities.py
+++ b/pym/repoman/utilities.py
@@ -5,6 +5,8 @@
"""This module contains utility functions to help repoman find ebuilds to
scan"""
+from __future__ import print_function
+
__all__ = [
"detect_vcs_conflicts",
"editor_is_executable",
@@ -17,13 +19,22 @@ __all__ = [
"have_profile_dir",
"parse_metadata_use",
"UnknownHerdsError",
- "check_metadata"
+ "check_metadata",
+ "UpdateChangeLog"
]
import errno
import io
+from itertools import chain
import logging
+import pwd
import sys
+import time
+import textwrap
+import difflib
+import shutil
+from tempfile import mkstemp
+
from portage import os
from portage import subprocess_getstatusoutput
from portage import _encodings
@@ -308,7 +319,6 @@ def get_commit_message_with_editor(editor, message=None):
@rtype: string or None
@returns: A string on success or None if an error occurs.
"""
- from tempfile import mkstemp
fd, filename = mkstemp()
try:
os.write(fd, _unicode_encode(_(
@@ -511,3 +521,111 @@ def FindVCS():
outvcs = seek()
return outvcs
+
+def UpdateChangeLog(pkgdir, category, package, new, removed, changed, msg, pretend):
+ """ Write an entry to an existing ChangeLog, or create a new one. """
+
+ # figure out who to write as
+ if 'GENTOO_COMMITTER_NAME' in os.environ and \
+ 'GENTOO_COMMITTER_EMAIL' in os.environ:
+ user = '%s <%s>' % (os.environ['GENTOO_COMMITTER_NAME'], \
+ os.environ['GENTOO_COMMITTER_EMAIL'])
+ elif 'GENTOO_AUTHOR_NAME' in os.environ and \
+ 'GENTOO_AUTHOR_EMAIL' in os.environ:
+ user = '%s <%s>' % (os.environ['GENTOO_AUTHOR_NAME'], \
+ os.environ['GENTOO_AUTHOR_EMAIL'])
+ elif 'ECHANGELOG_USER' in os.environ:
+ user = os.environ['ECHANGELOG_USER']
+ else:
+ (login, _, _, _, gecos, _, _) = pwd.getpwuid(os.getuid())
+ gecos = gecos.split(',')[0] # bug #80011
+ user = '%s <%s@gentoo.org>' % (gecos, login)
+
+ if '<root@' in user:
+ err = 'Please set ECHANGELOG_USER or run as non-root'
+ logging.critical(err)
+ return None
+
+ cl_path = os.path.join(pkgdir, 'ChangeLog')
+ f, clnew_path = mkstemp()
+
+ # create an empty ChangeLog.new with correct header first
+ try:
+ f = os.fdopen(f, 'w+')
+ f.write('# ChangeLog for %s/%s\n' % (category, package))
+ year = time.strftime('%Y')
+ f.write('# Copyright 1999-%s Gentoo Foundation; Distributed under the GPL v2\n' % year)
+ f.write('# $Header: $\n')
+ f.write('\n')
+
+ # write new ChangeLog entry
+ date = time.strftime('%d %b %Y')
+ newebuild = False
+ for fn in new:
+ if not fn.endswith('.ebuild'):
+ continue
+ ebuild = fn.split(os.sep)[-1][0:-7]
+ f.write('*%s (%s)\n' % (ebuild, date))
+ newebuild = True
+ if newebuild:
+ f.write('\n')
+ new = ['+' + elem for elem in new if elem not in ['ChangeLog', 'Manifest']]
+ removed = ['-' + elem for elem in removed]
+ changed = [elem for elem in changed if elem not in ['ChangeLog', 'Manifest']]
+ mesg = '%s; %s %s:' % (date, user, \
+ ', '.join(chain(new,removed,changed)))
+ for line in textwrap.wrap(mesg, 80, \
+ initial_indent=' ', subsequent_indent=' ', \
+ break_on_hyphens=False):
+ f.write('%s\n' % line)
+ for line in textwrap.wrap(msg, 80, \
+ initial_indent=' ', subsequent_indent=' '):
+ f.write('%s\n' % line)
+
+ # append stuff from old ChangeLog
+ cl_lines = []
+ if os.path.exists(cl_path):
+ c = open(cl_path, 'r')
+ cl_lines = c.readlines()
+ for index, line in enumerate(cl_lines):
+ # skip the headers
+ if line.startswith('#'):
+ # normalise to $Header: $ to avoid pointless diff line
+ if line.startswith('# $Header:'):
+ cl_lines[index] = '# $Header: $\n'
+ continue
+ f.write(line)
+ c.close()
+
+ # show diff (do we want to keep on doing this, or only when
+ # pretend?)
+ f.seek(0)
+ clnew_lines = f.readlines()
+ for line in difflib.unified_diff(cl_lines, clnew_lines, \
+ fromfile=cl_path, tofile=cl_path + '.new', n=0):
+ print(line.rstrip())
+ print()
+
+ f.close()
+
+ if pretend:
+ # remove what we've done
+ os.remove(clnew_path)
+ else:
+ # rename ChangeLog.new to ChangeLog
+ shutil.move(clnew_path, cl_path)
+
+ if cl_lines == []:
+ return True
+ else:
+ return False
+ except IOError as e:
+ err = 'Repoman is unable to create/write to Changelog.new file: %s' % (e,)
+ logging.critical(err)
+ # try to remove if possible
+ try:
+ os.remove(clnew_path)
+ except OSError:
+ pass
+ return None
+