public inbox for gentoo-commits@lists.gentoo.org
 help / color / mirror / Atom feed
* [gentoo-commits] proj/portage:master commit in: pym/repoman/, bin/
@ 2011-10-17  0:14 Zac Medico
  0 siblings, 0 replies; 6+ messages in thread
From: Zac Medico @ 2011-10-17  0:14 UTC (permalink / raw
  To: gentoo-commits

commit:     f757cd2a4dd2d3634743c207a4aadb3f217bfce1
Author:     Fabian Groffen <grobian <AT> gentoo <DOT> org>
AuthorDate: Sun Oct 16 22:31:07 2011 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Sun Oct 16 22:31:07 2011 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=f757cd2a

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.

---
 bin/repoman              |  117 ++++++++++++++++++++++----------------------
 pym/repoman/utilities.py |  122 +++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 179 insertions(+), 60 deletions(-)

diff --git a/bin/repoman b/bin/repoman
index b1a2ac3..1d7d71a 100755
--- a/bin/repoman
+++ b/bin/repoman
@@ -18,7 +18,6 @@ import optparse
 import re
 import signal
 import stat
-import subprocess
 import sys
 import tempfile
 import textwrap
@@ -73,7 +72,7 @@ from portage.process import find_binary, spawn
 from portage.output import bold, create_color_func, \
 	green, nocolor, red
 from portage.output import ConsoleStyleFile, StyleWriter
-from portage.util import cmp_sort_key, writemsg_level, writemsg_stdout
+from portage.util import cmp_sort_key, writemsg_level
 from portage.package.ebuild.digestgen import digestgen
 from portage.eapi import eapi_has_iuse_defaults, eapi_has_required_use
 
@@ -645,19 +644,15 @@ if options.echangelog is None and \
 if vcs is None:
 	options.echangelog = 'n'
 
-if 'commit' == options.mode and \
-	options.echangelog == 'y' and \
-	find_binary('echangelog') is None:
-	logging.error("echangelog not found, and --echangelog is enabled")
-	sys.exit(1)
-
 # The --echangelog option causes automatic ChangeLog generation,
 # which invalidates changelog.ebuildadded and changelog.missing
 # checks.
-# Note: We don't use ChangeLogs in distributed SCMs.
+# Note: Some don't use ChangeLogs in distributed SCMs.
 # It will be generated on server side from scm log,
 # before package moves to the rsync server.
-# This is needed because we try to avoid merge collisions.
+# This is needed because they try to avoid merge collisions.
+# Gentoo's Council decided to always use the ChangeLog file.
+# TODO: shouldn't this just be switched on the repo, iso the VCS?
 check_changelog = options.echangelog != 'y' and vcs in ('cvs', 'svn')
 
 # Generate an appropriate PORTDIR_OVERLAY value for passing into the
@@ -2284,36 +2279,6 @@ else:
 				myautoadd+=[myunadded[x]]
 				del myunadded[x]
 
-	if myautoadd:
-		print(">>> Auto-Adding missing Manifest(s)...")
-		if options.pretend:
-			if vcs == "cvs":
-				print("(cvs add "+" ".join(myautoadd)+")")
-			elif vcs == "svn":
-				print("(svn add "+" ".join(myautoadd)+")")
-			elif vcs == "git":
-				print("(git add "+" ".join(myautoadd)+")")
-			elif vcs == "bzr":
-				print("(bzr add "+" ".join(myautoadd)+")")
-			elif vcs == "hg":
-				print("(hg add "+" ".join(myautoadd)+")")
-			retval=0
-		else:
-			if vcs == "cvs":
-				retval=os.system("cvs add "+" ".join(myautoadd))
-			elif vcs == "svn":
-				retval=os.system("svn add "+" ".join(myautoadd))
-			elif vcs == "git":
-				retval=os.system("git add "+" ".join(myautoadd))
-			elif vcs == "bzr":
-				retval=os.system("bzr add "+" ".join(myautoadd))
-			elif vcs == "hg":
-				retval=os.system("hg add "+" ".join(myautoadd))
-		if retval:
-			writemsg_level("!!! Exiting on %s (shell) error code: %s\n" % \
-				(vcs, retval), level=logging.ERROR, noiselevel=-1)
-			sys.exit(retval)
-
 	if myunadded:
 		print(red("!!! The following files are in your local tree but are not added to the master"))
 		print(red("!!! tree. Please remove them from the local tree or add them to the master tree."))
@@ -2402,8 +2367,6 @@ else:
 	myheaders = []
 	mydirty = []
 
-	print("* %s files being committed..." % green(str(len(myupdates))), end=' ')
-
 	commitmessage = options.commitmsg
 	if options.commitmsgfile:
 		try:
@@ -2473,22 +2436,60 @@ else:
 			if changelog_modified:
 				continue
 
-			myupdates.append(changelog_path)
-			logging.info("calling echangelog for package %s" % x)
-			# --no-strict is required if only manifest(s) have changed
-			echangelog_args = ["echangelog", "--no-strict",
-				"--vcs", vcs, changelog_msg]
-			if options.pretend:
-				writemsg_stdout("(%s)\n" % (" ".join(echangelog_args),),
-					noiselevel=-1)
-				continue
-			echangelog_args = [_unicode_encode(arg) for arg in echangelog_args]
-			echangelog_cwd = _unicode_encode(checkdir,
-				encoding=_encodings['fs'], errors='strict')
-			retcode = subprocess.call(echangelog_args, cwd=echangelog_cwd)
-			if retcode != os.EX_OK:
-				logging.error("echangelog exited with '%s' status" % retcode)
-				sys.exit(retcode)
+			# get changes for this package
+			cdrlen = len(checkdir_relative)
+			clnew = [elem[cdrlen:] for elem in mynew if elem.startswith(checkdir_relative)]
+			clremoved = [elem[cdrlen:] for elem in myremoved if elem.startswith(checkdir_relative)]
+			clchanged = [elem[cdrlen:] for elem in mychanged if elem.startswith(checkdir_relative)]
+			new_changelog = utilities.UpdateChangeLog(checkdir_relative, \
+				catdir, pkgdir, \
+				clnew, clremoved, clchanged, \
+				changelog_msg, options.pretend)
+			if new_changelog is None:
+				writemsg_level("!!! Updating the ChangeLog failed\n", \
+					level=logging.ERROR, noiselevel=-1)
+				sys.exit(1)
+
+			# if the ChangeLog was just created, add it to vcs
+			if new_changelog:
+				myautoadd.append(changelog_path)
+				# myautoadd is appended to myupdates below
+			else:
+				myupdates.append(changelog_path)
+
+	if myautoadd:
+		print(">>> Auto-Adding missing Manifest/ChangeLog file(s)...")
+		if options.pretend:
+			if vcs == "cvs":
+				print("(cvs add "+" ".join(myautoadd)+")")
+			elif vcs == "svn":
+				print("(svn add "+" ".join(myautoadd)+")")
+			elif vcs == "git":
+				print("(git add "+" ".join(myautoadd)+")")
+			elif vcs == "bzr":
+				print("(bzr add "+" ".join(myautoadd)+")")
+			elif vcs == "hg":
+				print("(hg add "+" ".join(myautoadd)+")")
+			retval = os.EX_OK
+		else:
+			if vcs == "cvs":
+				retval = os.system("cvs add "+" ".join(myautoadd))
+			elif vcs == "svn":
+				retval = os.system("svn add "+" ".join(myautoadd))
+			elif vcs == "git":
+				retval = os.system("git add "+" ".join(myautoadd))
+			elif vcs == "bzr":
+				retval = os.system("bzr add "+" ".join(myautoadd))
+			elif vcs == "hg":
+				retval = os.system("hg add "+" ".join(myautoadd))
+		if retval != os.EX_OK:
+			writemsg_level("!!! Exiting on %s (shell) error code: %s\n" % \
+				(vcs, retval), level=logging.ERROR, noiselevel=-1)
+			sys.exit(retval)
+
+		myupdates += myautoadd
+
+	print("* %s files being committed..." % green(str(len(myupdates))), end=' ')
 
 	if vcs not in ('cvs', 'svn'):
 		# With git, bzr and hg, there's never any keyword expansion, so

diff --git a/pym/repoman/utilities.py b/pym/repoman/utilities.py
index 7913703..8f7d5d5 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
+



^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [gentoo-commits] proj/portage:master commit in: pym/repoman/, bin/
@ 2011-10-20 20:40 Fabian Groffen
  0 siblings, 0 replies; 6+ messages in thread
From: Fabian Groffen @ 2011-10-20 20:40 UTC (permalink / raw
  To: gentoo-commits

commit:     ef99ccb7710f090ab7166f95587ccdd19e2cc740
Author:     Fabian Groffen <grobian <AT> gentoo <DOT> org>
AuthorDate: Thu Oct 20 20:35:41 2011 +0000
Commit:     Fabian Groffen <grobian <AT> gentoo <DOT> org>
CommitDate: Thu Oct 20 20:35:41 2011 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=ef99ccb7

repoman: get ChangeLog header from skel.ChangeLog

Use skel.ChangeLog from the repo to create the header of a new ChangeLog
file.  Else, we just retain the original header of the ChangeLog.  When
no skel.ChangeLog file exists, and this is a new ChangeLog, no header is
used.

---
 bin/repoman              |    2 +-
 pym/repoman/utilities.py |   79 +++++++++++++++++++++++++---------------------
 2 files changed, 44 insertions(+), 37 deletions(-)

diff --git a/bin/repoman b/bin/repoman
index bec3b1e..5b01825 100755
--- a/bin/repoman
+++ b/bin/repoman
@@ -2471,7 +2471,7 @@ else:
 			new_changelog = utilities.UpdateChangeLog(checkdir_relative, \
 				catdir, pkgdir, \
 				clnew, clremoved, clchanged, \
-				changelog_msg, options.pretend)
+				changelog_msg, options.pretend, repodir)
 			if new_changelog is None:
 				writemsg_level("!!! Updating the ChangeLog failed\n", \
 					level=logging.ERROR, noiselevel=-1)

diff --git a/pym/repoman/utilities.py b/pym/repoman/utilities.py
index c8cbba7..0eeea8b 100644
--- a/pym/repoman/utilities.py
+++ b/pym/repoman/utilities.py
@@ -523,7 +523,8 @@ def FindVCS():
 
 	return outvcs
 
-def UpdateChangeLog(pkgdir, category, package, new, removed, changed, msg, pretend):
+def UpdateChangeLog(pkgdir, category, package, new, removed, changed, \
+		msg, pretend, repodir):
 	""" Write an entry to an existing ChangeLog, or create a new one. """
 
 	# figure out who to write as
@@ -550,7 +551,6 @@ def UpdateChangeLog(pkgdir, category, package, new, removed, changed, msg, prete
 	cl_path = os.path.join(pkgdir, 'ChangeLog')
 	clold_lines = []
 	clnew_lines = []
-	old_header_lines = []
 	header_lines = []
 
 	try:
@@ -560,42 +560,51 @@ def UpdateChangeLog(pkgdir, category, package, new, removed, changed, msg, prete
 	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_path = os.path.join(repodir, 'skel.ChangeLog')
+			clskel_file = io.open(_unicode_encode(clskel_path,
+				encoding=_encodings['fs'], errors='strict'),
+				mode='r', encoding=_encodings['repo.content'],
+				errors='replace')
+		except EnvironmentError:
+			pass
+
 	# ChangeLog times are in UTC
 	gmtime = time.gmtime()
 	f, clnew_path = mkstemp()
 
-	# create an empty ChangeLog.new with correct header first
+	# construct correct header first
 	try:
-		f = io.open(f, mode='w', encoding=_encodings['repo.content'],
-			errors='backslashreplace')
-
-		if clold_file is None:
-			header_lines.append(_unicode_decode('# ChangeLog for %s/%s\n' %
-				(category, package)))
-			year = time.strftime('%Y', gmtime)
-			header_lines.append(_unicode_decode('# Copyright 1999-'
-				'%s Gentoo Foundation; Distributed under the GPL v2\n' % year))
-			header_lines.append(_unicode_decode('# $Header: $\n'))
-			header_lines.append(_unicode_decode('\n'))
-		else:
+		if clold_file is not None:
+			# retain header from old ChangeLog
 			for line in clold_file:
-				line_strip =  line.strip()
-				if line_strip and line[:1] != "#":
-					clold_lines.append(line)
+				line_strip = line.strip()
+				clold_lines.append(line)
+				if line_strip[:1] != '#':
 					break
-				header_lines.append(line)
+				if clskel_file is None:
+					clnew_lines.append(line)
 				if not line_strip:
 					break
-
-			# update the copyright year
-			old_header_lines = header_lines[:]
-			if len(header_lines) >= 2:
-				header_lines[1] = re.sub(r'^(# Copyright \d\d\d\d)-\d\d\d\d ',
-					r'\1-%s ' % time.strftime('%Y', gmtime), header_lines[1])
+		elif clskel_file is not None:
+			# read skel.ChangeLog up to first empty line
+			for line in clskel_file:
+				line_strip = line.strip()
+				if not line_strip:
+					break
+				line = line.replace('<CATEGORY>', category)
+				line = line.replace('<PACKAGE_NAME>', package)
+				line = re.sub(r'^(# Copyright \d\d\d\d)-\d\d\d\d ',
+					r'\1-%s ' % time.strftime('%Y', gmtime), line)
+				clnew_lines.append(line)
+			clnew_lines.append(_unicode_decode('\n'))
+			clskel_file.close()
 
 		# write new ChangeLog entry
-		clnew_lines.extend(header_lines)
-		date = time.strftime('%d %b %Y', gmtime)
 		newebuild = False
 		for fn in new:
 			if not fn.endswith('.ebuild'):
@@ -634,20 +643,18 @@ def UpdateChangeLog(pkgdir, category, package, new, removed, changed, msg, prete
 			clnew_lines.append(_unicode_decode('%s\n' % line))
 		clnew_lines.append(_unicode_decode('\n'))
 
+		f = io.open(f, mode='w', encoding=_encodings['repo.content'],
+			errors='backslashreplace')
+
 		for line in clnew_lines:
 			f.write(line)
 
 		# append stuff from old ChangeLog
 		if clold_file is not None:
-			# If the old ChangeLog didn't have a header, then
 			# clold_lines may contain a saved non-header line
 			# that we want to write first.
-			for line in clold_lines:
-				f.write(line)
-
-			# Now prepend old_header_lines to clold_lines, for use
-			# in the unified_diff call below.
-			clold_lines = old_header_lines + clold_lines
+			if clold_lines and clold_lines[-1].strip():
+				f.write(clold_lines[-1])
 
 			for line in clold_file:
 				f.write(line)
@@ -657,7 +664,7 @@ def UpdateChangeLog(pkgdir, category, package, new, removed, changed, msg, prete
 		# 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 + '.new', n=0):
+			fromfile=cl_path, tofile=cl_path, n=0):
 			util.writemsg_stdout(line, noiselevel=-1)
 		util.writemsg_stdout("\n", noiselevel=-1)
 
@@ -665,7 +672,7 @@ def UpdateChangeLog(pkgdir, category, package, new, removed, changed, msg, prete
 			# remove what we've done
 			os.remove(clnew_path)
 		else:
-			# rename ChangeLog.new to ChangeLog, and set permissions
+			# rename to ChangeLog, and set permissions
 			try:
 				clold_stat = os.stat(cl_path)
 			except OSError:



^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [gentoo-commits] proj/portage:master commit in: pym/repoman/, bin/
@ 2011-10-21  4:08 Zac Medico
  0 siblings, 0 replies; 6+ messages in thread
From: Zac Medico @ 2011-10-21  4:08 UTC (permalink / raw
  To: gentoo-commits

commit:     0966be903d19dd9999568de3baa3f9815e1e4369
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Fri Oct 21 04:07:34 2011 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Fri Oct 21 04:07:34 2011 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=0966be90

UpdateChangeLog: split out get_committer_name()

---
 bin/repoman              |   11 +++++++----
 pym/repoman/utilities.py |   44 ++++++++++++++++++++++++--------------------
 2 files changed, 31 insertions(+), 24 deletions(-)

diff --git a/bin/repoman b/bin/repoman
index 5b01825..bf91b85 100755
--- a/bin/repoman
+++ b/bin/repoman
@@ -2447,6 +2447,7 @@ else:
 
 	if options.echangelog in ('y', 'force'):
 		logging.info("checking for unmodified ChangeLog files")
+		committer_name = utilities.get_committer_name(env=repoman_settings)
 		for x in sorted(vcs_files_to_cps(
 			chain(myupdates, mymanifests, myremoved))):
 			catdir, pkgdir = x.split("/")
@@ -2468,10 +2469,12 @@ else:
 			clnew = [elem[cdrlen:] for elem in mynew if elem.startswith(checkdir_relative)]
 			clremoved = [elem[cdrlen:] for elem in myremoved if elem.startswith(checkdir_relative)]
 			clchanged = [elem[cdrlen:] for elem in mychanged if elem.startswith(checkdir_relative)]
-			new_changelog = utilities.UpdateChangeLog(checkdir_relative, \
-				catdir, pkgdir, \
-				clnew, clremoved, clchanged, \
-				changelog_msg, options.pretend, repodir)
+			new_changelog = utilities.UpdateChangeLog(checkdir_relative,
+				committer_name, changelog_msg,
+				os.path.join(repodir, 'skel.ChangeLog'),
+				catdir, pkgdir,
+				new=clnew, removed=clremoved, changed=clchanged,
+				pretend=options.pretend)
 			if new_changelog is None:
 				writemsg_level("!!! Updating the ChangeLog failed\n", \
 					level=logging.ERROR, noiselevel=-1)

diff --git a/pym/repoman/utilities.py b/pym/repoman/utilities.py
index c1a9da8..0ecc92c 100644
--- a/pym/repoman/utilities.py
+++ b/pym/repoman/utilities.py
@@ -16,6 +16,7 @@ __all__ = [
 	"format_qa_output",
 	"get_commit_message_with_editor",
 	"get_commit_message_with_stdin",
+	"get_committer_name",
 	"have_profile_dir",
 	"parse_metadata_use",
 	"UnknownHerdsError",
@@ -588,30 +589,34 @@ def update_copyright(fn_path, year, pretend):
 			util.apply_stat_permissions(fn_path, fn_stat)
 	fn_hdl.close()
 
-def UpdateChangeLog(pkgdir, category, package, new, removed, changed, \
-		msg, pretend, repodir):
+def get_committer_name(env=None):
+	"""Generate a committer string like echangelog does."""
+	if env is None:
+		env = os.environ
+	if 'GENTOO_COMMITTER_NAME' in env and \
+		'GENTOO_COMMITTER_EMAIL' in env:
+		user = '%s <%s>' % (env['GENTOO_COMMITTER_NAME'],
+			env['GENTOO_COMMITTER_EMAIL'])
+	elif 'GENTOO_AUTHOR_NAME' in env and \
+			'GENTOO_AUTHOR_EMAIL' in env:
+		user = '%s <%s>' % (env['GENTOO_AUTHOR_NAME'],
+			env['GENTOO_AUTHOR_EMAIL'])
+	elif 'ECHANGELOG_USER' in env:
+		user = env['ECHANGELOG_USER']
+	else:
+		pwd_struct = pwd.getpwuid(os.getuid())
+		gecos = pwd_struct.pw_gecos.split(',')[0]  # bug #80011
+		user = '%s <%s@gentoo.org>' % (gecos, pwd_struct.pw_name)
+	return user
+
+def UpdateChangeLog(pkgdir, user, msg, skel_path, category, package,
+	new=(), removed=(), changed=(), pretend=False):
 	"""
 	Write an entry to an existing ChangeLog, or create a new one.
 	Updates copyright year on changed files, and updates the header of
 	ChangeLog with the contents of skel.ChangeLog.
 	"""
 
-	# 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:
-		pwd_struct = pwd.getpwuid(os.getuid())
-		gecos = pwd_struct.pw_gecos.split(',')[0]  # bug #80011
-		user = '%s <%s@gentoo.org>' % (gecos, pwd_struct.pw_name)
-
 	if '<root@' in user:
 		err = 'Please set ECHANGELOG_USER or run as non-root'
 		logging.critical(err)
@@ -647,8 +652,7 @@ def UpdateChangeLog(pkgdir, category, package, new, removed, changed, \
 		# we will only need the ChangeLog skeleton if there is no
 		# ChangeLog yet
 		try:
-			clskel_path = os.path.join(repodir, 'skel.ChangeLog')
-			clskel_file = io.open(_unicode_encode(clskel_path,
+			clskel_file = io.open(_unicode_encode(skel_path,
 				encoding=_encodings['fs'], errors='strict'),
 				mode='r', encoding=_encodings['repo.content'],
 				errors='replace')



^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [gentoo-commits] proj/portage:master commit in: pym/repoman/, bin/
@ 2011-11-21 17:12 Zac Medico
  0 siblings, 0 replies; 6+ messages in thread
From: Zac Medico @ 2011-11-21 17:12 UTC (permalink / raw
  To: gentoo-commits

commit:     77f3354b73f386ee874c742e449924fac1ffd1e2
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Mon Nov 21 17:12:32 2011 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Mon Nov 21 17:12:32 2011 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=77f3354b

repoman: fix svn "abiguous workdir", bug #391199

---
 bin/repoman              |    1 +
 pym/repoman/utilities.py |    4 ++++
 2 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/bin/repoman b/bin/repoman
index 42a6154..8f42a38 100755
--- a/bin/repoman
+++ b/bin/repoman
@@ -654,6 +654,7 @@ if vcs is None:
 # TODO: shouldn't this just be switched on the repo, iso the VCS?
 check_changelog = options.echangelog not in ('y', 'force') and vcs in ('cvs', 'svn')
 
+logging.debug("vcs: %s" % (vcs,))
 logging.debug("repo config: %s" % (repo_config,))
 logging.debug("options: %s" % (options,))
 

diff --git a/pym/repoman/utilities.py b/pym/repoman/utilities.py
index 81fa5e7..c42c4c5 100644
--- a/pym/repoman/utilities.py
+++ b/pym/repoman/utilities.py
@@ -522,6 +522,10 @@ def FindVCS():
 	else:
 		outvcs = seek()
 
+	if len(outvcs) > 1:
+		# eliminate duplicates, like for svn in bug #391199
+		outvcs = list(set(outvcs))
+
 	return outvcs
 
 _copyright_re1 = re.compile(br'^(# Copyright \d\d\d\d)-\d\d\d\d ')



^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [gentoo-commits] proj/portage:master commit in: pym/repoman/, bin/
@ 2012-05-25 16:18 Mike Frysinger
  0 siblings, 0 replies; 6+ messages in thread
From: Mike Frysinger @ 2012-05-25 16:18 UTC (permalink / raw
  To: gentoo-commits

commit:     da6d3bb8357445a228a797046eb0b76dbbbaada0
Author:     Mike Frysinger <vapier <AT> gentoo <DOT> org>
AuthorDate: Wed May 23 19:06:19 2012 +0000
Commit:     Mike Frysinger <vapier <AT> gentoo <DOT> org>
CommitDate: Fri May 25 16:20:12 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=da6d3bb8

repoman: add a mini framework for checking eclasses, and fill it out

Rather than copying & pasting the same behavior for the different eclass
checks, add a common class for them to extend.  This makes adding more
eclass checks trivial, and keeps down bitrot.

This does abuse the checking interface slightly -- the eclass will change
its category between unused and missing based on the checks.

URL: https://bugs.gentoo.org/417159
URL: https://bugs.gentoo.org/417231
Signed-off-by: Mike Frysinger <vapier <AT> gentoo.org>

---
 bin/repoman           |    6 +-
 pym/repoman/checks.py |  161 ++++++++++++++++++++++++++++++++++---------------
 pym/repoman/errors.py |    1 -
 3 files changed, 116 insertions(+), 52 deletions(-)

diff --git a/bin/repoman b/bin/repoman
index fd87847..779e651 100755
--- a/bin/repoman
+++ b/bin/repoman
@@ -315,8 +315,9 @@ qahelp={
 	"file.size.fatal":"Files in the files directory must be under 60 KiB",
 	"file.name":"File/dir name must be composed of only the following chars: %s " % allowed_filename_chars,
 	"file.UTF8":"File is not UTF8 compliant",
-	"inherit.autotools":"Ebuild inherits autotools but does not call eautomake, eautoconf or eautoreconf",
 	"inherit.deprecated":"Ebuild inherits a deprecated eclass",
+	"inherit.missing":"Ebuild uses functions from an eclass but does not inherit it",
+	"inherit.unused":"Ebuild inherits an eclass but does not use it",
 	"java.eclassesnotused":"With virtual/jdk in DEPEND you must inherit a java eclass",
 	"wxwidgets.eclassnotused":"Ebuild DEPENDs on x11-libs/wxGTK without inheriting wxwidgets.eclass",
 	"KEYWORDS.dropped":"Ebuilds that appear to have dropped KEYWORDS for some arch",
@@ -382,7 +383,6 @@ qahelp={
 	"ebuild.majorsyn":"This ebuild has a major syntax error that may cause the ebuild to fail partially or fully",
 	"ebuild.minorsyn":"This ebuild has a minor syntax error that contravenes gentoo coding style",
 	"ebuild.badheader":"This ebuild has a malformed header",
-	"eprefixify.defined":"The ebuild uses eprefixify, but does not inherit the prefix eclass",
 	"manifest.bad":"Manifest has missing or incorrect digests",
 	"metadata.missing":"Missing metadata.xml files",
 	"metadata.bad":"Bad metadata.xml files",
@@ -425,7 +425,7 @@ qawarnings = set((
 "ebuild.badheader",
 "ebuild.patches",
 "file.size",
-"inherit.autotools",
+"inherit.unused",
 "inherit.deprecated",
 "java.eclassesnotused",
 "wxwidgets.eclassnotused",

diff --git a/pym/repoman/checks.py b/pym/repoman/checks.py
index a413968..35225c2 100644
--- a/pym/repoman/checks.py
+++ b/pym/repoman/checks.py
@@ -332,24 +332,6 @@ class EbuildQuotedA(LineCheck):
 		if match:
 			return "Quoted \"${A}\" on line: %d"
 
-class EprefixifyDefined(LineCheck):
-	""" Check that prefix.eclass is inherited if needed"""
-
-	repoman_check_name = 'eprefixify.defined'
-
-	_eprefixify_re = re.compile(r'\beprefixify\b')
-	_inherit_prefix_re = re.compile(r'^\s*inherit\s(.*\s)?prefix\b')
-
-	def new(self, pkg):
-		self._prefix_inherited = False
-
-	def check(self, num, line):
-		if self._eprefixify_re.search(line) is not None:
-			if not self._prefix_inherited:
-				return errors.EPREFIXIFY_MISSING_INHERIT
-		elif self._inherit_prefix_re.search(line) is not None:
-			self._prefix_inherited = True
-
 class NoOffsetWithHelpers(LineCheck):
 	""" Check that the image location, the alternate root offset, and the
 	offset prefix (D, ROOT, ED, EROOT and EPREFIX) are not used with
@@ -465,43 +447,124 @@ class InheritDeprecated(LineCheck):
 					(eclass, replacement)
 		del self._indirect_deprecated
 
-class InheritAutotools(LineCheck):
+class InheritEclass(LineCheck):
 	"""
-	Make sure appropriate functions are called in
-	ebuilds that inherit autotools.eclass.
+	Base class for checking for missing inherits, as well as excess inherits.
+
+	Args:
+		_eclass: Set to the name of your eclass.
+		_funcs: A tuple of functions that this eclass provides.
+		_comprehensive: Is the list of functions complete?
+		_exempt_eclasses: If these eclasses are inherited, disable the missing
+		                  inherit check.
 	"""
 
-	repoman_check_name = 'inherit.autotools'
-	_inherit_autotools_re = re.compile(r'^\s*inherit\s(.*\s)?autotools(\s|$)')
-	_autotools_funcs = (
-		"eaclocal", "eautoconf", "eautoheader",
-		"eautomake", "eautoreconf", "_elibtoolize")
-	_autotools_func_re = re.compile(r'\b(' + \
-		"|".join(_autotools_funcs) + r')\b')
-	# Exempt eclasses:
-	# git - An EGIT_BOOTSTRAP variable may be used to call one of
-	#       the autotools functions.
-	# subversion - An ESVN_BOOTSTRAP variable may be used to call one of
-	#       the autotools functions.
-	_exempt_eclasses = frozenset(["git", "subversion"])
+	def __init__(self):
+		self._inherit_re = re.compile(r'^\s*inherit\s(.*\s)?%s(\s|$)' % self._eclass)
+		self._func_re = re.compile(r'\b(' + '|'.join(self._funcs) + r')\b')
 
 	def new(self, pkg):
-		self._inherit_autotools = None
-		self._autotools_func_call = None
-		self._disabled = self._exempt_eclasses.intersection(pkg.inherited)
+		self.repoman_check_name = 'inherit.missing'
+		# We can't use pkg.inherited because that tells us all the eclass that
+		# have been inherited and not just the ones we inherit directly.
+		self._inherit = False
+		self._func_call = False
+		if hasattr(self, '_exempt_eclasses'):
+			self._disabled = self._exempt_eclasses.intersection(pkg.inherited)
+		else:
+			self._disabled = False
 
 	def check(self, num, line):
-		if self._disabled:
-			return
-		if self._inherit_autotools is None:
-			self._inherit_autotools = self._inherit_autotools_re.match(line)
-		if self._inherit_autotools is not None and \
-			self._autotools_func_call is None:
-			self._autotools_func_call = self._autotools_func_re.search(line)
+		if not self._inherit:
+			self._inherit = self._inherit_re.match(line)
+		if not self._inherit:
+			if self._disabled:
+				return
+			s = self._func_re.search(line)
+			if s:
+				self._func_call = True
+				return '%s.eclass is not inherited, but "%s" found at line: %s' % \
+					(self._eclass, s.group(0), '%d')
+		elif not self._func_call:
+			self._func_call = self._func_re.search(line)
 
 	def end(self):
-		if self._inherit_autotools and self._autotools_func_call is None:
-			yield 'no eauto* function called'
+		if self._comprehensive and self._inherit and not self._func_call:
+			self.repoman_check_name = 'inherit.unused'
+			yield 'no function called from %s.eclass; please drop' % self._eclass
+
+class InheritAutotools(InheritEclass):
+	_eclass = 'autotools'
+	_funcs = (
+		'eaclocal', 'eautoconf', 'eautoheader',
+		'eautomake', 'eautoreconf', '_elibtoolize',
+		'eautopoint'
+	)
+	_comprehensive = True
+
+	# Exempt eclasses:
+	# git - An EGIT_BOOTSTRAP variable may be used to call one of
+	#       the autotools functions.
+	# subversion - An ESVN_BOOTSTRAP variable may be used to call one of
+	#       the autotools functions.
+	_exempt_eclasses = frozenset(['git', 'subversion', 'autotools-utils'])
+
+class InheritEutils(InheritEclass):
+	_eclass = 'eutils'
+	_funcs = (
+		'estack_push', 'estack_pop', 'eshopts_push', 'eshopts_pop',
+		'eumask_push', 'eumask_pop', 'epatch', 'epatch_user',
+		'emktemp', 'edos2unix', 'in_iuse', 'use_if_iuse', 'usex',
+		'makeopts_jobs'
+	)
+	_comprehensive = False
+
+	# These are "eclasses are the whole ebuild" type thing.
+	_exempt_eclasses = frozenset(['toolchain', 'toolchain-binutils'])
+
+class InheritFlagOMatic(InheritEclass):
+	_eclass = 'flag-o-matic'
+	_funcs = (
+		'filter-(ld)?flags', 'strip-flags', 'strip-unsupported-flags',
+		'append-((ld|c(pp|xx)?))?flags', 'append-libs',
+	)
+	_comprehensive = False
+
+class InheritLibtool(InheritEclass):
+	_eclass = 'libtool'
+	_funcs = (
+		'elibtoolize',
+	)
+	_comprehensive = True
+
+class InheritMultilib(InheritEclass):
+	_eclass = 'multilib'
+	_funcs = (
+		'get_libdir',
+	)
+	_comprehensive = False
+
+class InheritPrefix(InheritEclass):
+	_eclass = 'prefix'
+	_funcs = (
+		'eprefixify',
+	)
+	_comprehensive = True
+
+class InheritToolchainFuncs(InheritEclass):
+	_eclass = 'toolchain-funcs'
+	_funcs = (
+		'gen_usr_ldscript',
+	)
+	_comprehensive = False
+
+class InheritUser(InheritEclass):
+	_eclass = 'user'
+	_funcs = (
+		'enewuser', 'enewgroup',
+		'egetent', 'egethome', 'egetshell'
+	)
+	_comprehensive = True
 
 class IUseUndefined(LineCheck):
 	"""
@@ -680,8 +743,10 @@ _constant_checks = tuple((c() for c in (
 	EbuildHeader, EbuildWhitespace, EbuildBlankLine, EbuildQuote,
 	EbuildAssignment, Eapi3EbuildAssignment, EbuildUselessDodoc,
 	EbuildUselessCdS, EbuildNestedDie,
-	EbuildPatches, EbuildQuotedA, EapiDefinition, EprefixifyDefined,
-	ImplicitRuntimeDeps, InheritAutotools, InheritDeprecated, IUseUndefined,
+	EbuildPatches, EbuildQuotedA, EapiDefinition,
+	ImplicitRuntimeDeps, InheritAutotools, InheritDeprecated, InheritEutils,
+	InheritFlagOMatic, InheritMultilib, InheritLibtool, InheritPrefix,
+	InheritToolchainFuncs, InheritUser, IUseUndefined,
 	EMakeParallelDisabled, EMakeParallelDisabledViaMAKEOPTS, NoAsNeeded,
 	DeprecatedBindnowFlags, SrcUnpackPatches, WantAutoDefaultValue,
 	SrcCompileEconf, Eapi3DeprecatedFuncs, NoOffsetWithHelpers,

diff --git a/pym/repoman/errors.py b/pym/repoman/errors.py
index 3209243..c515502 100644
--- a/pym/repoman/errors.py
+++ b/pym/repoman/errors.py
@@ -19,7 +19,6 @@ EAPI_DEFINED_AFTER_INHERIT = 'EAPI defined after inherit on line: %d'
 NO_AS_NEEDED = 'Upstream asneeded linking bug (no-as-needed on line: %d)'
 PRESERVE_OLD_LIB = 'Upstream ABI change workaround on line: %d'
 BUILT_WITH_USE = 'built_with_use on line: %d'
-EPREFIXIFY_MISSING_INHERIT = "prefix.eclass is not inherited, but eprefixify is used on line: %d"
 NO_OFFSET_WITH_HELPERS = "Helper function is used with D, ROOT, ED, EROOT or EPREFIX on line :%d"
 SANDBOX_ADDPREDICT = 'Ebuild calls addpredict on line: %d'
 USEQ_ERROR = 'Ebuild calls deprecated useq function on line: %d'



^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [gentoo-commits] proj/portage:master commit in: pym/repoman/, bin/
@ 2014-02-12  0:53 Chris Reffett
  0 siblings, 0 replies; 6+ messages in thread
From: Chris Reffett @ 2014-02-12  0:53 UTC (permalink / raw
  To: gentoo-commits

commit:     af0eca982f04409439e6310e602b55bed6cc623c
Author:     Chris Reffett <creffett <AT> gentoo <DOT> org>
AuthorDate: Mon Feb 10 20:16:33 2014 +0000
Commit:     Chris Reffett <creffett <AT> gentoo <DOT> org>
CommitDate: Wed Feb 12 00:53:11 2014 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=af0eca98

Add --output-style option to repoman

This patch adds a --output-style option to repoman, which gives the user
a choice of output formats for the repoman checks. Choices are "default"
(current style) and "column" (a greppable format), but it should be easy
to add more. Fixes bug 481584.

v2: Fix docstring to be complete and in the standard format, make use of
default choices in --output-style wrt comments by antarus and dol-sen

---
 bin/repoman              | 15 ++++++++++++++-
 pym/repoman/utilities.py | 44 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 58 insertions(+), 1 deletion(-)

diff --git a/bin/repoman b/bin/repoman
index 3504b6b..c7a1c4c 100755
--- a/bin/repoman
+++ b/bin/repoman
@@ -144,9 +144,16 @@ def ParseArgs(argv, qahelp):
 		'scan' : 'Scan directory tree for QA issues'
 	}
 
+	output_choices = {
+		'default' : 'The normal output format',
+		'column' : 'Columnar output suitable for use with grep'
+	}
+
 	mode_keys = list(modes)
 	mode_keys.sort()
 
+	output_keys = sorted(output_choices)
+
 	parser = ArgumentParser(usage="repoman [options] [mode]",
 		description="Modes: %s" % " | ".join(mode_keys),
 		epilog="For more help consult the man page.")
@@ -228,6 +235,9 @@ def ParseArgs(argv, qahelp):
 	parser.add_argument('--without-mask', dest='without_mask', action='store_true',
 		default=False, help='behave as if no package.mask entries exist (not allowed with commit mode)')
 
+	parser.add_argument('--output-style', dest='output_style', choices=output_keys,
+		help='select output type', default='default')
+
 	parser.add_argument('--mode', dest='mode', choices=mode_keys,
 		help='specify which mode repoman will run in (default=full)')
 
@@ -2422,7 +2432,10 @@ console_writer.style_listener = style_file.new_styles
 
 f = formatter.AbstractFormatter(console_writer)
 
-utilities.format_qa_output(f, stats, fails, dofull, dofail, options, qawarnings)
+if options.output_style == 'column':
+	utilities.format_qa_output_column(f, stats, fails, dofull, dofail, options, qawarnings)
+else:
+	utilities.format_qa_output(f, stats, fails, dofull, dofail, options, qawarnings)
 
 style_file.flush()
 del console_writer, f, style_file

diff --git a/pym/repoman/utilities.py b/pym/repoman/utilities.py
index 3ec3a4a..aec61fe 100644
--- a/pym/repoman/utilities.py
+++ b/pym/repoman/utilities.py
@@ -330,6 +330,50 @@ def format_qa_output(formatter, stats, fails, dofull, dofail, options, qawarning
 				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


^ permalink raw reply related	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2014-02-12  0:53 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-10-21  4:08 [gentoo-commits] proj/portage:master commit in: pym/repoman/, bin/ Zac Medico
  -- strict thread matches above, loose matches on Subject: below --
2014-02-12  0:53 Chris Reffett
2012-05-25 16:18 Mike Frysinger
2011-11-21 17:12 Zac Medico
2011-10-20 20:40 Fabian Groffen
2011-10-17  0:14 Zac Medico

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox