from portage import os, _encodings, _unicode_encode, _unicode_decode
from _emerge.MetadataRegen import MetadataRegen
from portage.cache.cache_errors import CacheError, StatCollision
+from portage.manifest import guessManifestFileType
from portage.util import cmp_sort_key, writemsg_level
from portage import cpv_getkey
from portage.dep import Atom, isjustname
-from portage.versions import pkgcmp, pkgsplit
+from portage.versions import pkgcmp, pkgsplit, vercmp
try:
import xml.etree.ElementTree
output.close()
+if sys.hexversion < 0x3000000:
+ _filename_base = unicode
+else:
+ _filename_base = str
+
+class _special_filename(_filename_base):
+ """
+ Helps to sort file names by file type and other criteria.
+ """
+ def __new__(cls, status_change, file_name):
+ return _filename_base.__new__(cls, status_change + file_name)
+
+ def __init__(self, status_change, file_name):
+ _filename_base.__init__(status_change + file_name)
+ self.status_change = status_change
+ self.file_name = file_name
+ self.file_type = guessManifestFileType(file_name)
+
+ def file_type_lt(self, a, b):
+ """
+ Defines an ordering between file types.
+ """
+ first = a.file_type
+ second = b.file_type
+ if first == second:
+ return False
+
+ if first == "EBUILD":
+ return True
+ elif first == "MISC":
+ return second in ("EBUILD",)
+ elif first == "AUX":
+ return second in ("EBUILD", "MISC")
+ elif first == "DIST":
+ return second in ("EBUILD", "MISC", "AUX")
+ elif first is None:
+ return False
+ else:
+ raise ValueError("Unknown file type '%s'" % first)
+
+ def __lt__(self, other):
+ """
+ Compare different file names, first by file type and then
+ for ebuilds by version and lexicographically for others.
+ EBUILD < MISC < AUX < DIST < None
+ """
+ if self.__class__ != other.__class__:
+ raise NotImplementedError
+
+ # Sort by file type as defined by file_type_lt().
+ if self.file_type_lt(self, other):
+ return True
+ elif self.file_type_lt(other, self):
+ return False
+
+ # Files have the same type.
+ if self.file_type == "EBUILD":
+ # Sort by version. Lowest first.
+ ver = "-".join(pkgsplit(self.file_name[:-7])[1:3])
+ other_ver = "-".join(pkgsplit(other.file_name[:-7])[1:3])
+ return vercmp(ver, other_ver) < 0
+ else:
+ # Sort lexicographically.
+ return self.file_name < other.file_name
+
class GenChangeLogs(object):
def __init__(self, portdb):
self.returncode = os.EX_OK
elif f[1] == 'ChangeLog':
pass
elif f[0].startswith('A'):
- changed.append('+%s' % f[1])
+ changed.append(_special_filename("+", f[1]))
elif f[0].startswith('D'):
- changed.append('-%s' % f[1])
+ changed.append(_special_filename("-", f[1]))
elif f[0].startswith('M'):
- changed.append(f[1])
+ changed.append(_special_filename("", f[1]))
else:
writemsg_level(
"ERROR: unexpected git file status for %s: %s\n" % (cp,f,),
(ts, author) = cinfo[0].split(' ', 1)
date = time.strftime('%d %b %Y', time.gmtime(float(ts)))
- # XXX: sort changes (ebuilds should go by PV)
+ changed = [str(x) for x in sorted(changed)]
wroteheader = False
for c in changed:
def run(self):
repo_path = self._portdb.porttrees[0]
os.chdir(repo_path)
+
if 'git' not in FindVCS():
writemsg_level(
"ERROR: --update-changelogs supported only in git repos\n",
for cp in self._portdb.cp_all():
os.chdir(os.path.join(repo_path, cp))
-
# Determine whether ChangeLog is up-to-date by comparing
# the newest commit timestamp with the ChangeLog timestamp.
lmod = self.grab(['git', 'log', '--format=%ct', '-1', '.'])
+ if not lmod:
+ # This cp has not been added to the repo.
+ continue
+
try:
cmod = os.stat('ChangeLog').st_mtime
except OSError: